DevTools: [Audits] Roll Lighthouse to v3.0-beta

Bug: 772558, 846211
Change-Id: I4f74ea0d4a84908d2e7c4ccfe7035ee421bdf023
Reviewed-on: https://chromium-review.googlesource.com/1070532
Commit-Queue: Paul Irish <paulirish@chromium.org>
Reviewed-by: Pavel Feldman <pfeldman@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#561412}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: a745fe4457a6dda2ebca843cfbb9a9ec16563805
diff --git a/front_end/audits2/Audits2Controller.js b/front_end/audits2/Audits2Controller.js
index a33681c..2adb298 100644
--- a/front_end/audits2/Audits2Controller.js
+++ b/front_end/audits2/Audits2Controller.js
@@ -254,29 +254,50 @@
   },
   {
     setting: Common.settings.createSetting('audits2.throttling', 'default'),
-    description: ls`Apply network and CPU throttling during performance auditing`,
     setFlags: (flags, value) => {
-      flags.disableNetworkThrottling = value === 'off';
-      flags.disableCpuThrottling = value === 'off';
+  switch (value) {
+    case 'devtools':
+      flags.throttlingMethod = 'devtools';
+      break;
+    case 'off':
+      flags.throttlingMethod = 'provided';
+      break;
+    default:
+      flags.throttlingMethod = 'simulate';
+  }
     },
     options: [
-      {label: ls`Fast 3G with 4x CPU Slowdown`, value: 'default'},
-      {label: ls`No throttling`, value: 'off'},
+      {
+        label: ls`Simulated Fast 3G, 4x CPU Slowdown`,
+        value: 'default',
+        title: 'Throttling is simulated, resulting in faster audit runs with similar measurement accuracy'
+      },
+      {
+        label: ls`Applied Fast 3G, 4x CPU Slowdown`,
+        value: 'devtools',
+        title: 'Typical DevTools throttling, with actual traffic shaping and CPU slowdown applied'
+      },
+      {
+        label: ls`No throttling`,
+        value: 'off',
+        title: 'No network or CPU throttling used. (Useful when not evaluating performance)'
+      },
     ],
   },
   {
     setting: Common.settings.createSetting('audits2.clear_storage', true),
     title: ls`Clear storage`,
-    description: ls`Reset storage (localStorage, IndexedDB, etc) to a clean baseline before auditing`,
+    description: ls
+    `Reset storage (localStorage, IndexedDB, etc) before auditing. (Recommended for performance & PWA testing)`,
     setFlags: (flags, value) => {
       flags.disableStorageReset = !value;
     },
   },
 ];
 
-Audits2.Events = {
-  PageAuditabilityChanged: Symbol('PageAuditabilityChanged'),
-  AuditProgressChanged: Symbol('AuditProgressChanged'),
-  RequestAuditStart: Symbol('RequestAuditStart'),
-  RequestAuditCancel: Symbol('RequestAuditCancel'),
-};
\ No newline at end of file
+    Audits2.Events = {
+      PageAuditabilityChanged: Symbol('PageAuditabilityChanged'),
+      AuditProgressChanged: Symbol('AuditProgressChanged'),
+      RequestAuditStart: Symbol('RequestAuditStart'),
+      RequestAuditCancel: Symbol('RequestAuditCancel'),
+    };
diff --git a/front_end/audits2/Audits2Panel.js b/front_end/audits2/Audits2Panel.js
index bd9bf55..5b82bb9 100644
--- a/front_end/audits2/Audits2Panel.js
+++ b/front_end/audits2/Audits2Panel.js
@@ -116,8 +116,9 @@
 
   /**
    * @param {!ReportRenderer.ReportJSON} lighthouseResult
+   * @param {!ReportRenderer.RunnerResultArtifacts=} artifacts
    */
-  _renderReport(lighthouseResult) {
+  _renderReport(lighthouseResult, artifacts) {
     this.contentElement.classList.toggle('in-progress', false);
     this._startView.hideWidget();
     this._statusView.hide();
@@ -135,8 +136,7 @@
 
     const dom = new DOM(/** @type {!Document} */ (this._auditResultsElement.ownerDocument));
     const detailsRenderer = new Audits2.DetailsRenderer(dom);
-    const categoryRenderer = new Audits2.CategoryRenderer(dom, detailsRenderer);
-    categoryRenderer.setTraceArtifact(lighthouseResult);
+    const categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
     const renderer = new Audits2.ReportRenderer(dom, categoryRenderer);
 
     const templatesHTML = Runtime.cachedResources['audits2/lighthouse/templates.html'];
@@ -145,20 +145,22 @@
       return;
 
     renderer.setTemplateContext(templatesDOM);
-    renderer.renderReport(lighthouseResult, reportContainer);
+    const el = renderer.renderReport(lighthouseResult, reportContainer);
+    Audits2.ReportRenderer.addViewTraceButton(el, artifacts);
 
     this._cachedRenderedReports.set(lighthouseResult, reportContainer);
   }
 
   /**
    * @param {!ReportRenderer.ReportJSON} lighthouseResult
+   * @param {!ReportRenderer.RunnerResultArtifacts=} artifacts
    */
-  _buildReportUI(lighthouseResult) {
+  _buildReportUI(lighthouseResult, artifacts) {
     if (lighthouseResult === null)
       return;
 
     const optionElement = new Audits2.ReportSelector.Item(
-        lighthouseResult, () => this._renderReport(lighthouseResult), this._renderStartView.bind(this));
+        lighthouseResult, () => this._renderReport(lighthouseResult, artifacts), this._renderStartView.bind(this));
     this._reportSelector.prepend(optionElement);
     this._refreshToolbarUI();
     this._renderReport(lighthouseResult);
@@ -206,21 +208,21 @@
 
       this._renderStatusView(inspectedURL);
 
-      const lighthouseResult = await this._protocolService.startLighthouse(inspectedURL, categoryIDs, flags);
+      const lighthouseResponse = await this._protocolService.startLighthouse(inspectedURL, categoryIDs, flags);
 
-      if (lighthouseResult && lighthouseResult.fatal) {
-        const error = new Error(lighthouseResult.message);
-        error.stack = lighthouseResult.stack;
+      if (lighthouseResponse && lighthouseResponse.fatal) {
+        const error = new Error(lighthouseResponse.message);
+        error.stack = lighthouseResponse.stack;
         throw error;
       }
 
-      if (!lighthouseResult)
+      if (!lighthouseResponse)
         throw new Error('Auditing failed to produce a result');
 
       Host.userMetrics.actionTaken(Host.UserMetrics.Action.Audits2Finished);
 
       await this._resetEmulationAndProtocolConnection();
-      this._buildReportUI(lighthouseResult);
+      this._buildReportUI(lighthouseResponse.lhr, lighthouseResponse.artifacts);
     } catch (err) {
       if (err instanceof Error)
         this._statusView.renderBugReport(err);
diff --git a/front_end/audits2/Audits2ProtocolService.js b/front_end/audits2/Audits2ProtocolService.js
index 4c68a1f..99c2b81 100644
--- a/front_end/audits2/Audits2ProtocolService.js
+++ b/front_end/audits2/Audits2ProtocolService.js
@@ -28,7 +28,7 @@
    * @param {string} auditURL
    * @param {!Array<string>} categoryIDs
    * @param {!Object} flags
-   * @return {!Promise<!ReportRenderer.ReportJSON>}
+   * @return {!Promise<!ReportRenderer.RunnerResult>}
    */
   startLighthouse(auditURL, categoryIDs, flags) {
     return this._send('start', {url: auditURL, categoryIDs, flags});
@@ -80,7 +80,7 @@
   /**
    * @param {string} method
    * @param {!Object=} params
-   * @return {!Promise<!ReportRenderer.ReportJSON>}
+   * @return {!Promise<!ReportRenderer.RunnerResult>}
    */
   _send(method, params) {
     if (!this._backendPromise)
diff --git a/front_end/audits2/Audits2ReportRenderer.js b/front_end/audits2/Audits2ReportRenderer.js
index 0460011..62581c6 100644
--- a/front_end/audits2/Audits2ReportRenderer.js
+++ b/front_end/audits2/Audits2ReportRenderer.js
@@ -7,21 +7,22 @@
  */
 Audits2.ReportRenderer = class extends ReportRenderer {
   /**
-   * Provides empty element for left nav
-   * @override
-   * @returns {!DocumentFragment}
+   * @param {!Element} el Parent element to render the report into.
+   * @param {!ReportRenderer.RunnerResultArtifacts=} artifacts
    */
-  _renderReportNav() {
-    return createDocumentFragment();
-  }
+  static addViewTraceButton(el, artifacts) {
+    if (!artifacts || !artifacts.traces || !artifacts.traces.defaultPass)
+      return;
 
-  /**
-   * @param {!ReportRenderer.ReportJSON} report
-   * @override
-   * @return {!DocumentFragment}
-   */
-  _renderReportHeader(report) {
-    return createDocumentFragment();
+    const defaultPassTrace = artifacts.traces.defaultPass;
+    const timelineButton = UI.createTextButton(Common.UIString('View Trace'), onViewTraceClick, 'view-trace');
+    el.querySelector('.lh-metric-column').appendChild(timelineButton);
+    return el;
+
+    async function onViewTraceClick() {
+      await UI.inspectorView.showPanel('timeline');
+      Timeline.TimelinePanel.instance().loadFromEvents(defaultPassTrace.traceEvents);
+    }
   }
 };
 
@@ -33,48 +34,6 @@
   }
 }
 
-Audits2.CategoryRenderer = class extends CategoryRenderer {
-  /**
-   * @override
-   * @param {!DOM} dom
-   * @param {!DetailsRenderer} detailsRenderer
-   */
-  constructor(dom, detailsRenderer) {
-    super(dom, detailsRenderer);
-    this._defaultPassTrace = null;
-  }
-
-  /**
-   * @param {!ReportRenderer.ReportJSON} lhr
-   */
-  setTraceArtifact(lhr) {
-    if (!lhr.artifacts || !lhr.artifacts.traces || !lhr.artifacts.traces.defaultPass)
-      return;
-    this._defaultPassTrace = lhr.artifacts.traces.defaultPass;
-  }
-
-  /**
-   * @override
-   * @param {!ReportRenderer.CategoryJSON} category
-   * @param {!Object<string, !ReportRenderer.GroupJSON>} groups
-   * @return {!Element}
-   */
-  renderPerformanceCategory(category, groups) {
-    const defaultPassTrace = this._defaultPassTrace;
-    const element = super.renderPerformanceCategory(category, groups);
-    if (!defaultPassTrace)
-      return element;
-
-    const timelineButton = UI.createTextButton(Common.UIString('View Trace'), onViewTraceClick, 'view-trace');
-    element.querySelector('.lh-audit-group').prepend(timelineButton);
-    return element;
-
-    async function onViewTraceClick() {
-      await UI.inspectorView.showPanel('timeline');
-      Timeline.TimelinePanel.instance().loadFromEvents(defaultPassTrace.traceEvents);
-    }
-  }
-};
 
 Audits2.DetailsRenderer = class extends DetailsRenderer {
   /**
diff --git a/front_end/audits2/Audits2ReportSelector.js b/front_end/audits2/Audits2ReportSelector.js
index fda21c7..59261aa 100644
--- a/front_end/audits2/Audits2ReportSelector.js
+++ b/front_end/audits2/Audits2ReportSelector.js
@@ -111,8 +111,8 @@
     this._renderReport = renderReport;
     this._showLandingCallback = showLandingCallback;
 
-    const url = new Common.ParsedURL(lighthouseResult.url);
-    const timestamp = lighthouseResult.generatedTime;
+    const url = new Common.ParsedURL(lighthouseResult.finalUrl);
+    const timestamp = lighthouseResult.fetchTime;
     this._element = createElement('option');
     this._element.label = `${new Date(timestamp).toLocaleTimeString()} - ${url.domain()}`;
   }
@@ -135,9 +135,9 @@
   }
 
   download() {
-    const url = new Common.ParsedURL(this._lighthouseResult.url).domain();
-    const timestamp = this._lighthouseResult.generatedTime;
+    const url = new Common.ParsedURL(this._lighthouseResult.finalUrl).domain();
+    const timestamp = this._lighthouseResult.fetchTime;
     const fileName = `${url}-${new Date(timestamp).toISO8601Compact()}.json`;
     Workspace.fileManager.save(fileName, JSON.stringify(this._lighthouseResult), true);
   }
-};
\ No newline at end of file
+};
diff --git a/front_end/audits2/RadioSetting.js b/front_end/audits2/RadioSetting.js
index 15a146e..805b337 100644
--- a/front_end/audits2/RadioSetting.js
+++ b/front_end/audits2/RadioSetting.js
@@ -16,13 +16,15 @@
     this._radioElements = [];
     for (const option of this._options) {
       const fragment = UI.Fragment.build`
-        <label class="audits2-radio">
+        <label $="label" class="audits2-radio">
           <input $="input" type="radio" value=${option.value} name=${setting.name}>
           ${option.label}
         </label>
       `;
 
       this.element.appendChild(fragment.element());
+      if (option.title)
+        UI.Tooltip.install(fragment.$('label'), option.title);
       const radioElement = fragment.$('input');
       radioElement.addEventListener('change', this._valueChanged.bind(this));
       this._radioElements.push(radioElement);
@@ -57,4 +59,4 @@
     const selectedRadio = this._radioElements.find(radio => radio.checked);
     this._setting.set(selectedRadio.value);
   }
-};
\ No newline at end of file
+};
diff --git a/front_end/audits2/audits2Panel.css b/front_end/audits2/audits2Panel.css
index 01305bb..b1e84b9 100644
--- a/front_end/audits2/audits2Panel.css
+++ b/front_end/audits2/audits2Panel.css
@@ -40,8 +40,7 @@
   position: relative;
 }
 button.view-trace {
-  position: absolute;
-  right: 0;
+  margin: 10px;
 }
 
 .audits2-results-container {
diff --git a/front_end/audits2/lighthouse/renderer/category-renderer.js b/front_end/audits2/lighthouse/renderer/category-renderer.js
index c361200..1646e6e 100644
--- a/front_end/audits2/lighthouse/renderer/category-renderer.js
+++ b/front_end/audits2/lighthouse/renderer/category-renderer.js
@@ -7,233 +7,185 @@
 
 /* globals self, Util */
 
+/** @typedef {import('./dom.js')} DOM */
+/** @typedef {import('./report-renderer.js')} ReportRenderer */
+/** @typedef {import('./report-renderer.js').AuditJSON} AuditJSON */
+/** @typedef {import('./report-renderer.js').CategoryJSON} CategoryJSON */
+/** @typedef {import('./report-renderer.js').GroupJSON} GroupJSON */
+/** @typedef {import('./details-renderer.js')} DetailsRenderer */
+/** @typedef {import('./util.js')} Util */
+
 class CategoryRenderer {
   /**
-   * @param {!DOM} dom
-   * @param {!DetailsRenderer} detailsRenderer
+   * @param {DOM} dom
+   * @param {DetailsRenderer} detailsRenderer
    */
   constructor(dom, detailsRenderer) {
-    /** @private {!DOM} */
-    this._dom = dom;
-    /** @private {!DetailsRenderer} */
-    this._detailsRenderer = detailsRenderer;
-    /** @private {!Document|!Element} */
-    this._templateContext = this._dom.document();
+    /** @type {DOM} */
+    this.dom = dom;
+    /** @type {DetailsRenderer} */
+    this.detailsRenderer = detailsRenderer;
+    /** @type {ParentNode} */
+    this.templateContext = this.dom.document();
 
-    this._detailsRenderer.setTemplateContext(this._templateContext);
+    this.detailsRenderer.setTemplateContext(this.templateContext);
   }
 
   /**
-   * @param {!ReportRenderer.AuditJSON} audit
-   * @return {!Element}
+   * @param {AuditJSON} audit
+   * @param {number} index
+   * @return {Element}
    */
-  _renderAuditScore(audit) {
-    const tmpl = this._dom.cloneTemplate('#tmpl-lh-audit-score', this._templateContext);
+  renderAudit(audit, index) {
+    const tmpl = this.dom.cloneTemplate('#tmpl-lh-audit', this.templateContext);
+    return this.populateAuditValues(audit, index, tmpl);
+  }
 
-    const scoringMode = audit.result.scoringMode;
-    const description = audit.result.helpText;
-    let title = audit.result.description;
+  /**
+   * Populate an DOM tree with audit details. Used by renderAudit and renderOpportunity
+   * @param {AuditJSON} audit
+   * @param {number} index
+   * @param {DocumentFragment} tmpl
+   * @return {Element}
+   */
+  populateAuditValues(audit, index, tmpl) {
+    const auditEl = this.dom.find('.lh-audit', tmpl);
+    auditEl.id = audit.result.id;
+    const scoreDisplayMode = audit.result.scoreDisplayMode;
 
     if (audit.result.displayValue) {
-      title += `:  ${audit.result.displayValue}`;
+      const displayValue = Util.formatDisplayValue(audit.result.displayValue);
+      this.dom.find('.lh-audit__display-text', auditEl).textContent = displayValue;
     }
 
-    if (audit.result.debugString) {
-      const debugStrEl = tmpl.appendChild(this._dom.createElement('div', 'lh-debug'));
-      debugStrEl.textContent = audit.result.debugString;
-    }
+    const titleEl = this.dom.find('.lh-audit__title', auditEl);
+    titleEl.appendChild(this.dom.convertMarkdownCodeSnippets(audit.result.title));
+    this.dom.find('.lh-audit__description', auditEl)
+        .appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.description));
 
-    // Append audit details to header section so the entire audit is within a <details>.
-    const header = /** @type {!HTMLDetailsElement} */ (this._dom.find('.lh-score__header', tmpl));
-    if (audit.result.details) {
-      header.appendChild(this._detailsRenderer.render(audit.result.details));
+    const header = /** @type {HTMLDetailsElement} */ (this.dom.find('details', auditEl));
+    if (audit.result.details && audit.result.details.type) {
+      const elem = this.detailsRenderer.render(audit.result.details);
+      elem.classList.add('lh-details');
+      header.appendChild(elem);
     }
+    this.dom.find('.lh-audit__index', auditEl).textContent = `${index + 1}`;
 
-    const scoreEl = this._dom.find('.lh-score', tmpl);
-    if (audit.result.informative) {
-      scoreEl.classList.add('lh-score--informative');
-    }
-    if (audit.result.manual) {
-      scoreEl.classList.add('lh-score--manual');
-    }
+    // Add chevron SVG to the end of the summary
+    this.dom.find('.lh-chevron-container', auditEl).appendChild(this._createChevron());
+    this._setRatingClass(auditEl, audit.result.score, scoreDisplayMode);
 
-    return this._populateScore(tmpl, audit.score, scoringMode, title, description);
+    if (audit.result.scoreDisplayMode === 'error') {
+      auditEl.classList.add(`lh-audit--error`);
+      const textEl = this.dom.find('.lh-audit__display-text', auditEl);
+      textEl.textContent = 'Error!';
+      textEl.classList.add('tooltip-boundary');
+      const tooltip = this.dom.createChildOf(textEl, 'div', 'tooltip tooltip--error');
+      tooltip.textContent = audit.result.errorMessage || 'Report error: no audit information';
+    } else if (audit.result.explanation) {
+      const explEl = this.dom.createChildOf(titleEl, 'div', 'lh-audit-explanation');
+      explEl.textContent = audit.result.explanation;
+    }
+    const warnings = audit.result.warnings;
+    if (!warnings || warnings.length === 0) return auditEl;
+
+    // Add list of warnings or singular warning
+    const warningsEl = this.dom.createChildOf(titleEl, 'div', 'lh-warnings');
+    if (warnings.length === 1) {
+      warningsEl.textContent = `Warning: ${warnings.join('')}`;
+    } else {
+      warningsEl.textContent = 'Warnings: ';
+      const warningsUl = this.dom.createChildOf(warningsEl, 'ul');
+      for (const warning of warnings) {
+        const item = this.dom.createChildOf(warningsUl, 'li');
+        item.textContent = warning;
+      }
+    }
+    return auditEl;
   }
 
   /**
-   * @param {!DocumentFragment|!Element} element DOM node to populate with values.
-   * @param {number} score
-   * @param {string} scoringMode
-   * @param {string} title
-   * @param {string} description
-   * @return {!Element}
+   * @return {!HTMLElement}
    */
-  _populateScore(element, score, scoringMode, title, description) {
-    // Fill in the blanks.
-    const valueEl = this._dom.find('.lh-score__value', element);
-    valueEl.textContent = Util.formatNumber(score);
-    valueEl.classList.add(`lh-score__value--${Util.calculateRating(score)}`,
-        `lh-score__value--${scoringMode}`);
-
-    this._dom.find('.lh-score__title', element).appendChild(
-        this._dom.convertMarkdownCodeSnippets(title));
-    this._dom.find('.lh-score__description', element)
-        .appendChild(this._dom.convertMarkdownLinkSnippets(description));
-
-    return /** @type {!Element} **/ (element);
+  _createChevron() {
+    const chevronTmpl = this.dom.cloneTemplate('#tmpl-lh-chevron', this.templateContext);
+    const chevronEl = this.dom.find('.lh-chevron', chevronTmpl);
+    return chevronEl;
   }
 
   /**
-   * @param {!ReportRenderer.CategoryJSON} category
-   * @return {!Element}
+   * @param {!Element} element DOM node to populate with values.
+   * @param {number|null} score
+   * @param {string} scoreDisplayMode
+   * @return {Element}
    */
-  _renderCategoryScore(category) {
-    const tmpl = this._dom.cloneTemplate('#tmpl-lh-category-score', this._templateContext);
-    const score = Math.round(category.score);
+  _setRatingClass(element, score, scoreDisplayMode) {
+    const rating = Util.calculateRating(score, scoreDisplayMode);
+    element.classList.add(`lh-audit--${rating}`, `lh-audit--${scoreDisplayMode}`);
+    return element;
+  }
 
-    const gaugeContainerEl = this._dom.find('.lh-score__gauge', tmpl);
+  /**
+   * @param {CategoryJSON} category
+   * @return {Element}
+   */
+  renderCategoryHeader(category) {
+    const tmpl = this.dom.cloneTemplate('#tmpl-lh-category-header', this.templateContext);
+
+    const gaugeContainerEl = this.dom.find('.lh-score__gauge', tmpl);
     const gaugeEl = this.renderScoreGauge(category);
     gaugeContainerEl.appendChild(gaugeEl);
 
-    return this._populateScore(tmpl, score, 'numeric', category.name, category.description);
-  }
-
-  /**
-   * @param {!ReportRenderer.AuditJSON} audit
-   * @return {!Element}
-   */
-  _renderAudit(audit) {
-    const element = this._dom.createElement('div', 'lh-audit');
-    element.appendChild(this._renderAuditScore(audit));
-    return element;
-  }
-
-  /**
-   * @param {!ReportRenderer.AuditJSON} audit
-   * @param {number} scale
-   * @return {!Element}
-   */
-  _renderTimelineMetricAudit(audit, scale) {
-    const tmpl = this._dom.cloneTemplate('#tmpl-lh-timeline-metric', this._templateContext);
-    const element = this._dom.find('.lh-timeline-metric', tmpl);
-    element.classList.add(`lh-timeline-metric--${Util.calculateRating(audit.score)}`);
-
-    const titleEl = this._dom.find('.lh-timeline-metric__title', tmpl);
-    titleEl.textContent = audit.result.description;
-
-    const valueEl = this._dom.find('.lh-timeline-metric__value', tmpl);
-    valueEl.textContent = audit.result.displayValue;
-
-    const descriptionEl = this._dom.find('.lh-timeline-metric__description', tmpl);
-    descriptionEl.appendChild(this._dom.convertMarkdownLinkSnippets(audit.result.helpText));
-
-    if (typeof audit.result.rawValue !== 'number') {
-      const debugStrEl = this._dom.createChildOf(element, 'div', 'lh-debug');
-      debugStrEl.textContent = audit.result.debugString || 'Report error: no metric information';
-      return element;
+    this.dom.find('.lh-category-header__title', tmpl).appendChild(
+      this.dom.convertMarkdownCodeSnippets(category.title));
+    if (category.description) {
+      const descEl = this.dom.convertMarkdownLinkSnippets(category.description);
+      this.dom.find('.lh-category-header__description', tmpl).appendChild(descEl);
     }
 
-    const sparklineBarEl = this._dom.find('.lh-sparkline__bar', tmpl);
-    sparklineBarEl.style.width = `${audit.result.rawValue / scale * 100}%`;
-
-    return element;
-  }
-
-  /**
-   * @param {!ReportRenderer.AuditJSON} audit
-   * @param {number} scale
-   * @return {!Element}
-   */
-  _renderPerfHintAudit(audit, scale) {
-    const extendedInfo = /** @type {!CategoryRenderer.PerfHintExtendedInfo}
-        */ (audit.result.extendedInfo);
-    const tooltipAttrs = {title: audit.result.displayValue};
-
-    const element = this._dom.createElement('details', [
-      'lh-perf-hint',
-      `lh-perf-hint--${Util.calculateRating(audit.score)}`,
-      'lh-expandable-details',
-    ].join(' '));
-
-    const summary = this._dom.createChildOf(element, 'summary', 'lh-perf-hint__summary ' +
-        'lh-expandable-details__summary');
-    const titleEl = this._dom.createChildOf(summary, 'div', 'lh-perf-hint__title');
-    titleEl.textContent = audit.result.description;
-
-    this._dom.createChildOf(summary, 'div', 'lh-toggle-arrow', {title: 'See resources'});
-
-    if (!extendedInfo || typeof audit.result.rawValue !== 'number') {
-      const debugStrEl = this._dom.createChildOf(summary, 'div', 'lh-debug');
-      debugStrEl.textContent = audit.result.debugString || 'Report error: no extended information';
-      return element;
-    }
-
-    const sparklineContainerEl = this._dom.createChildOf(summary, 'div', 'lh-perf-hint__sparkline',
-        tooltipAttrs);
-    const sparklineEl = this._dom.createChildOf(sparklineContainerEl, 'div', 'lh-sparkline');
-    const sparklineBarEl = this._dom.createChildOf(sparklineEl, 'div', 'lh-sparkline__bar');
-    sparklineBarEl.style.width = audit.result.rawValue / scale * 100 + '%';
-
-    const statsEl = this._dom.createChildOf(summary, 'div', 'lh-perf-hint__stats', tooltipAttrs);
-    const statsMsEl = this._dom.createChildOf(statsEl, 'div', 'lh-perf-hint__primary-stat');
-    statsMsEl.textContent = Util.formatMilliseconds(audit.result.rawValue);
-
-    if (extendedInfo.value.wastedKb) {
-      const statsKbEl = this._dom.createChildOf(statsEl, 'div', 'lh-perf-hint__secondary-stat');
-      statsKbEl.textContent = Util.formatNumber(extendedInfo.value.wastedKb) + ' KB';
-    }
-
-    const descriptionEl = this._dom.createChildOf(element, 'div', 'lh-perf-hint__description');
-    descriptionEl.appendChild(this._dom.convertMarkdownLinkSnippets(audit.result.helpText));
-
-    if (audit.result.debugString) {
-      const debugStrEl = this._dom.createChildOf(summary, 'div', 'lh-debug');
-      debugStrEl.textContent = audit.result.debugString;
-    }
-
-    if (audit.result.details) {
-      element.appendChild(this._detailsRenderer.render(audit.result.details));
-    }
-
-    return element;
+    return /** @type {Element} */ (tmpl.firstElementChild);
   }
 
   /**
    * Renders the group container for a group of audits. Individual audit elements can be added
    * directly to the returned element.
-   * @param {!ReportRenderer.GroupJSON} group
-   * @param {{expandable: boolean}} opts
-   * @return {!Element}
+   * @param {GroupJSON} group
+   * @param {{expandable: boolean, itemCount?: number}} opts
+   * @return {Element}
    */
-  _renderAuditGroup(group, opts) {
+  renderAuditGroup(group, opts) {
     const expandable = opts.expandable;
-    const element = this._dom.createElement(expandable ? 'details' : 'div', 'lh-audit-group');
-    const summmaryEl = this._dom.createChildOf(element, 'summary', 'lh-audit-group__summary');
-    const headerEl = this._dom.createChildOf(summmaryEl, 'div', 'lh-audit-group__header');
-    this._dom.createChildOf(summmaryEl, 'div',
-      `lh-toggle-arrow  ${expandable ? '' : ' lh-toggle-arrow-unexpandable'}`, {
-        title: 'See audits',
-      });
+    const groupEl = this.dom.createElement(expandable ? 'details' : 'div', 'lh-audit-group');
+    const summmaryEl = this.dom.createChildOf(groupEl, 'summary', 'lh-audit-group__summary');
+    const headerEl = this.dom.createChildOf(summmaryEl, 'div', 'lh-audit-group__header');
+    const itemCountEl = this.dom.createChildOf(summmaryEl, 'div', 'lh-audit-group__itemcount');
+    if (expandable) {
+      const chevronEl = summmaryEl.appendChild(this._createChevron());
+      chevronEl.title = 'Show audits';
+    }
 
     if (group.description) {
-      const auditGroupDescription = this._dom.createElement('div', 'lh-audit-group__description');
-      auditGroupDescription.appendChild(this._dom.convertMarkdownLinkSnippets(group.description));
-      element.appendChild(auditGroupDescription);
+      const auditGroupDescription = this.dom.createElement('div', 'lh-audit-group__description');
+      auditGroupDescription.appendChild(this.dom.convertMarkdownLinkSnippets(group.description));
+      groupEl.appendChild(auditGroupDescription);
     }
     headerEl.textContent = group.title;
 
-    return element;
+    if (opts.itemCount) {
+      itemCountEl.textContent = `${opts.itemCount} audits`;
+    }
+    return groupEl;
   }
 
   /**
    * Find the total number of audits contained within a section.
    * Accounts for nested subsections like Accessibility.
-   * @param {!Array<!Element>} elements
+   * @param {Array<Element>} elements
    * @return {number}
    */
   _getTotalAuditsLength(elements) {
     // Create a scratch element to append sections to so we can reuse querySelectorAll().
-    const scratch = this._dom.createElement('div');
+    const scratch = this.dom.createElement('div');
     elements.forEach(function(element) {
       scratch.appendChild(element);
     });
@@ -246,283 +198,193 @@
   }
 
   /**
-   * @param {!Array<!Element>} elements
-   * @return {!Element}
+   * @param {Array<Element>} elements
+   * @return {Element}
    */
-  _renderPassedAuditsSection(elements) {
-    const passedElem = this._renderAuditGroup({
-      title: `${this._getTotalAuditsLength(elements)} Passed Audits`,
-    }, {expandable: true});
+  _renderFailedAuditsSection(elements) {
+    const failedElem = this.dom.createElement('div');
+    failedElem.classList.add('lh-failed-audits');
+    elements.forEach(elem => failedElem.appendChild(elem));
+    return failedElem;
+  }
+
+  /**
+   * @param {Array<Element>} elements
+   * @return {Element}
+   */
+  renderPassedAuditsSection(elements) {
+    const passedElem = this.renderAuditGroup({
+      title: `Passed audits`,
+    }, {expandable: true, itemCount: this._getTotalAuditsLength(elements)});
     passedElem.classList.add('lh-passed-audits');
     elements.forEach(elem => passedElem.appendChild(elem));
     return passedElem;
   }
 
   /**
-   * @param {!Array<!Element>} elements
-   * @return {!Element}
+   * @param {Array<Element>} elements
+   * @return {Element}
    */
   _renderNotApplicableAuditsSection(elements) {
-    const notApplicableElem = this._renderAuditGroup({
-      title: `${this._getTotalAuditsLength(elements)} Not Applicable Audits`,
-    }, {expandable: true});
-    notApplicableElem.classList.add('lh-audit-group--notapplicable');
+    const notApplicableElem = this.renderAuditGroup({
+      title: `Not applicable`,
+    }, {expandable: true, itemCount: this._getTotalAuditsLength(elements)});
+    notApplicableElem.classList.add('lh-audit-group--not-applicable');
     elements.forEach(elem => notApplicableElem.appendChild(elem));
     return notApplicableElem;
   }
 
   /**
-   * @param {!Array<!ReportRenderer.AuditJSON>} manualAudits
-   * @param {!Object<string, !ReportRenderer.GroupJSON>} groupDefinitions
-   * @param {!Element} element Parent container to add the manual audits to.
+   * @param {Array<AuditJSON>} manualAudits
+   * @param {string} manualDescription
+   * @return {Element}
    */
-  _renderManualAudits(manualAudits, groupDefinitions, element) {
-    const auditsGroupedByGroup = /** @type {!Object<string,
-        !Array<!ReportRenderer.AuditJSON>>} */ ({});
-    manualAudits.forEach(audit => {
-      const group = auditsGroupedByGroup[audit.group] || [];
-      group.push(audit);
-      auditsGroupedByGroup[audit.group] = group;
+  _renderManualAudits(manualAudits, manualDescription) {
+    const group = {title: 'Additional items to manually check', description: manualDescription};
+    const auditGroupElem = this.renderAuditGroup(group,
+        {expandable: true, itemCount: manualAudits.length});
+    auditGroupElem.classList.add('lh-audit-group--manual');
+    manualAudits.forEach((audit, i) => {
+      auditGroupElem.appendChild(this.renderAudit(audit, i));
     });
-
-    Object.keys(auditsGroupedByGroup).forEach(groupId => {
-      const group = groupDefinitions[groupId];
-      const auditGroupElem = this._renderAuditGroup(group, {expandable: true});
-      auditGroupElem.classList.add('lh-audit-group--manual');
-
-      auditsGroupedByGroup[groupId].forEach(audit => {
-        auditGroupElem.appendChild(this._renderAudit(audit));
-      });
-
-      element.appendChild(auditGroupElem);
-    });
+    return auditGroupElem;
   }
 
   /**
-   * @param {!Document|!Element} context
+   * @param {ParentNode} context
    */
   setTemplateContext(context) {
-    this._templateContext = context;
-    this._detailsRenderer.setTemplateContext(context);
+    this.templateContext = context;
+    this.detailsRenderer.setTemplateContext(context);
   }
 
   /**
-   * @param {!ReportRenderer.CategoryJSON} category
-   * @return {!DocumentFragment}
+   * @param {CategoryJSON} category
+   * @return {DocumentFragment}
    */
   renderScoreGauge(category) {
-    const tmpl = this._dom.cloneTemplate('#tmpl-lh-gauge', this._templateContext);
-    this._dom.find('.lh-gauge__wrapper', tmpl).href = `#${category.id}`;
-    this._dom.find('.lh-gauge__label', tmpl).textContent = category.name;
+    const tmpl = this.dom.cloneTemplate('#tmpl-lh-gauge', this.templateContext);
+    const wrapper = /** @type {HTMLAnchorElement} */ (this.dom.find('.lh-gauge__wrapper', tmpl));
+    wrapper.href = `#${category.id}`;
+    wrapper.classList.add(`lh-gauge__wrapper--${Util.calculateRating(category.score)}`);
 
-    const score = Math.round(category.score);
-    const fillRotation = Math.floor((score / 100) * 180);
+    // Cast `null` to 0
+    const numericScore = Number(category.score);
+    const gauge = this.dom.find('.lh-gauge', tmpl);
+    // 329 is ~= 2 * Math.PI * gauge radius (53)
+    // https://codepen.io/xgad/post/svg-radial-progress-meters
+    // score of 50: `stroke-dasharray: 164.5 329`;
+    /** @type {?SVGCircleElement} */
+    const gaugeArc = gauge.querySelector('.lh-gauge-arc');
+    if (gaugeArc) {
+      gaugeArc.style.strokeDasharray = `${numericScore * 329} 329`;
+    }
 
-    const gauge = this._dom.find('.lh-gauge', tmpl);
-    gauge.setAttribute('data-progress', score); // .dataset not supported in jsdom.
-    gauge.classList.add(`lh-gauge--${Util.calculateRating(score)}`);
+    const scoreOutOf100 = Math.round(numericScore * 100);
+    const percentageEl = this.dom.find('.lh-gauge__percentage', tmpl);
+    percentageEl.textContent = scoreOutOf100.toString();
+    if (category.score === null) {
+      percentageEl.textContent = '?';
+      percentageEl.title = 'Errors occurred while auditing';
+    }
 
-    this._dom.findAll('.lh-gauge__fill', gauge).forEach(el => {
-      el.style.transform = `rotate(${fillRotation}deg)`;
-    });
-
-    this._dom.find('.lh-gauge__mask--full', gauge).style.transform =
-        `rotate(${fillRotation}deg)`;
-    this._dom.find('.lh-gauge__fill--fix', gauge).style.transform =
-        `rotate(${fillRotation * 2}deg)`;
-    this._dom.find('.lh-gauge__percentage', gauge).textContent = score;
-
+    this.dom.find('.lh-gauge__label', tmpl).textContent = category.title;
     return tmpl;
   }
 
   /**
-   * @param {!ReportRenderer.CategoryJSON} category
-   * @param {!Object<string, !ReportRenderer.GroupJSON>} groups
-   * @return {!Element}
+   * @param {CategoryJSON} category
+   * @param {Object<string, GroupJSON>} groupDefinitions
+   * @return {Element}
    */
-  render(category, groups) {
-    switch (category.id) {
-      case 'performance':
-        return this.renderPerformanceCategory(category, groups);
-      case 'accessibility':
-        return this._renderAccessibilityCategory(category, groups);
-      default:
-        return this._renderDefaultCategory(category, groups);
-    }
-  }
+  render(category, groupDefinitions) {
+    const element = this.dom.createElement('div', 'lh-category');
+    this.createPermalinkSpan(element, category.id);
+    element.appendChild(this.renderCategoryHeader(category));
 
-  /**
-   * @param {!ReportRenderer.CategoryJSON} category
-   * @param {!Object<string, !ReportRenderer.GroupJSON>} groupDefinitions
-   * @return {!Element}
-   */
-  _renderDefaultCategory(category, groupDefinitions) {
-    const element = this._dom.createElement('div', 'lh-category');
-    this._createPermalinkSpan(element, category.id);
-    element.appendChild(this._renderCategoryScore(category));
+    const auditRefs = category.auditRefs;
+    const manualAudits = auditRefs.filter(audit => audit.result.scoreDisplayMode === 'manual');
+    const nonManualAudits = auditRefs.filter(audit => !manualAudits.includes(audit));
 
-    const manualAudits = category.audits.filter(audit => audit.result.manual);
-    const nonManualAudits = category.audits.filter(audit => !manualAudits.includes(audit));
-    const passedAudits = nonManualAudits.filter(audit => audit.score === 100 &&
-        !audit.result.debugString);
-    const nonPassedAudits = nonManualAudits.filter(audit => !passedAudits.includes(audit));
+    /** @type {Object<string, {passed: Array<AuditJSON>, failed: Array<AuditJSON>, notApplicable: Array<AuditJSON>}>} */
+    const auditsGroupedByGroup = {};
+    const auditsUngrouped = {passed: [], failed: [], notApplicable: []};
 
-    const nonPassedElem = this._renderAuditGroup({
-      title: `${nonPassedAudits.length} Failed Audits`,
-    }, {expandable: false});
-    nonPassedElem.classList.add('lh-failed-audits');
-    nonPassedAudits.forEach(audit => nonPassedElem.appendChild(this._renderAudit(audit)));
-    element.appendChild(nonPassedElem);
+    nonManualAudits.forEach(auditRef => {
+      let group;
 
-    // Create a passed section if there are passing audits.
-    if (passedAudits.length) {
-      const passedElem = this._renderPassedAuditsSection(
-        passedAudits.map(audit => this._renderAudit(audit))
-      );
-      element.appendChild(passedElem);
-    }
+      if (auditRef.group) {
+        const groupId = auditRef.group;
 
-    // Render manual audits after passing.
-    this._renderManualAudits(manualAudits, groupDefinitions, element);
-
-    return element;
-  }
-
-  /**
-   * @param {!ReportRenderer.CategoryJSON} category
-   * @param {!Object<string, !ReportRenderer.GroupJSON>} groups
-   * @return {!Element}
-   */
-  renderPerformanceCategory(category, groups) {
-    const element = this._dom.createElement('div', 'lh-category');
-    this._createPermalinkSpan(element, category.id);
-    element.appendChild(this._renderCategoryScore(category));
-
-    const metricAudits = category.audits.filter(audit => audit.group === 'perf-metric');
-    const metricAuditsEl = this._renderAuditGroup(groups['perf-metric'], {expandable: false});
-    const timelineContainerEl = this._dom.createChildOf(metricAuditsEl, 'div',
-        'lh-timeline-container');
-    const timelineEl = this._dom.createChildOf(timelineContainerEl, 'div', 'lh-timeline');
-
-    let perfTimelineScale = 0;
-    metricAudits.forEach(audit => {
-      if (typeof audit.result.rawValue === 'number' && audit.result.rawValue) {
-        perfTimelineScale = Math.max(perfTimelineScale, audit.result.rawValue);
-      }
-    });
-
-    const thumbnailAudit = category.audits.find(audit => audit.id === 'screenshot-thumbnails');
-    const thumbnailResult = thumbnailAudit && thumbnailAudit.result;
-    if (thumbnailResult && thumbnailResult.details) {
-      const thumbnailDetails = /** @type {!DetailsRenderer.FilmstripDetails} */
-          (thumbnailResult.details);
-      perfTimelineScale = Math.max(perfTimelineScale, thumbnailDetails.scale);
-      const filmstripEl = this._detailsRenderer.render(thumbnailDetails);
-      timelineEl.appendChild(filmstripEl);
-    }
-
-    metricAudits.forEach(item => {
-      if (item.id === 'speed-index-metric' || item.id === 'estimated-input-latency') {
-        return metricAuditsEl.appendChild(this._renderAudit(item));
-      }
-
-      timelineEl.appendChild(this._renderTimelineMetricAudit(item, perfTimelineScale));
-    });
-
-    metricAuditsEl.open = true;
-    element.appendChild(metricAuditsEl);
-
-    const hintAudits = category.audits
-        .filter(audit => audit.group === 'perf-hint' && audit.score < 100)
-        .sort((auditA, auditB) => auditB.result.rawValue - auditA.result.rawValue);
-    if (hintAudits.length) {
-      const maxWaste = Math.max(...hintAudits.map(audit => audit.result.rawValue));
-      const scale = Math.ceil(maxWaste / 1000) * 1000;
-      const hintAuditsEl = this._renderAuditGroup(groups['perf-hint'], {expandable: false});
-      hintAudits.forEach(item => hintAuditsEl.appendChild(this._renderPerfHintAudit(item, scale)));
-      hintAuditsEl.open = true;
-      element.appendChild(hintAuditsEl);
-    }
-
-    const infoAudits = category.audits
-        .filter(audit => audit.group === 'perf-info' && audit.score < 100);
-    if (infoAudits.length) {
-      const infoAuditsEl = this._renderAuditGroup(groups['perf-info'], {expandable: false});
-      infoAudits.forEach(item => infoAuditsEl.appendChild(this._renderAudit(item)));
-      infoAuditsEl.open = true;
-      element.appendChild(infoAuditsEl);
-    }
-
-    const passedElements = category.audits
-        .filter(audit => (audit.group === 'perf-hint' || audit.group === 'perf-info') &&
-            audit.score === 100)
-        .map(audit => this._renderAudit(audit));
-
-    if (!passedElements.length) return element;
-
-    const passedElem = this._renderPassedAuditsSection(passedElements);
-    element.appendChild(passedElem);
-    return element;
-  }
-
-  /**
-   * @param {!ReportRenderer.CategoryJSON} category
-   * @param {!Object<string, !ReportRenderer.GroupJSON>} groupDefinitions
-   * @return {!Element}
-   */
-  _renderAccessibilityCategory(category, groupDefinitions) {
-    const element = this._dom.createElement('div', 'lh-category');
-    this._createPermalinkSpan(element, category.id);
-    element.appendChild(this._renderCategoryScore(category));
-
-    const manualAudits = category.audits.filter(audit => audit.result.manual);
-    const nonManualAudits = category.audits.filter(audit => !manualAudits.includes(audit));
-    const auditsGroupedByGroup = /** @type {!Object<string,
-        {passed: !Array<!ReportRenderer.AuditJSON>,
-        failed: !Array<!ReportRenderer.AuditJSON>,
-        notApplicable: !Array<!ReportRenderer.AuditJSON>}>} */ ({});
-    nonManualAudits.forEach(audit => {
-      const groupId = audit.group;
-      const groups = auditsGroupedByGroup[groupId] || {passed: [], failed: [], notApplicable: []};
-
-      if (audit.result.notApplicable) {
-        groups.notApplicable.push(audit);
-      } else if (audit.score === 100) {
-        groups.passed.push(audit);
+        if (auditsGroupedByGroup[groupId]) {
+          group = auditsGroupedByGroup[groupId];
+        } else {
+          group = {passed: [], failed: [], notApplicable: []};
+          auditsGroupedByGroup[groupId] = group;
+        }
       } else {
-        groups.failed.push(audit);
+        group = auditsUngrouped;
       }
 
-      auditsGroupedByGroup[groupId] = groups;
+      if (auditRef.result.scoreDisplayMode === 'not-applicable') {
+        group.notApplicable.push(auditRef);
+      } else if (Util.showAsPassed(auditRef.result)) {
+        group.passed.push(auditRef);
+      } else {
+        group.failed.push(auditRef);
+      }
     });
 
-    const passedElements = /** @type {!Array<!Element>} */ ([]);
-    const notApplicableElements = /** @type {!Array<!Element>} */ ([]);
+    const failedElements = /** @type {Array<Element>} */ ([]);
+    const passedElements = /** @type {Array<Element>} */ ([]);
+    const notApplicableElements = /** @type {Array<Element>} */ ([]);
+
+    auditsUngrouped.failed.forEach((/** @type {AuditJSON} */ audit, i) =>
+      failedElements.push(this.renderAudit(audit, i)));
+    auditsUngrouped.passed.forEach((/** @type {AuditJSON} */ audit, i) =>
+      passedElements.push(this.renderAudit(audit, i)));
+    auditsUngrouped.notApplicable.forEach((/** @type {AuditJSON} */ audit, i) =>
+      notApplicableElements.push(this.renderAudit(audit, i)));
+
     Object.keys(auditsGroupedByGroup).forEach(groupId => {
       const group = groupDefinitions[groupId];
       const groups = auditsGroupedByGroup[groupId];
+
       if (groups.failed.length) {
-        const auditGroupElem = this._renderAuditGroup(group, {expandable: false});
-        groups.failed.forEach(item => auditGroupElem.appendChild(this._renderAudit(item)));
-        auditGroupElem.open = true;
-        element.appendChild(auditGroupElem);
+        const auditGroupElem = this.renderAuditGroup(group, {expandable: false});
+        groups.failed.forEach((item, i) => auditGroupElem.appendChild(this.renderAudit(item, i)));
+        auditGroupElem.classList.add('lh-audit-group--unadorned');
+        failedElements.push(auditGroupElem);
       }
 
       if (groups.passed.length) {
-        const auditGroupElem = this._renderAuditGroup(group, {expandable: true});
-        groups.passed.forEach(item => auditGroupElem.appendChild(this._renderAudit(item)));
+        const auditGroupElem = this.renderAuditGroup(group, {expandable: true});
+        groups.passed.forEach((item, i) => auditGroupElem.appendChild(this.renderAudit(item, i)));
+        auditGroupElem.classList.add('lh-audit-group--unadorned');
         passedElements.push(auditGroupElem);
       }
 
       if (groups.notApplicable.length) {
-        const auditGroupElem = this._renderAuditGroup(group, {expandable: true});
-        groups.notApplicable.forEach(item => auditGroupElem.appendChild(this._renderAudit(item)));
+        const auditGroupElem = this.renderAuditGroup(group, {expandable: true});
+        groups.notApplicable.forEach((item, i) =>
+            auditGroupElem.appendChild(this.renderAudit(item, i)));
+        auditGroupElem.classList.add('lh-audit-group--unadorned');
         notApplicableElements.push(auditGroupElem);
       }
     });
 
+    if (failedElements.length) {
+      const failedElem = this._renderFailedAuditsSection(failedElements);
+      element.appendChild(failedElem);
+    }
+
+    if (manualAudits.length) {
+      const manualEl = this._renderManualAudits(manualAudits, category.manualDescription);
+      element.appendChild(manualEl);
+    }
+
     if (passedElements.length) {
-      const passedElem = this._renderPassedAuditsSection(passedElements);
+      const passedElem = this.renderPassedAuditsSection(passedElements);
       element.appendChild(passedElem);
     }
 
@@ -531,19 +393,16 @@
       element.appendChild(notApplicableElem);
     }
 
-    // Render manual audits after passing.
-    this._renderManualAudits(manualAudits, groupDefinitions, element);
-
     return element;
   }
 
   /**
    * Create a non-semantic span used for hash navigation of categories
-   * @param {!Element} element
+   * @param {Element} element
    * @param {string} id
    */
-  _createPermalinkSpan(element, id) {
-    const permalinkEl = this._dom.createChildOf(element, 'span', 'lh-permalink');
+  createPermalinkSpan(element, id) {
+    const permalinkEl = this.dom.createChildOf(element, 'span', 'lh-permalink');
     permalinkEl.id = id;
   }
 }
@@ -553,14 +412,3 @@
 } else {
   self.CategoryRenderer = CategoryRenderer;
 }
-
-
-/**
- * @typedef {{
- *     value: {
- *       wastedMs: (number|undefined),
- *       wastedKb: (number|undefined),
- *     }
- * }}
- */
-CategoryRenderer.PerfHintExtendedInfo; // eslint-disable-line no-unused-expressions
diff --git a/front_end/audits2/lighthouse/renderer/crc-details-renderer.js b/front_end/audits2/lighthouse/renderer/crc-details-renderer.js
index 822b2f9..5c5fe79 100644
--- a/front_end/audits2/lighthouse/renderer/crc-details-renderer.js
+++ b/front_end/audits2/lighthouse/renderer/crc-details-renderer.js
@@ -12,11 +12,13 @@
 
 /* globals self Util */
 
+/** @typedef {import('./dom.js')} DOM */
+
 class CriticalRequestChainRenderer {
   /**
    * Create render context for critical-request-chain tree display.
-   * @param {!Object<string, !CriticalRequestChainRenderer.CRCNode>} tree
-   * @return {{tree: !Object<string, !CriticalRequestChainRenderer.CRCNode>, startTime: number, transferSize: number}}
+   * @param {LH.Audit.SimpleCriticalRequestNode} tree
+   * @return {{tree: LH.Audit.SimpleCriticalRequestNode, startTime: number, transferSize: number}}
    */
   static initTree(tree) {
     let startTime = 0;
@@ -34,13 +36,13 @@
    * parent. Calculates if this node is the last child, whether it has any
    * children itself and what the tree looks like all the way back up to the root,
    * so the tree markers can be drawn correctly.
-   * @param {!Object<string, !CriticalRequestChainRenderer.CRCNode>} parent
+   * @param {LH.Audit.SimpleCriticalRequestNode} parent
    * @param {string} id
    * @param {number} startTime
    * @param {number} transferSize
-   * @param {!Array<boolean>=} treeMarkers
+   * @param {Array<boolean>=} treeMarkers
    * @param {boolean=} parentIsLastChild
-   * @return {!CriticalRequestChainRenderer.CRCSegment}
+   * @return {CRCSegment}
    */
   static createSegment(parent, id, startTime, transferSize, treeMarkers, parentIsLastChild) {
     const node = parent[id];
@@ -68,10 +70,10 @@
 
   /**
    * Creates the DOM for a tree segment.
-   * @param {!DOM} dom
-   * @param {!DocumentFragment} tmpl
-   * @param {!CriticalRequestChainRenderer.CRCSegment} segment
-   * @return {!Node}
+   * @param {DOM} dom
+   * @param {DocumentFragment} tmpl
+   * @param {CRCSegment} segment
+   * @return {Node}
    */
   static createChainNode(dom, tmpl, segment) {
     const chainsEl = dom.cloneTemplate('#tmpl-lh-crc__chains', tmpl);
@@ -110,14 +112,14 @@
     const {file, hostname} = Util.parseURL(segment.node.request.url);
     const treevalEl = dom.find('.crc-node__tree-value', chainsEl);
     dom.find('.crc-node__tree-file', treevalEl).textContent = `${file}`;
-    dom.find('.crc-node__tree-hostname', treevalEl).textContent = `(${hostname})`;
+    dom.find('.crc-node__tree-hostname', treevalEl).textContent = hostname ? `(${hostname})` : '';
 
     if (!segment.hasChildren) {
       const span = dom.createElement('span', 'crc-node__chain-duration');
       span.textContent = ' - ' + Util.chainDuration(
           segment.node.request.startTime, segment.node.request.endTime) + 'ms, ';
       const span2 = dom.createElement('span', 'crc-node__chain-duration');
-      span2.textContent = Util.formatBytesToKB(segment.node.request.transferSize);
+      span2.textContent = Util.formatBytesToKB(segment.node.request.transferSize, 0.01);
 
       treevalEl.appendChild(span);
       treevalEl.appendChild(span2);
@@ -128,52 +130,48 @@
 
   /**
    * Recursively builds a tree from segments.
-   * @param {!DOM} dom
-   * @param {!DocumentFragment} tmpl
-   * @param {!CriticalRequestChainRenderer.CRCSegment} segment
-   * @param {!Element} detailsEl Parent details element.
-   * @param {!CriticalRequestChainRenderer.CRCDetailsJSON} details
+   * @param {DOM} dom
+   * @param {DocumentFragment} tmpl
+   * @param {CRCSegment} segment
+   * @param {Element} elem Parent element.
+   * @param {CRCDetailsJSON} details
    */
-  static buildTree(dom, tmpl, segment, detailsEl, details) {
-    detailsEl.appendChild(CriticalRequestChainRenderer.createChainNode(dom, tmpl, segment));
+  static buildTree(dom, tmpl, segment, elem, details) {
+    elem.appendChild(CriticalRequestChainRenderer.createChainNode(dom, tmpl, segment));
 
     for (const key of Object.keys(segment.node.children)) {
       const childSegment = CriticalRequestChainRenderer.createSegment(segment.node.children, key,
          segment.startTime, segment.transferSize, segment.treeMarkers, segment.isLastChild);
-      CriticalRequestChainRenderer.buildTree(dom, tmpl, childSegment, detailsEl, details);
+      CriticalRequestChainRenderer.buildTree(dom, tmpl, childSegment, elem, details);
     }
   }
 
   /**
-   * @param {!DOM} dom
-   * @param {!Node} templateContext
-   * @param {!CriticalRequestChainRenderer.CRCDetailsJSON} details
-   * @return {!Node}
+   * @param {DOM} dom
+   * @param {ParentNode} templateContext
+   * @param {CRCDetailsJSON} details
+   * @return {Element}
    */
   static render(dom, templateContext, details) {
     const tmpl = dom.cloneTemplate('#tmpl-lh-crc', templateContext);
+    const containerEl = dom.find('.lh-crc', tmpl);
 
     // Fill in top summary.
     dom.find('.lh-crc__longest_duration', tmpl).textContent =
         Util.formatNumber(details.longestChain.duration) + 'ms';
-    dom.find('.lh-crc__longest_length', tmpl).textContent = details.longestChain.length;
+    dom.find('.lh-crc__longest_length', tmpl).textContent = details.longestChain.length.toString();
     dom.find('.lh-crc__longest_transfersize', tmpl).textContent =
         Util.formatBytesToKB(details.longestChain.transferSize);
 
-    const detailsEl = dom.find('.lh-details', tmpl);
-    detailsEl.open = true;
-
-    dom.find('.lh-details > summary', tmpl).textContent = details.header.text;
-
     // Construct visual tree.
     const root = CriticalRequestChainRenderer.initTree(details.chains);
     for (const key of Object.keys(root.tree)) {
       const segment = CriticalRequestChainRenderer.createSegment(root.tree, key,
           root.startTime, root.transferSize);
-      CriticalRequestChainRenderer.buildTree(dom, tmpl, segment, detailsEl, details);
+      CriticalRequestChainRenderer.buildTree(dom, tmpl, segment, containerEl, details);
     }
 
-    return tmpl;
+    return dom.find('.lh-crc-container', tmpl);
   }
 }
 
@@ -185,44 +183,19 @@
 }
 
 /** @typedef {{
- *     type: string,
- *     header: {text: string},
- *     longestChain: {duration: number, length: number, transferSize: number},
- *     chains: !Object<string, !CriticalRequestChainRenderer.CRCNode>
- * }}
+      type: string,
+      header: {text: string},
+      longestChain: {duration: number, length: number, transferSize: number},
+      chains: LH.Audit.SimpleCriticalRequestNode
+  }} CRCDetailsJSON
  */
-CriticalRequestChainRenderer.CRCDetailsJSON; // eslint-disable-line no-unused-expressions
 
 /** @typedef {{
- *     endTime: number,
- *     responseReceivedTime: number,
- *     startTime: number,
- *     transferSize: number,
- *     url: string
- * }}
+      node: LH.Audit.SimpleCriticalRequestNode[string],
+      isLastChild: boolean,
+      hasChildren: boolean,
+      startTime: number,
+      transferSize: number,
+      treeMarkers: Array<boolean>
+  }} CRCSegment
  */
-CriticalRequestChainRenderer.CRCRequest; // eslint-disable-line no-unused-expressions
-
-/**
- * Record type so children can circularly have CRCNode values.
- * @struct
- * @record
- */
-CriticalRequestChainRenderer.CRCNode = function() {};
-
-/** @type {!Object<string, !CriticalRequestChainRenderer.CRCNode>} */
-CriticalRequestChainRenderer.CRCNode.prototype.children; // eslint-disable-line no-unused-expressions
-
-/** @type {!CriticalRequestChainRenderer.CRCRequest} */
-CriticalRequestChainRenderer.CRCNode.prototype.request; // eslint-disable-line no-unused-expressions
-
-/** @typedef {{
- *     node: !CriticalRequestChainRenderer.CRCNode,
- *     isLastChild: boolean,
- *     hasChildren: boolean,
- *     startTime: number,
- *     transferSize: number,
- *     treeMarkers: !Array<boolean>
- * }}
- */
-CriticalRequestChainRenderer.CRCSegment; // eslint-disable-line no-unused-expressions
diff --git a/front_end/audits2/lighthouse/renderer/details-renderer.js b/front_end/audits2/lighthouse/renderer/details-renderer.js
index 21f31d3..b908209 100644
--- a/front_end/audits2/lighthouse/renderer/details-renderer.js
+++ b/front_end/audits2/lighthouse/renderer/details-renderer.js
@@ -7,72 +7,104 @@
 
 /* globals self CriticalRequestChainRenderer Util URL */
 
+/** @typedef {import('./dom.js')} DOM */
+/** @typedef {import('./crc-details-renderer.js')} CRCDetailsJSON */
+
 class DetailsRenderer {
   /**
-   * @param {!DOM} dom
+   * @param {DOM} dom
    */
   constructor(dom) {
-    /** @private {!DOM} */
+    /** @type {DOM} */
     this._dom = dom;
-    /** @private {!Document|!Element} */
+    /** @type {ParentNode} */
     this._templateContext; // eslint-disable-line no-unused-expressions
   }
 
   /**
-   * @param {!Document|!Element} context
+   * @param {ParentNode} context
    */
   setTemplateContext(context) {
     this._templateContext = context;
   }
 
   /**
-   * @param {!DetailsRenderer.DetailsJSON} details
-   * @return {!Node}
+   * @param {DetailsJSON} details
+   * @return {Element}
    */
   render(details) {
     switch (details.type) {
       case 'text':
-        return this._renderText(details);
+        return this._renderText(/** @type {StringDetailsJSON} */ (details));
       case 'url':
-        return this._renderTextURL(details);
+        return this._renderTextURL(/** @type {StringDetailsJSON} */ (details));
+      case 'bytes':
+        return this._renderBytes(/** @type {NumericUnitDetailsJSON} */ (details));
+      case 'ms':
+        // eslint-disable-next-line max-len
+        return this._renderMilliseconds(/** @type {NumericUnitDetailsJSON} */ (details));
       case 'link':
-        return this._renderLink(/** @type {!DetailsRenderer.LinkDetailsJSON} */ (details));
+        // @ts-ignore - TODO(bckenny): Fix type hierarchy
+        return this._renderLink(/** @type {LinkDetailsJSON} */ (details));
       case 'thumbnail':
-        return this._renderThumbnail(/** @type {!DetailsRenderer.ThumbnailDetails} */ (details));
+        return this._renderThumbnail(/** @type {ThumbnailDetails} */ (details));
       case 'filmstrip':
-        return this._renderFilmstrip(/** @type {!DetailsRenderer.FilmstripDetails} */ (details));
-      case 'cards':
-        return this._renderCards(/** @type {!DetailsRenderer.CardsDetailsJSON} */ (details));
+        // @ts-ignore - TODO(bckenny): Fix type hierarchy
+        return this._renderFilmstrip(/** @type {FilmstripDetails} */ (details));
       case 'table':
-        return this._renderTable(/** @type {!DetailsRenderer.TableDetailsJSON} */ (details));
+        // @ts-ignore - TODO(bckenny): Fix type hierarchy
+        return this._renderTable(/** @type {TableDetailsJSON} */ (details));
       case 'code':
         return this._renderCode(details);
       case 'node':
-        return this.renderNode(/** @type {!DetailsRenderer.NodeDetailsJSON} */(details));
+        return this.renderNode(/** @type {NodeDetailsJSON} */(details));
       case 'criticalrequestchain':
         return CriticalRequestChainRenderer.render(this._dom, this._templateContext,
-          /** @type {!CriticalRequestChainRenderer.CRCDetailsJSON} */ (details));
-      case 'list':
-        return this._renderList(/** @type {!DetailsRenderer.ListDetailsJSON} */ (details));
-      default:
+          // @ts-ignore - TODO(bckenny): Fix type hierarchy
+          /** @type {CRCDetailsJSON} */ (details));
+      default: {
         throw new Error(`Unknown type: ${details.type}`);
+      }
     }
   }
 
   /**
-   * @param {!DetailsRenderer.DetailsJSON} text
-   * @return {!Element}
+   * @param {NumericUnitDetailsJSON} details
+   * @return {Element}
+   */
+  _renderBytes(details) {
+    // TODO: handle displayUnit once we have something other than 'kb'
+    const value = Util.formatBytesToKB(details.value, details.granularity);
+    return this._renderText({type: 'text', value});
+  }
+
+  /**
+   * @param {NumericUnitDetailsJSON} details
+   * @return {Element}
+   */
+  _renderMilliseconds(details) {
+    let value = Util.formatMilliseconds(details.value, details.granularity);
+    if (details.displayUnit === 'duration') {
+      value = Util.formatDuration(details.value);
+    }
+
+    return this._renderText({type: 'text', value});
+  }
+
+  /**
+   * @param {StringDetailsJSON} text
+   * @return {HTMLElement}
    */
   _renderTextURL(text) {
-    const url = text.text || '';
+    const url = text.value;
 
     let displayedPath;
     let displayedHost;
     let title;
     try {
       const parsed = Util.parseURL(url);
-      displayedPath = parsed.file;
-      displayedHost = `(${parsed.hostname})`;
+      displayedPath = parsed.file === '/' ? parsed.origin : parsed.file;
+      displayedHost = parsed.file === '/' ? '' : `(${parsed.hostname})`;
       title = url;
     } catch (/** @type {!Error} */ e) {
       if (!(e instanceof TypeError)) {
@@ -81,15 +113,15 @@
       displayedPath = url;
     }
 
-    const element = this._dom.createElement('div', 'lh-text__url');
+    const element = /** @type {HTMLElement} */ (this._dom.createElement('div', 'lh-text__url'));
     element.appendChild(this._renderText({
-      text: displayedPath,
+      value: displayedPath,
       type: 'text',
     }));
 
     if (displayedHost) {
       const hostElem = this._renderText({
-        text: displayedHost,
+        value: displayedHost,
         type: 'text',
       });
       hostElem.classList.add('lh-text__url-host');
@@ -101,18 +133,21 @@
   }
 
   /**
-   * @param {!DetailsRenderer.LinkDetailsJSON} details
-   * @return {!Element}
+   * @param {LinkDetailsJSON} details
+   * @return {Element}
    */
   _renderLink(details) {
     const allowedProtocols = ['https:', 'http:'];
     const url = new URL(details.url);
     if (!allowedProtocols.includes(url.protocol)) {
-      // Fall back to text if protocol not allowed.
-      return this._renderText(details);
+      // Fall back to just the link text if protocol not allowed.
+      return this._renderText({
+        type: 'text',
+        value: details.text,
+      });
     }
 
-    const a = /** @type {!HTMLAnchorElement} */ (this._dom.createElement('a'));
+    const a = /** @type {HTMLAnchorElement} */ (this._dom.createElement('a'));
     a.rel = 'noopener';
     a.target = '_blank';
     a.textContent = details.text;
@@ -122,100 +157,104 @@
   }
 
   /**
-   * @param {!DetailsRenderer.DetailsJSON} text
-   * @return {!Element}
+   * @param {StringDetailsJSON} text
+   * @return {Element}
    */
   _renderText(text) {
     const element = this._dom.createElement('div', 'lh-text');
-    element.textContent = text.text;
+    element.textContent = text.value;
     return element;
   }
 
   /**
    * Create small thumbnail with scaled down image asset.
    * If the supplied details doesn't have an image/* mimeType, then an empty span is returned.
-   * @param {!DetailsRenderer.ThumbnailDetails} value
-   * @return {!Element}
+   * @param {ThumbnailDetails} details
+   * @return {Element}
    */
-  _renderThumbnail(value) {
-    if (/^image/.test(value.mimeType) === false) {
-      return this._dom.createElement('span');
-    }
-
-    const element = this._dom.createElement('img', 'lh-thumbnail');
-    element.src = value.url;
+  _renderThumbnail(details) {
+    const element = /** @type {HTMLImageElement}*/ (this._dom.createElement('img', 'lh-thumbnail'));
+    /** @type {string} */
+    // @ts-ignore - type should have a value if we get here.
+    const strValue = details.value;
+    element.src = strValue;
+    element.title = strValue;
     element.alt = '';
-    element.title = value.url;
     return element;
   }
 
   /**
-   * @param {!DetailsRenderer.ListDetailsJSON} list
-   * @return {!Element}
-   */
-  _renderList(list) {
-    if (!list.items.length) return this._dom.createElement('span');
-
-    const element = this._dom.createElement('details', 'lh-details');
-    element.open = true;
-    if (list.header) {
-      const summary = this._dom.createElement('summary', 'lh-list__header');
-      summary.textContent = list.header.text;
-      element.appendChild(summary);
-    }
-
-    const itemsElem = this._dom.createChildOf(element, 'div', 'lh-list__items');
-    for (const item of list.items) {
-      const itemElem = this._dom.createChildOf(itemsElem, 'span', 'lh-list__item');
-      itemElem.appendChild(this.render(item));
-    }
-    return element;
-  }
-
-  /**
-   * @param {!DetailsRenderer.TableDetailsJSON} details
-   * @return {!Element}
+   * @param {TableDetailsJSON} details
+   * @return {Element}
    */
   _renderTable(details) {
     if (!details.items.length) return this._dom.createElement('span');
 
-    const element = this._dom.createElement('details', 'lh-details');
-    element.open = true;
-    if (details.header) {
-      element.appendChild(this._dom.createElement('summary')).textContent = details.header;
-    }
-
-    const tableElem = this._dom.createChildOf(element, 'table', 'lh-table');
+    const tableElem = this._dom.createElement('table', 'lh-table');
     const theadElem = this._dom.createChildOf(tableElem, 'thead');
     const theadTrElem = this._dom.createChildOf(theadElem, 'tr');
 
-    for (const heading of details.itemHeaders) {
+    for (const heading of details.headings) {
       const itemType = heading.itemType || 'text';
       const classes = `lh-table-column--${itemType}`;
-      this._dom.createChildOf(theadTrElem, 'th', classes).appendChild(this.render(heading));
+      this._dom.createChildOf(theadTrElem, 'th', classes).appendChild(this.render({
+        type: 'text',
+        value: heading.text || '',
+      }));
     }
 
     const tbodyElem = this._dom.createChildOf(tableElem, 'tbody');
     for (const row of details.items) {
       const rowElem = this._dom.createChildOf(tbodyElem, 'tr');
-      for (const columnItem of row) {
-        const classes = `lh-table-column--${columnItem.type}`;
-        this._dom.createChildOf(rowElem, 'td', classes).appendChild(this.render(columnItem));
+      for (const heading of details.headings) {
+        const key = /** @type {keyof DetailsJSON} */ (heading.key);
+        // TODO(bckenny): type should be naturally inferred here.
+        const value = /** @type {number|string|DetailsJSON|undefined} */ (row[key]);
+
+        if (typeof value === 'undefined' || value === null) {
+          this._dom.createChildOf(rowElem, 'td', 'lh-table-column--empty');
+          continue;
+        }
+        // handle nested types like code blocks in table rows.
+        // @ts-ignore - TODO(bckenny): narrow first
+        if (value.type) {
+          const valueAsDetails = /** @type {DetailsJSON} */ (value);
+          const classes = `lh-table-column--${valueAsDetails.type}`;
+          this._dom.createChildOf(rowElem, 'td', classes).appendChild(this.render(valueAsDetails));
+          continue;
+        }
+
+        // build new details item to render
+        const item = {
+          value: /** @type {number|string} */ (value),
+          type: heading.itemType,
+          displayUnit: heading.displayUnit,
+          granularity: heading.granularity,
+        };
+
+        /** @type {string|undefined} */
+        // @ts-ignore - TODO(bckenny): handle with refactoring above
+        const valueType = value.type;
+        const classes = `lh-table-column--${valueType || heading.itemType}`;
+        this._dom.createChildOf(rowElem, 'td', classes).appendChild(this.render(item));
       }
     }
-    return element;
+    return tableElem;
   }
 
   /**
-   * @param {!DetailsRenderer.NodeDetailsJSON} item
-   * @return {!Element}
+   * @param {NodeDetailsJSON} item
+   * @return {Element}
    * @protected
    */
   renderNode(item) {
-    const element = this._dom.createElement('span', 'lh-node');
-    element.textContent = item.snippet;
-    element.title = item.selector;
-    if (item.text) element.setAttribute('data-text', item.text);
+    const element = /** @type {HTMLSpanElement} */ (this._dom.createElement('span', 'lh-node'));
+    if (item.snippet) {
+      element.textContent = item.snippet;
+    }
+    if (item.selector) {
+      element.title = item.selector;
+    }
     if (item.path) element.setAttribute('data-path', item.path);
     if (item.selector) element.setAttribute('data-selector', item.selector);
     if (item.snippet) element.setAttribute('data-snippet', item.snippet);
@@ -223,71 +262,29 @@
   }
 
   /**
-   * @param {!DetailsRenderer.CardsDetailsJSON} details
-   * @return {!Element}
-   */
-  _renderCards(details) {
-    const element = this._dom.createElement('details', 'lh-details');
-    element.open = true;
-    if (details.header) {
-      element.appendChild(this._dom.createElement('summary')).textContent = details.header.text;
-    }
-
-    const cardsParent = this._dom.createElement('div', 'lh-scorecards');
-    for (const item of details.items) {
-      const card = cardsParent.appendChild(
-          this._dom.createElement('div', 'lh-scorecard', {title: item.snippet}));
-      const titleEl = this._dom.createElement('div', 'lh-scorecard__title');
-      const valueEl = this._dom.createElement('div', 'lh-scorecard__value');
-      const targetEl = this._dom.createElement('div', 'lh-scorecard__target');
-
-      card.appendChild(titleEl).textContent = item.title;
-      card.appendChild(valueEl).textContent = item.value;
-
-      if (item.target) {
-        card.appendChild(targetEl).textContent = `target: ${item.target}`;
-      }
-    }
-
-    element.appendChild(cardsParent);
-    return element;
-  }
-
-  /**
-   * @param {!DetailsRenderer.FilmstripDetails} details
-   * @return {!Element}
+   * @param {FilmstripDetails} details
+   * @return {Element}
    */
   _renderFilmstrip(details) {
     const filmstripEl = this._dom.createElement('div', 'lh-filmstrip');
 
     for (const thumbnail of details.items) {
       const frameEl = this._dom.createChildOf(filmstripEl, 'div', 'lh-filmstrip__frame');
-
-      let timing = Util.formatMilliseconds(thumbnail.timing, 1);
-      if (thumbnail.timing > 1000) {
-        timing = Util.formatNumber(thumbnail.timing / 1000) + ' s';
-      }
-
-      const timingEl = this._dom.createChildOf(frameEl, 'div', 'lh-filmstrip__timestamp');
-      timingEl.textContent = timing;
-
-      const base64data = thumbnail.data;
       this._dom.createChildOf(frameEl, 'img', 'lh-filmstrip__thumbnail', {
-        src: `data:image/jpeg;base64,${base64data}`,
-        alt: `Screenshot at ${timing}`,
+        src: `data:image/jpeg;base64,${thumbnail.data}`,
+        alt: `Screenshot`,
       });
     }
-
     return filmstripEl;
   }
 
   /**
-   * @param {!DetailsRenderer.DetailsJSON} details
-   * @return {!Element}
+   * @param {DetailsJSON} details
+   * @return {Element}
    */
   _renderCode(details) {
     const pre = this._dom.createElement('pre', 'lh-code');
-    pre.textContent = details.text;
+    pre.textContent = /** @type {string} */ (details.value);
     return pre;
   }
 }
@@ -298,91 +295,84 @@
   self.DetailsRenderer = DetailsRenderer;
 }
 
+// TODO, what's the diff between DetailsJSON and NumericUnitDetailsJSON?
 /**
  * @typedef {{
- *     type: string,
- *     text: (string|undefined)
- * }}
+      type: string,
+      value: (string|number|undefined),
+      summary?: OpportunitySummary,
+      granularity?: number,
+      displayUnit?: string
+  }} DetailsJSON
  */
-DetailsRenderer.DetailsJSON; // eslint-disable-line no-unused-expressions
 
 /**
  * @typedef {{
- *     type: string,
- *     header: ({text: string}|undefined),
- *     items: !Array<{type: string, text: (string|undefined)}>
- * }}
+      type: string,
+      value: string,
+      granularity?: number,
+      displayUnit?: string,
+  }} StringDetailsJSON
  */
-DetailsRenderer.ListDetailsJSON; // eslint-disable-line no-unused-expressions
 
 /**
  * @typedef {{
- *     type: string,
- *     text: (string|undefined),
- *     path: (string|undefined),
- *     selector: (string|undefined),
- *     snippet:(string|undefined)
- * }}
+      type: string,
+      value: number,
+      granularity?: number,
+      displayUnit?: string,
+  }} NumericUnitDetailsJSON
  */
-DetailsRenderer.NodeDetailsJSON; // eslint-disable-line no-unused-expressions
-
-/** @typedef {{
- *     type: string,
- *     header: ({text: string}|undefined),
- *     items: !Array<{title: string, value: string, snippet: (string|undefined), target: string}>
- * }}
- */
-DetailsRenderer.CardsDetailsJSON; // eslint-disable-line no-unused-expressions
 
 /**
  * @typedef {{
- *     type: string,
- *     itemType: (string|undefined),
- *     text: (string|undefined)
- * }}
+      type: string,
+      path?: string,
+      selector?: string,
+      snippet?: string
+  }} NodeDetailsJSON
  */
-DetailsRenderer.TableHeaderJSON; // eslint-disable-line no-unused-expressions
 
 /**
  * @typedef {{
- *     type: string,
- *     text: (string|undefined),
- *     path: (string|undefined),
- *     selector: (string|undefined),
- *     snippet:(string|undefined)
- * }}
+      itemType: string,
+      key: string,
+      text?: string,
+      granularity?: number,
+      displayUnit?: string,
+  }} TableHeaderJSON
  */
-DetailsRenderer.NodeDetailsJSON; // eslint-disable-line no-unused-expressions
 
 /** @typedef {{
- *     type: string,
- *     header: ({text: string}|undefined),
- *     items: !Array<!Array<!DetailsRenderer.DetailsJSON>>,
- *     itemHeaders: !Array<!DetailsRenderer.TableHeaderJSON>
- * }}
+      type: string,
+      items: Array<DetailsJSON>,
+      headings: Array<TableHeaderJSON>
+  }} TableDetailsJSON
  */
-DetailsRenderer.TableDetailsJSON; // eslint-disable-line no-unused-expressions
 
 /** @typedef {{
- *     type: string,
- *     url: ({text: string}|undefined),
- *     mimeType: ({text: string}|undefined)
- * }}
+      type: string,
+      value?: string,
+  }} ThumbnailDetails
  */
-DetailsRenderer.ThumbnailDetails; // eslint-disable-line no-unused-expressions
 
 /** @typedef {{
- *     type: string,
- *     url: string,
- *     text: string
- * }}
+      type: string,
+      text: string,
+      url: string
+  }} LinkDetailsJSON
  */
-DetailsRenderer.LinkDetailsJSON; // eslint-disable-line no-unused-expressions
 
 /** @typedef {{
- *     type: string,
- *     scale: number,
- *     items: !Array<{timing: number, timestamp: number, data: string}>,
- * }}
+      type: string,
+      scale: number,
+      items: Array<{timing: number, timestamp: number, data: string}>,
+  }} FilmstripDetails
  */
-DetailsRenderer.FilmstripDetails; // eslint-disable-line no-unused-expressions
+
+
+/** @typedef {{
+      wastedMs?: number,
+      wastedBytes?: number
+  }} OpportunitySummary
+ */
diff --git a/front_end/audits2/lighthouse/renderer/dom.js b/front_end/audits2/lighthouse/renderer/dom.js
index a12f794..69ce25b 100644
--- a/front_end/audits2/lighthouse/renderer/dom.js
+++ b/front_end/audits2/lighthouse/renderer/dom.js
@@ -9,20 +9,21 @@
 
 class DOM {
   /**
-   * @param {!Document} document
+   * @param {Document} document
    */
   constructor(document) {
-    /** @private {!Document} */
+    /** @type {Document} */
     this._document = document;
   }
 
+  // TODO(bckenny): can pass along `createElement`'s inferred type
   /**
    * @param {string} name
    * @param {string=} className
-   * @param {!Object<string, (string|undefined)>=} attrs Attribute key/val pairs.
+   * @param {Object<string, (string|undefined)>=} attrs Attribute key/val pairs.
    *     Note: if an attribute key has an undefined value, this method does not
    *     set the attribute on the node.
-   * @return {!Element}
+   * @return {Element}
    */
   createElement(name, className, attrs = {}) {
     const element = this._document.createElement(name);
@@ -39,13 +40,20 @@
   }
 
   /**
-   * @param {!Element} parentElem
+   * @return {DocumentFragment}
+   */
+  createFragment() {
+    return this._document.createDocumentFragment();
+  }
+
+  /**
+   * @param {Element} parentElem
    * @param {string} elementName
    * @param {string=} className
-   * @param {!Object<string, (string|undefined)>=} attrs Attribute key/val pairs.
+   * @param {Object<string, (string|undefined)>=} attrs Attribute key/val pairs.
    *     Note: if an attribute key has an undefined value, this method does not
    *     set the attribute on the node.
-   * @return {!Element}
+   * @return {Element}
    */
   createChildOf(parentElem, elementName, className, attrs) {
     const element = this.createElement(elementName, className, attrs);
@@ -55,8 +63,8 @@
 
   /**
    * @param {string} selector
-   * @param {!Node} context
-   * @return {!DocumentFragment} A clone of the template content.
+   * @param {ParentNode} context
+   * @return {DocumentFragment} A clone of the template content.
    * @throws {Error}
    */
   cloneTemplate(selector, context) {
@@ -65,15 +73,14 @@
       throw new Error(`Template not found: template${selector}`);
     }
 
-    const clone = /** @type {!DocumentFragment} */ (this._document.importNode(
-        template.content, true));
+    const clone = this._document.importNode(template.content, true);
 
     // Prevent duplicate styles in the DOM. After a template has been stamped
     // for the first time, remove the clone's styles so they're not re-added.
     if (template.hasAttribute('data-stamped')) {
       this.findAll('style', clone).forEach(style => style.remove());
     }
-    template.setAttribute('data-stamped', true);
+    template.setAttribute('data-stamped', 'true');
 
     return clone;
   }
@@ -89,7 +96,7 @@
 
   /**
    * @param {string} text
-   * @return {!Element}
+   * @return {Element}
    */
   convertMarkdownLinkSnippets(text) {
     const element = this.createElement('span');
@@ -104,7 +111,7 @@
 
       // Append link if there are any.
       if (linkText && linkHref) {
-        const a = /** @type {!HTMLAnchorElement} */ (this.createElement('a'));
+        const a = /** @type {HTMLAnchorElement} */ (this.createElement('a'));
         a.rel = 'noopener';
         a.target = '_blank';
         a.textContent = linkText;
@@ -118,7 +125,7 @@
 
   /**
    * @param {string} text
-   * @return {!Element}
+   * @return {Element}
    */
   convertMarkdownCodeSnippets(text) {
     const element = this.createElement('span');
@@ -129,7 +136,7 @@
       const [preambleText, codeText] = parts.splice(0, 2);
       element.appendChild(this._document.createTextNode(preambleText));
       if (codeText) {
-        const pre = /** @type {!HTMLPreElement} */ (this.createElement('code'));
+        const pre = /** @type {HTMLPreElement} */ (this.createElement('code'));
         pre.textContent = codeText;
         element.appendChild(pre);
       }
@@ -139,20 +146,29 @@
   }
 
   /**
-   * @return {!Document}
+   * @return {Document}
    */
   document() {
     return this._document;
   }
 
   /**
+   * TODO(paulirish): import and conditionally apply the DevTools frontend subclasses instead of this
+   * @return {boolean}
+   */
+  isDevTools() {
+    return !!this._document.querySelector('.lh-devtools');
+  }
+
+  /**
    * Guaranteed context.querySelector. Always returns an element or throws if
    * nothing matches query.
    * @param {string} query
-   * @param {!Node} context
-   * @return {!Element}
+   * @param {ParentNode} context
+   * @return {HTMLElement}
    */
   find(query, context) {
+    /** @type {?HTMLElement} */
     const result = context.querySelector(query);
     if (result === null) {
       throw new Error(`query ${query} not found`);
@@ -163,8 +179,8 @@
   /**
    * Helper for context.querySelectorAll. Returns an Array instead of a NodeList.
    * @param {string} query
-   * @param {!Node} context
-   * @return {!Array<!Element>}
+   * @param {ParentNode} context
+   * @return {Array<HTMLElement>}
    */
   findAll(query, context) {
     return Array.from(context.querySelectorAll(query));
diff --git a/front_end/audits2/lighthouse/renderer/performance-category-renderer.js b/front_end/audits2/lighthouse/renderer/performance-category-renderer.js
new file mode 100644
index 0000000..71b1667
--- /dev/null
+++ b/front_end/audits2/lighthouse/renderer/performance-category-renderer.js
@@ -0,0 +1,203 @@
+/**
+ * @license Copyright 2018 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+ */
+'use strict';
+
+/* globals self, Util, CategoryRenderer */
+
+/** @typedef {import('./dom.js')} DOM */
+/** @typedef {import('./report-renderer.js').CategoryJSON} CategoryJSON */
+/** @typedef {import('./report-renderer.js').GroupJSON} GroupJSON */
+/** @typedef {import('./report-renderer.js').AuditJSON} AuditJSON */
+/** @typedef {import('./details-renderer.js').OpportunitySummary} OpportunitySummary */
+/** @typedef {import('./details-renderer.js').FilmstripDetails} FilmstripDetails */
+
+class PerformanceCategoryRenderer extends CategoryRenderer {
+  /**
+   * @param {AuditJSON} audit
+   * @return {Element}
+   */
+  _renderMetric(audit) {
+    const tmpl = this.dom.cloneTemplate('#tmpl-lh-metric', this.templateContext);
+    const element = this.dom.find('.lh-metric', tmpl);
+    element.id = audit.result.id;
+    const rating = Util.calculateRating(audit.result.score, audit.result.scoreDisplayMode);
+    element.classList.add(`lh-metric--${rating}`);
+
+    const titleEl = this.dom.find('.lh-metric__title', tmpl);
+    titleEl.textContent = audit.result.title;
+
+    const valueEl = this.dom.find('.lh-metric__value', tmpl);
+    valueEl.textContent = Util.formatDisplayValue(audit.result.displayValue);
+
+    const descriptionEl = this.dom.find('.lh-metric__description', tmpl);
+    descriptionEl.appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.description));
+
+    if (audit.result.scoreDisplayMode === 'error') {
+      descriptionEl.textContent = '';
+      valueEl.textContent = 'Error!';
+      const tooltip = this.dom.createChildOf(descriptionEl, 'span');
+      tooltip.textContent = audit.result.errorMessage || 'Report error: no metric information';
+    }
+
+    return element;
+  }
+
+  /**
+   * @param {AuditJSON} audit
+   * @param {number} index
+   * @param {number} scale
+   * @return {Element}
+   */
+  _renderOpportunity(audit, index, scale) {
+    const oppTmpl = this.dom.cloneTemplate('#tmpl-lh-opportunity', this.templateContext);
+    const element = this.populateAuditValues(audit, index, oppTmpl);
+    element.id = audit.result.id;
+
+    const details = audit.result.details;
+    if (!details) {
+      return element;
+    }
+    const summaryInfo = /** @type {OpportunitySummary} */ (details.summary);
+    if (!summaryInfo || !summaryInfo.wastedMs || audit.result.scoreDisplayMode === 'error') {
+      return element;
+    }
+
+    // Overwrite the displayValue with opportunity's wastedMs
+    const displayEl = this.dom.find('.lh-audit__display-text', element);
+    const sparklineWidthPct = `${summaryInfo.wastedMs / scale * 100}%`;
+    this.dom.find('.lh-sparkline__bar', element).style.width = sparklineWidthPct;
+    displayEl.textContent = Util.formatSeconds(summaryInfo.wastedMs, 0.01);
+
+    // Set [title] tooltips
+    if (audit.result.displayValue) {
+      const displayValue = Util.formatDisplayValue(audit.result.displayValue);
+      this.dom.find('.lh-load-opportunity__sparkline', element).title = displayValue;
+      displayEl.title = displayValue;
+    }
+
+    return element;
+  }
+
+  /**
+   * Get an audit's wastedMs to sort the opportunity by, and scale the sparkline width
+   * Opportunties with an error won't have a summary object, so MIN_VALUE is returned to keep any
+   * erroring opportunities last in sort order.
+   * @param {AuditJSON} audit
+   * @return {number}
+   */
+  _getWastedMs(audit) {
+    if (
+      audit.result.details &&
+      audit.result.details.summary &&
+      typeof audit.result.details.summary.wastedMs === 'number'
+    ) {
+      return audit.result.details.summary.wastedMs;
+    } else {
+      return Number.MIN_VALUE;
+    }
+  }
+
+  /**
+   * @param {CategoryJSON} category
+   * @param {Object<string, GroupJSON>} groups
+   * @return {Element}
+   * @override
+   */
+  render(category, groups) {
+    const element = this.dom.createElement('div', 'lh-category');
+    this.createPermalinkSpan(element, category.id);
+    element.appendChild(this.renderCategoryHeader(category));
+
+    // Metrics
+    const metricAudits = category.auditRefs.filter(audit => audit.group === 'metrics');
+    const metricAuditsEl = this.renderAuditGroup(groups['metrics'], {expandable: false});
+
+    const keyMetrics = metricAudits.filter(a => a.weight >= 3);
+    const otherMetrics = metricAudits.filter(a => a.weight < 3);
+
+    const metricsBoxesEl = this.dom.createChildOf(metricAuditsEl, 'div', 'lh-metric-container');
+    const metricsColumn1El = this.dom.createChildOf(metricsBoxesEl, 'div', 'lh-metric-column');
+    const metricsColumn2El = this.dom.createChildOf(metricsBoxesEl, 'div', 'lh-metric-column');
+
+    keyMetrics.forEach(item => {
+      metricsColumn1El.appendChild(this._renderMetric(item));
+    });
+    otherMetrics.forEach(item => {
+      metricsColumn2El.appendChild(this._renderMetric(item));
+    });
+    const estValuesEl = this.dom.createChildOf(metricsColumn2El, 'div',
+        'lh-metrics__disclaimer lh-metrics__disclaimer');
+    estValuesEl.textContent = 'Values are estimated and may vary.';
+
+    metricAuditsEl.classList.add('lh-audit-group--metrics');
+    element.appendChild(metricAuditsEl);
+
+    // Filmstrip
+    const timelineEl = this.dom.createChildOf(element, 'div', 'lh-filmstrip-container');
+    const thumbnailAudit = category.auditRefs.find(audit => audit.id === 'screenshot-thumbnails');
+    const thumbnailResult = thumbnailAudit && thumbnailAudit.result;
+    if (thumbnailResult && thumbnailResult.details) {
+      timelineEl.id = thumbnailResult.id;
+      const filmstripEl = this.detailsRenderer.render(thumbnailResult.details);
+      timelineEl.appendChild(filmstripEl);
+    }
+
+    // Opportunities
+    const opportunityAudits = category.auditRefs
+        .filter(audit => audit.group === 'load-opportunities' && !Util.showAsPassed(audit.result))
+        .sort((auditA, auditB) => this._getWastedMs(auditB) - this._getWastedMs(auditA));
+
+    if (opportunityAudits.length) {
+      // Scale the sparklines relative to savings, minimum 2s to not overstate small savings
+      const minimumScale = 2000;
+      const wastedMsValues = opportunityAudits.map(audit => this._getWastedMs(audit));
+      const maxWaste = Math.max(...wastedMsValues);
+      const scale = Math.max(Math.ceil(maxWaste / 1000) * 1000, minimumScale);
+      const groupEl = this.renderAuditGroup(groups['load-opportunities'], {expandable: false});
+      const tmpl = this.dom.cloneTemplate('#tmpl-lh-opportunity-header', this.templateContext);
+      const headerEl = this.dom.find('.lh-load-opportunity__header', tmpl);
+      groupEl.appendChild(headerEl);
+      opportunityAudits.forEach((item, i) =>
+          groupEl.appendChild(this._renderOpportunity(item, i, scale)));
+      groupEl.classList.add('lh-audit-group--opportunities');
+      element.appendChild(groupEl);
+    }
+
+    // Diagnostics
+    const diagnosticAudits = category.auditRefs
+        .filter(audit => audit.group === 'diagnostics' && !Util.showAsPassed(audit.result))
+        .sort((a, b) => {
+          const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score);
+          const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score);
+          return scoreA - scoreB;
+        });
+
+    if (diagnosticAudits.length) {
+      const groupEl = this.renderAuditGroup(groups['diagnostics'], {expandable: false});
+      diagnosticAudits.forEach((item, i) => groupEl.appendChild(this.renderAudit(item, i)));
+      groupEl.classList.add('lh-audit-group--diagnostics');
+      element.appendChild(groupEl);
+    }
+
+    // Passed audits
+    const passedElements = category.auditRefs
+        .filter(audit => (audit.group === 'load-opportunities' || audit.group === 'diagnostics') &&
+            Util.showAsPassed(audit.result))
+        .map((audit, i) => this.renderAudit(audit, i));
+
+    if (!passedElements.length) return element;
+
+    const passedElem = this.renderPassedAuditsSection(passedElements);
+    element.appendChild(passedElem);
+    return element;
+  }
+}
+
+if (typeof module !== 'undefined' && module.exports) {
+  module.exports = PerformanceCategoryRenderer;
+} else {
+  self.PerformanceCategoryRenderer = PerformanceCategoryRenderer;
+}
diff --git a/front_end/audits2/lighthouse/renderer/report-renderer.js b/front_end/audits2/lighthouse/renderer/report-renderer.js
index 92ca071..011dfe8 100644
--- a/front_end/audits2/lighthouse/renderer/report-renderer.js
+++ b/front_end/audits2/lighthouse/renderer/report-renderer.js
@@ -12,119 +12,120 @@
  * Dummy text for ensuring report robustness: </script> pre$`post %%LIGHTHOUSE_JSON%%
  */
 
-/* globals self, Util */
+/** @typedef {import('./dom.js')} DOM */
+/** @typedef {import('./details-renderer.js').DetailsJSON} DetailsJSON */
+
+/* globals self, Util, DetailsRenderer, CategoryRenderer, PerformanceCategoryRenderer */
 
 class ReportRenderer {
   /**
-   * @param {!DOM} dom
-   * @param {!CategoryRenderer} categoryRenderer
+   * @param {DOM} dom
    */
-  constructor(dom, categoryRenderer) {
-    /** @private {!DOM} */
+  constructor(dom) {
+    /** @type {DOM} */
     this._dom = dom;
-    /** @private {!CategoryRenderer} */
-    this._categoryRenderer = categoryRenderer;
-    /** @private {!Document|!Element} */
+    /** @type {ParentNode} */
     this._templateContext = this._dom.document();
   }
 
   /**
-   * @param {!ReportRenderer.ReportJSON} report
-   * @param {!Element} container Parent element to render the report into.
+   * @param {ReportJSON} report
+   * @param {Element} container Parent element to render the report into.
    */
   renderReport(report, container) {
-    container.textContent = ''; // Remove previous report.
-    const element = container.appendChild(this._renderReport(report));
+    // If any mutations happen to the report within the renderers, we want the original object untouched
+    const clone = /** @type {ReportJSON} */ (JSON.parse(JSON.stringify(report)));
 
-    return /** @type {!Element} **/ (element);
+    // TODO(phulce): we all agree this is technical debt we should fix
+    if (typeof clone.categories !== 'object') throw new Error('No categories provided.');
+    clone.reportCategories = Object.values(clone.categories);
+    ReportRenderer.smooshAuditResultsIntoCategories(clone.audits, clone.reportCategories);
+
+    container.textContent = ''; // Remove previous report.
+    container.appendChild(this._renderReport(clone));
+    return /** @type {Element} **/ (container);
   }
 
   /**
    * Define a custom element for <templates> to be extracted from. For example:
    *     this.setTemplateContext(new DOMParser().parseFromString(htmlStr, 'text/html'))
-   * @param {!Document|!Element} context
+   * @param {ParentNode} context
    */
   setTemplateContext(context) {
     this._templateContext = context;
-    this._categoryRenderer.setTemplateContext(context);
   }
 
   /**
-   * @param {!ReportRenderer.ReportJSON} report
-   * @return {!DocumentFragment}
+   * @param {ReportJSON} report
+   * @return {DocumentFragment}
    */
   _renderReportHeader(report) {
-    const header = this._dom.cloneTemplate('#tmpl-lh-heading', this._templateContext);
-    this._dom.find('.lh-config__timestamp', header).textContent =
-        Util.formatDateTime(report.generatedTime);
-    const url = this._dom.find('.lh-metadata__url', header);
-    url.href = report.url;
-    url.textContent = report.url;
+    const el = this._dom.cloneTemplate('#tmpl-lh-heading', this._templateContext);
+    const domFragment = this._dom.cloneTemplate('#tmpl-lh-scores-wrapper', this._templateContext);
+    const placeholder = this._dom.find('.lh-scores-wrapper-placeholder', el);
+    /** @type {HTMLDivElement} */ (placeholder.parentNode).replaceChild(domFragment, placeholder);
 
-    this._dom.find('.lh-env__item__ua', header).textContent = report.userAgent;
+    this._dom.find('.lh-config__timestamp', el).textContent =
+        Util.formatDateTime(report.fetchTime);
+    this._dom.find('.lh-product-info__version', el).textContent = report.lighthouseVersion;
+    const metadataUrl = /** @type {HTMLAnchorElement} */ (this._dom.find('.lh-metadata__url', el));
+    const toolbarUrl = /** @type {HTMLAnchorElement}*/ (this._dom.find('.lh-toolbar__url', el));
+    metadataUrl.href = metadataUrl.textContent = report.finalUrl;
+    toolbarUrl.href = toolbarUrl.textContent = report.finalUrl;
 
-    const env = this._dom.find('.lh-env__items', header);
-    report.runtimeConfig.environment.forEach(runtime => {
-      const item = this._dom.cloneTemplate('#tmpl-lh-env__items', env);
-      this._dom.find('.lh-env__name', item).textContent = runtime.name;
-      this._dom.find('.lh-env__description', item).textContent = runtime.description;
-      this._dom.find('.lh-env__enabled', item).textContent =
-          runtime.enabled ? 'Enabled' : 'Disabled';
-      env.appendChild(item);
-    });
-
-    return header;
+    const emulationDescriptions = Util.getEmulationDescriptions(report.configSettings || {});
+    this._dom.find('.lh-config__emulation', el).textContent = emulationDescriptions.summary;
+    return el;
   }
 
   /**
-   * @param {!ReportRenderer.ReportJSON} report
-   * @return {!DocumentFragment}
+   * @return {Element}
+   */
+  _renderReportShortHeader() {
+    const shortHeaderContainer = this._dom.createElement('div', 'lh-header-container');
+    const wrapper = this._dom.cloneTemplate('#tmpl-lh-scores-wrapper', this._templateContext);
+    shortHeaderContainer.appendChild(wrapper);
+    return shortHeaderContainer;
+  }
+
+
+  /**
+   * @param {ReportJSON} report
+   * @return {DocumentFragment}
    */
   _renderReportFooter(report) {
     const footer = this._dom.cloneTemplate('#tmpl-lh-footer', this._templateContext);
+
+    const env = this._dom.find('.lh-env__items', footer);
+    env.id = 'runtime-settings';
+    const envValues = Util.getEnvironmentDisplayValues(report.configSettings || {});
+    [
+      {name: 'URL', description: report.finalUrl},
+      {name: 'Fetch time', description: Util.formatDateTime(report.fetchTime)},
+      ...envValues,
+      {name: 'User agent', description: report.userAgent},
+    ].forEach(runtime => {
+      const item = this._dom.cloneTemplate('#tmpl-lh-env__items', env);
+      this._dom.find('.lh-env__name', item).textContent = `${runtime.name}:`;
+      this._dom.find('.lh-env__description', item).textContent = runtime.description;
+      env.appendChild(item);
+    });
+
     this._dom.find('.lh-footer__version', footer).textContent = report.lighthouseVersion;
-    this._dom.find('.lh-footer__timestamp', footer).textContent =
-        Util.formatDateTime(report.generatedTime);
     return footer;
   }
 
   /**
-   * @param {!ReportRenderer.ReportJSON} report
-   * @return {!DocumentFragment}
-   */
-  _renderReportNav(report) {
-    const leftNav = this._dom.cloneTemplate('#tmpl-lh-leftnav', this._templateContext);
-
-    this._dom.find('.leftnav__header__version', leftNav).textContent =
-        `Version: ${report.lighthouseVersion}`;
-
-    const nav = this._dom.find('.lh-leftnav', leftNav);
-    for (const category of report.reportCategories) {
-      const itemsTmpl = this._dom.cloneTemplate('#tmpl-lh-leftnav__items', leftNav);
-
-      const navItem = this._dom.find('.lh-leftnav__item', itemsTmpl);
-      navItem.href = `#${category.id}`;
-
-      this._dom.find('.leftnav-item__category', navItem).textContent = category.name;
-      const score = this._dom.find('.leftnav-item__score', navItem);
-      score.classList.add(`lh-score__value--${Util.calculateRating(category.score)}`);
-      score.textContent = Math.round(category.score);
-      nav.appendChild(navItem);
-    }
-    return leftNav;
-  }
-
-  /**
    * Returns a div with a list of top-level warnings, or an empty div if no warnings.
-   * @param {!ReportRenderer.ReportJSON} report
-   * @return {!Node}
+   * @param {ReportJSON} report
+   * @return {Node}
    */
   _renderReportWarnings(report) {
     if (!report.runWarnings || report.runWarnings.length === 0) {
       return this._dom.createElement('div');
     }
 
-    const container = this._dom.cloneTemplate('#tmpl-lh-run-warnings', this._templateContext);
+    const container = this._dom.cloneTemplate('#tmpl-lh-warnings--toplevel', this._templateContext);
     const warnings = this._dom.find('ul', container);
     for (const warningString of report.runWarnings) {
       const warning = warnings.appendChild(this._dom.createElement('li'));
@@ -135,13 +136,23 @@
   }
 
   /**
-   * @param {!ReportRenderer.ReportJSON} report
-   * @return {!Element}
+   * @param {ReportJSON} report
+   * @return {DocumentFragment}
    */
   _renderReport(report) {
+    let header;
+    const headerContainer = this._dom.createElement('div');
+    if (this._dom.isDevTools()) {
+      headerContainer.classList.add('lh-header-plain');
+      header = this._renderReportShortHeader();
+    } else {
+      headerContainer.classList.add('lh-header-sticky');
+      header = this._renderReportHeader(report);
+    }
+    headerContainer.appendChild(header);
+    const scoresContainer = this._dom.find('.lh-scores-container', headerContainer);
+
     const container = this._dom.createElement('div', 'lh-container');
-    container.appendChild(this._renderReportHeader(report)); // sticky header goes at the top.
-    container.appendChild(this._renderReportNav(report));
     const reportSection = container.appendChild(this._dom.createElement('div', 'lh-report'));
 
     reportSection.appendChild(this._renderReportWarnings(report));
@@ -149,20 +160,58 @@
     let scoreHeader;
     const isSoloCategory = report.reportCategories.length === 1;
     if (!isSoloCategory) {
-      scoreHeader = reportSection.appendChild(this._dom.createElement('div', 'lh-scores-header'));
+      scoreHeader = this._dom.createElement('div', 'lh-scores-header');
+    } else {
+      headerContainer.classList.add('lh-header--solo-category');
     }
 
+    const detailsRenderer = new DetailsRenderer(this._dom);
+    const categoryRenderer = new CategoryRenderer(this._dom, detailsRenderer);
+    categoryRenderer.setTemplateContext(this._templateContext);
+    const perfCategoryRenderer = new PerformanceCategoryRenderer(this._dom, detailsRenderer);
+    perfCategoryRenderer.setTemplateContext(this._templateContext);
+
     const categories = reportSection.appendChild(this._dom.createElement('div', 'lh-categories'));
+
     for (const category of report.reportCategories) {
       if (scoreHeader) {
-        scoreHeader.appendChild(this._categoryRenderer.renderScoreGauge(category));
+        scoreHeader.appendChild(categoryRenderer.renderScoreGauge(category));
       }
-      categories.appendChild(this._categoryRenderer.render(category, report.reportGroups));
+
+      let renderer = categoryRenderer;
+      if (category.id === 'performance') {
+        renderer = perfCategoryRenderer;
+      }
+      categories.appendChild(renderer.render(category, report.categoryGroups));
+    }
+
+    if (scoreHeader) {
+      const scoreScale = this._dom.cloneTemplate('#tmpl-lh-scorescale', this._templateContext);
+      scoresContainer.appendChild(scoreHeader);
+      scoresContainer.appendChild(scoreScale);
     }
 
     reportSection.appendChild(this._renderReportFooter(report));
 
-    return container;
+    const reportFragment = this._dom.createFragment();
+    reportFragment.appendChild(headerContainer);
+    reportFragment.appendChild(container);
+
+    return reportFragment;
+  }
+
+  /**
+   * Place the AuditResult into the auditDfn (which has just weight & group)
+   * @param {Object<string, LH.Audit.Result>} audits
+   * @param {Array<CategoryJSON>} reportCategories
+   */
+  static smooshAuditResultsIntoCategories(audits, reportCategories) {
+    for (const category of reportCategories) {
+      category.auditRefs.forEach(auditMeta => {
+        const result = audits[auditMeta.id];
+        auditMeta.result = result;
+      });
+    }
   }
 }
 
@@ -174,65 +223,46 @@
 
 /**
  * @typedef {{
- *     id: string,
- *     weight: number,
- *     score: number,
- *     group: string,
- *     result: {
- *       rawValue: (number|undefined),
- *       description: string,
- *       informative: boolean,
- *       manual: boolean,
- *       notApplicable: boolean,
- *       debugString: string,
- *       displayValue: string,
- *       helpText: string,
- *       score: (number|boolean),
- *       scoringMode: string,
- *       extendedInfo: Object,
- *       details: (!DetailsRenderer.DetailsJSON|undefined)
- *     }
- * }}
+      id: string,
+      score: (number|null),
+      weight: number,
+      group?: string,
+      result: LH.Audit.Result
+  }} AuditJSON
  */
-ReportRenderer.AuditJSON; // eslint-disable-line no-unused-expressions
 
 /**
  * @typedef {{
- *     name: string,
- *     id: string,
- *     weight: number,
- *     score: number,
- *     description: string,
- *     audits: !Array<!ReportRenderer.AuditJSON>
- * }}
+      title: string,
+      id: string,
+      score: (number|null),
+      description?: string,
+      manualDescription: string,
+      auditRefs: Array<AuditJSON>
+  }} CategoryJSON
  */
-ReportRenderer.CategoryJSON; // eslint-disable-line no-unused-expressions
 
 /**
  * @typedef {{
- *     title: string,
- *     description: (string|undefined),
- * }}
+      title: string,
+      description?: string,
+  }} GroupJSON
  */
-ReportRenderer.GroupJSON; // eslint-disable-line no-unused-expressions
 
 /**
  * @typedef {{
- *     lighthouseVersion: string,
- *     userAgent: string,
- *     generatedTime: string,
- *     timing: {total: number},
- *     initialUrl: string,
- *     url: string,
- *     runWarnings: (!Array<string>|undefined),
- *     artifacts: {traces: {defaultPass: {traceEvents: !Array}}},
- *     reportCategories: !Array<!ReportRenderer.CategoryJSON>,
- *     reportGroups: !Object<string, !ReportRenderer.GroupJSON>,
- *     runtimeConfig: {
- *       blockedUrlPatterns: !Array<string>,
- *       extraHeaders: !Object,
- *       environment: !Array<{description: string, enabled: boolean, name: string}>
- *     }
- * }}
+      lighthouseVersion: string,
+      userAgent: string,
+      fetchTime: string,
+      timing: {total: number},
+      requestedUrl: string,
+      finalUrl: string,
+      runWarnings?: Array<string>,
+      artifacts: {traces: {defaultPass: {traceEvents: Array}}},
+      audits: Object<string, LH.Audit.Result>,
+      categories: Object<string, CategoryJSON>,
+      reportCategories: Array<CategoryJSON>,
+      categoryGroups: Object<string, GroupJSON>,
+      configSettings: LH.Config.Settings,
+  }} ReportJSON
  */
-ReportRenderer.ReportJSON; // eslint-disable-line no-unused-expressions
diff --git a/front_end/audits2/lighthouse/renderer/util.js b/front_end/audits2/lighthouse/renderer/util.js
index f979251..87fc3a7 100644
--- a/front_end/audits2/lighthouse/renderer/util.js
+++ b/front_end/audits2/lighthouse/renderer/util.js
@@ -9,20 +9,106 @@
 
 const ELLIPSIS = '\u2026';
 const NBSP = '\xa0';
+const PASS_THRESHOLD = 0.75;
 
 const RATINGS = {
-  PASS: {label: 'pass', minScore: 75},
-  AVERAGE: {label: 'average', minScore: 45},
+  PASS: {label: 'pass', minScore: PASS_THRESHOLD},
+  AVERAGE: {label: 'average', minScore: 0.45},
   FAIL: {label: 'fail'},
+  ERROR: {label: 'error'},
 };
 
 class Util {
+  static get PASS_THRESHOLD() {
+    return PASS_THRESHOLD;
+  }
+
+  static get MS_DISPLAY_VALUE() {
+    return `%10d${NBSP}ms`;
+  }
+
   /**
-   * Convert a score to a rating label.
-   * @param {number} score
+   * @param {string|Array<string|number>=} displayValue
    * @return {string}
    */
-  static calculateRating(score) {
+  static formatDisplayValue(displayValue) {
+    if (typeof displayValue === 'string') return displayValue;
+    if (!displayValue) return '';
+
+    const replacementRegex = /%([0-9]*(\.[0-9]+)?d|s)/;
+    const template = /** @type {string} */ (displayValue[0]);
+    if (typeof template !== 'string') {
+      // First value should always be the format string, but we don't want to fail to build
+      // a report, return a placeholder.
+      return 'UNKNOWN';
+    }
+
+    let output = template;
+    for (const replacement of displayValue.slice(1)) {
+      if (!replacementRegex.test(output)) {
+        // eslint-disable-next-line no-console
+        console.warn('Too many replacements given');
+        break;
+      }
+
+      output = output.replace(replacementRegex, match => {
+        const granularity = Number(match.match(/[0-9.]+/)) || 1;
+        return match === '%s' ?
+          replacement.toLocaleString() :
+          (Math.round(Number(replacement) / granularity) * granularity).toLocaleString();
+      });
+    }
+
+    if (replacementRegex.test(output)) {
+      // eslint-disable-next-line no-console
+      console.warn('Not enough replacements given');
+    }
+
+    return output;
+  }
+
+  /**
+   * Used to determine if the "passed" for the purposes of showing up in the "failed" or "passed"
+   * sections of the report.
+   *
+   * @param {{score: (number|null), scoreDisplayMode: string}} audit
+   * @return {boolean}
+   */
+  static showAsPassed(audit) {
+    switch (audit.scoreDisplayMode) {
+      case 'manual':
+      case 'not-applicable':
+        return true;
+      case 'error':
+      case 'informative':
+        return false;
+      case 'numeric':
+      case 'binary':
+      default:
+        // Numeric audits that are within PASS_THRESHOLD will still show up with failing.
+        // For opportunities, we want to have them show up with other failing for contrast.
+        // For diagnostics, we sort by score so they'll be lowest priority.
+        return Number(audit.score) === 1;
+    }
+  }
+
+  /**
+   * Convert a score to a rating label.
+   * @param {number|null} score
+   * @param {string=} scoreDisplayMode
+   * @return {string}
+   */
+  static calculateRating(score, scoreDisplayMode) {
+    // Handle edge cases first, manual and not applicable receive 'pass', errored audits receive 'error'
+    if (scoreDisplayMode === 'manual' || scoreDisplayMode === 'not-applicable') {
+      return RATINGS.PASS.label;
+    } else if (scoreDisplayMode === 'error') {
+      return RATINGS.ERROR.label;
+    } else if (score === null) {
+      return RATINGS.FAIL.label;
+    }
+
+    // At this point, we're rating a standard binary/numeric audit
     let rating = RATINGS.FAIL.label;
     if (score >= RATINGS.PASS.minScore) {
       rating = RATINGS.PASS.label;
@@ -35,20 +121,21 @@
   /**
    * Format number.
    * @param {number} number
-   * @param {number=} decimalPlaces Number of decimal places to include. Defaults to 1.
+   * @param {number=} granularity Number of decimal places to include. Defaults to 0.1.
    * @return {string}
    */
-  static formatNumber(number, decimalPlaces = 1) {
-    return number.toLocaleString(undefined, {maximumFractionDigits: decimalPlaces});
+  static formatNumber(number, granularity = 0.1) {
+    const coarseValue = Math.round(number / granularity) * granularity;
+    return coarseValue.toLocaleString();
   }
 
   /**
    * @param {number} size
-   * @param {number=} decimalPlaces Number of decimal places to include. Defaults to 2.
+   * @param {number=} granularity Controls how coarse the displayed value is, defaults to .01
    * @return {string}
    */
-  static formatBytesToKB(size, decimalPlaces = 2) {
-    const kbs = (size / 1024).toLocaleString(undefined, {maximumFractionDigits: decimalPlaces});
+  static formatBytesToKB(size, granularity = 0.1) {
+    const kbs = (Math.round(size / 1024 / granularity) * granularity).toLocaleString();
     return `${kbs}${NBSP}KB`;
   }
 
@@ -63,6 +150,16 @@
   }
 
   /**
+   * @param {number} ms
+   * @param {number=} granularity Controls how coarse the displayed value is, defaults to 0.1
+   * @return {string}
+   */
+  static formatSeconds(ms, granularity = 0.1) {
+    const coarseTime = Math.round(ms / 1000 / granularity) * granularity;
+    return `${coarseTime.toLocaleString()}${NBSP}s`;
+  }
+
+  /**
    * Format time.
    * @param {string} date
    * @return {string}
@@ -84,19 +181,19 @@
     return formatter.format(new Date(date));
   }
   /**
-   * Converts a time in seconds into a duration string, i.e. `1d 2h 13m 52s`
-   * @param {number} timeInSeconds
-   * @param {string=} zeroLabel
+   * Converts a time in milliseconds into a duration string, i.e. `1d 2h 13m 52s`
+   * @param {number} timeInMilliseconds
    * @return {string}
    */
-  static formatDuration(timeInSeconds, zeroLabel = 'None') {
-    if (timeInSeconds === 0) {
-      return zeroLabel;
+  static formatDuration(timeInMilliseconds) {
+    let timeInSeconds = timeInMilliseconds / 1000;
+    if (Math.round(timeInSeconds) === 0) {
+      return 'None';
     }
 
-    /** @type {!Array<string>} */
+    /** @type {Array<string>} */
     const parts = [];
-    const unitLabels = /** @type {!Object<string, number>} */ ({
+    const unitLabels = /** @type {Object<string, number>} */ ({
       d: 60 * 60 * 24,
       h: 60 * 60,
       m: 60,
@@ -116,12 +213,14 @@
   }
 
   /**
-   * @param {!URL} parsedUrl
-   * @param {{numPathParts: (number|undefined), preserveQuery: (boolean|undefined), preserveHost: (boolean|undefined)}=} options
+   * @param {URL} parsedUrl
+   * @param {{numPathParts?: number, preserveQuery?: boolean, preserveHost?: boolean}=} options
    * @return {string}
    */
   static getURLDisplayName(parsedUrl, options) {
-    options = options || {};
+    // Closure optional properties aren't optional in tsc, so fallback needs undefined  values.
+    options = options || {numPathParts: undefined, preserveQuery: undefined,
+      preserveHost: undefined};
     const numPathParts = options.numPathParts !== undefined ? options.numPathParts : 2;
     const preserveQuery = options.preserveQuery !== undefined ? options.preserveQuery : true;
     const preserveHost = options.preserveHost || false;
@@ -151,7 +250,7 @@
     name = name.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g, `$1${ELLIPSIS}`);
     // Also elide other hash-like mixed-case strings
     name = name.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,
-        `$1${ELLIPSIS}`);
+      `$1${ELLIPSIS}`);
     // Also elide long number sequences
     name = name.replace(/(\d{3})\d{6,}/g, `$1${ELLIPSIS}`);
     // Merge any adjacent ellipses
@@ -173,8 +272,8 @@
       const dotIndex = name.lastIndexOf('.');
       if (dotIndex >= 0) {
         name = name.slice(0, MAX_LENGTH - 1 - (name.length - dotIndex)) +
-            // Show file extension
-            `${ELLIPSIS}${name.slice(dotIndex)}`;
+          // Show file extension
+          `${ELLIPSIS}${name.slice(dotIndex)}`;
       } else {
         name = name.slice(0, MAX_LENGTH - 1) + ELLIPSIS;
       }
@@ -184,13 +283,17 @@
   }
 
   /**
-   * Split a URL into a file and hostname for easy display.
+   * Split a URL into a file, hostname and origin for easy display.
    * @param {string} url
-   * @return {{file: string, hostname: string}}
+   * @return {{file: string, hostname: string, origin: string}}
    */
   static parseURL(url) {
     const parsedUrl = new URL(url);
-    return {file: Util.getURLDisplayName(parsedUrl), hostname: parsedUrl.hostname};
+    return {
+      file: Util.getURLDisplayName(parsedUrl),
+      hostname: parsedUrl.hostname,
+      origin: parsedUrl.origin,
+    };
   }
 
   /**
@@ -201,11 +304,82 @@
   static chainDuration(startTime, endTime) {
     return Util.formatNumber((endTime - startTime) * 1000);
   }
+
+  /**
+   * @param {LH.Config.Settings} settings
+   * @return {Array<{name: string, description: string}>}
+   */
+  static getEnvironmentDisplayValues(settings) {
+    const emulationDesc = Util.getEmulationDescriptions(settings);
+
+    return [
+      {
+        name: 'Device',
+        description: emulationDesc.deviceEmulation,
+      },
+      {
+        name: 'Network throttling',
+        description: emulationDesc.networkThrottling,
+      },
+      {
+        name: 'CPU throttling',
+        description: emulationDesc.cpuThrottling,
+      },
+    ];
+  }
+
+  /**
+   * @param {LH.Config.Settings} settings
+   * @return {{deviceEmulation: string, networkThrottling: string, cpuThrottling: string, summary: string}}
+   */
+  static getEmulationDescriptions(settings) {
+    let cpuThrottling;
+    let networkThrottling;
+    let summary;
+
+    const throttling = settings.throttling;
+
+    switch (settings.throttlingMethod) {
+      case 'provided':
+        cpuThrottling = 'Provided by environment';
+        networkThrottling = 'Provided by environment';
+        summary = 'No throttling applied';
+        break;
+      case 'devtools': {
+        const {cpuSlowdownMultiplier, requestLatencyMs} = throttling;
+        cpuThrottling = `${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (DevTools)`;
+        networkThrottling = `${Util.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, ` +
+          `${Util.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, ` +
+          `${Util.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;
+        summary = 'Throttled Fast 3G network';
+        break;
+      }
+      case 'simulate': {
+        const {cpuSlowdownMultiplier, rttMs, throughputKbps} = throttling;
+        cpuThrottling = `${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
+        networkThrottling = `${Util.formatNumber(rttMs)}${NBSP}ms TCP RTT, ` +
+          `${Util.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;
+        summary = 'Simulated Fast 3G network';
+        break;
+      }
+      default:
+        cpuThrottling = 'Unknown';
+        networkThrottling = 'Unknown';
+        summary = 'Unknown';
+    }
+
+    const deviceEmulation = settings.disableDeviceEmulation ? 'No emulation' : 'Emulated Nexus 5X';
+    return {
+      deviceEmulation,
+      cpuThrottling,
+      networkThrottling,
+      summary: `${deviceEmulation}, ${summary}`,
+    };
+  }
 }
 
 if (typeof module !== 'undefined' && module.exports) {
   module.exports = Util;
 } else {
-  // @ts-ignore
   self.Util = Util;
 }
diff --git a/front_end/audits2/lighthouse/report-styles.css b/front_end/audits2/lighthouse/report-styles.css
index e56bc6e..c3c9a43 100644
--- a/front_end/audits2/lighthouse/report-styles.css
+++ b/front_end/audits2/lighthouse/report-styles.css
@@ -7,10 +7,13 @@
 .lh-vars {
   --text-font-family: Roboto, Helvetica, Arial, sans-serif;
   --monospace-font-family: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;
+  --body-background-color: #fff;
   --body-font-size: 14px;
   --body-line-height: 18px;
-  --subheader-font-size: 16px;
+  --subheader-font-size: 14px;
   --subheader-line-height: 20px;
+  --subheader-color: hsl(206, 6%, 25%);
+  --header-bg-color: #f1f3f4;
   --header-font-size: 20px;
   --header-line-height: 24px;
   --title-font-size: 24px;
@@ -18,25 +21,31 @@
   --caption-font-size: 12px;
   --caption-line-height: 16px;
   --default-padding: 12px;
-  --section-padding: 20px;
+  --section-padding: 16px;
   --section-indent: 16px;
   --audit-group-indent: 16px;
+  --audit-item-gap: 5px;
   --audit-indent: 16px;
+  --text-indent: 8px;
   --expandable-indent: 20px;
   --secondary-text-color: #565656;
   /*--accent-color: #3879d9;*/
-  --fail-color: #df332f;
-  --pass-color: #2b882f;
+  --fail-color: hsl(1, 73%, 45%);
+  --average-color: hsl(31, 100%, 45%); /* md orange 800 */
+  --pass-color: hsl(139, 70%, 30%);
   --informative-color: #0c50c7;
-  --manual-color: #757575;
-  --average-color: #ef6c00; /* md orange 800 */
+  --medium-75-gray: #757575;
+  --medium-50-gray: hsl(210, 17%, 98%);
+  --medium-100-gray: hsl(200, 12%, 95%);
   --warning-color: #ffab00; /* md amber a700 */
   --report-border-color: #ccc;
   --report-secondary-border-color: #ebebeb;
   --metric-timeline-rule-color: #b3b3b3;
+  --display-value-gray: hsl(216, 5%, 39%);
   --report-width: calc(60 * var(--body-font-size));
-  --report-menu-width: calc(20 * var(--body-font-size));
-  --report-content-width: calc(var(--report-width) + var(--report-menu-width));
+  --report-content-width: calc(var(--report-width));
+  --report-header-height: 161px;
+  --report-header-color: #202124;
   --navitem-font-size: var(--body-font-size);
   --navitem-line-height: var(--body-line-height);
   --navitem-hpadding: var(--body-font-size);
@@ -44,21 +53,34 @@
   --lh-score-highlight-bg: hsla(0, 0%, 90%, 0.2);
   --lh-score-icon-background-size: 24px;
   --lh-score-margin: 12px;
-  --lh-table-header-bg: hsla(0, 0%, 50%, 0.4);
+  --lh-table-header-bg: #f8f9fa;
   --lh-table-higlight-bg: hsla(0, 0%, 75%, 0.1);
   --lh-sparkline-height: 5px;
   --lh-sparkline-thin-height: 3px;
   --lh-filmstrip-thumbnail-width: 60px;
-  --lh-audit-score-width: calc(5 * var(--body-font-size));
+  --lh-score-icon-width: calc(var(--body-font-size) / 14 * 16);
   --lh-category-score-width: calc(5 * var(--body-font-size));
   --lh-audit-vpadding: 8px;
+  --lh-audit-index-width: 18px;
   --lh-audit-hgap: 12px;
-  --lh-audit-group-vpadding: 12px;
+  --lh-audit-group-vpadding: 8px;
   --lh-section-vpadding: 12px;
-  --pass-icon-url: url('data:image/svg+xml;utf8,<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path stroke="%23007F04" stroke-width="1.5" d="M1 5.75l3.5 3.5 6.5-6.5" fill="none" fill-rule="evenodd"/></svg>');
-  --fail-icon-url: url('data:image/svg+xml;utf8,<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><g stroke="%23EE1D0A" stroke-width="1.5" fill="none" fill-rule="evenodd"><path d="M2 10l8-8M10 10L2 2"/></g></svg>');
-  --collapsed-icon-url: url('data:image/svg+xml;utf8,<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="none" d="M0 0h12v12H0z"/><path fill="hsl(0, 0%, 60%)" d="M3 2l6 4-6 4z"/></g></svg>');
-  --expanded-icon-url: url('data:image/svg+xml;utf8,<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="none" d="M0 0h12v12H0z"/><path fill="hsl(0, 0%, 60%)" d="M10 3L6 9 2 3z"/></g></svg>');
+  --chevron-size: 12px;
+
+  /* Voodoo magic here to get narrow columns. 0 doesn't size the column like our friend 1px does */
+  --bytes-col-width: 1px;
+
+  --pass-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>check</title><path fill="hsl(139, 70%, 30%)" d="M24 4C12.95 4 4 12.95 4 24c0 11.04 8.95 20 20 20 11.04 0 20-8.96 20-20 0-11.05-8.96-20-20-20zm-4 30L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z"/></svg>');
+  --average-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>info</title><path fill="hsl(31, 100%, 45%)" d="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm2 30h-4V22h4v12zm0-16h-4v-4h4v4z"/></svg>');
+  --fail-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>warn</title><path fill="hsl(1, 73%, 45%)" d="M2 42h44L24 4 2 42zm24-6h-4v-4h4v4zm0-8h-4v-8h4v8z"/></svg>');
+
+  --av-timer-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M22 34c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zm0-28v8h4v-3.84c6.78.97 12 6.79 12 13.84 0 7.73-6.27 14-14 14s-14-6.27-14-14c0-3.36 1.18-6.43 3.15-8.85L24 26l2.83-2.83-13.6-13.6-.02.04C8.84 12.89 6 18.11 6 24c0 9.94 8.04 18 17.99 18S42 33.94 42 24 33.94 6 23.99 6H22zm14 18c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm-24 0c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2z" fill="hsl(216, 5%, 39%)"/></svg>');
+  --photo-filter-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path fill="none" d="M0 0h48v48H0V0z"/><path d="M38.04 20v18H10V10h18V6H10.04c-2.2 0-4 1.8-4 4v28c0 2.2 1.8 4 4 4h28c2.2 0 4-1.8 4-4V20h-4zM34 20l1.88-4.12L40 14l-4.12-1.88L34 8l-1.88 4.12L28 14l4.12 1.88zm-7.5 1.5L24 16l-2.5 5.5L16 24l5.5 2.5L24 32l2.5-5.5L32 24z" fill="hsl(216, 5%, 39%)"/></svg>');
+  --visibility-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M24 9C14 9 5.46 15.22 2 24c3.46 8.78 12 15 22 15 10.01 0 18.54-6.22 22-15-3.46-8.78-11.99-15-22-15zm0 25c-5.52 0-10-4.48-10-10s4.48-10 10-10 10 4.48 10 10-4.48 10-10 10zm0-16c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6z" fill="hsl(216, 5%, 39%)"/></svg>');
+  --check-circle-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M24 4C12.95 4 4 12.95 4 24c0 11.04 8.95 20 20 20 11.04 0 20-8.96 20-20 0-11.05-8.96-20-20-20zm-4 30L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z" fill="hsl(216, 5%, 39%)"/></svg>');
+  --check-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M0 0h48v48H0z" fill="none"/><path d="M18 32.34L9.66 24l-2.83 2.83L18 38l24-24-2.83-2.83z"/></svg>');
+  --search-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48"><path d="M31 28h-1.59l-.55-.55C30.82 25.18 32 22.23 32 19c0-7.18-5.82-13-13-13S6 11.82 6 19s5.82 13 13 13c3.23 0 6.18-1.18 8.45-3.13l.55.55V31l10 9.98L40.98 38 31 28zm-12 0a9 9 0 1 1 .001-18.001A9 9 0 0 1 19 28z" fill="hsl(216, 5%, 39%)"/><path d="M0 0h48v48H0z" fill="none" /></svg>');
+  --remove-circle-icon-url: url('data:image/svg+xml;utf8,<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" fill="hsl(216, 5%, 39%)"/></svg>');
 }
 
 .lh-vars.lh-devtools {
@@ -75,15 +97,15 @@
   --caption-font-size: 11px;
   --caption-line-height: 14px;
   --default-padding: 12px;
-  --section-padding: 16px;
-  --section-indent: 16px;
+  --section-padding: 12px;
+  --section-indent: 8px;
   --audit-group-indent: 16px;
   --audit-indent: 16px;
   --expandable-indent: 16px;
 
   --lh-audit-vpadding: 4px;
   --lh-audit-hgap: 12px;
-  --lh-audit-group-vpadding: 8px;
+  --lh-audit-group-vpadding: 12px;
   --lh-section-vpadding: 8px;
 }
 
@@ -101,37 +123,43 @@
   font-size: var(--body-font-size);
   margin: 0;
   line-height: var(--body-line-height);
-  background: #f5f5f5;
+  background: var(--body-background-color);
   scroll-behavior: smooth;
 }
 
 .lh-root :focus {
     outline: -webkit-focus-ring-color auto 3px;
 }
+.lh-root summary:focus {
+    outline: 1px solid hsl(217, 89%, 61%);
+}
+
 
 .lh-root [hidden] {
   display: none !important;
 }
 
-a {
+.lh-audit-group a,
+.lh-category-header__description a {
   color: #0c50c7;
 }
 
-summary {
-  cursor: pointer;
+
+.lh-audit__description,
+.lh-load-opportunity__description,
+.lh-details {
+  --inner-audit-left-padding: calc(var(--text-indent) + var(--lh-audit-index-width) + 2 * var(--audit-item-gap));
+  --inner-audit-right-padding: calc(var(--text-indent) + 2px);
+  margin-left: var(--inner-audit-left-padding);
+  margin-right: var(--inner-audit-right-padding);
 }
 
 .lh-details {
   font-size: var(--body-font-size);
   margin-top: var(--default-padding);
-}
-
-.lh-details[open] summary {
   margin-bottom: var(--default-padding);
-}
-
-.lh-details summary::-webkit-details-marker {
-  color: #9e9e9e;
+  /* whatever the .lh-details side margins are */
+  width: calc(100% - var(--inner-audit-left-padding) - var(--inner-audit-right-padding));
 }
 
 .lh-details.flex .lh-code {
@@ -167,20 +195,6 @@
   background-image: url('data:image/svg+xml;utf8,<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
 }
 
-/* List */
-.lh-list {
-  font-size: smaller;
-  margin-top: var(--default-padding);
-}
-
-.lh-list__items {
-  padding-left: var(--default-padding);
-}
-
-.lh-list__item {
-  margin-bottom: 2px;
-}
-
 /* Node */
 .lh-node {
   display: block;
@@ -188,195 +202,101 @@
   word-break: break-word;
   color: hsl(174, 100%, 27%);
 }
-span.lh-node:hover {
+.lh-node:hover {
     background: hsl(0, 0%, 98%);
     border-radius: 2px;
 }
 
-/* Card */
-.lh-scorecards {
-  display: flex;
-  flex-wrap: wrap;
-}
-.lh-scorecard {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex: 0 0 calc(12 * var(--body-font-size));
-  flex-direction: column;
-  padding: var(--default-padding);
-  padding-top: calc(32px + var(--default-padding));
-  border-radius: 3px;
-  margin-right: var(--default-padding);
-  position: relative;
-  line-height: inherit;
-  border: 1px solid #ebebeb;
-}
-.lh-scorecard__title {
-  background-color: #eee;
-  position: absolute;
-  top: 0;
-  right: 0;
-  left: 0;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  padding: calc(var(--default-padding) / 2);
-}
-.lh-scorecard__value {
-  font-size: calc(1.6 * var(--body-font-size));
-}
-.lh-scorecard__target {
-  margin-top: calc(var(--default-padding) / 2);
-}
-
 /* Score */
 
-.lh-score {
-  display: flex;
-  align-items: flex-start;
-}
-
-.lh-score__value {
-  flex: none;
+.lh-audit__score-icon {
   margin-left: var(--lh-score-margin);
-  width: calc(var(--lh-audit-score-width) - var(--lh-score-margin));
-  position: relative;
-  font-weight: bold;
-  top: 1px;
-  text-align: right;
+  width: var(--lh-score-icon-width);
+  height: var(--lh-score-icon-width);
+  background: none no-repeat center center / contain;
 }
 
-.lh-score__value::after {
-  content: '';
-  position: absolute;
-  right: 0;
-  top: 0;
-  bottom: 0;
-  border-radius: inherit;
-  width: 16px;
-}
-
-.lh-score--informative .lh-score__value {
-  color: var(--informative-color);
-  border-radius: 50%;
-  top: 3px;
-}
-
-.lh-score--informative .lh-score__value::after {
-  display: none;
-  background: url('data:image/svg+xml;utf8,<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>info</title><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" fill="hsl(218, 89%, 41%)"/></svg>') no-repeat 50% 50%;
-  background-size: var(--lh-score-icon-background-size);
-}
-
-.lh-score--manual .lh-score__value::after {
-  background: url('data:image/svg+xml;utf8,<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><title>manual</title><path d="M2 5h8v2H2z" fill="hsl(0, 0%, 100%)" fill-rule="evenodd"/></svg>') no-repeat 50% 50%;
-  background-size: 18px;
-  background-color: var(--manual-color);
-  width: 20px;
-  height:  20px;
-  position: relative;
-}
-
-.lh-score__value--binary {
-  color: transparent !important;
-}
-
-/* No icon for audits with number scores. */
-.lh-score__value:not(.lh-score__value--binary)::after {
-  content: none;
-}
-
-.lh-score__value--pass {
+.lh-audit--pass .lh-audit__display-text {
   color: var(--pass-color);
 }
-
-.lh-score__value--pass::after {
-  background: var(--pass-icon-url) no-repeat center center / 12px 12px;
+.lh-audit--pass .lh-audit__score-icon {
+  background-image: var(--pass-icon-url);
 }
 
-.lh-score__value--average {
+.lh-audit--average .lh-audit__display-text {
   color: var(--average-color);
 }
-
-.lh-score__value--average::after {
-  background: none;
-  content: '!';
-  color: var(--average-color);
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  font-weight: 500;
-  font-size: 15px;
+.lh-audit--average .lh-audit__score-icon {
+  background-image: var(--average-icon-url);
 }
 
-.lh-score__value--fail {
+.lh-audit--fail .lh-audit__display-text {
   color: var(--fail-color);
 }
-
-.lh-score__value--fail::after {
-  background: var(--fail-icon-url) no-repeat center center / 12px 12px;
+.lh-audit--fail .lh-audit__score-icon {
+  background-image: var(--fail-icon-url);
 }
 
-.lh-score__description {
-  font-size: var(--body-font-size);
-  color: var(--secondary-text-color);
-  line-height: var(--body-line-height);
+.lh-audit--informative .lh-audit__display-text {
+  color: var(--display-value-gray);
 }
 
-.lh-score__snippet {
-  align-items: center;
-  justify-content: space-between;
-  /*outline: none;*/
+.lh-audit--informative .lh-audit__score-icon,
+.lh-audit--manual .lh-audit__score-icon {
+  visibility: hidden;
 }
-
-.lh-score__snippet::-moz-list-bullet {
+.lh-audit--error .lh-audit__score-icon {
   display: none;
 }
 
-.lh-score__title {
+.lh-category-header__description,
+.lh-audit__description   {
+  color: var(--secondary-text-color);
+}
+
+.lh-category-header__description  {
+  font-size: var(--body-font-size);
+  margin: calc(var(--default-padding) / 2) 0 var(--default-padding);
+}
+
+
+.lh-audit__index,
+.lh-audit__title,
+.lh-audit__display-text,
+.lh-audit__score-icon,
+.lh-load-opportunity__sparkline,
+.lh-chevron-container {
+  margin: 0 var(--audit-item-gap);
+}
+.lh-audit__index {
+  margin-left: 0;
+}
+.lh-chevron-container {
+  margin-right: 0;
+}
+
+
+.lh-audit__header .lh-audit__index {
+  width: var(--lh-audit-index-width);
+}
+
+.lh-audit__title {
   flex: 1;
 }
 
-.lh-toggle-arrow {
-  background: var(--collapsed-icon-url) no-repeat center center / 12px 12px;
-  background-color: transparent;
-  width: 12px;
-  height: 12px;
-  flex: none;
-  transition: transform 150ms ease-in-out;
-  cursor: pointer;
-  border: none;
-  order: -1;
-  margin-right: calc(var(--expandable-indent) - 12px);
-  align-self: flex-start;
-}
-
-.lh-toggle-arrow-unexpandable {
-  visibility: hidden;
-}
-
 /* Expandable Details (Audit Groups, Audits) */
-
-.lh-score__header {
-  order: -1;
-  flex: 1;
-}
-
-.lh-expandable-details {
-  padding-left: var(--expandable-indent);
-}
-
-.lh-expandable-details__summary {
+.lh-audit__header {
   display: flex;
-  align-items: center;
+  padding: var(--lh-audit-vpadding) var(--text-indent);
   cursor: pointer;
-  margin-left: calc(0px - var(--expandable-indent));
 }
 
-.lh-audit-group[open] > .lh-audit-group__summary > .lh-toggle-arrow,
-.lh-expandable-details[open] > .lh-expandable-details__summary > .lh-toggle-arrow {
-  background-image: var(--expanded-icon-url);
+.lh-audit--load-opportunity .lh-audit__header {
+  display: block;
+}
+
+.lh-audit__header:hover {
+  background-color: #F8F9FA;
 }
 
 .lh-audit-group__summary::-webkit-details-marker,
@@ -384,200 +304,176 @@
   display: none;
 }
 
-.lh-score__snippet .lh-toggle-arrow {
-  margin-top: calc((var(--body-line-height) - 12px) / 2);
-}
 
-/* Perf Timeline */
+/* Perf Metric */
 
-.lh-timeline-container {
-  overflow: hidden;
-  border-top: 1px solid var(--metric-timeline-rule-color);
-}
-
-.lh-timeline {
-  padding: 0;
-  padding-bottom: 0;
-  width: calc(var(--lh-filmstrip-thumbnail-width) * 10 + var(--default-padding) * 2);
-}
-
-.lh-narrow .lh-timeline-container {
-  width: calc(100vw - var(--section-padding) * 2);
-  overflow-x: scroll;
-}
-
-.lh-devtools .lh-timeline-container {
-  width: 100%;
-  overflow-x: scroll;
-}
-
-/* Perf Timeline Metric */
-
-.lh-timeline-metric {
-  position: relative;
-  margin-bottom: calc(2 * var(--lh-audit-vpadding));
-  padding-top: var(--lh-audit-vpadding);
-  border-top: 1px solid var(--report-secondary-border-color);
-}
-
-.lh-timeline-metric__header {
+.lh-metric-container {
   display: flex;
 }
 
-.lh-timeline-metric__details {
+.lh-metric-column {
+  flex: 1;
+}
+.lh-metric-column:first-of-type {
+  margin-right: 20px;
+}
+
+.lh-metric {
+  border-bottom: 1px solid var(--report-secondary-border-color);
+}
+
+.lh-metric__innerwrap {
+  display: flex;
+  justify-content: space-between;
+  padding: 11px var(--text-indent);
+}
+
+.lh-metric__details {
   order: -1;
 }
 
-.lh-timeline-metric__title {
+.lh-metric__title {
   font-size: var(--body-font-size);
   line-height: var(--body-line-height);
   display: flex;
 }
 
-.lh-timeline-metric__name {
+.lh-metric__name {
   flex: 1;
 }
 
-.lh-timeline-metric__description {
+.lh-metrics__disclaimer {
+  color: var(--medium-75-gray);
+  text-align: right;
+  margin: var(--lh-section-vpadding) 0;
+  padding: 0 var(--text-indent);
+}
+
+.lh-metric__description {
   color: var(--secondary-text-color);
 }
 
-.lh-timeline-metric__value {
-  width: var(--lh-audit-score-width);
-  text-align: right;
+.lh-metric__value {
+  white-space: nowrap; /* No wrapping between metric value and the icon */
 }
 
-.lh-timeline-metric--pass .lh-timeline-metric__value {
+
+.lh-metric .lh-metric__value::after {
+  content: '';
+  width: var(--lh-score-icon-width);
+  height: var(--lh-score-icon-width);
+  background-size: contain;
+  display: inline-block;
+  vertical-align: text-bottom;
+  margin-left: calc(var(--body-font-size) / 2);
+}
+
+.lh-metric--pass .lh-metric__value {
   color: var(--pass-color);
 }
-
-.lh-timeline-metric--average .lh-timeline-metric__value {
-  color: var(--average-color);
+.lh-metric--pass .lh-metric__value::after {
+  background: var(--pass-icon-url) no-repeat 50% 50%;
 }
 
-.lh-timeline-metric--fail .lh-timeline-metric__value {
+
+.lh-metric--average .lh-metric__value {
+  color: var(--average-color);
+}
+.lh-metric--average .lh-metric__value::after {
+  background: var(--average-icon-url) no-repeat 50% 50%;
+}
+
+
+.lh-metric--fail .lh-metric__value {
+  color: var(--fail-color);
+}
+.lh-metric--fail .lh-metric__value::after {
+  background: var(--fail-icon-url) no-repeat 50% 50%;
+}
+
+.lh-metric--error .lh-metric__value,
+.lh-metric--error .lh-metric__description {
   color: var(--fail-color);
 }
 
-.lh-timeline-metric__sparkline {
-  position: absolute;
-  left: 0;
-  right: 0;
-  top: -1px;
-  height: 3px;
-  width: 100%;
+/* Hide icon if there was an error */
+.lh-metric--error .lh-metric__value::after {
+  display: none;
 }
 
-.lh-timeline-metric__sparkline .lh-sparkline__bar {
-  float: none;
-}
+/* Perf load opportunity */
 
-.lh-timeline-metric--pass .lh-sparkline__bar {
-  background: var(--pass-color);
-}
-
-.lh-timeline-metric--average .lh-sparkline__bar {
-  background: var(--average-color);
-}
-
-.lh-timeline-metric--fail .lh-sparkline__bar {
-  background: var(--fail-color);
-}
-
-.lh-timeline-metric .lh-debug {
-  margin-left: var(--expandable-indent);
-}
-
-/* Perf Hint */
-
-.lh-perf-hint {
-  padding-top: var(--lh-audit-vpadding);
-  padding-bottom: var(--lh-audit-vpadding);
-  border-top: 1px solid var(--report-secondary-border-color);
-}
-
-.lh-perf-hint:last-of-type {
-  border-bottom: none;
-}
-
-.lh-perf-hint__summary {
+.lh-load-opportunity__cols {
   display: flex;
   align-items: flex-start;
-  flex-wrap: wrap;
-  min-height: calc(var(--body-line-height) + var(--caption-line-height));
 }
 
-.lh-perf-hint__summary .lh-toggle-arrow {
-  margin-top: calc((var(--subheader-line-height) - 12px) / 2);
+.lh-load-opportunity__header .lh-load-opportunity__col {
+  background-color: var(--medium-50-gray);
+  color: var(--medium-75-gray);
+  text-align: center;
+  display: unset;
+  line-height: calc(2.3 * var(--body-font-size));
 }
 
-.lh-perf-hint__summary .lh-debug {
-  width: calc(100% - var(--expandable-indent));
-  margin: 0 var(--expandable-indent);
+.lh-load-opportunity__col {
+  display: flex;
+  justify-content: space-between;
 }
 
-.lh-perf-hint__title {
-  font-size: var(--body-font-size);
-  flex: 10;
+.lh-load-opportunity__col--one {
+  flex: 5;
+  margin-right: 2px;
+}
+.lh-load-opportunity__col--two {
+  flex: 4;
 }
 
-.lh-perf-hint__sparkline {
-  flex: 0 0 50%;
+.lh-audit--load-opportunity .lh-audit__display-text {
+  text-align: right;
+  flex: 0 0 calc(3 * var(--body-font-size));
+}
+
+
+/* Sparkline */
+
+.lh-load-opportunity__sparkline {
+  flex: 1;
   margin-top: calc((var(--body-line-height) - var(--lh-sparkline-height)) / 2);
 }
 
-.lh-perf-hint__sparkline .lh-sparkline {
+.lh-sparkline {
+  height: var(--lh-sparkline-height);
   width: 100%;
+}
+
+.lh-sparkline__bar {
+  height: 100%;
   float: right;
-  margin: 0;
 }
 
-.lh-perf-hint__stats {
-  text-align: right;
-  flex: 0 0 var(--lh-audit-score-width);
-}
-
-.lh-perf-hint__primary-stat {
-  font-size: var(--body-font-size);
-  line-height: var(--body-line-height);
-}
-
-.lh-perf-hint__secondary-stat {
-  font-size: var(--caption-font-size);
-  line-height: var(--caption-line-height);
-}
-
-.lh-perf-hint__description {
-  color: var(--secondary-text-color);
-  margin-top: calc(var(--default-padding) / 2);
-}
-
-.lh-perf-hint--pass .lh-perf-hint__stats {
-  color: var(--pass-color);
-}
-
-.lh-perf-hint--pass .lh-sparkline__bar {
+.lh-audit--pass .lh-sparkline__bar {
   background: var(--pass-color);
 }
 
-.lh-perf-hint--average .lh-sparkline__bar {
+.lh-audit--average .lh-sparkline__bar {
   background: var(--average-color);
 }
 
-.lh-perf-hint--average .lh-perf-hint__stats {
-  color: var(--average-color);
-}
-
-.lh-perf-hint--fail .lh-sparkline__bar {
+.lh-audit--fail .lh-sparkline__bar {
   background: var(--fail-color);
 }
 
-.lh-perf-hint--fail .lh-perf-hint__stats {
-  color: var(--fail-color);
-}
+
 
 /* Filmstrip */
 
+.lh-filmstrip-container {
+  padding: 0 var(--expandable-indent);
+  margin: 0 auto;
+}
+
+
 .lh-filmstrip {
   display: flex;
   flex-direction: row;
@@ -590,137 +486,117 @@
   position: relative;
 }
 
-.lh-filmstrip__timestamp {
-  margin-bottom: calc(0.5 * var(--caption-line-height));
-  font-size: var(--caption-font-size);
-  line-height: var(--caption-line-height);
-  padding-top: 1px;
-  padding-right: 6px;
-}
-
-.lh-filmstrip__timestamp::before {
-  content: '';
-  height: 7px;
-  width: 2px;
-  background: var(--metric-timeline-rule-color);
-  position: absolute;
-  right: 0;
-  top: -2px;
-}
-
 .lh-filmstrip__thumbnail {
   border: 1px solid var(--report-secondary-border-color);
   max-height: 100px;
   max-width: 60px;
 }
 
-/* Sparkline */
-
-.lh-sparkline {
-  margin: 5px;
-  height: var(--lh-sparkline-height);
-  width: 100%;
-}
-
-.lh-sparkline--thin {
-  height: calc(var(--lh-sparkline-height) / 2);
-}
-
-.lh-sparkline__bar {
-  background: var(--warning-color);
-  height: 100%;
-  float: right;
-  position: relative;
-}
-
-/* correlate metric end location with sparkline */
-.lh-timeline-metric:hover .lh-sparkline__bar::after {
-  content: '';
-  height: 100vh;
-  width: 2px;
-  background: inherit;
-  position: absolute;
-  right: 0;
-  bottom: 0;
-  opacity: 0;
-  animation: fadeIn 150ms;
-  animation-fill-mode: forwards;
-}
-
 /* Audit */
 
 .lh-audit {
-  margin-bottom: var(--lh-audit-vpadding);
-  padding-top: var(--lh-audit-vpadding);
-  border-top: 1px solid var(--report-secondary-border-color);
+  border-bottom: 1px solid var(--report-secondary-border-color);
 }
 
-.lh-audit:last-of-type {
+.lh-audit:last-child  {
   border-bottom: none;
 }
 
-.lh-audit > .lh-score {
-  font-size: var(--body-font-size);
-}
-
-.lh-audit .lh-debug {
-  margin-left: var(--expandable-indent);
-  margin-right: var(--lh-audit-score-width);
+.lh-audit--error .lh-audit__display-text {
+  color: var(--fail-color);
 }
 
 /* Audit Group */
 
 .lh-audit-group {
-  padding-top: var(--lh-audit-group-vpadding);
-  border-top: 1px solid var(--report-secondary-border-color);
-  padding-left: var(--expandable-indent);
+  padding: var(--lh-audit-group-vpadding) 0;
+  border-bottom: 1px solid var(--report-secondary-border-color);
+}
+
+.lh-audit-group:last-child {
+  border-bottom: none;
 }
 
 .lh-audit-group__header {
   font-size: var(--subheader-font-size);
   line-height: var(--subheader-line-height);
+  color: var(--subheader-color);
+  flex: 1;
+  font-weight: bold;
+}
+
+.lh-audit-group__header::before {
+  content: '';
+  width: calc(var(--subheader-font-size) / 14 * 24);
+  height: calc(var(--subheader-font-size) / 14 * 24);
+  margin-right: calc(var(--subheader-font-size) / 2);
+  background: var(--medium-100-gray) none no-repeat center / 16px;
+  display: inline-block;
+  border-radius: 50%;
+  vertical-align: middle;
+}
+
+/* A11y/Seo groups within Passed don't get an icon */
+.lh-audit-group--unadorned .lh-audit-group__header::before {
+  content: none;
+}
+
+
+.lh-audit-group--manual .lh-audit-group__header::before {
+  background-image: var(--search-icon-url);
+}
+.lh-passed-audits .lh-audit-group__header::before {
+  background-image: var(--check-icon-url);
+}
+.lh-audit-group--diagnostics .lh-audit-group__header::before {
+  background-image: var(--search-icon-url);
+}
+.lh-audit-group--opportunities .lh-audit-group__header::before {
+  background-image: var(--photo-filter-icon-url);
+}
+.lh-audit-group--metrics .lh-audit-group__header::before {
+  background-image: var(--av-timer-icon-url);
+}
+.lh-audit-group--not-applicable .lh-audit-group__header::before {
+  background-image: var(--remove-circle-icon-url);
+}
+
+/* Removing too much whitespace */
+.lh-audit-group--metrics {
+  margin-top: -28px;
+  border-bottom: none;
 }
 
 .lh-audit-group__summary {
   display: flex;
-  align-items: center;
-  margin-bottom: var(--lh-audit-group-vpadding);
-  margin-left: calc(0px - var(--expandable-indent));
+  justify-content: space-between;
+  padding-right: var(--text-indent);
 }
 
-.lh-audit-group__summary .lh-toggle-arrow {
-  margin-top: calc((var(--subheader-line-height) - 12px) / 2);
+.lh-audit-group__itemcount {
+  color: var(--display-value-gray);
+  margin: 0 10px;
 }
 
 .lh-audit-group__description {
   font-size: var(--body-font-size);
-  color: var(--secondary-text-color);
-  margin-top: calc(0px - var(--lh-audit-group-vpadding));
-  margin-bottom: var(--lh-audit-group-vpadding);
-  line-height: var(--body-line-height);
+  color: var(--medium-75-gray);
+  margin: var(--lh-audit-group-vpadding) 0;
 }
 
+.lh-audit-group--unadorned .lh-audit-group__description {
+  margin-top: 0;
+}
 
-.lh-debug {
-  font-size: var(--caption-font-size);
+.lh-audit-explanation {
+  margin: var(--lh-audit-vpadding) 0 calc(var(--lh-audit-vpadding) / 2);
   line-height: var(--caption-line-height);
+}
+
+.lh-audit--fail .lh-audit-explanation {
   color: var(--fail-color);
-  margin-top: 3px;
 }
 
-.lh-debug::before {
-  display: none;
-  content: '';
-  background: url('data:image/svg+xml;utf8,<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>warn</title><path d="M0 0h24v24H0z" fill="none"/><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" fill="hsl(40, 100%, 50%)"/></svg>') no-repeat 50% 50%;
-  background-size: contain;
-  width: 20px;
-  height: 20px;
-  position: relative;
-  margin-right: calc(var(--default-padding) / 2);
-  top: 5px;
-}
-
-
 /* Report */
 
 .lh-container {
@@ -730,10 +606,27 @@
   margin: 0 auto;
 }
 
+.lh-header-sticky {
+  position: sticky;
+  top: 0;
+  width: 100%;
+  z-index: 2;
+  will-change: transform;
+}
+.lh-header-plain {
+  margin-top: var(--section-padding);
+}
+
+.lh-header-container {
+  display: block;
+  margin: 0 auto;
+  max-width: var(--report-content-width);
+  position: relative;
+  word-wrap: break-word;
+}
+
 .lh-report {
-  margin-left: var(--report-menu-width);
   background-color: #fff;
-  padding-top: var(--report-header-height);
 }
 @media screen {
   .lh-report {
@@ -745,51 +638,106 @@
   font-size: large;
 }
 
-.lh-text {
-  white-space: nowrap;
-}
-
 .lh-code {
   white-space: normal;
   margin-top: 0;
+  font-size: 85%;
+  word-break: break-word;
 }
 
-.lh-run-warnings {
-  font-size: var(--body-font-size);
+.lh-warnings {
+  --item-margin: calc(var(--body-line-height) / 6);
+  border: 1px solid var(--average-color);
+  border-radius: 4px;
+  margin: var(--lh-audit-vpadding) 0;
+  padding: calc(var(--lh-audit-vpadding) / 2) var(--lh-audit-vpadding);
+}
+
+.lh-warnings--toplevel {
+  --item-margin: calc(var(--header-line-height) / 4);
+  color: var(--secondary-text-color);
   margin: var(--section-padding);
   padding: var(--section-padding);
-  background-color: hsla(40, 100%, 91%, 1);
-  color: var(--secondary-text-color);
 }
-.lh-run-warnings li {
-  margin-bottom: calc(var(--header-line-height) / 2);
+.lh-warnings ul {
+  padding-left: calc(var(--section-padding) * 2);
+  margin: 0;
 }
-.lh-run-warnings::before {
-  display: inline-block;
+.lh-warnings li {
+  margin: var(--item-margin) 0;
+}
+.lh-warnings li:last-of-type {
+  margin-bottom: 0;
 }
 
 .lh-scores-header {
   display: flex;
   justify-content: center;
   overflow-x: hidden;
-  padding: var(--section-padding);
-  border-bottom: 1px solid var(--report-border-color);
+  position: relative;
+  padding: var(--section-indent) calc(var(--section-indent) / 2) calc(var(--section-indent) * 2);
 }
 .lh-scores-header__solo {
   padding: 0;
   border: 0;
 }
 
+.lh-scorescale {
+  color: var(--medium-75-gray);
+  padding: 0 calc(var(--section-indent) * 1.5) 0;
+  text-align: right;
+  transform-origin: bottom right;
+  will-change: opacity; /* opacity is changed on scroll */
+}
+
+.lh-scorescale-range {
+  margin-left: 10px;
+}
+
+.lh-scorescale-range::before {
+  content: '';
+  width: var(--body-font-size);
+  height: calc(var(--body-font-size) * .60);
+  border-radius: 4px;
+  display: inline-block;
+  margin: 0 5px;
+}
+
+.lh-scorescale-range--pass::before {
+  background-color: var(--pass-color);
+}
+
+.lh-scorescale-range--average::before {
+  background-color: var(--average-color);
+}
+
+.lh-scorescale-range--fail::before {
+  background-color: var(--fail-color);
+}
+
+/* Hide category score gauages if it's a single category report */
+.lh-header--solo-category .lh-scores-wrapper {
+  display: none;
+}
+
+
 .lh-categories {
   width: 100%;
   overflow: hidden;
 }
 
 .lh-category {
+  --circle-size: calc(2.5 * var(--header-font-size));
+
   padding: var(--section-padding);
   border-top: 1px solid var(--report-border-color);
 }
 
+.lh-category:first-of-type {
+  padding-top: calc(2 * var(--section-padding));
+  border: none;
+}
+
 /* section hash link jump should preserve fixed header
    https://css-tricks.com/hash-tag-links-padding/
 */
@@ -800,36 +748,30 @@
   visibility: hidden;
 }
 
-.lh-category:first-of-type {
-  border: none;
-}
-
-.lh-category > .lh-score {
+.lh-category-header {
   font-size: var(--header-font-size);
-  padding-bottom: var(--lh-section-vpadding);
+  min-height: var(--circle-size);
+  margin-bottom: var(--lh-section-vpadding);
 }
 
-.lh-category > .lh-score .lh-score__value,
-.lh-category > .lh-score .lh-score__gauge .lh-gauge__label {
+.lh-category-header__title {
+  line-height: 24px;
+}
+
+.lh-category-header .lh-score__gauge .lh-gauge__label {
   display: none;
 }
 
+
+.lh-category-header .lh-score__gauge {
+  float: right;
+}
+
 .lh-category .lh-score__gauge {
   margin-left: var(--section-indent);
-  flex-basis: var(--circle-size);
-  flex-shrink: 0;
 }
 
-.lh-category .lh-score__gauge .lh-gauge {
-  --circle-size: calc(2.5 * var(--header-font-size));
-}
-
-/* Category snippet shouldnt have pointer cursor. */
-.lh-category > .lh-score .lh-score__snippet {
-  cursor: initial;
-}
-
-.lh-category > .lh-score .lh-score__title {
+.lh-category-header .lh-audit__title {
   font-size: var(--header-font-size);
   line-height: var(--header-line-height);
 }
@@ -900,16 +842,16 @@
 
 .lh-table {
   --image-preview-size: 24px;
-  border: 1px solid var(--report-secondary-border-color);
   border-collapse: collapse;
-  width: 100%;
-
-  --url-col-max-width: 450px;
 }
 
 .lh-table thead {
   background: var(--lh-table-header-bg);
 }
+.lh-table thead th {
+  color: var(--medium-75-gray);
+  font-weight: normal;
+}
 
 .lh-table tbody tr:nth-child(even) {
   background-color: var(--lh-table-higlight-bg);
@@ -920,7 +862,9 @@
   padding: 8px 6px;
 }
 
-.lh-table-column--text {
+.lh-table-column--text,
+.lh-table-column--bytes,
+.lh-table-column--ms {
   text-align: right;
 }
 
@@ -932,7 +876,13 @@
   text-align: left;
   min-width: 250px;
   white-space: nowrap;
-  max-width: var(--url-col-max-width);
+  max-width: 0;
+}
+
+/* Keep bytes columns narrow if they follow the URL column */
+.lh-table-column--url + th.lh-table-column--bytes,
+.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes {
+  width: var(--bytes-col-width);
 }
 
 .lh-table-column--code {
@@ -950,7 +900,7 @@
 }
 
 .lh-text__url > .lh-text, .lh-text__url-host {
-  display: inline;
+  display: inline-block;
 }
 
 .lh-text__url-host {
@@ -965,4 +915,103 @@
   object-fit: contain;
 }
 
-/*# sourceURL=report.styles.css */
+/* Chevron
+   https://codepen.io/paulirish/pen/LmzEmK
+ */
+.lh-chevron {
+  --chevron-angle: 42deg;
+  width: var(--chevron-size);
+  height: var(--chevron-size);
+  margin-top: calc((var(--body-line-height) - 12px) / 2);
+}
+
+.lh-chevron__lines {
+  transition: transform 0.4s;
+  transform: translateY(var(--body-line-height));
+}
+.lh-chevron__line {
+ stroke: var(--display-value-gray);
+ stroke-width: var(--chevron-size);
+ stroke-linecap: square;
+ transform-origin: 50%;
+ transform: rotate(var(--chevron-angle));
+ transition: transform 300ms, stroke 300ms;
+}
+
+.lh-audit-group > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-right,
+.lh-audit-group[open] > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-left,
+.lh-audit > .lh-expandable-details .lh-chevron__line-right,
+.lh-audit > .lh-expandable-details[open] .lh-chevron__line-left {
+ transform: rotate(calc(var(--chevron-angle) * -1));
+}
+
+.lh-audit-group[open] > .lh-audit-group__summary > .lh-chevron .lh-chevron__line-right,
+.lh-audit > .lh-expandable-details[open] .lh-chevron__line-right {
+  transform: rotate(var(--chevron-angle));
+}
+
+.lh-audit-group[open] > .lh-audit-group__summary > .lh-chevron .lh-chevron__lines,
+.lh-audit > .lh-expandable-details[open] .lh-chevron__lines {
+ transform: translateY(calc(var(--chevron-size) * -1));
+}
+
+
+
+/* Tooltip */
+.tooltip-boundary {
+  position: relative;
+}
+
+.tooltip {
+  position: absolute;
+  display: none; /* Don't retain these layers when not needed */
+  opacity: 0;
+  background: #ffffff;
+  min-width: 246px;
+  max-width: 275px;
+  padding: 15px;
+  border-radius: 5px;
+  text-align: initial;
+}
+/* shrink tooltips to not be cutoff on left edge of narrow viewports
+   45vw is chosen to be ~= width of the left column of metrics
+*/
+@media screen and (max-width: 535px) {
+  .tooltip {
+    min-width: 45vw;
+    padding: 3vw;
+  }
+}
+
+.tooltip-boundary:hover {
+  background-color: #F8F9FA;
+}
+
+.tooltip-boundary:hover .tooltip {
+  display: block;
+  animation: fadeInTooltip 250ms;
+  animation-fill-mode: forwards;
+  animation-delay: 850ms;
+  bottom: 100%;
+  z-index: 1;
+  will-change: opacity;
+  right: 0;
+}
+
+.tooltip::before {
+  content: "";
+  border: solid transparent;
+  border-bottom-color: #fff;
+  border-width: 10px;
+  position: absolute;
+  bottom: -20px;
+  right: 6px;
+  transform: rotate(180deg);
+  pointer-events: none;
+}
+
+@keyframes fadeInTooltip {
+  0% { opacity: 0; }
+  75% { opacity: 1; }
+  100% { opacity: 1;  filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); }
+}
diff --git a/front_end/audits2/lighthouse/templates.html b/front_end/audits2/lighthouse/templates.html
index 3a2bc90..770432f 100644
--- a/front_end/audits2/lighthouse/templates.html
+++ b/front_end/audits2/lighthouse/templates.html
@@ -1,192 +1,244 @@
 <!-- Lighthouse run warnings -->
-<template id="tmpl-lh-run-warnings">
-  <div class="lh-run-warnings lh-debug">
+<template id="tmpl-lh-warnings--toplevel">
+  <div class="lh-warnings lh-warnings--toplevel">
     <strong>There were issues affecting this run of Lighthouse:</strong>
     <ul></ul>
   </div>
 </template>
 
-<!-- Lighthouse category score -->
-<template id="tmpl-lh-category-score">
-  <div class="lh-score">
-    <div class="lh-score__value"><!-- fill me --></div>
-    <div class="lh-score__gauge"></div>
-    <div class="lh-score__header">
-      <div class="lh-score__snippet">
-        <span class="lh-score__title"><!-- fill me --></span>
-      </div>
-      <div class="lh-score__description"><!-- fill me --></div>
-    </div>
+<!-- Lighthouse score scale -->
+<template id="tmpl-lh-scorescale">
+  <div class="lh-scorescale">
+    <span class="lh-scorescale-label">Score scale:</span>
+    <span class="lh-scorescale-range lh-scorescale-range--fail">0-44</span>
+    <span class="lh-scorescale-range lh-scorescale-range--average">45-74</span>
+    <span class="lh-scorescale-range lh-scorescale-range--pass">75-100</span>
   </div>
 </template>
 
-<!-- Lighthouse audit score -->
-<template id="tmpl-lh-audit-score">
-  <div class="lh-score">
-    <div class="lh-score__value"><!-- fill me --></div>
-    <details class="lh-score__header lh-expandable-details">
-      <summary class="lh-score__snippet lh-expandable-details__summary">
-        <span class="lh-score__title"><!-- fill me --></span>
-        <div class="lh-toggle-arrow" title="See audits"></div>
+<!-- Toggle arrow chevron -->
+<template id="tmpl-lh-chevron">
+  <svg class="lh-chevron" title="See audits" xmlns="http://www.w3.org/2000/svg"  viewbox="0 0 100 100">
+    <g class="lh-chevron__lines">
+      <path class="lh-chevron__line lh-chevron__line-left" d="M10 50h40" stroke="#707173"/>
+      <path class="lh-chevron__line lh-chevron__line-right" d="M90 50H50" stroke="#707173"/>
+    </g>
+  </svg>
+</template>
+
+<!-- Lighthouse category header -->
+<template id="tmpl-lh-category-header">
+  <div class="lh-category-header">
+    <div class="lh-score__gauge"></div>
+    <span class="lh-category-header__title"></span>
+    <div class="lh-category-header__description"></div>
+  </div>
+</template>
+
+<!-- Lighthouse audit -->
+<template id="tmpl-lh-audit">
+  <div class="lh-audit">
+    <details class="lh-expandable-details">
+      <summary class="lh-audit__header lh-expandable-details__summary">
+        <span class="lh-audit__index"></span>
+        <span class="lh-audit__title"></span>
+        <span class="lh-audit__display-text"></span>
+        <div class="lh-audit__score-icon"></div>
+        <div class="lh-chevron-container"></div>
       </summary>
-      <div class="lh-score__description"><!-- fill me --></div>
+      <div class="lh-audit__description"></div>
     </details>
   </div>
 </template>
 
-<!-- Lighthouse timeline metric -->
-<template id="tmpl-lh-timeline-metric">
-  <div class="lh-timeline-metric">
-    <div class="lh-timeline-metric__sparkline">
-      <div class="lh-sparkline__bar"></div>
-    </div>
-    <div class="lh-timeline-metric__header">
-      <div class="lh-timeline-metric__value"><!-- fill me --></div>
-      <details class="lh-timeline-metric__details lh-expandable-details">
-        <summary class="lh-timeline-metric__summary lh-expandable-details__summary">
-          <span class="lh-timeline-metric__title"><!-- fill me --></span>
-          <div class="lh-toggle-arrow" title="See audits"></div>
-        </summary>
-        <div class="lh-timeline-metric__description"><!-- fill me --></div>
-      </details>
+<!-- Lighthouse perf metric -->
+<template id="tmpl-lh-metric">
+  <div class="lh-metric">
+    <div class="lh-metric__innerwrap tooltip-boundary">
+      <span class="lh-metric__title"></span>
+      <div class="lh-metric__value"></div>
+      <div class="lh-metric__description tooltip"></div>
     </div>
   </div>
 </template>
 
-<!-- Lighthouse left nav -->
-<template id="tmpl-lh-leftnav">
+<!-- Lighthouse perf opportunity -->
+<template id="tmpl-lh-opportunity">
+  <div class="lh-audit lh-audit--load-opportunity">
+    <details class="lh-expandable-details">
+      <summary class="lh-audit__header lh-expandable-details__summary">
+        <div class="lh-load-opportunity__cols">
+          <div class="lh-load-opportunity__col lh-load-opportunity__col--one">
+            <span class="lh-audit__index"></span>
+            <div class="lh-audit__title"></div>
+          </div>
+          <div class="lh-load-opportunity__col lh-load-opportunity__col--two">
+            <div class="lh-load-opportunity__sparkline">
+              <div class="lh-sparkline"><div class="lh-sparkline__bar"></div></div>
+            </div>
+            <div class="lh-audit__display-text"></div>
+            <div class="lh-chevron-container" title="See resources"></div>
+          </div>
+        </div>
+      </summary>
+      <div class="lh-audit__description"></div>
+    </details>
+  </div>
+</template>
+
+
+<!-- Lighthouse perf opportunity header -->
+<template id="tmpl-lh-opportunity-header">
+  <div class="lh-load-opportunity__header lh-load-opportunity__cols">
+    <div class="lh-load-opportunity__col lh-load-opportunity__col--one">
+      Resource to optimize
+    </div>
+    <div class="lh-load-opportunity__col lh-load-opportunity__col--two">
+      Estimated Savings
+    </div>
+  </div>
+</template>
+
+
+<!-- Lighthouse score container -->
+<template id="tmpl-lh-scores-wrapper">
   <style>
-    .lh-leftnav {
-      width: var(--report-menu-width);
-      border-right: 1px solid var(--report-border-color);
-      position: fixed;
+    .lh-scores-wrapper__background,
+    .lh-scores-wrapper__shadow {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
       height: 100%;
-      background: #fff;
-      will-change: transform; /* prevent excessive paints */
-      z-index: 2;
+      background: white;
+      border-radius: 8px;
     }
-    .lh-leftnav__item {
-      padding: var(--navitem-vpadding) var(--navitem-hpadding);
-      color: var(--secondary-text-color);
-      font-size: var(--navitem-font-size);
-      line-height: var(--navitem-line-height);
-      display: flex;
-      justify-content: space-between;
-      text-decoration: none;
-      color: inherit;
+    .lh-scores-wrapper__shadow {
+      border-radius: 0;
+      box-shadow: rgba(0, 0, 0, 0.2) 0px 3px 0px -2px
     }
-    .leftnav-item__score {
-      background: transparent;
-    }
-    .leftnav-item__score::after {
-      content: '';
-    }
-    .leftnav-item__score.lh-score__value--pass {
-      color: var(--pass-color);
-    }
-    .leftnav-item__score.lh-score__value--average {
-      color: var(--average-color);
-    }
-    .leftnav-item__score.lh-score__value--fail {
-      color: var(--fail-color);
-    }
-    .leftnav__header {
-      padding: 0 20px;
-      margin-bottom: var(--navitem-vpadding);
-      height: 115px;
-      font-size: 18px;
-      display: flex;
-      flex-direction: column;
-      justify-content: center;
-      background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZoAAADeCAYAAAAEuMatAABPH0lEQVR4Ae3dBZyk1ZX38d+59z5PSfv0uMPg7iQB4oRkIbrZbGSz7Js368mbrLtE1903nuzGVuIGgQgxCBbIAAPjru1d8sg9b091fxhBMsN0T1V13+/ncz5VNRaFP+ee89zi8QRBEARBEARBEARBEARBIARB0BTZuru7Be0HOoFYlcirAqgIiaoMGKtbAaWNBYFkD9/JzAuC4H3/57KeZKB0Wb/jea9YVrowFbNC0KVAj4Cr50olzTACCKCy11j/QLG/tlmEb5bXp18GdtFmgkDSy3lS7qxzLKsWzSfVcWCMIAiOzxfvuIZV3S+lp/hSUk5DYSzzCIcIkORKJcsQDqOg3gBgUj8qyP8YlU8DnyEI2oTsfc4ynkjvm65eaJ9z8cuMdQvwmoCpgAwiOlH2AERDCONABZUxICUIgob6R7/ynOz7D/+yjlRuEE8BryAccixBczQBUXCj+Xc73difhcAJ2oFUn1PmcV19dnfxZ1/yM2CXkucJIEeWGsCD1IAKSBUvIyCDGD0AphFEUz9fb9QcEATZvetPSd/7uT/2ef56CpFgDIecYNBMUSOAYES+YJ37XeA+WlQQyN6Xr+bxzP+XX3upJEPPIPdVnpwB5LBXEBQa5UHGgFGQUXIzBDIETFakg6B1IGMWCILq337+NfnajX8lxcISjDBl2oPmcCIMl7fXfh/4R1pQEMjwhX0cLfq5a1eUXn3lGxgZtSCeE2MeLcEAOZABOaIJyDAwAAxh4iFERqaCaQzrhwGlxQWBfv3+qP4/t/xZVo9+RZxhykkJGgCNDEZ4rxV5C1ChtQSho1nO0fr/6NWvMPN6Lif3dWaGABzVCZmpSoAaUMdSRRgGBkEGcbof0RGgAlIBMoKgSe5ev6KcRoVC18Z1C0758Hve7p39SZwBOMlBc4hFPmeM3AgM0iKCwEmqHK7nRef1miXzz6JST5k5etir50gCFIAiOX3AUkBAIUUQqaIyBhMlOlGMAIMoQzg9gGUMJQFSQDlOQbB7sLsDm5f/4+tXdW7b1rM0sqxQdInAotTbRV+9/8z+pEp3LnQV8aU/tz+39PSC70kkotly9MWo/9SY6XtNWIVuFYFsePHZHG78rTc+/fxz6jdQI6U1CWAOKwV8o+RgSRUYRhhBGUAZQnQIzBCqw+BrIYACgA994+m9Y2OF00yUnXLHnlWrvn3XmhVdsEpFVwBLKnWzMMuwIkxSEIFyQfEiGFL+2Pw6L+E/qVFGEYCmdjQABWrcaZ73wG8W/uPm3fPjnRbdirLJCI+IMAgoJ1EQyIpfyJnCaZ25fOqtf/36nrR6FpiE9iOPE0QeSBBJUFJEx0GGEBkE9qN+GBgDxhEZAZRgVvnSHWeVXSlddd8jq9d89vbzzi0V9FxVOXvTvu4VWUqXCOWCgUIBlENElMejQBXhzfLX/LK8m+qhkGmJoBGUAhU+ZH6Pf+U36aChKjAK7BR4QIW1ueUhYKsxbAH2MUOCQC55hTKFC/vW9r3/Tz76C4wXSoBn9pAnKIOQg1SBg1UBHQUZRBgAOYD3gwg1aFRK0NLW7Z7fsXt/39L33HTVeXGUP21guPviezb2L7OWJc7SFztAaYic8lRUEJ4nX+Ov5KcxeDIcQMsEDYAhx+L5Q/cRviYvpIjyBKoi7B4fZHNW415V+a6HtcBuYIBpEASy6gplCl/9t387/7SF219LEtWZO44MHhAmKQ2SIkxtwukoMAIyBAwjcgCfDwFZo0664LaHTu/64t1nnke9+MzP337uBanlTIFzvacIYA0UI0WZHhlCHwO817yMNTxEjRJAywUNQEyNHXIab7Zf4YD0EaE8EWMBYQqKss5Y1lq4R+EbKfJDYATwBMFxcvNW8ah0xK5iIcrcolMFkPMYKih9QD9gaNAcyFFyRGogI8AwRgbI/QDCKDCKyBAwzrQJ/ufWS1099pd86juXPX3z7r6nZXn89OFxWWYNrqOoOB5LmT4Z8Fp5L2ewlgqdtLKEIqv0QV6tf8/fyR8R8cR8zuEEOMvnnJXCjwO5ovtR7rQi30G402V8BxgjCI6BXH6DAvCMNevkz3//Yz8fj8kKkJTgyQjA46xoWwBEEqAO1EArIMPAIEYOkPv9wDhQmXr1BE/qextWnvuhW64+f/POeS9Yv2PeVRksLxcoOwMIGFFOhgThNDbwPvNiuhgmwwG0bEcDYMmoSwe/aG9ho5xKAWUaeOPZauCutCZf3rOOO1S4H1CC4HHIolUKwOtf84P+v/iNj7+RkVInkBNM53Hc4T+mIBXQcZAxiMeBySCSxkzoAFADkkbNQVv29/R84JZrTt+8e97131q79PkYLoosncZA7JRmUIQa8LvyB/y0/DPjdAK0fNCA0MEwn7Rv4S/MuyijTBcVEEAMVRV+oMLtqvIZ4F5gkCCYIhf8uALwyivvOeMPbvyv11MpekCZSYE5VCqAAh5BQXJgMnxERlAdBIanPg+hfgDVFPDMIg9tX1z87D1nPfPOh8684f7Ni5/rvZwLUC4orSBBWM5OPmReSB8HyHBtEjQQkTDAYt4U3cxOlhChzLBHVLnVeG4e7JObgRGCOc2NlGm48fnfWUg9ioAaMy3wUwUIj1IABOgCelA1gAFyIJ0skyCMggwh/gCqEyUjj86FoEKb+M7Dqwp/d8fVz9r24MIbSAo/tmsgXl0uYouRAkoryYBnyK0sZCdVOmgnGRGL2cIl+nU2y2uImHGni3A6lp/vqOpWb/nynsXyhTp8ExgimHPcvnk0dEWVhSCeoNl0qjyHSKNUC0AR6AFdgWJABEhAqqBVvKsiZnJF2+T7yQr70KgC1BBt+rU9P9i+oPjNe8666LaHlr30we2LXpqmnB1FIAK9nUorUoQIz/Pkc4DQbhQhw/Ec/2m+Yn8SxSAoM02BOGEl8HOnbNSf8ykbxg9wi4p8TOD7wDhzQuCWfRdWnlkR63QB4AlakR56fVyCahnoQFIBBAAPmBRE6iBjiB/BuxGIRoAhxA+QR/ungigDUmbIr9/03FOHHu77iVsfWPby2HIlQCGCUlFpdSmwWrazhnVkRLSjjIg1ej+djDBML5aTQ4WGXIAiazpXsgb05wTuxvNFKcgnpcBawDNrBXL5jcrPveBrpTdee/P/Y7wYFgFmJzlsJmSYlCPkqOSIVEGGER3EuwF8NAwMoYxQYBio8xR8/BsXlbfumn/DR799/ktG6/bFkdJdLihKe6kgvEBu5m/lddQoAgLQNjMaAINHEd7t3sPNcgNFlJYg1FX4qop8PEr57Oyc5wTOD0BhWHuBCFBmo0CBfLKERykCWFS7QHtQVkNisIkH6igJSp2IKsgAogOo3U9eGAYqCOPAKEf59HfPP+O9X73iVQ9unPdTKGd2laA7VgCU9mOg8dyMJQOEduQxdDDKGl3LFxtB0yKUgijXC3q9wmbj+S9V+ShwL7NG4Mgh7ZBefAiaNjQDt2jLoQCCMjllMuYBy0EEvEGq+VTQVIARjB1Mk6jy/YdPWfr7n7/2RYPbup9jnfbP68ypp5YkAxHBCIiAESaJIrQ2RXDASjbgsbQzwVPWYQytyRtW55bfENU3E3MzVt6rwteAUYK25rIesOQ9gANSggB0qiYJRxOMdwhd1Wph2cM7F527bseiC/YNdS99zXn34s8Xxusx47UCo9UiY7WDFTNaKTJUKTFWLZB7g5+ozINXEMAYpoJIaSUGWC5byLG0s5SYFWygm4wEh0VpNaIAFKnzYtCJ4h6FD8WpfBTYR9CWXDQEL7/qni6qBfukQRMEAhifgeZDo539D25dcvEjuxZfPBEgfaA46/EIAnQV6/SUapj+IUDJvWlU5i311DbCZqRSYvhg8NQKVA4G00SNVYtU6hGqNCiThEPdkIgy01KEjEkCdDLMyaAzfHzWowcQlCpgESLAoTwV3gtJDtZAZJVpJTQIXHywfKS/Jrl8RHM+DKwjaCtyyQuV7/7du14ex/kVQJ2jBYGgGJ+j6IGhrkVrty29aP2uhReN1wpdzipGPD+KAIgCIAKCYmSyEEgyO1GOWhJRT10jfIbGywxO1ESQUU0d9SSi2vh5g+pU6BxeAJx4ECUI8xnkeXyOpbINUF4qH6OL4RntanJVMq/MFEPOKPO41byCGmU2s4Zv6I8xQgcRyvHIvFBwGacu2sS+4QXsHemd+VsbBIADAh8zKv8KrCVoC/K6X97p3vuWD766GKVnAylBcDibZ6joroG+ZfdvXnbl5j3zz03SqGBNjjHK9DgUPiL66PsGARTqWcR4bbLrqUzUwSAaHi9PVImRarERTlluSHNLltMgAuY4u6AEYTWb+DPzc5zH9/E4QKhRQhFmmjBzFMHgialiUIScb3Mtv+3/hSH6j7mz8SqU4grv+Mm38dwLb2HrvlX84cf/mLs2nk/BKSfJuCqfVZW/B75H0NLkNW/a2fH+t3zotUVXXwmSEwQA1mcounugZ8n9m5dfuWnPgguT1EXOekSUk01EMVMloiiC9wfL4FWoJlFjHjRSKTJaK07OhyZq4nPjOC7NLKrgG3XUUZxRBFCEFOWP5Dd5lfwb4/Qx23UwxN/r2/lnfQsllGNRqQsvvuwW/vINb4U8gtIoX/r2T/LWD7yTcgFAOYkyVfkE8A/A7QQtyWW5iVHKIEoAhIBBNN83ETD3bFz19C17+8+vp67gjCdyOc2iKuQHiyMJYIzSWazTXaqxfP5kGOVeGt1NmrmJspMdUKV0MHgar9WDnVESUZnqkNIccqBb6pxu7ieVInAokWYrT8xF8j1U38KxEgOj1S7II3AJoAxXulGawono64BXCHxCkb8FfkDQUuR3fmv9oj964yd/puDSMqDMTYFRj/Hp0Ejn/B9sXHHlwzsXX1JLXCma6mDakYgicMRxXONVlCw31NKoETjVg4GTxAxVyoyOxfxK9Te5OPkmtawAaQZpDl7BCFjDbNLBKJ/hdfym/wfKKMdCAVXPG5/3YW648lNs2H42f/6ZX2fX4AKcVZpsTOAjxjQC52GCliB619+eyryR14I65p5AVLF5MjZe7vnBppVXrtu2+NLxetzlrMeIMlsdCqBDCwkopMScyoM8N/8spl4nq+ZQT9BaSj5Sw+8agiwHYQYICDPKyKH/XWPqjNHFm/3HuIOnUUCPq8OsZ1CMlCQTjNAImRYyCLzHO/kbYDdNFYhu/aOLyM0NgGOOCQHj06QeFddtW3reDzYvv3pwrGOBszlGlLlL8Ahnyf2ca+6lJFUQQUUoZGP4u9eh1QREmHbqwecgwkwQYLxeppoUEFF2sZz/0F/kq/pCIkBQjpeqtHTHK45NQzvkr8cH+AAwTlMEolvecTXePwewzClhk2z9jkVn3b1h9bP2DXetEFGs8QQAQoajSIUCdRTwavixp9/N/Pm7IQcQpp/C4B6ojoIYppUo2Ix//tKNfPS7z6cjVoboY5QCRQCU2cpYEOFuQd4BfJrjpB30qNIjUGRSAowCBwiOiejmt12HckUImjkyhxGf7RvsWXz3+tXXbNi94CJVcNYTPJbHoAgAuTe86nnfY9GqPaAWVJl2YiCrw96tkCUgMu1B8+7/eTP/dut1dBXAABZlLokyPm28vAu4kyfgu+jP+rjCC9dV53GONSxVZZ4IJSbVUYaBnSiPqHKLV24DdhI8LgdSBhWC2UsAmyfVaqF8z4aVz3pg67Kn1ZKo7GyOGJ5AYPAcouA9ZB48M8SDRFDug4HdIExv0KhifUYMRChzURLxMtDnCfKP3vCXwABTagu4uL6AnykrL1FhNYA9+iraQxYBZwDPFvhZa9iP50uqfBC4leBxg4bZLTwPs2H74jPvePjU5+8f6Vwa2ZzI5bSiQKHcA2NDkNRAhGB68xboAv0d43mJyeV3h5awTubzK7HwUx05HQoIx0mZj/B6EV4twmeBdwL3EjQ4lCIgBLNx2J8MT6wr377u1Gdt2LXgYo+Y2GW0sEAVrJ0Mm6QKCDMgUMBzbjqPTxfnMaDQjwflhEUKP64511W28Bfe86dAEoJGNEYJZhPjM/XG3Ld+9ZV3r1/17PFa3OOsx4knaJOwKXXAqIN82rfQAgUMZIuFvB9B6UeZPgpi6Ow6g7chXK7KzwK753jQMMuCJnQxBwa7F333oTXXbtk7/xwjvh2PyULQRAVwMeRVgukPmXQZ+D4gZ8b4FARu8I7Pbt3OK4GtzFEOJAYlaP9ZjM+NTHQxT7vnkVXPHU/izsjmBG0sLkK9AgjBNBHIlgq+F8hPUq55Ll9R5n+yUW4A9jAHORQHCG0tPHg5ONzV/50HTnvBxj0LznPG0+4hEwi4AiggBNPBQ7ZEyOcBOSeNerC9XObm8T6ElwEZc4wDNQTtyfgcFX1w87KLvrduzbXj1UJvGPbPEgJYByjBNPDgeyCfD3hOOvWNul7ht4B3Mcc4wBC0H5cnlWqh4ztrz3jBup2LLjNomMXMNiKNOkGBAhFkiwQE8DSNgd/0yufn2g3TDhFBlaBNiHpsnm7dvXDNtx847cf2j3QueZIbloMgUMjmgZaAnKZS6Eb4A+CVzCFhPtNOrM99buWuB0951l0bVj0nz20cu5xgFlLA+xOd0QQKWgDfJ+BpCQIvF8MzgW8yRzi8KiC0tsBlyeh4ufub9591/cbd88+LrMfZnGAWy1NOTCAKebegMa0UNCaHX8wM95cMw4CfC0dnHlVDSwvPxmzbveDU2x444/qBkY4lc6GLCRTSOgjBU6WgFnwXLUUB4/mJ2PNMEWoC6wVuQ7kF+C6zkAP1tKbAaK6ov/fh1U+fuKfsusybeI4M/AP1kNQAIXjqNAZfAjytxgJLMwWFU4EXAG+zwje85W+AzzGLOIQcpQWFBzBr9Tj+9trTrntw29IrrPU445kDAjFQG4P8hL4qINCpkLGAp2UJjzJeeY5mPAflw1h+HdjHLOBAUtBwsWYribL64GD3gq/df9ZLdg70rpljXUwgQHUMcg/G8AQCzyHCIXroVUtCuxEA4adRzspyXgVsoc050DrQRcsI85ituxas+fp9Z71spFrqD0/4zzEikNahMgJGCB6HBwxoGXwn+JKgEQ2iQB1MVbEjoBHtS7kisnwmHeF6YAdtzKEkBK0RMqLZ2k0rLv3W2tNfnHsTz8WQCQRGDkCeghiCo3jwXZD3C74TMBxBATrAi5AnoAJ42pfhQp/wntoOXgYk7dzRJDRXYHyuKnz3gdOfc+/Glc8VVKzxzDGBMVAZhfFhQDhMoIBAtkjIFwAG8I16QuoApa1pDoWFvKi0hJ8F/ok25RBTQb0CQnDy2TxLkjj6+n1n3vDwzsWXOBOe8p+TxEBah6E9oAoiBEeFzFIhnwco4PnRlFlBc8hzfgvhk8C+dn1gswIoQTNCJh2vljq/es85r9i6r/+MyOUISvMEXs0T/7gIGAGEaSUCSQ0GdkKegDVMOwGMoGLIgRzhaAYQlJajU7cu9wM5c9UK8bwC+DfakEO0gtIE4VLM/YM9C2/9wdmv3DvUtaz5ty4HRjwFk/B4cjFInkEtA2+YPgK1MRjci9brIMcwVJCncDONKNiMOB2nm1E6UQ5RFKFGGY9tzVuX+wHPnKbCq9s3aKwbJ8sITiKX1Xbt61/51XvPeeVIpbSg+evLQeojTu3cwrVLv0nuHQACIAKAihDtSknv2AtpBiJMH0VrCdkdD0Oag/Ckqt6TAsLxe3n9d3mReRuS8ShLTpUyb7cf4CE5nwilZRjI5wtICBrgfIFlwI42DJp0hEyU4OSIstq2ifXlm+8991XVetzd3PvKAhFFAGs8TnIilxIhAKgCuQfvIVd8LYPUQy4gTB9jIFG0kkGW/8gQ0zTDe0U4fmWp0SEKemTQVOjAkaAt2M34MuAJoFuFs9oyaP7s6y8e+ZUrv5LHJo0AZeYELq9v3Lb43FvuO+fHk8yWQsic1AfgAMXIZIkoAGnuqGeWSlZmODHQMUYuRUgydKLIPZr7Q4EjAobpZQSt1EEVjAHhyRnhqfJYHkvIcShCSxHIOwED5AQQAYtpQ+62HSuSt6jUgRKgBDMWMg9tWX7xN+4/4yW5N4Vwncz0E0DMkUHiveD1YBnSzDFSLTI6UePVmNFakZFKkbFagX3VLq5KDvATV27Gz18GWU6DMEVAhBkhgg6NQZaDs0wJDGhJwDMlUKVIG3IlmyagM3p7X3jaP68/sGnFZd/44ZkvQ8WGZ2ROIEhEpwoE5VECWW4Yqxao1GOqScxItcBwpcToeInhaolqPSLNLVluJkoeveHFCFQF8B72DcHC5WCEk0IEkhS/fxiMcJhAAMdhAoE6bcgZpA4yDgjB9BIU45O1G1de/s0fnvFSBGueNGQCEQA9LFR4tEPJvVBPo4ly1DPXCJShgyEyXn60M6klEbXUkUxUmoMRkEPVIICzekTzYBAwAjsH0NU1pFQA75lx1uB3DaDDVTCGKYGCGlDhkCATwx7akJNIEzSvAIZgehmf3rd+1dO//eDpP4aoNaIcEkwFCOZgGcWrkOV2srw5GBqNIBmplBrHXaO1AuMTVanFjNdjkswggB7R8RyqQqTHP5Sv1sk37sadtwoEUGaOEbSekm/YxWMF4kEAJUBAc4aTAzxAG3J33r9UudZVcLkhmM7LMev3r1/59G89ePr1ImrmYMgc6kamCkBVUAWvQiWJGKsWGas3AmSi4smjrkZ3UqSWOLwKuRe8BwWMHOpSIqtMO2PwW/fh+7swy/ohzZkxIuTrd6JDFXCGwwQCKJADjkBAPWtdDztoQ871wKc3Xjj66gtvU5ICJygQYGom860HTn+xiIoRneUzE4DJV+HQ5zS3jNViKvVCIzTGapMzk6GxcmMoX6nHjV+TZpYkE1TBmENBIgCiWHOwTmI6eiX/4VYoxpj+rukPGxFwQr5xD37THp7gP1zgQaqgRUDDkXJ9Fx+nTbn6Ltj5YHGIyzUlOeFONbB5/cGpwT+CGNFZtBoMcth6cJabRkjUs4gks42OZGi8fLAaQVKtxxMVUUliaqnF50fNSmSqgNgpLcPI5AOUd2/AXXQKZn4P5B5UOWFTKZpv2E3+4DYahODxKJhRxfdJyFzYVjX8D23KVQ2YNX6ElAxwIWhO7AvL1m1efuFEyLwUsEa0PWcmRhEUr2bq2MqQedvoQEarxcbcZOJ1alZSaAziD75muQCgOlkcdszljIKhfdjJeU1253rsmcuxKxeAtZDnPCUiYA1aT/HrtpNv2QcCiPAEAgN2DPIaaBHwzFmJ5y86lrOXNuU6lkOn+CGYCpqnLDzxv2nH4rO+PhEyCq4FQ+bILS4UAAUEIVeoJVEjMMarxcaR13C12JiXTA3jSb0hb6wGG3IPHD4zMYo1yqxiDGQ5+Q83o/uGsWuWIH2dYAAPqAfliclhSZvl+O37G52MDo+BtRyDIAV3QEmXC3ORCkSGr3QY3kMbc/McfHn9paOvPueu8c64WsIbguPksmT77vmn3nLv2a/Mc1O0xrfMarCgGFEUoZ5Z6knUCJTqRI1MBcnkcVeJetZYC278fJo/9u+VwiTTCBXmBpFG+d2D+P0jmAU9mGXzkJ4OpBhDZEAB1aN+D5Bk6HiC7h/B7ziAHxoD5XhCJrBgBsB2QN4H5MwdBiTlIfH8dAI12phLKvBIpS9PE7ePAguBnOMSrvrfvb9/2c33nPeqehp1nKxrZUSOnJmAkuWWqQcSG6ExVi0wWikx2JiZFKgmcWNuMvm8iUUfM9g/9HrUzCSwBrzH7xpolJQLSFcJKRehFCOxo0EVradotY6OTdRoBerpVGIbMARPgdulqBN8F5Az+1mQcYh2aJlElgF7aWNO1tNQNPk+wAIpwTGHzPBoZ9/BTqZSj3uczWfkKXgjCnJoNVhVSHLbWAkeO1jVIsOVIqPVwkQVD1YjVLyXRuUKqiACZqqcVYKnMmcRALSaoON1GgwgQoMCKPjD/gt3lhMQCJBBtFVJlwq+F9BGzT4GUDAD4HYrkrIS0f8GuRbY2L5B42lYu/b0PZc9424lNxyDwPqsXi8Uv3rv2T8+0TEsjI4zZARAjlwJFhQEBMi8aWxs1dJoagg/GSgjjWF8ufF5qoMhzQzZYU/BGwMCMDXYNwTTbSqxn3hNzxBMJwFyiLYr+biQ94MWOURpX8IkDzIG9gDYEaXBAHCqop/0yHXAAdqQy4WG/3rw9AOXPev2cepRDHieWGDU+8zYiZB5xc6B3tWxy580TI5+eNFMXaeSZo4ks40aqxcad3KN1A52JxOv40VqU9etVBtPwYPIVHHke2OUgiEIZjehwR5Q7DD4TvBdgi8CBlRAaDMeJAVTBRnVxiseMBxB4FKDfsyovAyo0GacUxpKqe73uR01sOBJgiYQnYD/+v1n3rBx98JzYpcBIKJHBIki5I3trIMlVJP40WtURiuNMGmsB1eSyZlJNXGgNCgcCieOuE4lCAID5GCGwAwrCKgFDO1FQXLAA8ok06jHJXCtyfWfXcYbAE8bcXFdAfjy7efVX3vdyr1nrN6+iCTiMQJB1OCy2n0Pn3rV+p2LrywXEqZQSx3j1UIjOMZrcePZkpFqibHGVfSFxtPxuZep4AFVMHLYMb5RjlEQBDJVUySjPcmhOhaZ48aJ2gC8gzbiakUeFTu/Gbhgzv9fVxFQAcyhH9c6pfruu3549iWfvf3C68brMaNTYTI8PvnAYpJaktyRpIbcHxkkIjSIKJGlBQUGD9SJKfB4shxUAWFGGQEB9InHgxOlyFN+KJcjWHIyHIKnbQlzgtDwNlFZD3yMNuGMClP4yNev2PIHr/9Uwuy+NFWYZB4twQAZUAcSIptgzSjKAdBBusoH6JAD7/i7Z57xpW+f87bhasEAiDz+avDUFfRBGxGgoh3s4HQqdPAYCj09OZEDVWaMAEkqZDlPqFY2pIBwfERgvOao1CKMKFMw5NQoUaMDIWgDoqLvSXLZCnybNiDn3KBM4fzVO6OP/+E/vpGx4nKElPZ2eJAI4B8tLznoGCoDGB0hZQjPCDCI6DAdpWEg5TB37Ty9+6ff+fJbNOOyMC+ZvQTlaKqQ5cJvvWGQs9ck1BNhpkRWueehIht2uCdZQReeCmeVBzYWeHBDTOR4HErQVjYoPBvYTotzh1+1/tC2JemB8d4t/XZ8Jd7S4g4dbSkCCJMEUESqwDDoOCmjwADIAIYBhnSIROuIJkDO0QarHO7OTSvNL3zs+vdIzmVxCJlZzWM4mgLWgnUCGBBhxhgFDNooZVoJGAMKqADa5qdPwRoR3q/Ii4E6LcwhwuE+e9OlP/yZF996pdStAErzCMBRQWIapQCSAOOI1ihQRWQYZB/4ARIGQSvAOGiVCE+D0tDPcfm/7/6pt2d59Kq5+7R86GjiWImsoqqgzBxVQJGpmk6C4owigKgSzALKtaL6V8CbaGFOvHK4j9125fb/88LbtiF6CirpSR7EW8CACkKGkjZeY6kBQygDCIP06jCiYyhDGB0FasyQt7//xT8+Xo1+p7usKHNRoAjOeVwjaGhbChijiBDMJsIvA3cD76dFOYQj7Bvt8A9tX37XWadsOYV6NF1dzZEdCQqgh90AmYKMgQ6BDONLI8DBGsDoAGUdATLAA5BwUrzjo88/7QP/e+k/9HaqUdpLkgkCRE45QYFC5MA52p41IKJMJ++FegJewVmIoxBmTfCXGLkXuJsW5DDC0f7iw1ev/dff3XxlZHQlXpLj3whXATFTr4KQA1NHWTKOxiMIA6gOYO0A3Z3DoAlQAzJawL++75LyP3/y0g8sXswSlLahCEkGK/r34L1lx8D8E3zYM1DAWW2UqtC2VLAWjIACwolLUqFYUC48c4zOzpRde4us21zGWbBGOTkCEfryTD+wa508Bxigxbgda3mMHWvPSn7r515w8xnLv/jTjJcdQgYIU47qTgyCAlNBIXXUjTVCRMwBvB8kYxiRCqpjwNgRWZLkUBmg1Xzq3vP+on8+V6NKO0kz5bVX/y8/+4J/w6vwL196E//zvRefwG3MgSrEUx2N0r4UsFYRAVVATjxkli+q80e/uJ5nXDIINmdsLOaTX1jKP3xsJV4FI8rMC1TBGC5Yfq7+A/A6Woxbfq7yeF79zms2/O/v3PXF1Wt2v4jUxkA+WeJBKogMgg7hoyHUjQIjiA6jdgCo8yhLu/n5v3rda9bt7PqleZ2KajuFjLC49wC/cO2/M3/eThDPm174L9x83/Op1EoYowTHTxUiB1Gbz2hQsAaMQK6cEK+Cs57ffeNGnnH5fsgsJI7Ocs4bfnIzewciPvDppZRLnFzBa9Nxvg38My3EpeM8oRf//ltv/9Nf+d+9jNpTERlD9AA+HkRdBUiBjFlmy76+0773yLK/6i0rqrQXgdw7kiwGkwNKksZ4b0A4AYFzOlG0PWMUkenoZuC8NVWedsEQeAteaMgEYuGFV+/nEzctIc/lZB+hhc4m5h1JVb4F3EeLcFkuPJlf/8sf3wRsYg5QT4zjX4pllghKu4mssm+kh7/5/Fv55Rf9UyNg/v6Lb2asVghHZyfc0SjOKr7dt86sRYQTHtKoh45yTqHgwXMUoaOUUyp4RsctJ1GgYCzzSt3670bluUCFFuA6ugim5J7fRvT5tLHYKV+4+3nc9tBVqAqj1UJTlwFUBQARbf+gcUo9EdqRGosKdGYDRMwjoYCgJ9DhwZZdRXbvK7B4aRUS4RDPI1vLDAxbirFy8gXqudKj7wbeSgtwXhUIRLka4bdpf41gqdSLyNT7Zq5YR/bQ+3buqiIH1tBmBDUWUOLxAboGNtAxvJWSXs8YBU5E5JSde2Pe8z/L+f1fegSJcyYpe3aXed//rsAaECFoEoU3Gy83AV+kyZx4Ya5TodOL/iNQYpawRpu+mPDMs2/nLTf8Lbka/v7zb+FbD13RnmEjUIg9SpsQwYtF1FMc20PngY2Uhndg8xqIwZkMPCesVFA+/uXFHBiOecXz9tDVnbJpa5kPf3YpD28pU4iVoKmMN/q3InInsJcmcmqZ88aL+q6OCheqMA0Cr0JXqcrvv/JdLFvyCAj89sv+gtf/wwcYrnTirNJOBCjGCtoOAeMwPqU8sp2u/esbQWN8hheLNxEGTyzptKw3i0DklC9/ex5fmag4gmodIkcImRahcHqk+hfAjU1eplHmMoe8IK/ySypMk0CByGV0FschiwDoKIwT2RSl/YhAIVaU1qQiYCwmS+gc3krnwEaKY3tBPdoIGAdTRJRIUqaLyGRnowqqQkdJCVqHACm83iBfAD5Jk7gcYa6q7qdHO/UvSiWmMW8DIzAw1sW/3/xGfunH/hFV4X23/h/2jvYRGdpSK/4TuopBxWKzKh0HNtF5YD1xdRDUo8aBGB5PbFJUpj+MRZSg9SgI6J/1WfkGsIcmcH2WOcsu5I9S5QJVgmm/JRg+/I3X8I0HngkKW/YvI7KKtHNHo7QEFYuKIUrG6BjcQsfAJqLa0KHhvxieiAAFk4ICAhB4FbwHY8CIMtsI4GH1/lz/FPg/NIHbnytz0f7N8rwFp+ibUGZAIALWwMa9yxAgsiAA7Ro0BW2JFWUQotownQObKQ9uJqqPosagxnFslILJmBTkXjAC/V1DDFV6yf3sfcBU4MahnfIZ4NOcZG54pzDXdPTTOREyfw5EzJhARCm42RGahQhQmmIqRIgrA435S3loKy6tomLwNuJ4CBwxowlLK2P81kv+mqed9W1uf/jp/PlnfoXhSs9sDRuZt1L/DOQbwCAnkZu3kjnH57wJ5RKC4JgoxYKiJ3uDzFhEtTHYn1xR3o7N6/ipAf9TFZGiBJU6/NTVn+cl13wU0iIvfuZ/sm7Hmfz7La+ho8Cs5DPOUOG3gd/iJHJ5ztxiOcegv6UEwY+mj3Y0Hj1J8xdvY0RzyiO76dr3CMWx3YetKDtOlCNlUhBFCQigFlAil6DKrCaqb/bCfwPf5yRxijJXjOzDdHbxp1KglyA4RgKNjgZlxqiZDJhiMkDf7g1UNhygo7bniBXl6aE4MiAoxfCZ79/AFWu+z0Vn3M4P7n0hn73reooRs5ooJYG/3LNIrgUSTgK3d6EwVxQjXhlV9cVKEBwjBZGZu8rH2wg1jrhygAWbv8Oy9V+gsm0F++rnoNaAGKaTAFYzILBGOTA6j//3gb+lv3sfB0bmU88cziqzmQoIPHPeADcC7zk5M5oB5oRinT4VfZtaguC4OAvOgSrTRPDWocZRHNnFwo3fYNGGWykObQeTomY1ahyQMt0UsJJjhGAqbNLcsvPAYowBZ5S5opDo74nwOWA3M8wVU2VOsLxVlbMIguOgCnGsWKOATEPARCDSeP5l4fpbWbDpNuLR3WAcuBhEmFmCJcOhKIKghAeMFWOZeyyr6qP8LvD/mGGuPs6sVx2Rs3qW6VtQguC4qApx5DEG9EQCxsWI+sb9Y4sfuZn5W76DrQyCdRCVOFkUsOKxeDIsc1egHlyZ/ytePgjczQxyUVGY7Uq9/F6W0kMQHCcF4miqo1GOi4ppBIzxGT277mPJRMDM2/Z9TG0EXAGiIiefYMmxkpOqRZjLAhHK4vhD4GXMICeO2U24Jkv11TwFQaAKhUgx5ngDpoBLK/RtuYOl675Ez64fIGl1KmBKNIsqOMlxkqEaEwSq+lLgBuDzzBCnqsxahkhy/hjBcYIUQEGEOSRQnepoLOixPAPjYqLaKAs33dY4Iuva8wD4DGzcCJhmUwRnPFY8KCAQBAp/LCq3AhVmgEOF2ao6yMvLffpcPE+ZKtQTwTmInFJPBfXh+zbm1tEZGDmWFeUB5j/y3YmA+Sod+x8B9eBiMI5W4iRvFEEwxSiX1or6U8C/MwNcvajMRuOdUuqp6++gJxYyWS68/Ln7eNWLdtE/r86mbR188H+X8937u8P3oc8FCoVDM5rHX1Ee3cPCTd9k0SO3UBzeCgjYCBBajQKWyaBRDgkCl/Mb1ZJ8Ehhimrk0FmajZQO8rlriIlWesloi3PiSXfzOLz5Cgworlla54txh/t+fns037+qlVFCC2b7e7LEWcn/kinJ5aBuL1t/C/E23URjZBcaBjQGhdQmWvFHKpCBQAZdyWlfK/wX+imnmukaYdayntyb66xiesjwXFs5L+ZmX7gAEEgNTip2TP37H/d14bzBGCWb31pkxkJoCeN+44LKxorz5W7jKAJipFeU2oIAjx5ATBIdTAUHfIiofAfYyjZww+9QtP2XhTE5AlsOKRTX6ulPIhSOosLLxczn7Bg3GEMxSquAKESZy9Gy9n4WPfJX5Ww+uKA+BmxrwtxXBkGPwIATBERRW5OjPA+9gGrkMZTYxnl5n+FUVTogxMDgSUU8MxY4ccg4RZWjMMV41GCGYzSwsGl3H2V/7AMUN9yFp5dCKctvyODIeTxAY4Ze95z3AbqaJQ5lVROQNKnoKJyhyyqadRb7y7QW86sXbwFjwAk4B4dO3LmJ4zFIuKsHspAhxDOft/SKlka+B6W0ETPsTXPg65ycWLDoYNsAfME2cEWYNL9Kj8ItME2fhbz6yEms91z9rH8VSxsBQzEc+s5z/umkxpQKzXTg2M9ARZ+BKoIbZIibjCQWB8EaQfwZ2MQ0cIswWBm4EPW36gkYZqzre9i+n8YFPL6e7K2XfQMyOPQWiSBEhmOWcKJ1RFVSYTSJJEeGJBMFihJ8F3j5NQcOs4A09NtdfUqaXs4pX2LSjiGoRYyCeEyETKOAkp2xq4IXZQoFIwtFZ8ORU9Y058i/APk6Qy5RZwRpepjlnMgOMTIbL3BNYySnNsqABIZYMEZ5QEAisMJbXAH/PCXLG0vb21Ijnj+mb4m5Qz7QIAgUMOUVqgDCbxCYlCJ6MKCj6i3sXynuBCifA7VlI2+sf4kVxlcvUM62CwOIpzLKgUaAgKUHwZFTA5py1bDs/AXyIE+CWbaetqSBi9Jc80y8IDDkFnX0dTWRShCD40bzTX1DkY0DCU+RyR3tTrhR4LtMsCBQQ9UR+tgWNEJERBMdEeRpWnw3cxFPkMEo7k1zeCDhmQBA4UqxPQZhVnKYEwbEynp8/oaAxnrY1ulNWdyzWV4ow7YJAgbJUEfGzbkZjJUNQguBYeOX6eUbOA37IU+B6RWhXbon+dAI9zIAgUKDLVTEos43B4yQnUxcCJ/iRBApDXt8A/CpPgRvySjvKPB3G8JPCzAgCVeiJK4goKLOCqEd8huCxeDKC4Ngo/DiedwCDHCennrZUynhuvcA5KDMiCBTojiogHlRmQcB48qhIre8UtsqZ1IcjBCUIjoUKKwuZ3AB8hOPk4kxoR2msbxRlxgSBBzpdFVBA2jZg0Jw87mS8dxXjfavJu/pIBgyqIEIQHBNRSGJ9AyL/ASjHwSUF2o7COaI8nxkUBKrQYaogSrsRnwNKVuhuhMvYvNVkhS5AcXlGJAYhIgiO09UevRL4HsfBeZR2EyfyijSmLMqMCoKSVAEPWFqfIt4DSlrqY2zeqYz3riCPO2BqNgOgBqwFhDYQqAoAIkqzCTjNedVxB43mtBeRUhbrT4oyo4JAgRLtcHSmiM9BDPWO+Yz1r6HSs4w8KjV+XHzG0Ywo1kDuQQhaVT0VjAHvQUSInTZ/Nd7wciPydmCIY+QiK7QTD89COY8ZFgQKFLUK+JYOGDWOWtcSRvtPo9azhNzEiOaYPOWJiIA1Sp4LCEELSjLhGWfexY3P+RC1pMQ/f+UXeGTXKURWaSphdZZyHfAJjpHLUtqKi/Q1npMjCCKtAdqCA36PGkeldxVj/adS61yEGjsZMD7lR5gKGoIWleXCgu5B/vAn3snKFWtBlN7SCG/8139GVZp6jGYE6jV97XEFTVpT2kWlLIvmwbWcDEEgEOU1UG2ZgBHNyV2RavcyxuafRq3cD2IOHZEdCwURMEYBIWg9uUJXcZwlvbugVgaXsWrBFiKXk+YOoXm8h2I31xRgNbCZY+B6umkfRZ7rKywRZlYQKIIViKUOSEsETBZ1UOld2ehgklLfoeG/ZhwPBYwBawkrzi0qsrDtwGL+5/ZX8MqrPkFWL/CRb76OauKIndJs6unLM7kO+DeOgcsToV10JPqaNAKUGRUECsQCJUlApWkryoKSxl2Mz1vdWFNOit0IiviMEyEyFTQErciIknvHn336N7jl/udRSwrcu/k8Iqu0iiTSVx9z0CSR0g6sl9UKzxBlVlIVVMEYJWg+VShaT9nVOal0MkTMRKWlHsbnncJ43yqyyRXlxo9PB0GxRglalzWKqvCtBy9FBAqR0kpEuRzkHOABfgQnKrSDzPI84+mfrYO/3EMhUqqJUIxaYmc+bJzZlLKtA4YZpx7yFGze2CA7sPAK0r7FZIetKE8nY8AaQAVQgtYkohRjWlWH8bwQeGDWfE2AoC9VZp/MC/O7Bnnri/+O5Qs3cfNdN/Cxb78SmrpZEqhCbNLJjsYLM0chq4MrMLz0Qg6cex2bRq9idE8nkWSYPGUmiIAxoDx1QaBWX6xe/hbwPAnnhZZnhGUqXI3Oxm4GfuY5H+alz/wPyGIuXXUfa7efxZ3rz6cY00xhRmMyimaGgkZzyBKISgysega7z7iWoaUXYYoF/P3SCBixyoxQEAPWKKBND/R6ImQ5GAPFOBwftxNVnqY5pwPr2v5mAF/gOnL6mIVEYGnfLvAOkhKURpnXMYQSND1oJKUgCSBMG59BnuALPQyccs1EwLyA4YVn402EzevYtIpoETAz/MVnYG1zj85yL3gPF505xtLFNUZGHfc+1M14zVCIlLYQFK3R639k0LT6QDDOReqi1ymzlMLHv/NKLjr1Hnq7DvD9e6/jro0XEzmCJlIgIqUgdVABmY6ASck6+tm36ir2nH4tY/PXAGDyFJvVTvrZvzWK0hzeC3Hk+fUbN/Gya/dQLKXgLXf8oJc//MfT2La7SBzCpi0oXBfJkx+fOSdCK6sYXWAyns0sVYiU7667jBv/4QMs6dvND7eeS6VewFklaC5HRsQJdjR5CupJuhaz99RnsWfNsxvPwogqJksApVmMBRGaolqHN7x8F69+yXbILSQODFxx8QF+942GN/3J2WiYU7YHy9N3bNCVwGaegNuxSWll3QvlilKPLvQ5zOaw2bp/KZv2LCWOCCHTAhSwpIgmIBwnfTRgaj0r2HPac9k7ETAHr4kRzRvdSytwTZrR5F7o6fQ8/8r9gEAuNHggt1xx/jCnr6zwwMaOMKdsA6p09S3l6U8aNH1LaWmurNf7nFkvsjpRBM2ioHrYew9RWod8CLQAGBALGECefEUZqCw4g12nP58Dq55GvTz/0PFYi9AmdjSqUIg9pWIOCEdQKERKuehRpU0ErsSLgY/xBJwr0bKMl06vejUzJAjUAwomAhuDLYEpCJGF8bifz5Vfy7xsiFXZVvrzfZT8IGBAYkBoUIW8DjZmdMn57DrzOg6suIIs7sLkSWPA33JUcFYx0pwHEQ8MOR7e0sGpp44Chkc5z/adJbbsLIY5ZTtRno5IHzDI43AgtKrhbs7sGuEMhGkXhIARIOqCeL4Q94DrBAyI0DDEIv5KfwUBYvWsTjdxcf1erqp9k/OT+8HXwAu4AgMrn8aeM17A4NKLyKMSJjsYMJXWPhq0IAIKCCePCIiBf//vFVxwxihLl40DAihp3fHPn1jJnoGIclFpE4GwMk64CPgaj8PFCS2rXOFpCDFtJvdCmoM1tNLdRMHhx2LdUFoO8TzBRICC6mGvgAARk3IMD8VruH+iPtXxEi6r3cWra//N6kUR209/IQMLz8Xb+NEV5XbgDJMUkJM/l3xoU5mff/u5vO76XaxeMc7wcMz/3rKI2+7qDSHTbhSTW572hEGTW1qWy/Q6lfa7TqYUJ5yxZBv7Ruazf7SHglOUoNnUgzFQPkUoLwOJQD1ozo8kQKwQA5lEfKP8NO6YqCsXJTx3YY0uWyfNarQNBWMUEVClKQqxsmlHiT/8p1MpxlBPwQgUC0r7CbzRFwB/wuNw3mirzmfmqeEStL06md6OYd792j/kmnNuY/2u0/id/3wXD2w/vQWu9g4hYwvQebpQWACaN+opMUBJIQe+sTlm+5DwE+emLOrISHKhHRx+dNZMkdOJAq9CqaCI0KYChQuNyjJgR9tcqpkZvUyURbSRegrPPe+bXHPBVyEtcdqp9/CKKz/N2m2/gSIIStCkkClC95kQzQPNmBYWsBY2DkV8+Ae9vP6CIRZ3tk/YWAMitAQjStsLenOjzwD+i6O43CgtyculiDraiAiMVLtALbgEUMaqXShB0yiYCLrOEKI+0IxpV7Cwa8zysR/2cONFQ/QVPKmn5VmryPQNaIJAQC5/3KABoQWJiD6DNlOI4Btrr+bfv/RLvOiyL/DDTRfxn996Nc4QupkmUYXOU4S4HzRjxhQsbBtxfOahbl53/hBGwCstSxWcDUdV0ysQ1SuACEg5jBNVWo0aehQuF23Db8VTx99+8Rf4l5t+niQXjEBkFeVkCzSHwgIoLQbNmXGxhR/ujbljR4lrVlWoZ0IrsyFoplkgcImKLDx6TuMQodWo5yKDLqQNGVEKDlSF2CoAStAMxkF5pYAAnhkngBG4bUsH5y6s013w5J6WJQLGMG2CQKEL1UseGzSqtJoCPD0BEdqXiBI0j+ZQXCJEXaCek8YZ2Fsx3LO7yAvXjJHkglfwKqiC0jrksK8LFmG6BMHVwOc4jKMFiXARylMTBArGQmERIJx0kYE7dpQpO09sob+c0V/K6Yg8CmReaAUi4CzTKghUuIijOBVai5euOnq28NQFgSkz2c3kzVkbHqwa/vfBbkTACI2gOXN+nYsX11jenTbCxitNZ4yiTJ8gEOV0PPOB/UxxktNajC4BziAIjpVyiDB1xYyABTxNYQQQUCZr77hlx1iZ7+8ocdXKKs9ePUZktHndjYaOZsYEq3CsOiJocLQUUTlPVQsEwZNQD3gQe7AO/Zjmk+U6QQyop6nksC7HArVc+PL6MttHHK88e4SuQt6UsFFABKxTQABlmgSBQeVC4C6mOFRoJap6OcGTCQEjU7cu9wuuA0x02LclVyAZVGwBUFqOFbBucg069T381PlDlCJP7oVmsAZUmV5BoHoZ8P6W3ToT5QIVguAxNAfbAR0rIZ4vGMckZZLQUFoqAGhOyyo6WLc/4qYNnbz8rBF8E3JRRDDWoEy7ILigZbfOjJcONXoqjyMIIRP3Q9fpgi3/iEsxDaC0vNjC7TtKnLewxhn9yUm8I01QY1HxdMkoTroAwzQKghWozAMGWu7oLDe6WmApRwtCyPRBz9mCONCMJ6e0BSNQz+FbWztYMy89aQGDeopje+k58DDl8Tob7fOoaBGDMk2CYKEYPR24HcCJUVpFlLIyjehGaQgC1anr/U8TJALNmVUiA1uGI/aMWRZ15swIEVQs4jNKwzvpPLCB0uhOnE9ItA8RBWU6BUExyzn10aDJclqGWDkdVYLgUR6KS8B1gubMOiIwlghbhmOWd1fImT4qBhWL8QkdQzvoPPAIhfF9GJ/jjWuU9YrBo0yvIBAjpzHFiRFaRS6cI8qkIFAwMRQXCeqZlQTIFfZXLF4B4cSJwRuDTauNgOkY2Eihsh9UUWMbAQOgCE4yLDkoIEybIDCiZzHFGVFahnI2QTBFPcTdgikwq1mBSmLIvOCsnlAHgxhsUqFraAudBzYS14ZQpmYzwmM0gkY8yjQLAuVsFRyQOaU1uFzKip7qDUETeS8T1TpXyLvyoQcvZzPlqVNjUQxRbZjOwc10TJSrjwHgjeOJKIIjx+CZAUGw0ov0AvudF6EVpJaVRukmaAqvQq0GnWWlsytj/1CEVyjGStMoiAMM4Jm1vEIpUqwoelwbZAaAuDpE54FNlIe24NIKKgY1lmNhJMdJxgwIgk6Tc2ojaExOSxDR1UAHJ13gPYDyhpfv5seevZeuUsb23UXe898ruWNtV1PDRhVQZjUR6C9lWAM5P5oaB+opjO2j6+AG2fAObF5DZWr+cpxiSZgBQVCY+vv6HU5EaQUCKxQsJ11QT4W3vHYrv/j6zUwSVq8a44IzR/nld57LnQ80L2x8Cujs7mY6ImV5T0rmBTH6I1aUc0oju+gcmAwYyTMwBm8inqqCpCjTLwgUVgO0zowmlZVprIhyEgVpJpyytMZrfmw3qEBqmGTo7k14/Yt3cPeDZ+IVjHByGchGFc0FDKDMOpmH1X0Zyzszcg/OPP6KsvUppeFtdB1YT2FsL+Iz1FjUOk6UI2O6BYEA3rMSwKmnJWSOlaKcZEGWw8oldXq7MsiFI8nEz9Xo6coZHXcYq5xMYiAbm6yoB1SZVRQwwFUrKjirJLkcETDeTq4ol4d3NI7I4vEDgJ8MGOOYLpGkTLcgUMAalgM4a2gB4lR0GcpJFlihMfiv1gylTg+ewygDQxGVqsUITaE5VHcqUY/Mutvs6xlcuqTOuQvqpF4A8DZqlEvG6TmwlY7BLcTVAfTR4b9jmp3kZYBwglBPQBWcg2KsiDBrKSxFKDkVmk6ML5PLYk66IIqUdZvLfP3OebzouTvBOfCAU/DCp29dRK0ulIpKM4iB+j6o90NxMfiMWaGew4runOvPGEWA3MSoGLoHN7Fo407qG8YoZSMogjeOmeQkZ+YF1bpw5uoq11wySKGY8+AjnXzr3j6YepxgllqoaIdTlGarDkix2MVSMZxkgchkvfu9p5Dm8OwrB+gqerbvjPnwp5bzpW/Np1hQmkYAhdENiikIUR9oDihtySskOazqyXj1+SN0dTqSXOjcv55F629h4ZavMbLvPHZkF854wAAIEEnGzApqdeG6Zwzwx7+0nr7+KgA+t/zXF5bwp+87FVUQYTZaVEil7Aqp0Gx5Kn0q2iMEzeCsMjQS8bt/dwanrajS1ZGxY0+BHftiSoUWaO0FfAIjDygda4TiQsCAekBpeQqoQuohtvC0FXWuOzOh23lKOx5iybovMW/7nZjaCDgldzGaGyBnmoX15ibIcmHZooTf/7kN9PXXIHEAGKf85Et2sHZjF5/48kLKRWUWKuYq/S5XodmiBSxTxRA0jXOKKjy8pYRXcJaW+j++GPAJjD6kJAegtERw3YCACCBMqyQFryCcGCOTVYqU8+alXLLSc3b3CL0772X+uluYt+MuSKtgY4hKIAknWyQpCDMkSFK49OxhFiyoQ2p5VCYQw9UXD/DpWxfgVTCizDZZzDKXxTSdKIsImk4ECrHSsgwNtT1Q36+4TiZKMDGIZVqoghG48oIaXR0e709s0aJgPf2dwpI+Yb4ZZuHOO5l3+0307F4LeQKu0AiYZookm8FLNQNVsJYnZI1iBJTZyaALnUFpNoWFBMExEgsopCOQDiso00YVIgfXvniMJfMzslxO6A6y3BZw4weYt/l7LHz4Zsr714PPwcbgirSCiJRg5hRiuOehLoYGY3r765AYGqwCyvfu76Val7Y9OvMqpBkgEFsQUQ6nqgucqtJsgixUjkMQCIgw7VTBRAoGqpkhzzluOvVdL8WRvSzcfBuLHrmF0uBmwICNwDlahU51NJEoiiBo697Fl4AIFCMQ0baagW7eUeQvPria3/+FDZQ6EiYJX7x1CZ+6ZRHFuH1DxpmcS864jyQp8sPtZ4OCCIeRBQ4kdDRBMAWFOAJrAeW4eBujYhoPWC7a8DUWTlQ8uhtEwBVpRYpgG0GTkmhMK8q9UIrrXHfhbVSTIt966Kq2m2cUC8r/3rKQrbtKPPfKA8RFz9p1nXzl2wtIMmmEUbtRBMj5rZf9Ba+6+uNkueNvPverfOjrr8VZEJQpCwwtwAvzaAFBoEAhVkSUYyIG7woTVaRzYCNrbn8PF375d1l+z38Sj+8DVwAb08ocOZFkKK3He8GahD985bv48zf8Cn//c2/iTS/8F9KMtlOMlbse6OLd71nN2/7xVP7nqwvJPW0ZMgB5Dsv79/LyKz4DanBRwque/t/0livknkkCqvQ6VZpOlE6EpgsCVaEQ+R89nBUhtwWMz+je+wBLHvoK87bdga0NgW0M+NvmP6+TqaBRQGgpaQ5nLNrNtRfcArlDTMZLLv8c//7V/0s9LSCibTav0YmaHbsXIjBaLbN/tJ8lS9aDydk1uIRa6jBMUUAoO4QmE2PQDqX5gkAV4lgx5skDxmZ1+rd9n8WP3Dy5opxUplaUy7QbQ44lR2k91sC+kXls3HsKZ53+PQAe2nEmlSTGGaVdCe3PGmVgrIff/eg7ef1zPkStXubfbv55amlMZJXDFB1NJlBSKNMigiCOwIg+ZoPM2xiXjLNg27dY/PBN9O66D/LkUAfTpiweR9a6DxOPd/JHn/wDXnfNR6kmZT74tRtRFUBpriCyyh3rL+LeTRfhFTIPBacohwiUndBcAkWFDlpAEKhCIVKMARTUOHIbE9cGGwP+JetuomP/w+CzyYBxRdqZIhjxWPEorSl2yg+3nslvfPhtKFBwEFtFCVrlfx+vgsjke+UxSo4mU7QAlFrlvFoEQAnmcNDECs6R2YjC6B7mb/oWi9Z/jfLABkDAxuAcs4WhETQt/zezyAkCQKuFTGBEeRKFVgiaSJC4Fb5l0hqmtkAEZxQlmItBExUs5epeFjz8NRZMBExhZCeIAVdkNjIohpxWJyhtKYgdTScRUKCJ0ly45uzvc8MVn2HX/uV88OuvZ6xWxhqCOSazcNaBW7ngy/+AHRoEE4ErMnsJIh5BUYJgRkSOJhOIgJgmSTJhzaJt/PXP/Bod3XvBZhSiOn/26bdgjRLMLWpgyeiDWLsbXC+znQIGj8UTBDMkNjRbk4Mm97Codw8dPXvx1R5IC5y9/CGMIZhjFCESiF0GJmKuEJTIJAhBMCMiQ/NZwNEkkYWHdpzO/euejimNkGcFPvv9G8g9wRwUCZRNDRDmCgVKUiMIZog1NJmCaf6efg9vfv/f8Jvv/1ve+I8f4LN3Xk/BKcEcXAQwSperg86loBFKUscQBDPCOppMwLTCQ2EHRnv57B3XYQRiByIEc4wCkcnocFVQw9whlEwVEYJgJhhH85lWeQLZWYK5HjSS02Frc6yjgYIkCMz0VwUEIWjCtT9B4CSnaOqQC8dFOUQf53OD8BjKkUQopoZC6ojE84QElEkqAPrYzwIKqChPToglQVAUYZoFgTiCIGhQwJFRliqoHBkEhz4fWQgIYISalamC1CmpUfKp8gdLFDUKoiQGcgEz9T4VsCi5y/lObZBNtW3E3gNgVbC5AcB4wXmDUcH6g2UO/djUZ+uFKDdEmcUdfM0doqACioKAF300hIxRSmSIF1QABESZLkHgaD5PEDSjiVYQBXJQD5qDoYDzOVVxJNaS2cmQGImVfSXYV1b2d+SMFXOqsSePcnKXkUQ5SexJo4xarNScklgltZ7MKrmdChvjwSgCgGJQhElGPE48t4449td3gXiekBfIDW6qotzi/KHPcWYppG6ibKNKqaNUjykljnI9oqtaaFR3NaazbqknVTSuQx4juWASAQU1gAGVqfcCoByHIPBy0Us9TXY5cAfTLQhUjggSD6iZLBHAebLOAbRnN653F65zP/0927h26acYLtXY36GMFjOSQoZzKc5mWJtOdSegoqiAoFgFg2JRppoWBBAVBEBpECbpobA7QiQ5Xxw+n021hSA5T0oO/0OPei+H/7wCwmFnaeAFUcGoNDqfqNJFPj4fV+0iGu8hGp2HrXQTjfcRjfbhKj1EI/3YpAAK4gEFODqIlCA4StoKQXMpcCdB8BSJCuoBD6qThUIeQVauYnp2E3Xtw3bvxS7YSLz0IQp92ykVR+gojBAVhzGFCiauYiQn80UiBTNVqIAeHg7CTIkl40vD57GpthgkY8Yc3ZmIB+NB/KH3KpAWkaSAyQrYtIAb7yUeWExxcDHx4BKikXlElV5cpQs31odNQAVo1KH3agCUYE6qt0LQXAzczY8UBALKZOVANvVSBDqHiUpDaP827Mr7KC9eR0fXHsqd+3A9uxvdSsHVKOIxKqgaUEER8FPvMYcCpUkKJuNLQ+excSpomk50KnwA/NRnPRRGWYSt9GCrnUQHQ2hwEcV9KylNVGFwSePHG1W3iIJaUAMqc+gYLqi2QtBcANwFOILgKOIFMvAecgsaK6Y4Sr70YeIV99HZu43SvK24JQ9T7N1BVzxKwSYgHgGMN6h34C2qgkdoYY2g+crQuayvLQHJaHmHh47kIBw6R0sj4pEFFBrdz2KK+1dQ2rOK4oEVuGoHkllMBmqYCiAlmJVGWyFozgLuJHz5WaACGaiCB0Qg7R6Fxesp9m+iOBEm8cp76Vn4CD3lfdjiGNYmRCqQOdQ7vBoUoV0VJOOmkXN4pLoEJKetiYLJD1UeIUkRk5Qp7l9KefepFPespjiwbOLzcqKxTlAmayp8VJS2Fww4mk1JEeohaOYgL6Cg+WRlRWDRdgrzdhCvvpPO075Lb/8GCr27iMqDlCTD5g4/FShkEaQxGS0pfO+KCuSuUQ2iqE3Jy0OMrz7A+Jp7AEEqXVPHbkvo2H4GHdvOojjxPh5eiK2aqW4HkDbteoKkFTqalcD3gCUEs5yABzLIPeRlj+3eg5x6Nx2n3E7vwocpLn2Acu8OOkyCqIC3jdKJ8gizXUEybhk5i4eqy0By5gSTH7aIoKBgR+dT3L+M0t5T6Nx6Dh07zsCN9+CqEQqoa6MFg2Cro9lEE1TqBLOTCqTgFdSBdowhp9xF54r76FjzXbpW3k1v+QDW1bCAZDE+dXgi5iIFDMqc4m2jDpeXhxk/ZT/jp/6A/Zd/HlProLTnFDq3nUV55xl0bD+LaLQbyQUEvANEaUlB6mg2lQSoE8wScsQDkHkBdPWDlFffQ/ncm5i/9Id09OxqrBTH3qBZAX/wtd5BTgAg4W+YR4WP4uMq46fcx/iauyEpNVapO3aeRtfGi+nYfnqj87F1QQ2TZQGUlhDUHU0nVdBx2legAgpkkCn4vmGi+ZspnPtV+k+/je5l99PRtZeCF/zUBpjWOsgQfrQQNIGACqQxEIN4su79DPfuYfi8b2LGeynuW9E4Yut+5DJKe1cRjXaCCGpb4IgtqDiaTJWawChCOwoBk0BmQDoqmDV3MO/8r9B12rfoXfQwHa6KKJDF+EawBNNwnXmgBvKD5QAa3U5l5QNUVq1l7zM+RXEiaDq2nU3PI5fSsfVcXKWMeEGjJm2xBVVHk4moIlRQ2kAgXvAZKJCX69izv0fvWd+k57yvMH/eBuLiKDaL8AfDJS8TnNyts3DMBrVFm6ktXc+BS25q3GLQs/5SujZdSOeW83DjRZCT+dxOIFBxQvPFhtFaDkLQumuqoBkkJcWdeg+dl36KBWd+na4F6ykXRjBpgdw7tNZJRvDUCQYFlOApyqLJEiXp38m+ieDZd8XnKexfTvdE6PSuu7KxUOCqFu9m+o62wAvjcuHLPE2n/JvAz9F6QsDUIY3ALNxG8cIv0H/el+k75Xa641HwDs0ivFqmRxBLzu3jp3DX2GoQzzQJxIPNwWaQxo2g6XnoSvoefAaFgcVIBj4KgTMTBD7ojNJ0CntoHUEm5DloZ43okptYfP5EuJzzVXo792BRNC2Q1ztpG+HoLFADmXm006mseIDKyrXsuep/6N54EX1rr6Z7/WW4aoQ3oE6ZHoHCPqe0At0DQhMFXtAMvIJfvIPOi77I/Cs+2lhHLkZVSErkB4tgJikgBDP/bFfh0UWCofO/ztDZ36G4dzXz7ns2vQ9dSXHfYhBQd+ILBIHucaA0ncouhGYJAZNAVlSiM+6m7+kfZdE5N9HTvwmXOfI8Jq91cvIERjwnSaAGkhKIUlu8kZ3L1rH3Gf9L9yNX0H/v8+ncdiYmOaGNtUDNbocamk2F3YJyEgVe8An4jhR74VdZds0HWXjm1+hwFchj/Jwb6oejs3Cha9SorGOYgUu/yMAFtza21frveR49D18xeawWh8A5XiLsdSI0XVHYU1e8giGYWbngM8g7a5Se/jn6n/FhFq2+nZKtomk5zF5C0AS5myxRRs+4g9E1dzeuvOm/+zp6H3wG0VgBHx3renSQ5exxWU7TeWHYGPYDCwlmjgc/byelSz7L4qf/J/1L7ydWJc+K5HkHrSEwBK3zQHIRUMZXPNCovU/7DP33PJ++tc/AjfeBEDy5cTE6+P8BW01E00mieO8AAAAASUVORK5CYII=) no-repeat 150% 100%;
-      background-color: #2238b3;
-      background-size: 205px;
-      background-blend-mode: luminosity;
-    }
-    .leftnav__header__title {
-      font-family: var(--text-font-family);
-      font-size: var(--title-font-size);
-      line-height: var(--title-line-height);
-      font-weight: 300;
-      color: #fff;
-      margin: 0;
-      padding: 0;
-    }
-    .leftnav__header__version {
-      color: #aab3ed;
-      font-family: var(--text-font-family);
-      font-size: var(--body-font-size);
-      line-height: var(--body-line-height);
-    }
-    @media screen and (max-width: 964px) {
-      .lh-leftnav {
-        display: none;
-      }
-    }
-    @media print {
-      .lh-leftnav {
-        display: none;
-      }
+    .lh-scores-container {
+      padding-bottom: calc(var(--section-indent) / 2);
+      position: relative;
+      width: 100%;
     }
   </style>
-  <nav class="lh-leftnav">
-    <div class="leftnav__header">
-      <h1 class="leftnav__header__title">Lighthouse</h1>
-      <div class="leftnav__header__version"><!-- fill me --></div>
+  <div class="lh-scores-wrapper">
+    <div class="lh-scores-container">
+      <div class="lh-scores-wrapper__background"></div>
+      <div class="lh-scores-wrapper__shadow"></div>
     </div>
-    <template id="tmpl-lh-leftnav__items">
-      <a href="#" class="lh-leftnav__item">
-        <span class="leftnav-item__category"><!-- fill me --></span>
-        <span class="leftnav-item__score"><!-- fill me --></span>
-      </a>
-    </template>
-  </nav>
+  </div>
 </template>
 
+
 <!-- Lighthouse header -->
 <template id="tmpl-lh-heading">
   <style>
     :root {
-      --report-header-height: 58px;
-      --report-header-bg-color: #fafafa;
+      --report-header-overlap-top: 30px;
     }
-    .lh-header {
-      display: flex;
+    .lh-header-bg {
+      background-color: var(--header-bg-color);
       height: var(--report-header-height);
       left: 0;
-      right: 0;
-      max-width: 100%; /* support text-overflow on url */
-      border-bottom: 1px solid var(--report-secondary-border-color);
-      position: fixed;
-      z-index: 1;
+      position: absolute;
+      top: 0;
+      width: 100%;
       will-change: transform;
-      background-color: var(--report-header-bg-color);
-      margin-left: var(--report-menu-width);
-      align-items: center;
-      padding: 0 calc(var(--default-padding) * 2);
+    }
+    .lh-lighthouse {
+      position: absolute;
+      top: var(--report-header-height);
+      right: 50%;
+      transform: translate3d(calc(var(--report-content-width) / 2), -100%, 0);
+      opacity: 1;
+      transform-origin: bottom right;
+      will-change: transform, opacity;
+    }
+    .lh-header {
+      width: 100%;
+      height: var(--report-header-height);
+      max-width: 100%; /* support text-overflow on url */
+      position: relative;
     }
     .lh-metadata {
       flex: 1 1 0;
-      padding-right: calc(var(--default-padding) / 2);
+      padding: calc(var(--section-padding) / 2);
+      padding-left: var(--section-indent);
       line-height: 20px;
-      color: var(--secondary-text-color);
-      overflow-x: hidden;
+      color: var(--report-header-color);
+      z-index: 1;
+      position: relative;
     }
     .lh-metadata__results {
-      overflow: hidden;
       text-overflow: ellipsis;
       white-space: nowrap;
     }
     .lh-metadata__url {
       color: currentColor;
     }
+    .lh-scores-wrapper {
+      margin-top: -30px;
+      transform: translateZ(1px);
+    }
+    .lh-scores-wrapper__shadow {
+      opacity: 0;
+    }
+    .lh-scores-wrapper__background,
+    .lh-scores-wrapper__shadow {
+      box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.1);
+      border-radius: 8px;
+      will-change: opacity, transform;
+      transform-origin: top;
+    }
+
+    .lh-product-info, .lh-toolbar__metadata {
+      align-items: center;
+      white-space: nowrap;
+      color: #5F6369;
+      display: flex;
+      font-size: calc(var(--body-font-size) * 0.9);
+      margin-left: var(--section-indent);
+      opacity: 0;
+      transform: translateY(-50%);
+      will-change: opacity;
+    }
+    .lh-product-info__icon {
+      height: 20px;
+      margin-right: var(--default-padding);
+    }
+    .lh-toolbar {
+      height: 50px;
+      position: absolute;
+      top: 25px;
+      will-change: transform;
+      display: flex;
+      width: calc(100% - 70px);  /* give room for export */
+    }
+    .lh-toolbar__metadata {
+      overflow: hidden;
+      text-overflow: ellipsis;
+      width: 100%;
+    }
+    .lh-toolbar__url {
+      color: currentColor;
+      display: block;
+      white-space: nowrap;
+      margin-right: 2px;
+    }
     .lh-export {
-      position: relative;
+      position: absolute;
+      right: var(--section-indent);
+      transform: translateY(0);
+      top: calc(var(--section-padding) / 2);
+      will-change: transform;
+      z-index: 2;
     }
     .lh-export__button {
       background-color: #fff;
-      border: 1px solid var(--report-border-color);
-      border-radius: 3px;
+      border: 1px solid #dadada;
+      border-radius: 2px;
       cursor: pointer;
       outline: none;
       height: 32px;
@@ -194,6 +246,7 @@
       background-repeat: no-repeat;
       background-size: 20px;
       background-position: 50% 50%;
+      will-change: transform;
     }
     .lh-export__button:focus,
     .lh-export__button.active {
@@ -249,68 +302,21 @@
       display: none;
     }
     .lh-config {
-      display: flex;
-    }
-    .lh-env {
-      padding: var(--default-padding) 0 var(--default-padding) calc(var(--default-padding) * 2);
-      left: 0;
-      top: 100%;
-      position: absolute;
-      width: 100%;
-      background-color: var(--report-header-bg-color);
-      border-top: 1px solid var(--report-secondary-border-color);
-      border-bottom: 1px solid var(--report-secondary-border-color);
-    }
-    .lh-env__title {
-      font-size: var(--header-font-size);
-    }
-    .lh-env__items {
-      margin: var(--default-padding) 0 0 0;
-    }
-    .lh-config__timestamp {
-      margin-right: 6px;
-    }
-    .lh-config__settings-toggle {
-      margin-left: 6px;
-    }
-    .lh-config__timestamp,
-    .lh-config__settings-toggle summary {
       color: var(--secondary-text-color);
     }
-    .lh-config__settings-toggle summary {
-      display: flex;
-      align-items: center;
+    .lh-config__timestamp {
+      font-size: var(--caption-font-size);
+      display: block;
     }
-    .lh-config__settings-toggle .lh-toggle-arrow {
-      width: 16px;
-      height: 16px;
-      margin-left: 2px;
-    }
-    .lh-config__settings-toggle[open] .lh-toggle-arrow {
-      transform: rotateZ(90deg);
-    }
-    .lh-config__settings-toggle summary::-moz-list-bullet {
-      display: none;
-    }
-    .lh-config__settings-toggle summary::-webkit-details-marker {
-      display: none;
-    }
-    @media screen and (min-width: 965px) {
-      .lh-header {
-        width: var(--report-width);
-        right: initial;
-        left: initial;
-      }
+    a.lh-config__emulation {
+      color: inherit;
+      text-decoration: none;
     }
     @media screen and (max-width: 964px) {
       .lh-export__dropdown {
         right: 0;
         left: initial;
       }
-      .lh-header {
-        padding: 0 var(--default-padding);
-        margin-left: 0;
-      }
     }
     @media print {
       .lh-header {
@@ -318,36 +324,73 @@
         margin-left: 0;
       }
     }
+/*
+    TODO: Enable animating the clouds
+    .lh-lighthouse__clouds {
+      animation: panacross 30s linear infinite;
+      animation-play-state: paused;
+    }
+    @keyframes panacross {
+      0% { transform: translateX(0px); }
+      77% { transform: translateX(-680px); }
+      77.0001% { transform: translateX(195px); }
+      100% { transform: translateX(0px); }
+    } */
   </style>
-  <div class="lh-header">
-    <div class="lh-metadata">
-      <div class="lh-metadata__results">Results for: <a href="" class="lh-metadata__url" target="_blank" rel="noopener"><!-- fill me --></a></div>
-      <div class="lh-config">
-        <span class="lh-config__timestamp"><!-- fill me --></span> &bullet;
-        <details class="lh-config__settings-toggle">
-          <summary>
-            <span>Runtime settings</span>
-            <span class="lh-toggle-arrow" title="See report's runtime settings"></span>
-          </summary>
-          <div class="lh-env">
-            <div class="lh-env__title">Runtime environment</div>
-            <ul class="lh-env__items">
-              <li class="lh-env__item">
-                <span class="lh-env__name">User agent:</span>
-                <b class="lh-env__item__ua"><!-- fill me --></b>
-              </li>
-              <template id="tmpl-lh-env__items">
-                <li class="lh-env__item">
-                  <span class="lh-env__name"><!-- fill me --></span>
-                  <span class="lh-env__description"><!-- fill me --></span>:
-                  <b class="lh-env__enabled"><!-- fill me --></b>
-                </li>
-              </template>
-            </ul>
-          </div>
-        </details>
+  <div class="lh-header-bg"></div>
+  <div class="lh-lighthouse">
+    <svg width="217" height="148" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+      <defs>
+        <mask id="a" x="-56" y="-54" width="284" height="202" maskUnits="userSpaceOnUse">
+          <path d="M-56-54h284v202H-56z" fill="#fff"/>
+        </mask>
+        <linearGradient id="b" x1="-525.16" y1="560.08" x2="-524.23" y2="560.08" gradientTransform="matrix(91 0 0 -77 47797 43181)" gradientUnits="userSpaceOnUse">
+          <stop offset="0" stop-color="#f1f3f4"/>
+          <stop offset="1" stop-color="#fff"/>
+        </linearGradient>
+      </defs>
+      <g mask="url(#a)">
+        <path d="M95 47h24v2H95z" fill="#ec5548"/>
+        <path d="M98 49h18v11H98z" fill="#fbc21b"/>
+        <path d="M95 59h24v7H95z" fill="#ec5548"/>
+        <path d="M97.63 66h19.74l2.63 47H95z" fill="#fff"/>
+        <path d="M107 38a10 10 0 0 1 10 10v1H97v-1a10 10 0 0 1 10-10zM96.77 82.23l21-10.7.63 11.87-22.31 11.87zM95 110.8L119.1 98l.9 14H95z" fill="#ec5548"/>
+        <path d="M0 148a177.58 177.58 0 0 1 217 0z" fill="#e8eaed"/>
+        <path d="M103 49a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5z" fill="#fef0c8"/>
+        <path d="M7 16l91 33.18v10L7 93z" fill="url(#b)"/>
+      </g>
+      <g mask="url(#a)" class="lh-lighthouse__clouds">
+        <path d="M60 .19A9.77 9.77 0 0 1 61.93 0a9.44 9.44 0 0 1 9.24 7.83A7.24 7.24 0 0 1 79 14.45v.73A7.37 7.37 0 0 1 76.2 21h-31a7.44 7.44 0 0 1-1.2-4.09 7.31 7.31 0 0 1 7.26-7.36 6.84 6.84 0 0 1 1.28.1v-.11A9.51 9.51 0 0 1 60 .19m79.78 22.31h-17.9a4.37 4.37 0 0 1-.63-2.25 4.2 4.2 0 0 1 4.16-4.25 4.37 4.37 0 0 1 .72.06V16a5.35 5.35 0 0 1 10.64-1h.33a4.2 4.2 0 0 1 4.15 4.25 4.29 4.29 0 0 1-1.47 3.25zM163 62h-24.15a5.1 5.1 0 0 1-.85-2.81 5.65 5.65 0 0 1 6.59-5.19v-.08a7.07 7.07 0 0 1 7.24-6.92 7.15 7.15 0 0 1 7.17 5.64h.44a5.46 5.46 0 0 1 5.6 5.32A5.19 5.19 0 0 1 163 62z" fill="#fff"/>
+      </g>
+    </svg>
+  </div>
+
+  <div class="lh-header-container">
+    <div class="lh-header">
+      <div class="lh-metadata">
+        <div class="lh-metadata__results"><a href="" class="lh-metadata__url" target="_blank" rel="noopener"></a></div>
+        <div class="lh-config">
+          <span class="lh-config__timestamp"></span>
+          <a href="#runtime-settings" class="lh-config__emulation"></a>
+        </div>
       </div>
     </div>
+
+    <div class="lh-scores-wrapper-placeholder"></div>
+
+    <div class="lh-toolbar">
+      <div class="lh-product-info">
+        <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAADjklEQVR4AWI08P/HQEvAQrxSQKvlECfLFYXx75xCY2qmh89GbNvOMjb3v9jOOlxnFWxj206ebQ3b7q6q+z1rNagu8/zvPSZACAABpeUAA0miMgU7SA7JjCraFGwZwECOwvL75dWjsKgWBKtx0jvWo+vkBAFbACCkByMP6nMn48+AVgXB2fzSCwsv22/lMGlUhmJ0AE7BH8dyUUDbUEgN6RzJRSeaPxhdRYR0Inel+7Hd5lBiFpkMAxACc0394//9C4voFHDiAAGLpuOXebdfdHfctgwJKaZRLRKy6ItrSis6RBnVBgGtbHyKTEmJHQoEXoBCE5BCrDeA2ogMUIGDAKEBDEhUqwgMqBYDjW4DQzmuffVdqff42/ZQYYqVcMXGZsMPyCsH3lyJSetxvEaxAQXdjR1HjfwCdIS7lo2DZke26Qe+MXO12OWkGT0O6oE7vMGkMnkYw4aN1KQgMKExhXqswfiov4+a7MQ11XPnbr/5qpKlgACAAQj94Lu271bN9DUecQasIZlNzG72llRAAKJiAi+/BSHrSFjRvQhg3DEKEqJh08tsmLTx597+f6enr4cc2Zpk57pihfX24dW7RHcOLLUbJYhJSl0ErQCI9BVXH/XrO97QasuvQQSiECa0BrQCIIJp6X9T/r8QG6L71WYSqCoIIGo2BZDUBnS/D9EA9Nun1iYvbM0MFExIDQRoKFatc1Z6zrm5uWeObJotq0BGV9FuQBWq5a4Fw3PPz848rZHstZSuA5FWAFSMP2nOppOOGpl6qh9PCSg0IFyHKjSQyDNQHTru2t75NOEe0fsf246oAmFkI6vCdnWvbQFQFCKx8vCswV8TrDLiDLgH4Nr7RAtNsrC9d8sfk7b8ls4igdNy8CQKAISlsB0FjZfd3Lfp155tf8fKI4BxZZIj/oTdVEAIAcJFOCmzauHG71I7/rdreUAgAqpDP05fDARCAQQARwEIBQSVxq0FyaLvZZtevpHa8WHw8cft6cpxlq8eAJtIhnSbWDf951yx3y13OqUuu5qyGgkxCgGFh9cDihDGbTa6BqvT1lWmrav3bmt2ZMJ4mU6TGgIC4DBzcv/JqAau1WhzSt3x9Ixk/4Jk/8J4ZrrViFMA4W6A7+WK8xcVjvyrOmVD0FbAXokcT48r+xVqLKvuJYbmpNadnlp3mpufJHOe/GXktM+r09bT8kEdq9BRYAbGSgzP7ll82U71Mc+ZFooXgwAAAABJRU5ErkJggg==" alt="" class="lh-product-info__icon" />
+        <span class="lh-product-info__name">Lighthouse</span>&nbsp;
+        <span class="lh-product-info__version"></span>
+      </div>
+
+      <div class="lh-toolbar__metadata">
+        <a href="" class="lh-toolbar__url" target="_blank" rel="noopener"></a>
+        <span class="lh-toggle-arrow" title="See report's runtime settings"></span>
+      </div>
+    </div>
+
     <div class="lh-export">
       <button class="report-icon report-icon--share lh-export__button" title="Export report"></button>
       <div class="lh-export__dropdown">
@@ -360,200 +403,227 @@
         <a href="#" class="report-icon report-icon--open lh-export--gist" data-action="save-gist">Save as Gist</a>
       </div>
     </div>
-  </div>
 </template>
 
+
 <!-- Lighthouse footer -->
 <template id="tmpl-lh-footer">
   <style>
     .lh-footer {
-      min-height: 90px;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      background-color: var(--report-header-bg-color);
+      background-color: var(--header-bg-color);
       border-top: 1px solid var(--report-secondary-border-color);
+      padding: var(--section-indent) calc(var(--default-padding) * 2);
     }
-
-    .lh-footer span {
+    .lh-footer .lh-generated {
       text-align: center;
+      border-top: 1px solid var(--report-border-color);
+      padding-top: var(--default-padding);
+    }
+    .lh-env {
+      padding: var(--default-padding) 0;
+    }
+    .lh-env__items {
+      padding-left: 16px;
+    }
+    span.lh-env__name {
+      font-weight: bold;
+      color: var(--secondary-text-color);
+    }
+    span.lh-env__description {
+      font-family: var(--monospace-font-family);
+      font-size: var(--caption-font-size);
+      padding-left: 5px;
     }
   </style>
   <footer class="lh-footer">
-    <span>
-      Generated by <b>Lighthouse</b> <span class="lh-footer__version"><!-- fill me --></span> on
-      <span class="lh-footer__timestamp"><!-- fill me --></span> |
+    <div class="lh-env">
+      <div class="lh-env__title">Runtime settings</div>
+      <ul class="lh-env__items">
+        <template id="tmpl-lh-env__items">
+          <li class="lh-env__item">
+            <span class="lh-env__name"></span>
+            <span class="lh-env__description"></span>
+          </li>
+        </template>
+      </ul>
+    </div>
+
+    <div class="lh-generated">
+      Generated by <b>Lighthouse</b> <span class="lh-footer__version"></span> |
       <a href="https://github.com/GoogleChrome/Lighthouse/issues" target="_blank" rel="noopener">File an issue</a>
-    </span>
+    </div>
   </footer>
 </template>
 
 <!-- Lighthouse score gauge -->
 <template id="tmpl-lh-gauge">
   <style>
-    .lh-gauge {
-      --circle-size: calc(2.5 * var(--header-font-size));
+    .lh-gauge__wrapper {
+      --circle-size: calc(3 * var(--header-font-size));
       --circle-size-half: calc(var(--circle-size) / 2);
-      --circle-background: #ccc;
-      --circle-border-width: 2px;
+      --circle-background: hsl(216, 12%, 92%);
+      --circle-border-width: 9;
       --inset-size: calc(var(--circle-size) - 2 * var(--circle-border-width));
-      --inset-color: #fff;
       --transition-length: 1s;
-      width: var(--circle-size);
-      height: var(--circle-size);
-      background-color: var(--circle-background);
-      border-radius: 50%;
     }
-    .lh-gauge--pass {
+
+    .lh-gauge__wrapper--pass,
+    .lh-gauge__wrapper--pass .lh-gauge {
       --circle-color: var(--pass-color);
       color: var(--circle-color);
     }
-    .lh-gauge--average {
+
+    .lh-gauge__wrapper--average,
+    .lh-gauge__wrapper--average .lh-gauge {
       --circle-color: var(--average-color);
       color: var(--circle-color);
     }
-    .lh-gauge--fail {
+
+    .lh-gauge__wrapper--fail,
+    .lh-gauge__wrapper--fail .lh-gauge {
       --circle-color: var(--fail-color);
       color: var(--circle-color);
     }
-    .lh-gauge__mask,
-    .lh-gauge__fill {
-      width: var(--circle-size);
-      height: var(--circle-size);
-      position: absolute;
-      transition: transform var(--transition-length);
-      border-radius: 50%;
+
+    .lh-gauge {
+        max-width: 360px;
+        max-height: 360px;
+        stroke-linecap: round;
+        width: var(--circle-size);
+        height: var(--circle-size);
     }
-    .lh-gauge__mask {
-      clip: rect(0px, var(--circle-size), var(--circle-size), var(--circle-size-half));
+
+    .lh-gauge-base {
+        fill: none;
+        stroke: var(--circle-background);
+        stroke-width: var(--circle-border-width);
     }
-    .lh-gauge__mask .lh-gauge__fill {
-      clip: rect(0px, var(--circle-size-half), var(--circle-size), 0px);
-      background-color: var(--circle-color);
-      backface-visibility: hidden;
+    .lh-gauge-arc {
+        fill: none;
+        stroke: var(--circle-color);
+        stroke-width: var(--circle-border-width);
+        animation: load-gauge var(--transition-length) ease forwards;
+        animation-delay: 250ms;
     }
+
+    @keyframes load-gauge {
+      from { stroke-dasharray: 0 329; }
+    }
+
     .lh-gauge__percentage {
       --spacer: calc((var(--circle-size) - var(--inset-size)) / 2);
       width: var(--inset-size);
       height: var(--inset-size);
       position: absolute;
-      margin-left: var(--spacer);
-      margin-top: var(--spacer);
-      background-color: var(--inset-color);
       border-radius: inherit;
-      display: flex;
-      align-items: center;
-      justify-content: center;
       font-size: var(--header-font-size);
+      text-align: center;
+      top: calc(var(--circle-size) / 3);
     }
+
     .lh-gauge__wrapper {
       display: inline-flex;
       align-items: center;
       flex-direction: column;
       text-decoration: none;
-      color: inherit;
       flex: 1;
       min-width: auto;
       position: relative;
+
+      /* Contain the layout style paint & layers during animation*/
+      contain: content;
+      will-change: opacity; /* Only using for layer promotion */
     }
-    .lh-scores-header .lh-gauge__wrapper {
-      width: calc(10.5 * var(--body-font-size));
-    }
+
     .lh-gauge__label {
       font-size: var(--body-font-size);
       line-height: var(--body-line-height);
       margin-top: calc(0.5 * var(--body-line-height));
       text-align: center;
+      color: black;
     }
+
   </style>
   <a href="#" class="lh-gauge__wrapper">
-    <div class="lh-gauge" data-progress="0">
-      <div class="lh-gauge__circle">
-        <div class="lh-gauge__mask lh-gauge__mask--full">
-          <div class="lh-gauge__fill"></div>
-        </div>
-        <div class="lh-gauge__mask lh-gauge__mask--half">
-          <div class="lh-gauge__fill"></div>
-          <div class="lh-gauge__fill lh-gauge__fill--fix"></div>
-        </div>
-      </div>
-      <div class="lh-gauge__percentage"></div>
-    </div>
-    <div class="lh-gauge__label"><!-- fill me --></div>
+    <svg viewBox="0 0 120 120" class="lh-gauge" fill="none" stroke-width="2">
+      <circle class="lh-gauge-base" r="53" cx="60" cy="60"></circle>
+      <circle class="lh-gauge-arc" transform="rotate(-90 60 60)" stroke-dasharray="0 329" stroke-dashoffset="0" r="53" cx="60" cy="60"></circle>
+    </svg>
+    <div class="lh-gauge__percentage"></div>
+    <div class="lh-gauge__label"></div>
   </a>
 </template>
 
 <!-- Lighthouse crtiical request chains component -->
 <template id="tmpl-lh-crc">
-  <style>
-    .lh-crc .tree-marker {
-      width: 12px;
-      height: 26px;
-      display: block;
-      float: left;
-      background-position: top left;
-    }
-    .lh-crc .horiz-down {
-      background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><g fill="%23D8D8D8" fill-rule="evenodd"><path d="M16 12v2H-2v-2z"/><path d="M9 12v14H7V12z"/></g></svg>');
-    }
-    .lh-crc .right {
-      background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><path d="M16 12v2H0v-2z" fill="%23D8D8D8" fill-rule="evenodd"/></svg>');
-    }
-    .lh-crc .up-right {
-      background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><path d="M7 0h2v14H7zm2 12h7v2H9z" fill="%23D8D8D8" fill-rule="evenodd"/></svg>');
-    }
-    .lh-crc .vert-right {
-      background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><path d="M7 0h2v27H7zm2 12h7v2H9z" fill="%23D8D8D8" fill-rule="evenodd"/></svg>');
-    }
-    .lh-crc .vert {
-      background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><path d="M7 0h2v26H7z" fill="%23D8D8D8" fill-rule="evenodd"/></svg>');
-    }
-    .lh-crc .crc-tree {
-      font-size: 14px;
-      width: 100%;
-      overflow-x: auto;
-    }
-    .lh-crc .crc-node {
-      height: 26px;
-      line-height: 26px;
-      white-space: nowrap;
-    }
-    .lh-crc .crc-node__tree-value {
-      margin-left: 10px;
-    }
-    .lh-crc .crc-node__chain-duration {
-      font-weight: 700;
-    }
-    .lh-crc .crc-node__tree-hostname {
-      color: #595959;
-    }
-    .lh-crc .crc-initial-nav {
-      color: #595959;
-      font-style: italic;
-    }
-  </style>
-  <div class="lh-score__description">
-    Longest chain: <b class="lh-crc__longest_duration"><!-- fill me: longestChain.duration --></b>
-    over <b class="lh-crc__longest_length"><!-- fill me: longestChain.length --></b> requests, totalling
-    <b class="lh-crc__longest_transfersize"><!-- fill me: longestChain.length --></b>
-  </div>
-  <div class="lh-crc">
-    <details class="lh-details">
-      <summary><!-- fill me --></summary>
+  <div class="lh-crc-container">
+    <style>
+      .lh-crc .tree-marker {
+        width: 12px;
+        height: 26px;
+        display: block;
+        float: left;
+        background-position: top left;
+      }
+      .lh-crc .horiz-down {
+        background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><g fill="%23D8D8D8" fill-rule="evenodd"><path d="M16 12v2H-2v-2z"/><path d="M9 12v14H7V12z"/></g></svg>');
+      }
+      .lh-crc .right {
+        background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><path d="M16 12v2H0v-2z" fill="%23D8D8D8" fill-rule="evenodd"/></svg>');
+      }
+      .lh-crc .up-right {
+        background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><path d="M7 0h2v14H7zm2 12h7v2H9z" fill="%23D8D8D8" fill-rule="evenodd"/></svg>');
+      }
+      .lh-crc .vert-right {
+        background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><path d="M7 0h2v27H7zm2 12h7v2H9z" fill="%23D8D8D8" fill-rule="evenodd"/></svg>');
+      }
+      .lh-crc .vert {
+        background: url('data:image/svg+xml;utf8,<svg width="16" height="26" viewBox="0 0 16 26" xmlns="http://www.w3.org/2000/svg"><path d="M7 0h2v26H7z" fill="%23D8D8D8" fill-rule="evenodd"/></svg>');
+      }
+      .lh-crc .crc-tree {
+        font-size: 14px;
+        width: 100%;
+        overflow-x: auto;
+      }
+      .lh-crc .crc-node {
+        height: 26px;
+        line-height: 26px;
+        white-space: nowrap;
+      }
+      .lh-crc .crc-node__tree-value {
+        margin-left: 10px;
+      }
+      .lh-crc .crc-node__chain-duration {
+        font-weight: 700;
+      }
+      .lh-crc .crc-node__tree-hostname {
+        color: #595959;
+      }
+      .lh-crc .crc-initial-nav {
+        color: #595959;
+        font-style: italic;
+      }
+    </style>
+    <div>
+      Longest chain: <b class="lh-crc__longest_duration"><!-- fill me: longestChain.duration --></b>
+      over <b class="lh-crc__longest_length"><!-- fill me: longestChain.length --></b> requests, totalling
+      <b class="lh-crc__longest_transfersize"><!-- fill me: longestChain.length --></b>
+    </div>
+    <div class="lh-crc">
       <div class="crc-initial-nav">Initial Navigation</div>
       <!-- stamp for each chain -->
       <template id="tmpl-lh-crc__chains">
         <div class="crc-node">
           <span class="crc-node__tree-marker">
-            <!-- fill me -->
+
           </span>
           <span class="crc-node__tree-value">
             <span class="crc-node__tree-file"><!-- fill me: node.request.url.file --></span>
             <span class="crc-node__tree-hostname">(<!-- fill me: node.request.url.host -->)</span>
-            <!-- fill me -->
+
           </span>
         </div>
       </template>
-    </details>
+    </div>
   </div>
 </template>
diff --git a/front_end/audits2/module.json b/front_end/audits2/module.json
index 41ee085..a99df71 100644
--- a/front_end/audits2/module.json
+++ b/front_end/audits2/module.json
@@ -22,6 +22,7 @@
         "lighthouse/renderer/util.js",
         "lighthouse/renderer/dom.js",
         "lighthouse/renderer/category-renderer.js",
+        "lighthouse/renderer/performance-category-renderer.js",
         "lighthouse/renderer/details-renderer.js",
         "lighthouse/renderer/crc-details-renderer.js",
         "lighthouse/renderer/report-renderer.js",
@@ -40,5 +41,14 @@
         "audits2Panel.css",
         "lighthouse/report-styles.css",
         "lighthouse/templates.html"
-    ]
+    ],
+    "skip_compilation": [
+      "lighthouse/renderer/util.js",
+      "lighthouse/renderer/dom.js",
+      "lighthouse/renderer/category-renderer.js",
+      "lighthouse/renderer/performance-category-renderer.js",
+      "lighthouse/renderer/details-renderer.js",
+      "lighthouse/renderer/crc-details-renderer.js",
+      "lighthouse/renderer/report-renderer.js"
+  ]
 }
diff --git a/front_end/audits2_worker/Audits2Service.js b/front_end/audits2_worker/Audits2Service.js
index f19bee6..be445dd 100644
--- a/front_end/audits2_worker/Audits2Service.js
+++ b/front_end/audits2_worker/Audits2Service.js
@@ -37,7 +37,7 @@
   }
 
   /**
-   * @return {!Promise<!ReportRenderer.ReportJSON>}
+   * @return {!Promise<!ReportRenderer.RunnerResult>}
    */
   start(params) {
     if (Runtime.queryParam('isUnderTest'))
@@ -49,7 +49,7 @@
 
     return Promise.resolve()
         .then(_ => self.runLighthouseInWorker(this, params.url, {flags: params.flags}, params.categoryIDs))
-        .then(/** @type {!ReportRenderer.ReportJSON} */ result => {
+        .then(/** @type {!ReportRenderer.RunnerResult} */ result => {
           // Keep all artifacts on the result, no trimming
           return result;
         })
diff --git a/front_end/audits2_worker/lighthouse/lighthouse-background.js b/front_end/audits2_worker/lighthouse/lighthouse-background.js
index c7b59ac..21f7dca 100644
--- a/front_end/audits2_worker/lighthouse/lighthouse-background.js
+++ b/front_end/audits2_worker/lighthouse/lighthouse-background.js
@@ -1,5 +1,5 @@
-// lighthouse, browserified. 2.9.1 (f9171e0133fa0bffd8cd419ac3ec91861d5d5713)
-require=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f;}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e);},l,l.exports,e,t,n,r);}return n[o].exports;}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s;}({"../audits/accessibility/accesskeys":[function(require,module,exports){
+// lighthouse, browserified. 3.0.0-beta.0 (a194e972771bcf85071a796142d50d5bfbe3cc7b)
+require=function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a;}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r);},p,p.exports,r,e,n,t);}return n[i].exports;}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o;}return r;}()({"../audits/accessibility/accesskeys":[function(require,module,exports){
 
 
 
@@ -506,10 +506,10 @@
 return{
 name:'document-title',
 description:'Document has a `<title>` element',
-failureDescription:'Document does not have a `<title>` element',
-helpText:'Screen reader users use page titles to get an overview of the contents of '+
-'the page. '+
-'[Learn more](https://dequeuniversity.com/rules/axe/2.2/document-title?application=lighthouse).',
+failureDescription:'Document doesn\'t have a `<title>` element',
+helpText:'The title gives screen reader users an overview of the page, and search '+
+'engine users rely on it heavily to determine if a page is relevant to their search. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/title).',
 requiredArtifacts:['Accessibility']};
 
 }}
@@ -680,7 +680,7 @@
 description:'Image elements have `[alt]` attributes',
 failureDescription:'Image elements do not have `[alt]` attributes',
 helpText:'Informative elements should aim for short, descriptive alternate text. '+
-'Decorative elements can be ignored with an empty alt attribute.'+
+'Decorative elements can be ignored with an empty alt attribute. '+
 '[Learn more](https://dequeuniversity.com/rules/axe/2.2/image-alt?application=lighthouse).',
 requiredArtifacts:['Accessibility']};
 
@@ -925,7 +925,7 @@
 name:'custom-controls-labels',
 helpText:'Custom interactive controls have associated labels, provided by aria-label or aria-labelledby. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
 description:'Custom controls have associated labels'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -955,7 +955,7 @@
 name:'custom-controls-roles',
 helpText:'Custom interactive controls have appropriate ARIA roles. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
 description:'Custom controls have ARIA roles'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -985,7 +985,7 @@
 name:'focus-traps',
 helpText:'A user can tab into and out of any control or region without accidentally trapping their focus. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
 description:'User focus is not accidentally trapped in a region'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -1015,7 +1015,7 @@
 name:'focusable-controls',
 helpText:'Custom interactive controls are keyboard focusable and display a focus indicator. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
 description:'Interactive controls are keyboard focusable'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -1045,7 +1045,7 @@
 name:'heading-levels',
 helpText:'Headings are used to create an outline for the page and heading levels are not skipped. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#take_advantage_of_headings_and_landmarks).',
 description:'Headings don\'t skip levels'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -1075,7 +1075,7 @@
 name:'logical-tab-order',
 helpText:'Tabbing through the page follows the visual layout. Users cannot focus elements that are offscreen. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
 description:'The page has a logical tab order'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -1105,7 +1105,7 @@
 name:'managed-focus',
 helpText:'If new content, such as a dialog, is added to the page, the user\'s focus is directed to it. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#start_with_the_keyboard).',
 description:'The user\'s focus is directed to new content added to the page'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -1136,7 +1136,7 @@
 name:'offscreen-content-hidden',
 helpText:'Offscreen content is hidden with display: none or aria-hidden=true. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
 description:'Offscreen content is hidden from assistive technology'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -1166,7 +1166,7 @@
 name:'use-landmarks',
 helpText:'Landmark elements (<main>, <nav>, etc.) are used to improve the keyboard navigation of the page for assistive technology. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#take_advantage_of_headings_and_landmarks).',
 description:'HTML5 landmark elements are used to improve navigation'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -1196,7 +1196,7 @@
 name:'visual-order-follows-dom',
 helpText:'DOM order matches the visual order, improving navigation for assistive technology. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).',
 description:'Visual order on the page follows DOM order'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -1530,9 +1530,8 @@
 
 const Audit=require('./audit');
 const WebInspector=require('../lib/web-inspector');
-const Util=require('../report/v2/renderer/util');
+const Util=require('../report/html/renderer/util');
 const{groupIdToName,taskToGroup}=require('../lib/task-groups');
-const THRESHOLD_IN_MS=10;
 
 class BootupTime extends Audit{
 
@@ -1540,12 +1539,13 @@
 
 static get meta(){
 return{
-category:'Performance',
 name:'bootup-time',
 description:'JavaScript boot-up time',
 failureDescription:'JavaScript boot-up time is too high',
-helpText:'Consider reducing the time spent parsing, compiling and executing JS. '+
-'You may find delivering smaller JS payloads helps with this.',
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+helpText:'Consider reducing the time spent parsing, compiling, and executing JS. '+
+'You may find delivering smaller JS payloads helps with this. [Learn '+
+'more](https://developers.google.com/web/tools/lighthouse/audits/bootup).',
 requiredArtifacts:['traces']};
 
 }
@@ -1553,9 +1553,24 @@
 
 
 
+static get defaultOptions(){
+return{
+
+
+scorePODR:600,
+scoreMedian:3500,
+thresholdInMs:50};
+
+}
+
+
+
+
+
 
 static getExecutionTimingsByURL(timelineModel){
 const bottomUpByURL=timelineModel.bottomUpGroupBy('URL');
+
 const result=new Map();
 
 bottomUpByURL.children.forEach((perUrlNode,url)=>{
@@ -1564,6 +1579,7 @@
 return;
 }
 
+
 const taskGroups={};
 perUrlNode.children.forEach(perTaskPerUrlNode=>{
 
@@ -1583,24 +1599,34 @@
 
 
 
-static audit(artifacts){
+
+static async audit(artifacts,context){
+const settings=context.settings||{};
 const trace=artifacts.traces[BootupTime.DEFAULT_PASS];
-return artifacts.requestDevtoolsTimelineModel(trace).then(devtoolsTimelineModel=>{
+const devtoolsTimelineModel=await artifacts.requestDevtoolsTimelineModel(trace);
 const executionTimings=BootupTime.getExecutionTimingsByURL(devtoolsTimelineModel);
 let totalBootupTime=0;
+
 const extendedInfo={};
 
 const headings=[
 {key:'url',itemType:'url',text:'URL'},
-{key:'scripting',itemType:'text',text:groupIdToName.scripting},
-{key:'scriptParseCompile',itemType:'text',text:groupIdToName.scriptParseCompile}];
+{key:'scripting',granularity:1,itemType:'ms',text:groupIdToName.scripting},
+{key:'scriptParseCompile',granularity:1,itemType:'ms',
+text:groupIdToName.scriptParseCompile}];
 
 
+const multiplier=settings.throttlingMethod==='simulate'?
+settings.throttling.cpuSlowdownMultiplier:1;
 
 const results=Array.from(executionTimings).
 map(([url,groups])=>{
 
-totalBootupTime+=Object.keys(groups).reduce((sum,name)=>sum+=groups[name],0);
+for(const[name,value]of Object.entries(groups)){
+groups[name]=value*multiplier;
+totalBootupTime+=value*multiplier;
+}
+
 extendedInfo[url]=groups;
 
 const scriptingTotal=groups[groupIdToName.scripting]||0;
@@ -1610,31 +1636,131 @@
 sum:scriptingTotal+parseCompileTotal,
 
 
-scripting:Util.formatMilliseconds(scriptingTotal,1),
-scriptParseCompile:Util.formatMilliseconds(parseCompileTotal,1)};
+scripting:scriptingTotal,
+scriptParseCompile:parseCompileTotal};
 
 }).
-filter(result=>result.sum>=THRESHOLD_IN_MS).
+filter(result=>result.sum>=context.options.thresholdInMs).
 sort((a,b)=>b.sum-a.sum);
 
-const tableDetails=BootupTime.makeTableDetails(headings,results);
+const summary={wastedMs:totalBootupTime};
+const details=BootupTime.makeTableDetails(headings,results,summary);
+
+const score=Audit.computeLogNormalScore(
+totalBootupTime,
+context.options.scorePODR,
+context.options.scoreMedian);
+
 
 return{
-score:totalBootupTime<2000,
+score,
 rawValue:totalBootupTime,
-displayValue:Util.formatMilliseconds(totalBootupTime),
-details:tableDetails,
+displayValue:[Util.MS_DISPLAY_VALUE,totalBootupTime],
+details,
 extendedInfo:{
 value:extendedInfo}};
 
 
-});
 }}
 
 
 module.exports=BootupTime;
 
-},{"../lib/task-groups":36,"../lib/web-inspector":42,"../report/v2/renderer/util":43,"./audit":2}],"../audits/byte-efficiency/offscreen-images":[function(require,module,exports){
+},{"../lib/task-groups":42,"../lib/web-inspector":47,"../report/html/renderer/util":48,"./audit":2}],"../audits/byte-efficiency/efficient-animated-content":[function(require,module,exports){
+
+
+
+
+
+
+
+
+'use strict';
+
+const WebInspector=require('../../lib/web-inspector');
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+
+
+
+const GIF_BYTE_THRESHOLD=100*1024;
+
+class EfficientAnimatedContent extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+name:'efficient-animated-content',
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+description:'Use video formats for animated content',
+helpText:'Large GIFs are inefficient for delivering animated content. Consider using '+
+'MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save '+
+'network bytes. [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)',
+requiredArtifacts:['devtoolsLogs']};
+
+}
+
+
+
+
+
+
+
+static getPercentSavings(bytes){
+return Math.round(29.1*Math.log10(bytes)-100.7)/100;
+}
+
+
+
+
+
+
+static audit_(artifacts,networkRecords){
+const unoptimizedContent=networkRecords.filter(
+record=>record._mimeType==='image/gif'&&
+record._resourceType===WebInspector.resourceTypes.Image&&
+(record._resourceSize||0)>GIF_BYTE_THRESHOLD);
+
+
+
+const results=unoptimizedContent.map(record=>{
+const resourceSize=record._resourceSize||0;
+return{
+url:record.url,
+totalBytes:resourceSize,
+wastedBytes:Math.round(resourceSize*
+EfficientAnimatedContent.getPercentSavings(resourceSize))};
+
+});
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{
+key:'totalBytes',
+itemType:'bytes',
+displayUnit:'kb',
+granularity:1,
+text:'Transfer Size'},
+
+{
+key:'wastedBytes',
+itemType:'bytes',
+displayUnit:'kb',
+granularity:1,
+text:'Byte Savings'}];
+
+
+
+return{
+results,
+headings};
+
+}}
+
+
+module.exports=EfficientAnimatedContent;
+
+},{"../../lib/web-inspector":47,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/offscreen-images":[function(require,module,exports){
 
 
 
@@ -1656,6 +1782,8 @@
 const IGNORE_THRESHOLD_IN_BYTES=2048;
 const IGNORE_THRESHOLD_IN_PERCENT=75;
 
+
+
 class OffscreenImages extends ByteEfficiencyAudit{
 
 
@@ -1663,10 +1791,11 @@
 static get meta(){
 return{
 name:'offscreen-images',
-description:'Offscreen images',
-informative:true,
-helpText:'Consider lazy-loading offscreen and hidden images to improve page load speed '+
-'and time to interactive. '+
+description:'Defer offscreen images',
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+helpText:
+'Consider lazy-loading offscreen and hidden images after all critical resources have '+
+'finished loading to lower time to interactive. '+
 '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images).',
 requiredArtifacts:['ImageUsage','ViewportDimensions','traces','devtoolsLogs']};
 
@@ -1695,6 +1824,10 @@
 
 
 static computeWaste(image,viewportDimensions){
+if(!image.networkRecord){
+return null;
+}
+
 const url=URL.elideDataURI(image.src);
 const totalPixels=image.clientWidth*image.clientHeight;
 const visiblePixels=this.computeVisiblePixels(image.clientRect,viewportDimensions);
@@ -1709,11 +1842,6 @@
 
 return{
 url,
-preview:{
-type:'thumbnail',
-url:image.networkRecord.url,
-mimeType:image.networkRecord.mimeType},
-
 requestStartTime:image.networkRecord.startTime,
 totalBytes,
 wastedBytes,
@@ -1725,51 +1853,83 @@
 
 
 
-static audit_(artifacts){
+
+
+
+
+
+
+static computeWasteWithTTIGraph(results,graph,simulator){
+return ByteEfficiencyAudit.computeWasteWithTTIGraph(results,graph,simulator,
+{includeLoad:false});
+}
+
+
+
+
+
+
+
+static audit_(artifacts,networkRecords,context){
 const images=artifacts.ImageUsage;
 const viewportDimensions=artifacts.ViewportDimensions;
 const trace=artifacts.traces[ByteEfficiencyAudit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
 
-let debugString;
+
+const warnings=[];
 const resultsMap=images.reduce((results,image)=>{
-if(!image.networkRecord){
+const processed=OffscreenImages.computeWaste(image,viewportDimensions);
+if(processed===null){
 return results;
 }
 
-const processed=OffscreenImages.computeWaste(image,viewportDimensions);
 if(processed instanceof Error){
-debugString=processed.message;
+warnings.push(processed.message);
+
 Sentry.captureException(processed,{tags:{audit:this.meta.name},level:'warning'});
 return results;
 }
 
 
-const existing=results.get(processed.preview.url);
+const existing=results.get(processed.url);
 if(!existing||existing.wastedBytes>processed.wastedBytes){
-results.set(processed.preview.url,processed);
+results.set(processed.url,processed);
 }
 
 return results;
 },new Map());
 
-return artifacts.requestFirstInteractive(trace).then(firstInteractive=>{
-const ttiTimestamp=firstInteractive.timestamp/1000000;
+const settings=context.settings;
+return artifacts.requestFirstCPUIdle({trace,devtoolsLog,settings}).then(firstInteractive=>{
+
+
+
+const ttiTimestamp=firstInteractive.timestamp?firstInteractive.timestamp/1e6:Infinity;
+
 const results=Array.from(resultsMap.values()).filter(item=>{
-const isWasteful=item.wastedBytes>IGNORE_THRESHOLD_IN_BYTES&&
+const isWasteful=
+item.wastedBytes>IGNORE_THRESHOLD_IN_BYTES&&
 item.wastedPercent>IGNORE_THRESHOLD_IN_PERCENT;
 const loadedEarly=item.requestStartTime<ttiTimestamp;
 return isWasteful&&loadedEarly;
 });
 
 const headings=[
-{key:'preview',itemType:'thumbnail',text:''},
+{key:'url',itemType:'thumbnail',text:''},
 {key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'Potential Savings'}];
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{
+key:'wastedBytes',
+itemType:'bytes',
+displayUnit:'kb',
+granularity:1,
+text:'Potential Savings'}];
+
 
 
 return{
-debugString,
+warnings,
 results,
 headings};
 
@@ -1779,7 +1939,243 @@
 
 module.exports=OffscreenImages;
 
-},{"../../lib/sentry":33,"../../lib/url-shim":41,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/total-byte-weight":[function(require,module,exports){
+},{"../../lib/sentry":39,"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/byte-efficiency/render-blocking-resources":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const Audit=require('../audit');
+const Node=require('../../lib/dependency-graph/node');
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const UnusedCSS=require('./unused-css-rules');
+const WebInspector=require('../../lib/web-inspector');
+
+const Simulator=require('../../lib/dependency-graph/simulator/simulator');
+const NetworkNode=require('../../lib/dependency-graph/network-node.js');
+
+
+
+
+
+const MINIMUM_WASTED_MS=50;
+
+
+
+
+
+
+function getNodesAndTimingByUrl(nodeTimings){
+
+const urlMap={};
+const nodes=Array.from(nodeTimings.keys());
+nodes.forEach(node=>{
+if(node.type!=='network')return;
+const networkNode=node;
+const nodeTiming=nodeTimings.get(node);
+if(!nodeTiming)return;
+
+urlMap[networkNode.record.url]={node,nodeTiming};
+});
+
+return urlMap;
+}
+
+class RenderBlockingResources extends Audit{
+
+
+
+static get meta(){
+return{
+name:'render-blocking-resources',
+description:'Eliminate render-blocking resources',
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+helpText:
+'Resources are blocking the first paint of your page. Consider '+
+'delivering critical JS/CSS inline and deferring all non-critical '+
+'JS/styles. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).',
+
+
+
+requiredArtifacts:['URL','TagsBlockingFirstPaint','traces']};
+
+}
+
+
+
+
+
+
+static async computeResults(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const simulatorData={devtoolsLog,settings:context.settings};
+const traceOfTab=await artifacts.requestTraceOfTab(trace);
+const simulator=await artifacts.requestLoadSimulator(simulatorData);
+const wastedCssBytes=await RenderBlockingResources.computeWastedCSSBytes(artifacts,context);
+
+const metricSettings={throttlingMethod:'simulate'};
+const metricComputationData={trace,devtoolsLog,simulator,settings:metricSettings};
+
+const fcpSimulation=await artifacts.requestFirstContentfulPaint(metricComputationData);
+const fcpTsInMs=traceOfTab.timestamps.firstContentfulPaint/1000;
+
+const nodesByUrl=getNodesAndTimingByUrl(fcpSimulation.optimisticEstimate.nodeTimings);
+
+const results=[];
+const deferredNodeIds=new Set();
+for(const resource of artifacts.TagsBlockingFirstPaint){
+
+if(resource.endTime*1000>fcpTsInMs)continue;
+
+if(!nodesByUrl[resource.tag.url])continue;
+
+const{node,nodeTiming}=nodesByUrl[resource.tag.url];
+
+
+
+
+node.traverse(node=>deferredNodeIds.add(node.id));
+
+
+
+const wastedMs=Math.round(nodeTiming.endTime-nodeTiming.startTime);
+if(wastedMs<MINIMUM_WASTED_MS)continue;
+
+results.push({
+url:resource.tag.url,
+totalBytes:resource.transferSize,
+wastedMs});
+
+}
+
+if(!results.length){
+return{results,wastedMs:0};
+}
+
+const wastedMs=RenderBlockingResources.estimateSavingsWithGraphs(
+simulator,
+fcpSimulation.optimisticGraph,
+deferredNodeIds,
+wastedCssBytes);
+
+
+return{results,wastedMs};
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static estimateSavingsWithGraphs(simulator,fcpGraph,deferredIds,wastedCssBytesByUrl){
+const originalEstimate=simulator.simulate(fcpGraph).timeInMs;
+
+let totalChildNetworkBytes=0;
+const minimalFCPGraph=fcpGraph.cloneWithRelationships(node=>{
+
+const canDeferRequest=deferredIds.has(node.id);
+if(node.type!==Node.TYPES.NETWORK)return!canDeferRequest;
+
+const networkNode=node;
+
+const isStylesheet=
+networkNode.record._resourceType===WebInspector.resourceTypes.Stylesheet;
+if(canDeferRequest&&isStylesheet){
+
+const wastedBytes=wastedCssBytesByUrl.get(networkNode.record.url)||0;
+totalChildNetworkBytes+=(networkNode.record._transferSize||0)-wastedBytes;
+}
+return!canDeferRequest;
+});
+
+
+const originalTransferSize=minimalFCPGraph.record._transferSize;
+const safeTransferSize=originalTransferSize||0;
+minimalFCPGraph.record._transferSize=safeTransferSize+totalChildNetworkBytes;
+const estimateAfterInline=simulator.simulate(minimalFCPGraph).timeInMs;
+minimalFCPGraph.record._transferSize=originalTransferSize;
+return Math.round(Math.max(originalEstimate-estimateAfterInline,0));
+}
+
+
+
+
+
+
+static async computeWastedCSSBytes(artifacts,context){
+const wastedBytesByUrl=new Map();
+try{
+
+const results=await UnusedCSS.audit(artifacts,context);
+
+for(const item of results.details.items){
+wastedBytesByUrl.set(item.url,item.wastedBytes);
+}
+}catch(_){}
+
+return wastedBytesByUrl;
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const{results,wastedMs}=await RenderBlockingResources.computeResults(artifacts,context);
+
+let displayValue='';
+if(results.length>1){
+displayValue=`${results.length} resources delayed first paint by ${wastedMs}ms`;
+}else if(results.length===1){
+displayValue=`${results.length} resource delayed first paint by ${wastedMs}ms`;
+}
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{
+key:'totalBytes',
+itemType:'bytes',
+displayUnit:'kb',
+granularity:0.01,
+text:'Size (KB)'},
+
+{key:'wastedMs',itemType:'ms',text:'Download Time (ms)',granularity:1}];
+
+
+const summary={wastedMs};
+const details=Audit.makeTableDetails(headings,results,summary);
+
+return{
+displayValue,
+score:ByteEfficiencyAudit.scoreForWastedMs(wastedMs),
+rawValue:wastedMs,
+details};
+
+}}
+
+
+module.exports=RenderBlockingResources;
+
+},{"../../lib/dependency-graph/network-node.js":24,"../../lib/dependency-graph/node":25,"../../lib/dependency-graph/simulator/simulator":28,"../../lib/web-inspector":47,"../audit":2,"./byte-efficiency-audit":3,"./unused-css-rules":"../audits/byte-efficiency/unused-css-rules"}],"../audits/byte-efficiency/total-byte-weight":[function(require,module,exports){
 
 
 
@@ -1789,11 +2185,6 @@
 
 const ByteEfficiencyAudit=require('./byte-efficiency-audit');
 
-
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=2500*1024;
-const SCORING_MEDIAN=4000*1024;
-
 class TotalByteWeight extends ByteEfficiencyAudit{
 
 
@@ -1803,11 +2194,11 @@
 name:'total-byte-weight',
 description:'Avoids enormous network payloads',
 failureDescription:'Has enormous network payloads',
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
 helpText:
 'Large network payloads cost users real money and are highly correlated with '+
 'long load times. [Learn '+
 'more](https://developers.google.com/web/tools/lighthouse/audits/network-payloads).',
-scoringMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
 requiredArtifacts:['devtoolsLogs']};
 
 }
@@ -1815,25 +2206,39 @@
 
 
 
+static get defaultOptions(){
+return{
 
-static audit(artifacts){
+
+scorePODR:2500*1024,
+scoreMedian:4000*1024};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
 const devtoolsLogs=artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
-return Promise.all([
+const[networkRecords,networkThroughput]=await Promise.all([
 artifacts.requestNetworkRecords(devtoolsLogs),
-artifacts.requestNetworkThroughput(devtoolsLogs)]).
-then(([networkRecords,networkThroughput])=>{
+artifacts.requestNetworkThroughput(devtoolsLogs)]);
+
+
 let totalBytes=0;
+
 let results=[];
 networkRecords.forEach(record=>{
 
 
-if(record.scheme==='data'||!record.finished)return;
+if(record.parsedURL.scheme==='data'||!record.finished)return;
 
 const result={
 url:record.url,
 totalBytes:record.transferSize,
-totalKb:this.bytesToKbString(record.transferSize),
-totalMs:this.bytesToMsString(record.transferSize,networkThroughput)};
+totalMs:ByteEfficiencyAudit.bytesToMs(record.transferSize,networkThroughput)};
 
 
 totalBytes+=result.totalBytes;
@@ -1842,21 +2247,22 @@
 const totalCompletedRequests=results.length;
 results=results.sort((itemA,itemB)=>itemB.totalBytes-itemA.totalBytes).slice(0,10);
 
-
-
-
-
-
 const score=ByteEfficiencyAudit.computeLogNormalScore(
 totalBytes,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN);
+context.options.scorePODR,
+context.options.scoreMedian);
 
 
 const headings=[
 {key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Total Size'},
-{key:'totalMs',itemType:'text',text:'Transfer Time'}];
+{
+key:'totalBytes',
+itemType:'bytes',
+displayUnit:'kb',
+granularity:1,
+text:'Total Size'},
+
+{key:'totalMs',itemType:'ms',text:'Transfer Time'}];
 
 
 const tableDetails=ByteEfficiencyAudit.makeTableDetails(headings,results);
@@ -1864,7 +2270,10 @@
 return{
 score,
 rawValue:totalBytes,
-displayValue:`Total size was ${ByteEfficiencyAudit.bytesToKbString(totalBytes)}`,
+displayValue:[
+'Total size was %d\xa0KB',
+totalBytes/1024],
+
 extendedInfo:{
 value:{
 results,
@@ -1873,7 +2282,6 @@
 
 details:tableDetails};
 
-});
 }}
 
 
@@ -1904,8 +2312,8 @@
 return{
 name:'unminified-css',
 description:'Minify CSS',
-informative:true,
-helpText:'Minifying CSS files can reduce network payload sizes.'+
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+helpText:'Minifying CSS files can reduce network payload sizes. '+
 '[Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).',
 requiredArtifacts:['CSSUsage','devtoolsLogs']};
 
@@ -1982,10 +2390,11 @@
 const content=stylesheet.content;
 const totalTokenLength=UnminifiedCSS.computeTokenLength(content);
 
+
 let url=stylesheet.header.sourceURL;
 if(!url||url===pageUrl){
 const contentPreview=UnusedCSSRules.determineContentPreview(stylesheet.content);
-url={type:'code',text:contentPreview};
+url={type:'code',value:contentPreview};
 }
 
 const totalBytes=ByteEfficiencyAudit.estimateTransferSize(networkRecord,content.length,
@@ -2005,6 +2414,7 @@
 
 
 
+
 static audit_(artifacts,networkRecords){
 const pageUrl=artifacts.URL.finalUrl;
 const results=[];
@@ -2018,7 +2428,8 @@
 
 
 if(result.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT||
-result.wastedBytes<IGNORE_THRESHOLD_IN_BYTES)continue;
+result.wastedBytes<IGNORE_THRESHOLD_IN_BYTES||
+!Number.isFinite(result.wastedBytes))continue;
 results.push(result);
 }
 
@@ -2026,8 +2437,9 @@
 results,
 headings:[
 {key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'Potential Savings'}]};
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{key:'wastedBytes',itemType:'bytes',displayUnit:'kb',granularity:1,
+text:'Potential Savings'}]};
 
 
 }}
@@ -2044,6 +2456,7 @@
 'use strict';
 
 const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+
 const esprima=require('esprima');
 
 const IGNORE_THRESHOLD_IN_PERCENT=10;
@@ -2067,7 +2480,8 @@
 return{
 name:'unminified-javascript',
 description:'Minify JavaScript',
-informative:true,
+
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
 helpText:'Minifying JavaScript files can reduce payload sizes and script parse time. '+
 '[Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).',
 requiredArtifacts:['Scripts','devtoolsLogs']};
@@ -2078,6 +2492,7 @@
 
 
 
+
 static computeWaste(scriptContent,networkRecord){
 const contentLength=scriptContent.length;
 let totalTokenLength=0;
@@ -2108,9 +2523,11 @@
 
 
 
+
 static audit_(artifacts,networkRecords){
+
 const results=[];
-let debugString;
+const warnings=[];
 for(const requestId of Object.keys(artifacts.Scripts)){
 const scriptContent=artifacts.Scripts[requestId];
 const networkRecord=networkRecords.find(record=>record.requestId===requestId);
@@ -2121,20 +2538,22 @@
 
 
 if(result.wastedPercent<IGNORE_THRESHOLD_IN_PERCENT||
-result.wastedBytes<IGNORE_THRESHOLD_IN_BYTES)continue;
+result.wastedBytes<IGNORE_THRESHOLD_IN_BYTES||
+!Number.isFinite(result.wastedBytes))continue;
 results.push(result);
 }catch(err){
-debugString=`Unable to process ${networkRecord._url}: ${err.message}`;
+warnings.push(`Unable to process ${networkRecord._url}: ${err.message}`);
 }
 }
 
 return{
 results,
-debugString,
+warnings,
 headings:[
 {key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'Potential Savings'}]};
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{key:'wastedBytes',itemType:'bytes',displayUnit:'kb',granularity:1,
+text:'Potential Savings'}]};
 
 
 }}
@@ -2142,7 +2561,7 @@
 
 module.exports=UnminifiedJavaScript;
 
-},{"./byte-efficiency-audit":3,"esprima":130}],"../audits/byte-efficiency/unused-css-rules":[function(require,module,exports){
+},{"./byte-efficiency-audit":3,"esprima":136}],"../audits/byte-efficiency/unused-css-rules":[function(require,module,exports){
 
 
 
@@ -2155,6 +2574,8 @@
 const IGNORE_THRESHOLD_IN_BYTES=2048;
 const PREVIEW_LENGTH=100;
 
+
+
 class UnusedCSSRules extends ByteEfficiencyAudit{
 
 
@@ -2162,11 +2583,11 @@
 static get meta(){
 return{
 name:'unused-css-rules',
-description:'Unused CSS rules',
-informative:true,
+description:'Defer unused CSS',
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
 helpText:'Remove unused rules from stylesheets to reduce unnecessary '+
 'bytes consumed by network activity. '+
-'[Learn more](https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery)',
+'[Learn more](https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery).',
 requiredArtifacts:['CSSUsage','URL','devtoolsLogs']};
 
 }
@@ -2277,14 +2698,11 @@
 
 
 static mapSheetToResult(stylesheetInfo,pageUrl){
-if(stylesheetInfo.isDuplicate){
-return null;
-}
 
 let url=stylesheetInfo.header.sourceURL;
 if(!url||url===pageUrl){
 const contentPreview=UnusedCSSRules.determineContentPreview(stylesheetInfo.content);
-url={type:'code',text:contentPreview};
+url={type:'code',value:contentPreview};
 }
 
 const usage=UnusedCSSRules.computeUsage(stylesheetInfo);
@@ -2311,8 +2729,9 @@
 
 const headings=[
 {key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'Potential Savings'}];
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{key:'wastedBytes',itemType:'bytes',displayUnit:'kb',granularity:1,
+text:'Potential Savings'}];
 
 
 return{
@@ -2345,7 +2764,7 @@
 return{
 name:'unused-javascript',
 description:'Unused JavaScript',
-informative:true,
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
 helpText:'Remove unused JavaScript to reduce bytes consumed by network activity.',
 requiredArtifacts:['JsUsage','devtoolsLogs']};
 
@@ -2417,7 +2836,9 @@
 
 
 
+
 static audit_(artifacts,networkRecords){
+
 const scriptsByUrl=new Map();
 for(const script of artifacts.JsUsage){
 const scripts=scriptsByUrl.get(script.url)||[];
@@ -2425,6 +2846,7 @@
 scriptsByUrl.set(script.url,scripts);
 }
 
+
 const results=[];
 for(const[url,scripts]of scriptsByUrl.entries()){
 const networkRecord=networkRecords.find(record=>record.url===url);
@@ -2439,8 +2861,9 @@
 results,
 headings:[
 {key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'Potential Savings'}]};
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{key:'wastedBytes',itemType:'bytes',displayUnit:'kb',granularity:1,
+text:'Potential Savings'}]};
 
 
 }}
@@ -2457,33 +2880,28 @@
 'use strict';
 
 const assert=require('assert');
+
 const parseCacheControl=require('parse-cache-control');
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const formatDuration=require('../../report/v2/renderer/util.js').formatDuration;
+const Audit=require('../audit');
 const WebInspector=require('../../lib/web-inspector');
 const URL=require('../../lib/url-shim');
 
 
 const IGNORE_THRESHOLD_IN_PERCENT=0.925;
 
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=4;
-const SCORING_MEDIAN=768;
-
-class CacheHeaders extends ByteEfficiencyAudit{
+class CacheHeaders extends Audit{
 
 
 
 static get meta(){
 return{
-category:'Caching',
 name:'uses-long-cache-ttl',
 description:'Uses efficient cache policy on static assets',
 failureDescription:'Uses inefficient cache policy on static assets',
 helpText:
 'A long cache lifetime can speed up repeat visits to your page. '+
 '[Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#cache-control).',
-scoringMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
 requiredArtifacts:['devtoolsLogs']};
 
 }
@@ -2491,6 +2909,19 @@
 
 
 
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:4*1024,
+scoreMedian:128*1024};
+
+}
+
+
+
+
 
 
 
@@ -2554,14 +2985,16 @@
 if(cacheControl){
 
 if(cacheControl['no-cache']||cacheControl['no-store'])return 0;
-if(Number.isFinite(cacheControl['max-age']))return Math.max(cacheControl['max-age'],0);
+const maxAge=cacheControl['max-age'];
+if(maxAge!==undefined&&Number.isFinite(maxAge))return Math.max(maxAge,0);
 }else if((headers.get('pragma')||'').includes('no-cache')){
 
 return 0;
 }
 
-if(headers.has('expires')){
-const expires=new Date(headers.get('expires')).getTime();
+const expiresHeaders=headers.get('expires');
+if(expiresHeaders){
+const expires=new Date(expiresHeaders).getTime();
 
 if(!expires)return 0;
 return Math.max(0,Math.ceil((expires-Date.now())/1000));
@@ -2608,8 +3041,9 @@
 
 
 
-static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS];
+
+static audit(artifacts,context){
+const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
 return artifacts.requestNetworkRecords(devtoolsLogs).then(records=>{
 const results=[];
 let queryStringCount=0;
@@ -2618,8 +3052,9 @@
 for(const record of records){
 if(!CacheHeaders.isCacheableAsset(record))continue;
 
+
 const headers=new Map();
-for(const header of record._responseHeaders){
+for(const header of record._responseHeaders||[]){
 headers.set(header.name.toLowerCase(),header.value);
 }
 
@@ -2637,10 +3072,8 @@
 if(cacheHitProbability>IGNORE_THRESHOLD_IN_PERCENT)continue;
 
 const url=URL.elideDataURI(record._url);
-const totalBytes=record._transferSize;
-const totalKb=ByteEfficiencyAudit.bytesToKbString(totalBytes);
+const totalBytes=record._transferSize||0;
 const wastedBytes=(1-cacheHitProbability)*totalBytes;
-const cacheLifetimeDisplay=formatDuration(cacheLifetimeInSeconds);
 
 totalWastedBytes+=wastedBytes;
 if(url.includes('?'))queryStringCount++;
@@ -2648,36 +3081,32 @@
 results.push({
 url,
 cacheControl,
-cacheLifetimeInSeconds,
-cacheLifetimeDisplay,
+cacheLifetimeMs:cacheLifetimeInSeconds*1000,
 cacheHitProbability,
-totalKb,
 totalBytes,
 wastedBytes});
 
 }
 
 results.sort(
-(a,b)=>a.cacheLifetimeInSeconds-b.cacheLifetimeInSeconds||b.totalBytes-a.totalBytes);
+(a,b)=>a.cacheLifetimeMs-b.cacheLifetimeMs||b.totalBytes-a.totalBytes);
 
 
-
-
-
-
-const score=ByteEfficiencyAudit.computeLogNormalScore(
-totalWastedBytes/1024,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN);
+const score=Audit.computeLogNormalScore(
+totalWastedBytes,
+context.options.scorePODR,
+context.options.scoreMedian);
 
 
 const headings=[
 {key:'url',itemType:'url',text:'URL'},
-{key:'cacheLifetimeDisplay',itemType:'text',text:'Cache TTL'},
-{key:'totalKb',itemType:'text',text:'Size (KB)'}];
+{key:'cacheLifetimeMs',itemType:'ms',text:'Cache TTL',displayUnit:'duration'},
+{key:'totalBytes',itemType:'bytes',text:'Size (KB)',displayUnit:'kb',
+granularity:1}];
 
 
-const tableDetails=ByteEfficiencyAudit.makeTableDetails(headings,results);
+const summary={wastedBytes:totalWastedBytes};
+const details=Audit.makeTableDetails(headings,results,summary);
 
 return{
 score,
@@ -2689,7 +3118,7 @@
 queryStringCount}},
 
 
-details:tableDetails};
+details};
 
 });
 }}
@@ -2697,7 +3126,7 @@
 
 module.exports=CacheHeaders;
 
-},{"../../lib/url-shim":41,"../../lib/web-inspector":42,"../../report/v2/renderer/util.js":43,"./byte-efficiency-audit":3,"assert":47,"parse-cache-control":141}],"../audits/byte-efficiency/uses-optimized-images":[function(require,module,exports){
+},{"../../lib/url-shim":"url","../../lib/web-inspector":47,"../audit":2,"assert":53,"parse-cache-control":147}],"../audits/byte-efficiency/uses-optimized-images":[function(require,module,exports){
 
 
 
@@ -2721,8 +3150,8 @@
 static get meta(){
 return{
 name:'uses-optimized-images',
-description:'Optimize images',
-informative:true,
+description:'Efficiently encode images',
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
 helpText:'Optimized images load faster and consume less cellular data. '+
 '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/optimize-images).',
 requiredArtifacts:['OptimizedImages','devtoolsLogs']};
@@ -2733,9 +3162,8 @@
 
 
 
-
-static computeSavings(image,type){
-const bytes=image.originalSize-image[type+'Size'];
+static computeSavings(image){
+const bytes=image.originalSize-image.jpegSize;
 const percent=100*bytes/image.originalSize;
 return{bytes,percent};
 }
@@ -2747,45 +3175,40 @@
 static audit_(artifacts){
 const images=artifacts.OptimizedImages;
 
-const failedImages=[];
+
 const results=[];
-images.forEach(image=>{
+const warnings=[];
+for(const image of images){
 if(image.failed){
-failedImages.push(image);
-return;
+warnings.push(`Unable to decode ${URL.getURLDisplayName(image.url)}`);
+continue;
 }else if(/(jpeg|bmp)/.test(image.mimeType)===false||
 image.originalSize<image.jpegSize+IGNORE_THRESHOLD_IN_BYTES){
-return;
+continue;
 }
 
 const url=URL.elideDataURI(image.url);
-const jpegSavings=UsesOptimizedImages.computeSavings(image,'jpeg');
+const jpegSavings=UsesOptimizedImages.computeSavings(image);
 
 results.push({
 url,
 fromProtocol:image.fromProtocol,
 isCrossOrigin:!image.isSameOrigin,
-preview:{url:image.url,mimeType:image.mimeType,type:'thumbnail'},
 totalBytes:image.originalSize,
 wastedBytes:jpegSavings.bytes});
 
-});
-
-let debugString;
-if(failedImages.length){
-const urls=failedImages.map(image=>URL.getURLDisplayName(image.url));
-debugString=`Lighthouse was unable to decode some of your images: ${urls.join(', ')}`;
 }
 
 const headings=[
-{key:'preview',itemType:'thumbnail',text:''},
+{key:'url',itemType:'thumbnail',text:''},
 {key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'Potential Savings'}];
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{key:'wastedBytes',itemType:'bytes',displayUnit:'kb',granularity:1,
+text:'Potential Savings'}];
 
 
 return{
-debugString,
+warnings,
 results,
 headings};
 
@@ -2794,7 +3217,138 @@
 
 module.exports=UsesOptimizedImages;
 
-},{"../../lib/url-shim":41,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-request-compression":[function(require,module,exports){
+},{"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-responsive-images":[function(require,module,exports){
+
+
+
+
+
+
+
+
+
+
+
+
+
+'use strict';
+
+const ByteEfficiencyAudit=require('./byte-efficiency-audit');
+const Sentry=require('../../lib/sentry');
+const URL=require('../../lib/url-shim');
+
+const IGNORE_THRESHOLD_IN_BYTES=2048;
+
+class UsesResponsiveImages extends ByteEfficiencyAudit{
+
+
+
+static get meta(){
+return{
+name:'uses-responsive-images',
+description:'Properly size images',
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
+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).',
+requiredArtifacts:['ImageUsage','ViewportDimensions','devtoolsLogs']};
+
+}
+
+
+
+
+
+
+static computeWaste(image,DPR){
+
+if(!image.networkRecord){
+return null;
+}
+
+const url=URL.elideDataURI(image.src);
+const actualPixels=image.naturalWidth*image.naturalHeight;
+const usedPixels=image.clientWidth*image.clientHeight*Math.pow(DPR,2);
+const wastedRatio=1-usedPixels/actualPixels;
+const totalBytes=image.networkRecord.resourceSize;
+const wastedBytes=Math.round(totalBytes*wastedRatio);
+
+
+
+if(!usedPixels){
+return null;
+}
+
+if(!Number.isFinite(wastedRatio)){
+return new Error(`Invalid image sizing information ${url}`);
+}
+
+return{
+url,
+totalBytes,
+wastedBytes,
+wastedPercent:100*wastedRatio};
+
+}
+
+
+
+
+
+static audit_(artifacts){
+const images=artifacts.ImageUsage;
+const DPR=artifacts.ViewportDimensions.devicePixelRatio;
+
+
+const warnings=[];
+
+const resultsMap=new Map();
+images.forEach(image=>{
+
+if(!image.networkRecord||image.networkRecord.mimeType==='image/svg+xml'){
+return;
+}
+
+const processed=UsesResponsiveImages.computeWaste(image,DPR);
+if(!processed)return;
+
+if(processed instanceof Error){
+warnings.push(processed.message);
+
+Sentry.captureException(processed,{tags:{audit:this.meta.name},level:'warning'});
+return;
+}
+
+
+const existing=resultsMap.get(processed.url);
+if(!existing||existing.wastedBytes>processed.wastedBytes){
+resultsMap.set(processed.url,processed);
+}
+});
+
+const results=Array.from(resultsMap.values()).
+filter(item=>item.wastedBytes>IGNORE_THRESHOLD_IN_BYTES);
+
+const headings=[
+{key:'url',itemType:'thumbnail',text:''},
+{key:'url',itemType:'url',text:'URL'},
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{key:'wastedBytes',itemType:'bytes',displayUnit:'kb',granularity:1,
+text:'Potential Savings'}];
+
+
+return{
+warnings,
+results,
+headings};
+
+}}
+
+
+module.exports=UsesResponsiveImages;
+
+},{"../../lib/sentry":39,"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-text-compression":[function(require,module,exports){
 
 
 
@@ -2818,8 +3372,8 @@
 
 static get meta(){
 return{
-name:'uses-request-compression',
-informative:true,
+name:'uses-text-compression',
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
 description:'Enable text compression',
 helpText:'Text-based responses should be served with compression (gzip, deflate or brotli)'+
 ' to minimize total network bytes.'+
@@ -2832,10 +3386,10 @@
 
 
 
-
 static audit_(artifacts){
 const uncompressedResponses=artifacts.ResponseCompression;
 
+
 const results=[];
 uncompressedResponses.forEach(record=>{
 const originalSize=record.resourceSize;
@@ -2868,8 +3422,9 @@
 
 const headings=[
 {key:'url',itemType:'url',text:'Uncompressed resource URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'GZIP Savings'}];
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{key:'wastedBytes',itemType:'bytes',displayUnit:'kb',granularity:1,
+text:'GZIP Savings'}];
 
 
 return{
@@ -2881,136 +3436,7 @@
 
 module.exports=ResponsesAreCompressed;
 
-},{"../../lib/url-shim":41,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-responsive-images":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const Sentry=require('../../lib/sentry');
-const URL=require('../../lib/url-shim');
-
-const IGNORE_THRESHOLD_IN_BYTES=2048;
-const WASTEFUL_THRESHOLD_IN_BYTES=25*1024;
-
-class UsesResponsiveImages extends ByteEfficiencyAudit{
-
-
-
-static get meta(){
-return{
-name:'uses-responsive-images',
-description:'Properly size images',
-informative:true,
-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).',
-requiredArtifacts:['ImageUsage','ViewportDimensions','devtoolsLogs']};
-
-}
-
-
-
-
-
-
-static computeWaste(image,DPR){
-const url=URL.elideDataURI(image.src);
-const actualPixels=image.naturalWidth*image.naturalHeight;
-const usedPixels=image.clientWidth*image.clientHeight*Math.pow(DPR,2);
-const wastedRatio=1-usedPixels/actualPixels;
-const totalBytes=image.networkRecord.resourceSize;
-const wastedBytes=Math.round(totalBytes*wastedRatio);
-
-
-
-if(!usedPixels){
-return null;
-}
-
-if(!Number.isFinite(wastedRatio)){
-return new Error(`Invalid image sizing information ${url}`);
-}
-
-return{
-url,
-preview:{
-type:'thumbnail',
-url:image.networkRecord.url,
-mimeType:image.networkRecord.mimeType},
-
-totalBytes,
-wastedBytes,
-wastedPercent:100*wastedRatio,
-isWasteful:wastedBytes>WASTEFUL_THRESHOLD_IN_BYTES};
-
-}
-
-
-
-
-
-static audit_(artifacts){
-const images=artifacts.ImageUsage;
-const DPR=artifacts.ViewportDimensions.devicePixelRatio;
-
-let debugString;
-const resultsMap=new Map();
-images.forEach(image=>{
-
-if(!image.networkRecord||image.networkRecord.mimeType==='image/svg+xml'){
-return;
-}
-
-const processed=UsesResponsiveImages.computeWaste(image,DPR);
-if(!processed)return;
-
-if(processed instanceof Error){
-debugString=processed.message;
-Sentry.captureException(processed,{tags:{audit:this.meta.name},level:'warning'});
-return;
-}
-
-
-const existing=resultsMap.get(processed.preview.url);
-if(!existing||existing.wastedBytes>processed.wastedBytes){
-resultsMap.set(processed.preview.url,processed);
-}
-});
-
-const results=Array.from(resultsMap.values()).
-filter(item=>item.wastedBytes>IGNORE_THRESHOLD_IN_BYTES);
-
-const headings=[
-{key:'preview',itemType:'thumbnail',text:''},
-{key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'Potential Savings'}];
-
-
-return{
-debugString,
-results,
-headings};
-
-}}
-
-
-module.exports=UsesResponsiveImages;
-
-},{"../../lib/sentry":33,"../../lib/url-shim":41,"./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-webp-images":[function(require,module,exports){
+},{"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/byte-efficiency/uses-webp-images":[function(require,module,exports){
 
 
 
@@ -3022,7 +3448,6 @@
 'use strict';
 
 const ByteEfficiencyAudit=require('./byte-efficiency-audit');
-const OptimizedImages=require('./uses-optimized-images');
 const URL=require('../../lib/url-shim');
 
 const IGNORE_THRESHOLD_IN_BYTES=8192;
@@ -3035,7 +3460,7 @@
 return{
 name:'uses-webp-images',
 description:'Serve images in next-gen formats',
-informative:true,
+scoreDisplayMode:ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
 helpText:'Image formats like JPEG 2000, JPEG XR, and WebP often provide better '+
 'compression than PNG or JPEG, which means faster downloads and less data consumption. '+
 '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/webp).',
@@ -3047,47 +3472,52 @@
 
 
 
+static computeSavings(image){
+const bytes=image.originalSize-image.webpSize;
+const percent=100*bytes/image.originalSize;
+return{bytes,percent};
+}
+
+
+
+
+
 static audit_(artifacts){
 const images=artifacts.OptimizedImages;
 
-const failedImages=[];
+
 const results=[];
-images.forEach(image=>{
+const warnings=[];
+for(const image of images){
 if(image.failed){
-failedImages.push(image);
-return;
+warnings.push(`Unable to decode ${URL.getURLDisplayName(image.url)}`);
+continue;
 }else if(image.originalSize<image.webpSize+IGNORE_THRESHOLD_IN_BYTES){
-return;
+continue;
 }
 
 const url=URL.elideDataURI(image.url);
-const webpSavings=OptimizedImages.computeSavings(image,'webp');
+const webpSavings=UsesWebPImages.computeSavings(image);
 
 results.push({
 url,
 fromProtocol:image.fromProtocol,
 isCrossOrigin:!image.isSameOrigin,
-preview:{url:image.url,mimeType:image.mimeType,type:'thumbnail'},
 totalBytes:image.originalSize,
 wastedBytes:webpSavings.bytes});
 
-});
-
-let debugString;
-if(failedImages.length){
-const urls=failedImages.map(image=>URL.getURLDisplayName(image.url));
-debugString=`Lighthouse was unable to decode some of your images: ${urls.join(', ')}`;
 }
 
 const headings=[
-{key:'preview',itemType:'thumbnail',text:''},
+{key:'url',itemType:'thumbnail',text:''},
 {key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Original'},
-{key:'potentialSavings',itemType:'text',text:'Potential Savings'}];
+{key:'totalBytes',itemType:'bytes',displayUnit:'kb',granularity:1,text:'Original'},
+{key:'wastedBytes',itemType:'bytes',displayUnit:'kb',granularity:1,
+text:'Potential Savings'}];
 
 
 return{
-debugString,
+warnings,
 results,
 headings};
 
@@ -3096,293 +3526,7 @@
 
 module.exports=UsesWebPImages;
 
-},{"../../lib/url-shim":41,"./byte-efficiency-audit":3,"./uses-optimized-images":"../audits/byte-efficiency/uses-optimized-images"}],"../audits/cache-start-url":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-
-class CacheStartUrl extends Audit{
-
-
-
-static get meta(){
-return{
-name:'cache-start-url',
-description:'Cache contains start_url from manifest (alpha)',
-failureDescription:'Cache does not contain start_url from manifest (alpha)',
-requiredArtifacts:['CacheContents','Manifest','URL']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-if(!artifacts.Manifest||!artifacts.Manifest.value){
-
-return{
-rawValue:false};
-
-}
-
-const manifest=artifacts.Manifest.value;
-if(!(manifest.start_url&&manifest.start_url.value)){
-return{
-rawValue:false,
-debugString:'start_url not present in Manifest'};
-
-}
-
-
-const startURL=manifest.start_url.value;
-
-const altStartURL=startURL.
-replace(/\?utm_([^=]*)=([^&]|$)*/,'').
-replace(/\?$/,'');
-
-
-
-
-
-
-const cacheContents=artifacts.CacheContents;
-const cacheHasStartUrl=cacheContents.find(req=>{
-return startURL===req||altStartURL===req;
-});
-
-return{
-rawValue:cacheHasStartUrl!==undefined};
-
-}}
-
-
-module.exports=CacheStartUrl;
-
-},{"./audit":2}],"../audits/consistently-interactive":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
-const NetworkRecorder=require('../lib/network-recorder');
-const TracingProcessor=require('../lib/traces/tracing-processor');
-const LHError=require('../lib/errors');
-
-
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=1700;
-const SCORING_MEDIAN=10000;
-
-const REQUIRED_QUIET_WINDOW=5000;
-const ALLOWED_CONCURRENT_REQUESTS=2;
-
-
-
-
-
-
-
-class ConsistentlyInteractiveMetric extends Audit{
-
-
-
-static get meta(){
-return{
-name:'consistently-interactive',
-description:'Consistently Interactive (beta)',
-helpText:'Consistently Interactive marks the time at which the page is '+
-'fully interactive. '+
-'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).',
-scoringMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces','devtoolsLogs']};
-
-}
-
-
-
-
-
-
-
-
-static _findNetworkQuietPeriods(networkRecords,traceOfTab){
-const traceEndTsInMs=traceOfTab.timestamps.traceEnd/1000;
-return NetworkRecorder.findNetworkQuietPeriods(networkRecords,
-ALLOWED_CONCURRENT_REQUESTS,traceEndTsInMs);
-}
-
-
-
-
-
-
-
-static _findCPUQuietPeriods(longTasks,traceOfTab){
-const navStartTsInMs=traceOfTab.timestamps.navigationStart/1000;
-const traceEndTsInMs=traceOfTab.timestamps.traceEnd/1000;
-if(longTasks.length===0){
-return[{start:0,end:traceEndTsInMs}];
-}
-
-const quietPeriods=[];
-longTasks.forEach((task,index)=>{
-if(index===0){
-quietPeriods.push({
-start:0,
-end:task.start+navStartTsInMs});
-
-}
-
-if(index===longTasks.length-1){
-quietPeriods.push({
-start:task.end+navStartTsInMs,
-end:traceEndTsInMs});
-
-}else{
-quietPeriods.push({
-start:task.end+navStartTsInMs,
-end:longTasks[index+1].start+navStartTsInMs});
-
-}
-});
-
-return quietPeriods;
-}
-
-
-
-
-
-
-
-
-
-
-static findOverlappingQuietPeriods(longTasks,networkRecords,traceOfTab){
-const FMPTsInMs=traceOfTab.timestamps.firstMeaningfulPaint/1000;
-
-const isLongEnoughQuietPeriod=period=>
-period.end>FMPTsInMs+REQUIRED_QUIET_WINDOW&&
-period.end-period.start>=REQUIRED_QUIET_WINDOW;
-const networkQuietPeriods=this._findNetworkQuietPeriods(networkRecords,traceOfTab).
-filter(isLongEnoughQuietPeriod);
-const cpuQuietPeriods=this._findCPUQuietPeriods(longTasks,traceOfTab).
-filter(isLongEnoughQuietPeriod);
-
-const cpuQueue=cpuQuietPeriods.slice();
-const networkQueue=networkQuietPeriods.slice();
-
-
-let cpuCandidate=cpuQueue.shift();
-let networkCandidate=networkQueue.shift();
-while(cpuCandidate&&networkCandidate){
-if(cpuCandidate.start>=networkCandidate.start){
-
-if(networkCandidate.end>=cpuCandidate.start+REQUIRED_QUIET_WINDOW){
-return{
-cpuQuietPeriod:cpuCandidate,
-networkQuietPeriod:networkCandidate,
-cpuQuietPeriods,
-networkQuietPeriods};
-
-}else{
-networkCandidate=networkQueue.shift();
-}
-}else{
-
-if(cpuCandidate.end>=networkCandidate.start+REQUIRED_QUIET_WINDOW){
-return{
-cpuQuietPeriod:cpuCandidate,
-networkQuietPeriod:networkCandidate,
-cpuQuietPeriods,
-networkQuietPeriods};
-
-}else{
-cpuCandidate=cpuQueue.shift();
-}
-}
-}
-
-throw new LHError(
-cpuCandidate?
-LHError.errors.NO_TTI_NETWORK_IDLE_PERIOD:
-LHError.errors.NO_TTI_CPU_IDLE_PERIOD);
-
-}
-
-
-
-
-
-static audit(artifacts){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-const computedArtifacts=[
-artifacts.requestNetworkRecords(devtoolsLog),
-artifacts.requestTraceOfTab(trace)];
-
-
-return Promise.all(computedArtifacts).
-then(([networkRecords,traceOfTab])=>{
-if(!traceOfTab.timestamps.firstMeaningfulPaint){
-throw new LHError(LHError.errors.NO_FMP);
-}
-
-if(!traceOfTab.timestamps.domContentLoaded){
-throw new LHError(LHError.errors.NO_DCL);
-}
-
-const longTasks=TracingProcessor.getMainThreadTopLevelEvents(traceOfTab).
-filter(event=>event.duration>=50);
-const quietPeriodInfo=this.findOverlappingQuietPeriods(longTasks,networkRecords,
-traceOfTab);
-const cpuQuietPeriod=quietPeriodInfo.cpuQuietPeriod;
-
-const timestamp=Math.max(
-cpuQuietPeriod.start,
-traceOfTab.timestamps.firstMeaningfulPaint/1000,
-traceOfTab.timestamps.domContentLoaded/1000)*
-1000;
-const timeInMs=(timestamp-traceOfTab.timestamps.navigationStart)/1000;
-const extendedInfo=Object.assign(quietPeriodInfo,{timestamp,timeInMs});
-
-return{
-score:Audit.computeLogNormalScore(
-timeInMs,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN),
-
-rawValue:timeInMs,
-displayValue:Util.formatMilliseconds(timeInMs),
-extendedInfo:{
-value:extendedInfo}};
-
-
-});
-}}
-
-
-module.exports=ConsistentlyInteractiveMetric;
-
-
-
-
-
-
-
-let TimePeriod;
-
-},{"../lib/errors":28,"../lib/network-recorder":32,"../lib/traces/tracing-processor":40,"../report/v2/renderer/util":43,"./audit":2}],"../audits/content-width":[function(require,module,exports){
+},{"../../lib/url-shim":"url","./byte-efficiency-audit":3}],"../audits/content-width":[function(require,module,exports){
 
 
 
@@ -3419,11 +3563,16 @@
 
 return{
 rawValue:widthsMatch,
-debugString:this.createDebugString(widthsMatch,artifacts.ViewportDimensions)};
+explanation:this.createExplanation(widthsMatch,artifacts.ViewportDimensions)};
 
 }
 
-static createDebugString(match,artifact){
+
+
+
+
+
+static createExplanation(match,artifact){
 if(match){
 return'';
 }
@@ -3444,7 +3593,7 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
+const Util=require('../report/html/renderer/util');
 
 class CriticalRequestChains extends Audit{
 
@@ -3454,17 +3603,29 @@
 return{
 name:'critical-request-chains',
 description:'Critical Request Chains',
-informative:true,
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
 helpText:'The Critical Request Chains below show you what resources are '+
 'issued with a high priority. Consider reducing '+
 'the length of chains, reducing the download size of resources, or '+
 'deferring the download of unnecessary resources to improve page load. '+
 '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains).',
-requiredArtifacts:['devtoolsLogs']};
+requiredArtifacts:['devtoolsLogs','URL']};
 
 }
 
+
+
+
+
+
+
 static _traverse(tree,cb){
+
+
+
+
+
+
 function walk(node,depth,startTime,transferSize=0){
 const children=Object.keys(node);
 if(children.length===0){
@@ -3497,6 +3658,7 @@
 
 
 
+
 static _getLongestChain(tree){
 const longest={
 duration:0,
@@ -3519,35 +3681,49 @@
 
 
 
-static flattenRequests(tree){
-const flattendChains={};
-const chainMap=new Map();
-CriticalRequestChains._traverse(tree,opts=>{
-let chain;
-if(chainMap.has(opts.id)){
-chain=chainMap.get(opts.id);
-}else{
-chain={};
-flattendChains[opts.id]=chain;
-}
 
+static flattenRequests(tree){
+
+const flattendChains={};
+
+const chainMap=new Map();
+
+
+function flatten(opts){
 const request=opts.node.request;
-chain.request={
+const simpleRequest={
 url:request.url,
 startTime:request.startTime,
 endTime:request.endTime,
-responseReceivedTime:request.responseReceivedTime,
+_responseReceivedTime:request._responseReceivedTime,
 transferSize:request.transferSize};
 
-chain.children={};
-Object.keys(opts.node.children).forEach(chainId=>{
-const childChain={};
+
+let chain=chainMap.get(opts.id);
+if(chain){
+chain.request=simpleRequest;
+}else{
+chain={
+request:simpleRequest,
+children:{}};
+
+flattendChains[opts.id]=chain;
+}
+
+for(const chainId of Object.keys(opts.node.children)){
+
+const childChain={
+request:{},
+children:{}};
+
 chainMap.set(chainId,childChain);
 chain.children[chainId]=childChain;
-});
+}
 
 chainMap.set(opts.id,chain);
-});
+}
+
+CriticalRequestChains._traverse(tree,flatten);
 
 return flattendChains;
 }
@@ -3558,9 +3734,14 @@
 
 
 static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-return artifacts.requestCriticalRequestChains(devtoolsLogs).then(chains=>{
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const URL=artifacts.URL;
+return artifacts.requestCriticalRequestChains({devtoolsLog,URL}).then(chains=>{
 let chainCount=0;
+
+
+
+
 function walk(node,depth){
 const children=Object.keys(node);
 
@@ -3589,7 +3770,8 @@
 
 return{
 rawValue:chainCount===0,
-displayValue:Util.formatNumber(chainCount),
+notApplicable:chainCount===0,
+displayValue:chainCount?`${Util.formatNumber(chainCount)} chains found`:'',
 extendedInfo:{
 value:{
 chains:flattenedChains,
@@ -3609,7 +3791,7 @@
 
 module.exports=CriticalRequestChains;
 
-},{"../report/v2/renderer/util":43,"./audit":2}],"../audits/deprecations":[function(require,module,exports){
+},{"../report/html/renderer/util":48,"./audit":2}],"../audits/deprecations":[function(require,module,exports){
 
 
 
@@ -3624,7 +3806,7 @@
 
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
+const Util=require('../report/html/renderer/util');
 
 class Deprecations extends Audit{
 
@@ -3650,16 +3832,15 @@
 
 const deprecations=entries.filter(log=>log.entry.source==='deprecation').map(log=>{
 return{
-type:'code',
-text:log.entry.text,
-url:log.entry.url,
+value:log.entry.text,
+url:log.entry.url||'',
 source:log.entry.source,
 lineNumber:log.entry.lineNumber};
 
 });
 
 const headings=[
-{key:'text',itemType:'code',text:'Deprecation / Warning'},
+{key:'value',itemType:'code',text:'Deprecation / Warning'},
 {key:'url',itemType:'url',text:'URL'},
 {key:'lineNumber',itemType:'text',text:'Line'}];
 
@@ -3685,7 +3866,7 @@
 
 module.exports=Deprecations;
 
-},{"../report/v2/renderer/util":43,"./audit":2}],"../audits/dobetterweb/appcache-manifest":[function(require,module,exports){
+},{"../report/html/renderer/util":48,"./audit":2}],"../audits/dobetterweb/appcache-manifest":[function(require,module,exports){
 
 
 
@@ -3721,12 +3902,11 @@
 
 static audit(artifacts){
 const usingAppcache=artifacts.AppCacheManifest!==null;
-const debugString=usingAppcache?
-`Found <html manifest="${artifacts.AppCacheManifest}">.`:'';
+const displayValue=usingAppcache?`Found "${artifacts.AppCacheManifest}"`:'';
 
 return{
 rawValue:!usingAppcache,
-debugString};
+displayValue};
 
 }}
 
@@ -3749,16 +3929,12 @@
 'use strict';
 
 const Audit=require('../audit');
-const Util=require('../../report/v2/renderer/util.js');
+const Util=require('../../report/html/renderer/util.js');
 
 const MAX_DOM_NODES=1500;
 const MAX_DOM_TREE_WIDTH=60;
 const MAX_DOM_TREE_DEPTH=32;
 
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=2400;
-const SCORING_MEDIAN=3000;
-
 class DOMSize extends Audit{
 static get MAX_DOM_NODES(){
 return MAX_DOM_NODES;
@@ -3777,8 +3953,8 @@
 `depth < ${MAX_DOM_TREE_DEPTH} elements and fewer than ${MAX_DOM_TREE_WIDTH} `+
 'children/parent element. A large DOM can increase memory usage, 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/).',
-scoringMode:Audit.SCORING_MODES.NUMERIC,
+'and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/tools/lighthouse/audits/dom-size).',
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
 requiredArtifacts:['DOMStats']};
 
 }
@@ -3786,67 +3962,71 @@
 
 
 
+static get defaultOptions(){
+return{
 
-static audit(artifacts){
+
+
+scorePODR:700,
+scoreMedian:1400};
+
+}
+
+
+
+
+
+
+
+static audit(artifacts,context){
 const stats=artifacts.DOMStats;
 
-
-
-
-
-
-
-const depthSnippet=stats.depth.pathToElement.reduce((str,curr,i)=>{
-return`${str}\n`+'  '.repeat(i)+`${curr} >`;
-},'').replace(/>$/g,'').trim();
-const widthSnippet='Element with most children:\n'+
-stats.width.pathToElement[stats.width.pathToElement.length-1];
-
-
-
-
-
 const score=Audit.computeLogNormalScore(
 stats.totalDOMNodes,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN);
+context.options.scorePODR,
+context.options.scoreMedian);
 
 
-const cards=[{
-title:'Total DOM Nodes',
-value:Util.formatNumber(stats.totalDOMNodes),
-target:`< ${Util.formatNumber(MAX_DOM_NODES)} nodes`},
+const headings=[
+{key:'totalNodes',itemType:'text',text:'Total DOM Nodes'},
+{key:'depth',itemType:'text',text:'Maximum DOM Depth'},
+{key:'width',itemType:'text',text:'Maximum Children'}];
+
+
+const items=[
 {
-title:'DOM Depth',
-value:Util.formatNumber(stats.depth.max),
-snippet:depthSnippet,
-target:`< ${Util.formatNumber(MAX_DOM_TREE_DEPTH)}`},
+totalNodes:Util.formatNumber(stats.totalDOMNodes),
+depth:Util.formatNumber(stats.depth.max),
+width:Util.formatNumber(stats.width.max)},
+
 {
-title:'Maximum Children',
-value:Util.formatNumber(stats.width.max),
-snippet:widthSnippet,
-target:`< ${Util.formatNumber(MAX_DOM_TREE_WIDTH)} nodes`}];
+totalNodes:'',
+depth:{
+type:'code',
+value:stats.depth.snippet},
+
+width:{
+type:'code',
+value:stats.width.snippet}}];
+
+
 
 
 return{
 score,
 rawValue:stats.totalDOMNodes,
-displayValue:`${Util.formatNumber(stats.totalDOMNodes)} nodes`,
+displayValue:['%d nodes',stats.totalDOMNodes],
 extendedInfo:{
-value:cards},
+value:items},
 
-details:{
-type:'cards',
-header:{type:'text',text:'View details'},
-items:cards}};
-
+details:Audit.makeTableDetails(headings,items)};
 
 }}
 
 
 module.exports=DOMSize;
 
-},{"../../report/v2/renderer/util.js":43,"../audit":2}],"../audits/dobetterweb/external-anchors-use-rel-noopener":[function(require,module,exports){
+},{"../../report/html/renderer/util.js":48,"../audit":2}],"../audits/dobetterweb/external-anchors-use-rel-noopener":[function(require,module,exports){
 
 
 
@@ -3864,10 +4044,10 @@
 static get meta(){
 return{
 name:'external-anchors-use-rel-noopener',
-description:'Opens external anchors using `rel="noopener"`',
-failureDescription:'Does not open external anchors using `rel="noopener"`',
-helpText:'Open new tabs using `rel="noopener"` to improve performance and '+
-'prevent security vulnerabilities. '+
+description:'Links to cross-origin destinations are safe',
+failureDescription:'Links to cross-origin destinations are unsafe',
+helpText:'Add `rel="noopener"` or `rel="noreferrer"` to any external links to improve '+
+'performance and prevent security vulnerabilities. '+
 '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/noopener).',
 requiredArtifacts:['URL','AnchorsWithNoRelNoopener']};
 
@@ -3878,7 +4058,8 @@
 
 
 static audit(artifacts){
-let debugString;
+
+const warnings=[];
 const pageHost=new URL(artifacts.URL.finalUrl).host;
 
 
@@ -3889,9 +4070,9 @@
 try{
 return new URL(anchor.href).host!==pageHost;
 }catch(err){
-debugString='Lighthouse was unable to determine the destination '+
-'of some anchor tags. If they are not used as hyperlinks, '+
-'consider removing the _blank target.';
+
+warnings.push('Unable to determine the destination for anchor tag. '+
+'If not used as a hyperlink, consider removing target=_blank.');
 return true;
 }
 }).
@@ -3924,14 +4105,14 @@
 value:failingAnchors},
 
 details,
-debugString};
+warnings};
 
 }}
 
 
 module.exports=ExternalAnchorsUseRelNoopenerAudit;
 
-},{"../../lib/url-shim":41,"../audit":2}],"../audits/dobetterweb/geolocation-on-start":[function(require,module,exports){
+},{"../../lib/url-shim":"url","../audit":2}],"../audits/dobetterweb/geolocation-on-start":[function(require,module,exports){
 
 
 
@@ -3975,6 +4156,8 @@
 {key:'url',itemType:'url',text:'URL'},
 {key:'label',itemType:'text',text:'Location'}];
 
+
+
 const details=ViolationAudit.makeTableDetails(headings,results);
 
 return{
@@ -3989,125 +4172,7 @@
 
 module.exports=GeolocationOnStart;
 
-},{"../violation-audit":6}],"../audits/dobetterweb/link-blocking-first-paint":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const Util=require('../../report/v2/renderer/util.js');
-const scoreForWastedMs=require('../byte-efficiency/byte-efficiency-audit').scoreForWastedMs;
-
-
-
-
-
-const LOAD_THRESHOLD_IN_MS=50;
-
-class LinkBlockingFirstPaintAudit extends Audit{
-
-
-
-static get meta(){
-return{
-name:'link-blocking-first-paint',
-description:'Reduce render-blocking stylesheets',
-informative:true,
-helpText:'External stylesheets are blocking the first paint of your page. Consider '+
-'delivering critical CSS via `<style>` tags and deferring non-critical '+
-'styles. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).',
-requiredArtifacts:['TagsBlockingFirstPaint','traces']};
-
-}
-
-
-
-
-
-
-
-
-
-
-static computeAuditResultForTags(artifacts,tagFilter,endTimeMax=Infinity,
-loadDurationThreshold=0){
-const artifact=artifacts.TagsBlockingFirstPaint;
-
-const filtered=artifact.filter(item=>{
-return item.tag.tagName===tagFilter&&
-(item.endTime-item.startTime)*1000>=loadDurationThreshold&&
-item.endTime*1000<endTimeMax;
-});
-
-const startTime=filtered.length===0?0:
-filtered.reduce((t,item)=>Math.min(t,item.startTime),Number.MAX_VALUE);
-let endTime=0;
-
-const results=filtered.map(item=>{
-endTime=Math.max(item.endTime,endTime);
-
-return{
-url:item.tag.url,
-totalKb:Util.formatBytesToKB(item.transferSize),
-totalMs:Util.formatMilliseconds(Math.round((item.endTime-startTime)*1000),1)};
-
-});
-
-const rawDelayTime=Math.round((endTime-startTime)*1000);
-const delayTime=Util.formatMilliseconds(rawDelayTime,1);
-let displayValue='';
-if(results.length>1){
-displayValue=`${results.length} resources delayed first paint by ${delayTime}`;
-}else if(results.length===1){
-displayValue=`${results.length} resource delayed first paint by ${delayTime}`;
-}
-
-const headings=[
-{key:'url',itemType:'url',text:'URL'},
-{key:'totalKb',itemType:'text',text:'Size (KB)'},
-{key:'totalMs',itemType:'text',text:'Delayed Paint By (ms)'}];
-
-
-const tableDetails=Audit.makeTableDetails(headings,results);
-
-return{
-displayValue,
-score:scoreForWastedMs(rawDelayTime),
-rawValue:rawDelayTime,
-extendedInfo:{
-value:{
-wastedMs:delayTime,
-results}},
-
-
-details:tableDetails};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-return artifacts.requestTraceOfTab(trace).then(traceOfTab=>{
-const fcpTsInMs=traceOfTab.timestamps.firstContentfulPaint/1000;
-return this.computeAuditResultForTags(artifacts,'LINK',fcpTsInMs,LOAD_THRESHOLD_IN_MS);
-});
-}}
-
-
-module.exports=LinkBlockingFirstPaintAudit;
-
-},{"../../report/v2/renderer/util.js":43,"../audit":2,"../byte-efficiency/byte-efficiency-audit":3}],"../audits/dobetterweb/no-document-write":[function(require,module,exports){
+},{"../violation-audit":6}],"../audits/dobetterweb/no-document-write":[function(require,module,exports){
 
 
 
@@ -4149,6 +4214,7 @@
 {key:'url',itemType:'url',text:'URL'},
 {key:'label',itemType:'text',text:'Location'}];
 
+
 const details=ViolationAudit.makeTableDetails(headings,results);
 
 return{
@@ -4215,7 +4281,8 @@
 
 
 static audit(artifacts){
-let debugString;
+
+const warnings=[];
 const listeners=artifacts.EventListeners;
 
 const results=listeners.filter(loc=>{
@@ -4224,7 +4291,7 @@
 
 if(!URL.isValid(loc.url)&&isMutationEvent){
 sameHost=true;
-debugString=URL.INVALID_URL_DEBUG_STRING;
+warnings.push(URL.INVALID_URL_DEBUG_STRING);
 }
 
 return sameHost&&isMutationEvent;
@@ -4249,14 +4316,14 @@
 
 
 details,
-debugString};
+warnings};
 
 }}
 
 
 module.exports=NoMutationEventsAudit;
 
-},{"../../lib/event-helpers":29,"../../lib/url-shim":41,"../audit":2}],"../audits/dobetterweb/no-vulnerable-libraries":[function(require,module,exports){
+},{"../../lib/event-helpers":34,"../../lib/url-shim":"url","../audit":2}],"../audits/dobetterweb/no-vulnerable-libraries":[function(require,module,exports){
 
 
 
@@ -4274,10 +4341,14 @@
 const Audit=require('../audit');
 const Sentry=require('../../lib/sentry');
 const semver=require('semver');
+
 const snykDatabase=require('../../../third-party/snyk/snapshot.json');
 
 const SEMVER_REGEX=/^(\d+\.\d+\.\d+)[^-0-9]+/;
 
+
+
+
 class NoVulnerableLibrariesAudit extends Audit{
 
 
@@ -4325,7 +4396,8 @@
 
 if(/^\d+\.\d+$/.test(version))return`${version}.0`;
 
-if(SEMVER_REGEX.test(version))return version.match(SEMVER_REGEX)[1];
+const versionMatch=version.match(SEMVER_REGEX);
+if(versionMatch)return versionMatch[1];
 
 return version;
 }
@@ -4335,34 +4407,35 @@
 
 
 
-static getVulns(lib,snykDB){
-const vulns=[];
-if(!snykDB.npm[lib.npmPkgName]){
-return vulns;
+static getVulnerabilities(normalizedVersion,lib){
+const snykDB=NoVulnerableLibrariesAudit.snykDB;
+if(!lib.npmPkgName||!snykDB.npm[lib.npmPkgName]){
+return[];
 }
 
 try{
-semver.satisfies(lib.version,'*');
+semver.satisfies(normalizedVersion,'*');
 }catch(err){
 err.pkgName=lib.npmPkgName;
 
+
 Sentry.captureException(err,{level:'warning'});
-return vulns;
+return[];
 }
 
-lib.pkgLink=`https://snyk.io/vuln/npm:${lib.npmPkgName}?lh@${lib.version}`;
 const snykInfo=snykDB.npm[lib.npmPkgName];
-snykInfo.forEach(vuln=>{
-if(semver.satisfies(lib.version,vuln.semver.vulnerable[0])){
+const vulns=snykInfo.
+filter(vuln=>semver.satisfies(normalizedVersion,vuln.semver.vulnerable[0])).
 
-vulns.push({
+map(vuln=>{
+return{
 severity:vuln.severity,
 numericSeverity:this.severityMap[vuln.severity],
-library:`${lib.name}@${lib.version}`,
-url:'https://snyk.io/vuln/'+vuln.id});
+library:`${lib.name}@${normalizedVersion}`,
+url:'https://snyk.io/vuln/'+vuln.id};
 
-}
 });
+
 return vulns;
 }
 
@@ -4370,8 +4443,8 @@
 
 
 
-static highestSeverity(vulns){
-const sortedVulns=vulns.
+static highestSeverity(vulnerabilities){
+const sortedVulns=vulnerabilities.
 sort((a,b)=>b.numericSeverity-a.numericSeverity);
 return sortedVulns[0].severity;
 }
@@ -4381,37 +4454,52 @@
 
 
 static audit(artifacts){
-const libraries=artifacts.JSLibraries;
-if(!libraries.length){
+const foundLibraries=artifacts.JSLibraries;
+if(!foundLibraries.length){
 return{
 rawValue:true};
 
 }
 
 let totalVulns=0;
-const finalVulns=libraries.map(lib=>{
-lib.version=this.normalizeVersion(lib.version);
-lib.vulns=this.getVulns(lib,this.snykDB);
-if(lib.vulns.length>0){
-lib.vulnCount=lib.vulns.length;
-lib.highestSeverity=this.highestSeverity(lib.vulns).replace(/^\w/,l=>l.toUpperCase());
-totalVulns+=lib.vulnCount;
-lib.detectedLib={};
-lib.detectedLib.text=lib.name+'@'+lib.version;
-lib.detectedLib.url=lib.pkgLink;
-lib.detectedLib.type='link';
+
+const vulnerabilityResults=[];
+
+const libraryVulns=foundLibraries.map(lib=>{
+const version=this.normalizeVersion(lib.version)||'';
+const vulns=this.getVulnerabilities(version,lib);
+const vulnCount=vulns.length;
+totalVulns+=vulnCount;
+
+let highestSeverity;
+if(vulns.length>0){
+highestSeverity=this.highestSeverity(vulns).replace(/^\w/,l=>l.toUpperCase());
+
+vulnerabilityResults.push({
+highestSeverity,
+vulnCount,
+detectedLib:{
+text:lib.name+'@'+version,
+url:`https://snyk.io/vuln/npm:${lib.npmPkgName}?lh@${version}`,
+type:'link'}});
+
+
 }
-return lib;
-}).
-filter(obj=>{
-return obj.vulns.length>0;
+
+return{
+name:lib.name,
+npmPkgName:lib.npmPkgName,
+version,
+vulns,
+highestSeverity};
+
 });
 
 let displayValue='';
 if(totalVulns>1){
-displayValue=`${totalVulns} vulnerabilities detected.`;
+displayValue=`${totalVulns} vulnerabilities detected`;
 }else if(totalVulns===1){
-displayValue=`${totalVulns} vulnerability was detected.`;
+displayValue=`${totalVulns} vulnerability detected`;
 }
 
 const headings=[
@@ -4419,14 +4507,14 @@
 {key:'vulnCount',itemType:'text',text:'Vulnerability Count'},
 {key:'highestSeverity',itemType:'text',text:'Highest Severity'}];
 
-const details=Audit.makeTableDetails(headings,finalVulns);
+const details=Audit.makeTableDetails(headings,vulnerabilityResults,{});
 
 return{
 rawValue:totalVulns===0,
 displayValue,
 extendedInfo:{
-jsLibs:libraries,
-vulnerabilities:finalVulns},
+jsLibs:libraryVulns,
+vulnerabilities:vulnerabilityResults},
 
 details};
 
@@ -4435,7 +4523,7 @@
 
 module.exports=NoVulnerableLibrariesAudit;
 
-},{"../../../third-party/snyk/snapshot.json":147,"../../lib/sentry":33,"../audit":2,"semver":142}],"../audits/dobetterweb/no-websql":[function(require,module,exports){
+},{"../../../third-party/snyk/snapshot.json":155,"../../lib/sentry":39,"../audit":2,"semver":150}],"../audits/dobetterweb/no-websql":[function(require,module,exports){
 
 
 
@@ -4472,12 +4560,12 @@
 
 static audit(artifacts){
 const db=artifacts.WebSQL;
-const debugString=db?
-`Found database "${db.name}", version: ${db.version}.`:'';
+const displayValue=db?
+`Found "${db.name}" (v${db.version})`:'';
 
 return{
 rawValue:!db,
-debugString};
+displayValue};
 
 }}
 
@@ -4527,6 +4615,7 @@
 {key:'url',itemType:'url',text:'URL'},
 {key:'label',itemType:'text',text:'Location'}];
 
+
 const details=ViolationAudit.makeTableDetails(headings,results);
 
 return{
@@ -4561,7 +4650,7 @@
 description:'Allows users to paste into password fields',
 failureDescription:'Prevents users to paste into password fields',
 helpText:'Preventing password pasting undermines good security policy. '+
-'[Learn more](https://www.ncsc.gov.uk/blog-post/let-them-paste-passwords)',
+'[Learn more](https://www.ncsc.gov.uk/blog-post/let-them-paste-passwords).',
 requiredArtifacts:['PasswordInputsWithPreventedPaste']};
 
 }
@@ -4573,76 +4662,31 @@
 static audit(artifacts){
 const passwordInputsWithPreventedPaste=artifacts.PasswordInputsWithPreventedPaste;
 
+
+const items=[];
+passwordInputsWithPreventedPaste.forEach(input=>{
+items.push({
+node:{type:'node',snippet:input.snippet}});
+
+});
+
+const headings=[
+{key:'node',itemType:'node',text:'Failing Elements'}];
+
+
 return{
 rawValue:passwordInputsWithPreventedPaste.length===0,
 extendedInfo:{
 value:passwordInputsWithPreventedPaste},
 
-details:{
-type:'list',
-header:{
-type:'text',
-text:'Password inputs that prevent pasting into'},
-
-items:passwordInputsWithPreventedPaste.map(input=>({
-type:'text',
-text:input.snippet}))}};
-
-
+details:Audit.makeTableDetails(headings,items)};
 
 }}
 
 
 module.exports=PasswordInputsCanBePastedIntoAudit;
 
-},{"../audit":2}],"../audits/dobetterweb/script-blocking-first-paint":[function(require,module,exports){
-
-
-
-
-
-
-
-
-
-
-'use strict';
-
-const Audit=require('../audit');
-const LinkBlockingFirstPaintAudit=require('./link-blocking-first-paint');
-
-class ScriptBlockingFirstPaint extends Audit{
-
-
-
-static get meta(){
-return{
-name:'script-blocking-first-paint',
-description:'Reduce render-blocking scripts',
-informative:true,
-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).',
-requiredArtifacts:['TagsBlockingFirstPaint','traces']};
-
-}
-
-
-
-
-
-static audit(artifacts){
-const trace=artifacts.traces[Audit.DEFAULT_PASS];
-return artifacts.requestTraceOfTab(trace).then(traceOfTab=>{
-const fcpTsInMs=traceOfTab.timestamps.firstContentfulPaint/1000;
-return LinkBlockingFirstPaintAudit.computeAuditResultForTags(artifacts,'SCRIPT',fcpTsInMs);
-});
-}}
-
-
-module.exports=ScriptBlockingFirstPaint;
-
-},{"../audit":2,"./link-blocking-first-paint":"../audits/dobetterweb/link-blocking-first-paint"}],"../audits/dobetterweb/uses-http2":[function(require,module,exports){
+},{"../audit":2}],"../audits/dobetterweb/uses-http2":[function(require,module,exports){
 
 
 
@@ -4658,7 +4702,7 @@
 
 const URL=require('../../lib/url-shim');
 const Audit=require('../audit');
-const Util=require('../../report/v2/renderer/util.js');
+const Util=require('../../report/html/renderer/util.js');
 
 class UsesHTTP2Audit extends Audit{
 
@@ -4684,6 +4728,7 @@
 return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords=>{
 const finalHost=new URL(artifacts.URL.finalUrl).host;
 
+const seenURLs=new Set();
 
 const resources=networkRecords.filter(record=>{
 
@@ -4694,16 +4739,20 @@
 }).map(record=>{
 return{
 protocol:record.protocol,
-url:record.url};
+url:record._url};
 
+}).filter(record=>{
+if(seenURLs.has(record.url))return false;
+seenURLs.add(record.url);
+return true;
 });
 
 let displayValue='';
 if(resources.length>1){
 displayValue=
-`${Util.formatNumber(resources.length)} requests were not handled over HTTP/2`;
+`${Util.formatNumber(resources.length)} requests not served via HTTP/2`;
 }else if(resources.length===1){
-displayValue=`${resources.length} request was not handled over HTTP/2`;
+displayValue=`${resources.length} request not served via HTTP/2`;
 }
 
 const headings=[
@@ -4728,7 +4777,7 @@
 
 module.exports=UsesHTTP2Audit;
 
-},{"../../lib/url-shim":41,"../../report/v2/renderer/util.js":43,"../audit":2}],"../audits/dobetterweb/uses-passive-event-listeners":[function(require,module,exports){
+},{"../../lib/url-shim":"url","../../report/html/renderer/util.js":48,"../audit":2}],"../audits/dobetterweb/uses-passive-event-listeners":[function(require,module,exports){
 
 
 
@@ -4771,6 +4820,7 @@
 {key:'url',itemType:'url',text:'URL'},
 {key:'label',itemType:'text',text:'Location'}];
 
+
 const details=ViolationAudit.makeTableDetails(headings,results);
 
 return{
@@ -4822,6 +4872,7 @@
 static audit(artifacts){
 const consoleEntries=artifacts.ChromeConsoleMessages;
 const runtimeExceptions=artifacts.RuntimeExceptions;
+
 const consoleRows=
 consoleEntries.filter(log=>log.entry&&log.entry.level==='error').
 map(item=>{
@@ -4856,7 +4907,7 @@
 const numErrors=tableRows.length;
 
 return{
-score:numErrors===0,
+score:Number(numErrors===0),
 rawValue:numErrors,
 details};
 
@@ -4874,14 +4925,6 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
-const TracingProcessor=require('../lib/traces/tracing-processor');
-const LHError=require('../lib/errors');
-
-
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=50;
-const SCORING_MEDIAN=100;
 
 class EstimatedInputLatency extends Audit{
 
@@ -4892,24 +4935,25 @@
 name:'estimated-input-latency',
 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 '+
+'input, in milliseconds, during the busiest 5s window of page load. If your '+
 'latency is higher than 50 ms, users may perceive your app as laggy. '+
 '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency).',
-scoringMode:Audit.SCORING_MODES.NUMERIC,
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
 requiredArtifacts:['traces']};
 
 }
 
-static calculate(tabTrace){
-const startTime=tabTrace.timings.firstMeaningfulPaint;
-if(!startTime){
-throw new LHError(LHError.errors.NO_FMP);
+
+
+
+static get defaultOptions(){
+return{
+
+scorePODR:50,
+scoreMedian:100};
+
 }
 
-const latencyPercentiles=TracingProcessor.getRiskToResponsiveness(tabTrace,startTime);
-const ninetieth=latencyPercentiles.find(result=>result.percentile===0.9);
-const rawValue=parseFloat(ninetieth.time.toFixed(1));
 
 
 
@@ -4917,39 +4961,28 @@
 
 
 
-const score=Audit.computeLogNormalScore(
-ninetieth.time,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN);
 
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await artifacts.requestEstimatedInputLatency(metricComputationData);
 
 return{
-score,
-rawValue,
-displayValue:Util.formatMilliseconds(rawValue,1),
-extendedInfo:{
-value:latencyPercentiles}};
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
 
+rawValue:metricResult.timing,
+displayValue:['%d\xa0ms',metricResult.timing]};
 
-}
-
-
-
-
-
-
-
-static audit(artifacts){
-const trace=artifacts.traces[this.DEFAULT_PASS];
-
-return artifacts.requestTraceOfTab(trace).
-then(EstimatedInputLatency.calculate);
 }}
 
 
 module.exports=EstimatedInputLatency;
 
-},{"../lib/errors":28,"../lib/traces/tracing-processor":40,"../report/v2/renderer/util":43,"./audit":2}],"../audits/first-interactive":[function(require,module,exports){
+},{"./audit":2}],"../audits/first-contentful-paint":[function(require,module,exports){
 
 
 
@@ -4958,25 +4991,84 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util.js');
+const Util=require('../report/html/renderer/util.js');
 
-
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=1700;
-const SCORING_MEDIAN=10000;
-
-class FirstInteractiveMetric extends Audit{
+class FirstContentfulPaint extends Audit{
 
 
 
 static get meta(){
 return{
-name:'first-interactive',
-description:'First Interactive (beta)',
-helpText:'First Interactive marks the time at which the page is '+
-'minimally interactive. '+
+name:'first-contentful-paint',
+description:'First Contentful Paint',
+helpText:'First contentful paint marks the time at which the first text/image is painted. '+
+`[Learn more](https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics#first_paint_and_first_contentful_paint).`,
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:2900,
+scoreMedian:4000};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await artifacts.requestFirstContentfulPaint(metricComputationData);
+
+return{
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
+
+rawValue:metricResult.timing,
+displayValue:[Util.MS_DISPLAY_VALUE,metricResult.timing]};
+
+}}
+
+
+module.exports=FirstContentfulPaint;
+
+},{"../report/html/renderer/util.js":48,"./audit":2}],"../audits/first-cpu-idle":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const Util=require('../report/html/renderer/util.js');
+
+class FirstCPUIdle extends Audit{
+
+
+
+static get meta(){
+return{
+name:'first-cpu-idle',
+description:'First CPU Idle',
+helpText:'First CPU Idle marks the first time at which the page\'s main thread is '+
+'quiet enough to handle input. '+
 '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-interactive).',
-scoringMode:Audit.SCORING_MODES.NUMERIC,
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
 requiredArtifacts:['traces']};
 
 }
@@ -4984,33 +5076,45 @@
 
 
 
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:2900,
+scoreMedian:6500};
+
+}
+
+
+
+
 
 
 
 
-static audit(artifacts){
+
+static async audit(artifacts,context){
 const trace=artifacts.traces[Audit.DEFAULT_PASS];
-return artifacts.requestFirstInteractive(trace).
-then(firstInteractive=>{
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await artifacts.requestFirstCPUIdle(metricComputationData);
+
 return{
 score:Audit.computeLogNormalScore(
-firstInteractive.timeInMs,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN),
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
 
-rawValue:firstInteractive.timeInMs,
-displayValue:Util.formatMilliseconds(firstInteractive.timeInMs),
-extendedInfo:{
-value:firstInteractive}};
+rawValue:metricResult.timing,
+displayValue:[Util.MS_DISPLAY_VALUE,metricResult.timing]};
 
-
-});
 }}
 
 
-module.exports=FirstInteractiveMetric;
+module.exports=FirstCPUIdle;
 
-},{"../report/v2/renderer/util.js":43,"./audit":2}],"../audits/first-meaningful-paint":[function(require,module,exports){
+},{"../report/html/renderer/util.js":48,"./audit":2}],"../audits/first-meaningful-paint":[function(require,module,exports){
 
 
 
@@ -5019,14 +5123,7 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
-const LHError=require('../lib/errors');
-
-
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=1600;
-const SCORING_MEDIAN=4000;
-
+const Util=require('../report/html/renderer/util');
 
 class FirstMeaningfulPaint extends Audit{
 
@@ -5035,10 +5132,10 @@
 static get meta(){
 return{
 name:'first-meaningful-paint',
-description:'First meaningful paint',
-helpText:'First meaningful paint measures when the primary content of a page is visible. '+
+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).',
-scoringMode:Audit.SCORING_MODES.NUMERIC,
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
 requiredArtifacts:['traces']};
 
 }
@@ -5046,90 +5143,45 @@
 
 
 
+static get defaultOptions(){
+return{
 
 
 
+scorePODR:2000,
+scoreMedian:4000};
 
-static audit(artifacts){
-const trace=artifacts.traces[this.DEFAULT_PASS];
-return artifacts.requestTraceOfTab(trace).then(tabTrace=>{
-if(!tabTrace.firstMeaningfulPaintEvt){
-throw new LHError(LHError.errors.NO_FMP);
 }
 
 
 
-if(!tabTrace.navigationStartEvt){
-throw new LHError(LHError.errors.NO_NAVSTART);
-}
 
-const result=this.calculateScore(tabTrace);
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await artifacts.requestFirstMeaningfulPaint(metricComputationData);
 
 return{
-score:result.score,
-rawValue:parseFloat(result.duration),
-displayValue:Util.formatMilliseconds(result.duration),
-debugString:result.debugString,
-extendedInfo:{
-value:result.extendedInfo}};
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
 
-
-});
-}
-
-static calculateScore(traceOfTab){
-
-const extendedInfo={
-timestamps:{
-navStart:traceOfTab.timestamps.navigationStart,
-fCP:traceOfTab.timestamps.firstContentfulPaint,
-fMP:traceOfTab.timestamps.firstMeaningfulPaint,
-onLoad:traceOfTab.timestamps.onLoad,
-endOfTrace:traceOfTab.timestamps.traceEnd},
-
-timings:{
-navStart:0,
-fCP:traceOfTab.timings.firstContentfulPaint,
-fMP:traceOfTab.timings.firstMeaningfulPaint,
-onLoad:traceOfTab.timings.onLoad,
-endOfTrace:traceOfTab.timings.traceEnd},
-
-fmpFellBack:traceOfTab.fmpFellBack};
-
-
-Object.keys(extendedInfo.timings).forEach(key=>{
-const val=extendedInfo.timings[key];
-if(typeof val!=='number'||Number.isNaN(val)){
-extendedInfo.timings[key]=undefined;
-extendedInfo.timestamps[key]=undefined;
-}else{
-extendedInfo.timings[key]=parseFloat(extendedInfo.timings[key].toFixed(3));
-}
-});
-
-
-
-
-
-const firstMeaningfulPaint=traceOfTab.timings.firstMeaningfulPaint;
-const score=Audit.computeLogNormalScore(
-firstMeaningfulPaint,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN);
-
-
-return{
-score,
-duration:firstMeaningfulPaint.toFixed(1),
-rawValue:firstMeaningfulPaint,
-extendedInfo};
+rawValue:metricResult.timing,
+displayValue:[Util.MS_DISPLAY_VALUE,metricResult.timing]};
 
 }}
 
 
 module.exports=FirstMeaningfulPaint;
 
-},{"../lib/errors":28,"../report/v2/renderer/util":43,"./audit":2}],"../audits/font-display":[function(require,module,exports){
+},{"../report/html/renderer/util":48,"./audit":2}],"../audits/font-display":[function(require,module,exports){
 
 
 
@@ -5138,7 +5190,6 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
 const WebInspector=require('../lib/web-inspector');
 const allowedFontFaceDisplays=['block','fallback','optional','swap'];
 
@@ -5150,7 +5201,7 @@
 return{
 name:'font-display',
 description:'All text remains visible during webfont loads',
-failureDescription:'Avoid invisible text while webfonts are loading',
+failureDescription:'Text is invisible while webfonts are loading',
 helpText:'Leverage the font-display CSS feature to ensure text is user-visible while '+
 'webfonts are loading. '+
 '[Learn more](https://developers.google.com/web/updates/2016/02/font-display).',
@@ -5180,29 +5231,29 @@
 filter(fontRecord=>{
 
 return!!fontsWithoutProperDisplay.find(fontFace=>{
-return fontFace.src.find(src=>fontRecord.url===src);
+return!!fontFace.src&&!!fontFace.src.find(src=>fontRecord.url===src);
 });
 }).
 
 map(record=>{
 
 
-const wastedTime=Math.min((record._endTime-record._startTime)*1000,3000);
+const wastedTime=Math.min((record.endTime-record.startTime)*1000,3000);
 
 return{
 url:record.url,
-wastedTime:Util.formatMilliseconds(wastedTime,1)};
+wastedTime};
 
 });
 
 const headings=[
 {key:'url',itemType:'url',text:'Font URL'},
-{key:'wastedTime',itemType:'text',text:'Font download time'}];
+{key:'wastedTime',itemType:'ms',granularity:1,text:'Font download time'}];
 
 const details=Audit.makeTableDetails(headings,results);
 
 return{
-score:results.length===0,
+score:Number(results.length===0),
 rawValue:results.length===0,
 details};
 
@@ -5212,7 +5263,7 @@
 
 module.exports=FontDisplay;
 
-},{"../lib/web-inspector":42,"../report/v2/renderer/util":43,"./audit":2}],"../audits/image-aspect-ratio":[function(require,module,exports){
+},{"../lib/web-inspector":47,"./audit":2}],"../audits/image-aspect-ratio":[function(require,module,exports){
 
 
 
@@ -5231,6 +5282,8 @@
 const URL=require('../lib/url-shim');
 const THRESHOLD=0.05;
 
+
+
 class ImageAspectRatio extends Audit{
 
 
@@ -5262,11 +5315,6 @@
 
 return{
 url,
-preview:{
-type:'thumbnail',
-url:image.networkRecord.url,
-mimeType:image.networkRecord.mimeType},
-
 displayedAspectRatio:`${image.width} x ${image.height}
         (${displayedAspectRatio.toFixed(2)})`,
 actualAspectRatio:`${image.naturalWidth} x ${image.naturalHeight}
@@ -5282,7 +5330,9 @@
 static audit(artifacts){
 const images=artifacts.ImageUsage;
 
-let debugString;
+
+const warnings=[];
+
 const results=[];
 images.filter(image=>{
 
@@ -5294,9 +5344,10 @@
 image.height&&
 !image.usesObjectFit;
 }).forEach(image=>{
-const processed=ImageAspectRatio.computeAspectRatios(image);
+const wellDefinedImage=image;
+const processed=ImageAspectRatio.computeAspectRatios(wellDefinedImage);
 if(processed instanceof Error){
-debugString=processed.message;
+warnings.push(processed.message);
 return;
 }
 
@@ -5304,7 +5355,7 @@
 });
 
 const headings=[
-{key:'preview',itemType:'thumbnail',text:''},
+{key:'url',itemType:'thumbnail',text:''},
 {key:'url',itemType:'url',text:'URL'},
 {key:'displayedAspectRatio',itemType:'text',text:'Aspect Ratio (Displayed)'},
 {key:'actualAspectRatio',itemType:'text',text:'Aspect Ratio (Actual)'}];
@@ -5312,7 +5363,7 @@
 
 return{
 rawValue:results.length===0,
-debugString,
+warnings,
 details:Audit.makeTableDetails(headings,results)};
 
 }}
@@ -5320,7 +5371,89 @@
 
 module.exports=ImageAspectRatio;
 
-},{"../lib/url-shim":41,"./audit":2}],"../audits/is-on-https":[function(require,module,exports){
+},{"../lib/url-shim":"url","./audit":2}],"../audits/interactive":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const Util=require('../report/html/renderer/util');
+
+
+
+
+
+
+
+class InteractiveMetric extends Audit{
+
+
+
+static get meta(){
+return{
+name:'interactive',
+description:'Time to Interactive',
+helpText:'Interactive marks the time at which the page is fully interactive. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).',
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+static get defaultOptions(){
+return{
+
+
+
+scorePODR:2900,
+scoreMedian:7300};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await artifacts.requestInteractive(metricComputationData);
+const timeInMs=metricResult.timing;
+const extendedInfo={
+timeInMs,
+timestamp:metricResult.timestamp,
+
+optimistic:metricResult.optimisticEstimate&&metricResult.optimisticEstimate.timeInMs,
+
+pessimistic:metricResult.pessimisticEstimate&&metricResult.pessimisticEstimate.timeInMs};
+
+
+return{
+score:Audit.computeLogNormalScore(
+timeInMs,
+context.options.scorePODR,
+context.options.scoreMedian),
+
+rawValue:timeInMs,
+displayValue:[Util.MS_DISPLAY_VALUE,timeInMs],
+extendedInfo:{
+value:extendedInfo}};
+
+
+}}
+
+
+module.exports=InteractiveMetric;
+
+},{"../report/html/renderer/util":48,"./audit":2}],"../audits/is-on-https":[function(require,module,exports){
 
 
 
@@ -5330,9 +5463,9 @@
 
 const Audit=require('./audit');
 const URL=require('../lib/url-shim');
-const Util=require('../report/v2/renderer/util');
+const Util=require('../report/html/renderer/util');
 
-const SECURE_SCHEMES=['data','https','wss','blob','chrome','chrome-extension'];
+const SECURE_SCHEMES=['data','https','wss','blob','chrome','chrome-extension','about'];
 const SECURE_DOMAINS=['localhost','127.0.0.1'];
 
 class HTTPS extends Audit{
@@ -5358,9 +5491,9 @@
 
 
 static isSecureRecord(record){
-return SECURE_SCHEMES.includes(record.scheme)||
+return SECURE_SCHEMES.includes(record.parsedURL.scheme)||
 SECURE_SCHEMES.includes(record.protocol)||
-SECURE_DOMAINS.includes(record.domain);
+SECURE_DOMAINS.includes(record.parsedURL.host);
 }
 
 
@@ -5370,28 +5503,30 @@
 static audit(artifacts){
 const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
 return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords=>{
-const insecureRecords=networkRecords.
+const insecureURLs=networkRecords.
 filter(record=>!HTTPS.isSecureRecord(record)).
-map(record=>({url:URL.elideDataURI(record.url)}));
+map(record=>URL.elideDataURI(record.url));
 
 let displayValue='';
-if(insecureRecords.length>1){
-displayValue=`${Util.formatNumber(insecureRecords.length)} insecure requests found`;
-}else if(insecureRecords.length===1){
-displayValue=`${insecureRecords.length} insecure request found`;
+if(insecureURLs.length>1){
+displayValue=`${Util.formatNumber(insecureURLs.length)} insecure requests found`;
+}else if(insecureURLs.length===1){
+displayValue=`${insecureURLs.length} insecure request found`;
 }
 
+const items=Array.from(new Set(insecureURLs)).map(url=>({url}));
+
+const headings=[
+{key:'url',itemType:'url',text:'Insecure URL'}];
+
+
 return{
-rawValue:insecureRecords.length===0,
+rawValue:items.length===0,
 displayValue,
 extendedInfo:{
-value:insecureRecords},
+value:items},
 
-details:{
-type:'list',
-header:{type:'text',text:'Insecure URLs:'},
-items:insecureRecords.map(record=>({type:'url',text:record.url}))}};
-
+details:Audit.makeTableDetails(headings,items)};
 
 });
 }}
@@ -5399,7 +5534,7 @@
 
 module.exports=HTTPS;
 
-},{"../lib/url-shim":41,"../report/v2/renderer/util":43,"./audit":2}],"../audits/load-fast-enough-for-pwa":[function(require,module,exports){
+},{"../lib/url-shim":"url","../report/html/renderer/util":48,"./audit":2}],"../audits/load-fast-enough-for-pwa":[function(require,module,exports){
 
 
 
@@ -5413,17 +5548,13 @@
 
 
 
+const isDeepEqual=require('lodash.isequal');
 const Audit=require('./audit');
-const URL=require('../lib/url-shim');
-const Emulation=require('../lib/emulation');
-const Sentry=require('../lib/sentry');
-const Util=require('../report/v2/renderer/util.js');
+const mobile3GThrottling=require('../config/constants').throttling.mobile3G;
 
 
 
-const MAXIMUM_TTFI=10*1000;
-
-const WHITELISTED_STATUS_CODES=[307];
+const MAXIMUM_TTI=10*1000;
 
 class LoadFastEnough4Pwa extends Audit{
 
@@ -5434,7 +5565,8 @@
 name:'load-fast-enough-for-pwa',
 description:'Page load is fast enough on 3G',
 failureDescription:'Page load is not fast enough on 3G',
-helpText:'A fast page load over a 3G network ensures a good mobile user experience. '+
+helpText:
+'A fast page load over a 3G network ensures a good mobile user experience. '+
 '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/fast-3g).',
 requiredArtifacts:['traces','devtoolsLogs']};
 
@@ -5444,112 +5576,48 @@
 
 
 
-static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-return artifacts.requestNetworkRecords(devtoolsLogs).then(networkRecords=>{
-const firstRequestLatenciesByOrigin=new Map();
-networkRecords.forEach(record=>{
 
-
-const fromCache=record._fromDiskCache||record._fromMemoryCache;
-const origin=URL.getOrigin(record._url);
-if(!origin||!record._timing||fromCache||
-WHITELISTED_STATUS_CODES.includes(record.statusCode)||!record.finished){
-return;
-}
-
-
-
-if(record._startTime<record._issueTime){
-return;
-}
-
-
-const latency=record._timing.receiveHeadersEnd-record._timing.sendEnd;
-const latencyInfo={
-url:record._url,
-startTime:record._startTime,
-origin,
-latency};
-
-
-
-
-const existing=firstRequestLatenciesByOrigin.get(origin);
-if(!existing||latencyInfo.startTime<existing.startTime){
-firstRequestLatenciesByOrigin.set(origin,latencyInfo);
-}
-});
-
-let firstRequestLatencies=Array.from(firstRequestLatenciesByOrigin.values());
-const latency3gMin=Emulation.settings.TYPICAL_MOBILE_THROTTLING_METRICS.targetLatency-10;
-const areLatenciesAll3G=firstRequestLatencies.every(val=>val.latency>latency3gMin);
-firstRequestLatencies=firstRequestLatencies.map(item=>({
-url:item.url,
-latency:Util.formatNumber(item.latency,2)}));
-
-
+static async audit(artifacts,context){
 const trace=artifacts.traces[Audit.DEFAULT_PASS];
-return artifacts.requestFirstInteractive(trace).then(firstInteractive=>{
-const timeToFirstInteractive=firstInteractive.timeInMs;
-const isFast=timeToFirstInteractive<MAXIMUM_TTFI;
-
-const extendedInfo={
-value:{areLatenciesAll3G,firstRequestLatencies,isFast,timeToFirstInteractive}};
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
 
 
-const details=Audit.makeTableDetails([
-{key:'url',itemType:'url',text:'URL'},
-{key:'latency',itemType:'text',text:'Latency (ms)'}],
-firstRequestLatencies);
 
-if(!isFast){
-return{
-rawValue:false,
+const settingOverrides={throttlingMethod:'simulate',throttling:mobile3GThrottling};
+const settings=
+context.settings.throttlingMethod!=='provided'&&
+isDeepEqual(context.settings.throttling,mobile3GThrottling)?
+context.settings:
+Object.assign({},context.settings,settingOverrides);
 
-debugString:`First Interactive was at ${Util.formatMilliseconds(timeToFirstInteractive)}. More details in the "Performance" section.`,
-extendedInfo};
+const metricComputationData={trace,devtoolsLog,settings};
+const tti=await artifacts.requestInteractive(metricComputationData);
 
-}
-
-if(!areLatenciesAll3G){
-const sentryContext=Sentry.getContext();
-const hadThrottlingEnabled=sentryContext&&sentryContext.extra&&
-sentryContext.extra.networkThrottling;
-
-if(hadThrottlingEnabled){
+const score=Number(tti.timing<MAXIMUM_TTI);
 
 
-const violatingLatency=firstRequestLatencies.
-find(item=>Number(item.latency)<latency3gMin);
-Sentry.captureMessage('Network request latencies were not realistic',{
-tags:{audit:this.meta.name},
-extra:{violatingLatency},
-level:'warning'});
+let displayValue;
 
+let explanation;
+if(!score){
+displayValue=[`Interactive at %d\xa0s`,tti.timing/1000];
+explanation='Your page loads too slowly and is not interactive within 10 seconds. '+
+'Look at the opportunities and diagnostics in the "Performance" section to learn how to '+
+'improve.';
 }
 
 return{
-rawValue:true,
+score,
+displayValue,
+explanation,
+rawValue:tti.timing};
 
-debugString:`First Interactive was found at ${Util.formatMilliseconds(timeToFirstInteractive)}; however, the network request latencies were not sufficiently realistic, so the performance measurements cannot be trusted.`,
-extendedInfo,
-details};
-
-}
-
-return{
-rawValue:true,
-extendedInfo};
-
-});
-});
 }}
 
 
 module.exports=LoadFastEnough4Pwa;
 
-},{"../lib/emulation":27,"../lib/sentry":33,"../lib/url-shim":41,"../report/v2/renderer/util.js":43,"./audit":2}],"../audits/mainthread-work-breakdown":[function(require,module,exports){
+},{"../config/constants":8,"./audit":2,"lodash.isequal":144}],"../audits/mainthread-work-breakdown":[function(require,module,exports){
 
 
 
@@ -5563,21 +5631,21 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
+const Util=require('../report/html/renderer/util');
 
 const{taskToGroup}=require('../lib/task-groups');
 
-class PageExecutionTimings extends Audit{
+class MainThreadWorkBreakdown extends Audit{
 
 
 
 static get meta(){
 return{
-category:'Performance',
 name:'mainthread-work-breakdown',
-description:'Main thread work breakdown',
-informative:true,
-helpText:'Consider reducing the time spent parsing, compiling and executing JS.'+
+description:'Minimizes main thread work',
+failureDescription:'Has significant main thread work',
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+helpText:'Consider reducing the time spent parsing, compiling and executing JS. '+
 'You may find delivering smaller JS payloads helps with this.',
 requiredArtifacts:['traces']};
 
@@ -5586,6 +5654,17 @@
 
 
 
+static get defaultOptions(){
+return{
+
+scorePODR:1500,
+scoreMedian:4000};
+
+}
+
+
+
+
 
 static getExecutionTimingsByCategory(timelineModel){
 const bottomUpByName=timelineModel.bottomUpGroupBy('EventName');
@@ -5601,19 +5680,24 @@
 
 
 
-static audit(artifacts){
-const trace=artifacts.traces[PageExecutionTimings.DEFAULT_PASS];
 
-return artifacts.requestDevtoolsTimelineModel(trace).
-then(devtoolsTimelineModel=>{
-const executionTimings=PageExecutionTimings.getExecutionTimingsByCategory(
+static async audit(artifacts,context){
+const settings=context.settings||{};
+const trace=artifacts.traces[MainThreadWorkBreakdown.DEFAULT_PASS];
+
+const devtoolsTimelineModel=await artifacts.requestDevtoolsTimelineModel(trace);
+const executionTimings=MainThreadWorkBreakdown.getExecutionTimingsByCategory(
 devtoolsTimelineModel);
 
 let totalExecutionTime=0;
 
+const multiplier=settings.throttlingMethod==='simulate'?
+settings.throttling.cpuSlowdownMultiplier:1;
+
 const extendedInfo={};
 const categoryTotals={};
 const results=Array.from(executionTimings).map(([eventName,duration])=>{
+duration*=multiplier;
 totalExecutionTime+=duration;
 extendedInfo[eventName]=duration;
 const groupName=taskToGroup[eventName];
@@ -5624,34 +5708,40 @@
 return{
 category:eventName,
 group:groupName,
-duration:Util.formatMilliseconds(duration,1)};
+duration:duration};
 
 });
 
 const headings=[
 {key:'group',itemType:'text',text:'Category'},
 {key:'category',itemType:'text',text:'Work'},
-{key:'duration',itemType:'text',text:'Time spent'}];
+{key:'duration',itemType:'ms',granularity:1,text:'Time spent'}];
+
 
 results.stableSort((a,b)=>categoryTotals[b.group]-categoryTotals[a.group]);
-const tableDetails=PageExecutionTimings.makeTableDetails(headings,results);
+const tableDetails=MainThreadWorkBreakdown.makeTableDetails(headings,results);
+
+const score=Audit.computeLogNormalScore(
+totalExecutionTime,
+context.options.scorePODR,
+context.options.scoreMedian);
+
 
 return{
-score:totalExecutionTime<3000,
+score,
 rawValue:totalExecutionTime,
-displayValue:Util.formatMilliseconds(totalExecutionTime),
+displayValue:[Util.MS_DISPLAY_VALUE,totalExecutionTime],
 details:tableDetails,
 extendedInfo:{
 value:extendedInfo}};
 
 
-});
 }}
 
 
-module.exports=PageExecutionTimings;
+module.exports=MainThreadWorkBreakdown;
 
-},{"../lib/task-groups":36,"../report/v2/renderer/util":43,"./audit":2}],"../audits/manifest-short-name-length":[function(require,module,exports){
+},{"../lib/task-groups":42,"../report/html/renderer/util":48,"./audit":2}],"../audits/manifest-short-name-length":[function(require,module,exports){
 
 
 
@@ -5690,17 +5780,17 @@
 
 }
 
-const hasShortName=manifestValues.allChecks.find(i=>i.id==='hasShortName').passing;
-if(!hasShortName){
+const hasShortName=manifestValues.allChecks.find(i=>i.id==='hasShortName');
+if(!hasShortName||!hasShortName.passing){
 return{
 rawValue:false,
-debugString:'No short_name found in manifest.'};
+explanation:'No short_name found in manifest.'};
 
 }
 
-const isShortEnough=manifestValues.allChecks.find(i=>i.id==='shortNameLength').passing;
+const isShortEnough=manifestValues.allChecks.find(i=>i.id==='shortNameLength');
 return{
-rawValue:isShortEnough};
+rawValue:!!isShortEnough&&isShortEnough.passing};
 
 });
 }}
@@ -5733,7 +5823,7 @@
 helpText:'To reach the most number of users, sites should work across '+
 'every major browser. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#site-works-cross-browser).',
 description:'Site works cross-browser'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -5763,7 +5853,7 @@
 helpText:'Ensure individual pages are deep linkable via the URLs and that URLs are '+
 'unique for the purpose of shareability on social media. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#each-page-has-a-url).',
 description:'Each page has a URL'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -5793,13 +5883,156 @@
 helpText:'Transitions should feel snappy as you tap around, even on a slow network, a key '+
 'to perceived performance. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist#page-transitions-dont-feel-like-they-block-on-the-network).',
 description:'Page transitions don\'t feel like they block on the network'},
-super.meta);
+super.partialMeta);
 }}
 
 
 module.exports=PWAPageTransitions;
 
-},{"./manual-audit":4}],"../audits/mixed-content":[function(require,module,exports){
+},{"./manual-audit":4}],"../audits/metrics":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+
+class Metrics extends Audit{
+
+
+
+static get meta(){
+return{
+name:'metrics',
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
+description:'Metrics',
+helpText:'Collects all available metrics.',
+requiredArtifacts:['traces','devtoolsLogs']};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+
+const traceOfTab=await artifacts.requestTraceOfTab(trace);
+const speedline=await artifacts.requestSpeedline(trace);
+const firstContentfulPaint=await artifacts.requestFirstContentfulPaint(metricComputationData);
+const firstMeaningfulPaint=await artifacts.requestFirstMeaningfulPaint(metricComputationData);
+const firstCPUIdle=await artifacts.requestFirstCPUIdle(metricComputationData);
+const interactive=await artifacts.requestInteractive(metricComputationData);
+const speedIndex=await artifacts.requestSpeedIndex(metricComputationData);
+const estimatedInputLatency=await artifacts.requestEstimatedInputLatency(metricComputationData);
+
+
+const metrics={
+
+firstContentfulPaint:firstContentfulPaint.timing,
+firstContentfulPaintTs:firstContentfulPaint.timestamp,
+firstMeaningfulPaint:firstMeaningfulPaint.timing,
+firstMeaningfulPaintTs:firstMeaningfulPaint.timestamp,
+firstCPUIdle:firstCPUIdle.timing,
+firstCPUIdleTs:firstCPUIdle.timestamp,
+interactive:interactive.timing,
+interactiveTs:interactive.timestamp,
+speedIndex:speedIndex.timing,
+speedIndexTs:speedIndex.timestamp,
+estimatedInputLatency:estimatedInputLatency.timing,
+estimatedInputLatencyTs:estimatedInputLatency.timestamp,
+
+
+observedNavigationStart:traceOfTab.timings.navigationStart,
+observedNavigationStartTs:traceOfTab.timestamps.navigationStart,
+observedFirstPaint:traceOfTab.timings.firstPaint,
+observedFirstPaintTs:traceOfTab.timestamps.firstPaint,
+observedFirstContentfulPaint:traceOfTab.timings.firstContentfulPaint,
+observedFirstContentfulPaintTs:traceOfTab.timestamps.firstContentfulPaint,
+observedFirstMeaningfulPaint:traceOfTab.timings.firstMeaningfulPaint,
+observedFirstMeaningfulPaintTs:traceOfTab.timestamps.firstMeaningfulPaint,
+observedTraceEnd:traceOfTab.timings.traceEnd,
+observedTraceEndTs:traceOfTab.timestamps.traceEnd,
+observedLoad:traceOfTab.timings.load,
+observedLoadTs:traceOfTab.timestamps.load,
+observedDomContentLoaded:traceOfTab.timings.domContentLoaded,
+observedDomContentLoadedTs:traceOfTab.timestamps.domContentLoaded,
+
+
+observedFirstVisualChange:speedline.first,
+observedFirstVisualChangeTs:(speedline.first+speedline.beginning)*1000,
+observedLastVisualChange:speedline.complete,
+observedLastVisualChangeTs:(speedline.complete+speedline.beginning)*1000,
+observedSpeedIndex:speedline.speedIndex,
+observedSpeedIndexTs:(speedline.speedIndex+speedline.beginning)*1000};
+
+
+for(const[name,value]of Object.entries(metrics)){
+const key=name;
+if(typeof value!=='undefined'){
+metrics[key]=Math.round(value);
+}
+}
+
+
+const details={items:[metrics]};
+
+return{
+score:1,
+rawValue:interactive.timing,
+details};
+
+}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+module.exports=Metrics;
+
+},{"./audit":2}],"../audits/mixed-content":[function(require,module,exports){
+
 
 
 
@@ -5809,7 +6042,7 @@
 
 const Audit=require('./audit');
 const URL=require('../lib/url-shim');
-const Util=require('../report/v2/renderer/util');
+const Util=require('../report/html/renderer/util');
 
 
 
@@ -5823,10 +6056,8 @@
 
 static get meta(){
 return{
-category:'Mixed Content',
 name:'mixed-content',
 description:'All resources loaded are secure',
-informative:true,
 failureDescription:'Some insecure resources can be upgraded to HTTPS',
 helpText:`Mixed content warnings can prevent you from upgrading to HTTPS.
       This audit shows which insecure resources this page uses that can be
@@ -5949,12 +6180,11 @@
 const details=Audit.makeTableDetails(headings,upgradeableResources);
 
 const totalRecords=defaultRecords.length;
-const score=100*(
-secureRecords.length+0.5*upgradeableResources.length)/
-totalRecords;
+const score=(secureRecords.length+0.5*upgradeableResources.length)/totalRecords;
 
 return{
-rawValue:score,
+rawValue:upgradeableResources.length===0,
+score,
 displayValue:displayValue,
 details};
 
@@ -5964,7 +6194,7 @@
 
 module.exports=MixedContent;
 
-},{"../lib/url-shim":41,"../report/v2/renderer/util":43,"./audit":2}],"../audits/predictive-perf":[function(require,module,exports){
+},{"../lib/url-shim":"url","../report/html/renderer/util":48,"./audit":2}],"../audits/network-requests":[function(require,module,exports){
 
 
 
@@ -5973,37 +6203,92 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util.js');
-const LoadSimulator=require('../lib/dependency-graph/simulator/simulator.js');
-const Node=require('../lib/dependency-graph/node.js');
-const WebInspector=require('../lib/web-inspector');
+const URL=require('../lib/url-shim');
+
+class NetworkRequests extends Audit{
+
+
+
+static get meta(){
+return{
+name:'network-requests',
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
+description:'Network Requests',
+helpText:'Lists the network requests that were made during page load.',
+requiredArtifacts:['devtoolsLogs']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+return artifacts.requestNetworkRecords(devtoolsLog).then(records=>{
+const earliestStartTime=records.reduce(
+(min,record)=>Math.min(min,record.startTime),
+Infinity);
+
+
+const results=records.map(record=>{
+return{
+url:URL.elideDataURI(record.url),
+startTime:(record.startTime-earliestStartTime)*1000,
+endTime:(record.endTime-earliestStartTime)*1000,
+transferSize:record.transferSize,
+statusCode:record.statusCode,
+mimeType:record._mimeType,
+resourceType:record._resourceType&&record._resourceType._name};
+
+});
+
+const headings=[
+{key:'url',itemType:'url',text:'URL'},
+{key:'startTime',itemType:'ms',granularity:1,text:'Start Time'},
+{key:'endTime',itemType:'ms',granularity:1,text:'End Time'},
+{
+key:'transferSize',
+itemType:'bytes',
+displayUnit:'kb',
+granularity:1,
+text:'Transfer Size'},
+
+{key:'statusCode',itemType:'text',text:'Status Code'},
+{key:'mimeType',itemType:'text',text:'MIME Type'},
+{key:'resourceType',itemType:'text',text:'Resource Type'}];
+
+
+const tableDetails=Audit.makeTableDetails(headings,results);
+
+return{
+score:1,
+rawValue:results.length,
+extendedInfo:{value:results},
+details:tableDetails};
+
+});
+}}
+
+
+module.exports=NetworkRequests;
+
+},{"../lib/url-shim":"url","./audit":2}],"../audits/predictive-perf":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
+const Util=require('../report/html/renderer/util');
 
 
 
 const SCORING_POINT_OF_DIMINISHING_RETURNS=1700;
 const SCORING_MEDIAN=10000;
 
-
-const CRITICAL_LONG_TASK_THRESHOLD=20;
-
-const COEFFICIENTS={
-FCP:{
-intercept:1440,
-optimistic:-1.75,
-pessimistic:2.73},
-
-FMP:{
-intercept:1532,
-optimistic:-.30,
-pessimistic:1.33},
-
-TTCI:{
-intercept:1582,
-optimistic:.97,
-pessimistic:.49}};
-
-
-
 class PredictivePerf extends Audit{
 
 
@@ -6015,7 +6300,7 @@
 helpText:
 'Predicted performance evaluates how your site will perform under '+
 'a 3G connection on a mobile device.',
-scoringMode:Audit.SCORING_MODES.NUMERIC,
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
 requiredArtifacts:['traces','devtoolsLogs']};
 
 }
@@ -6024,223 +6309,63 @@
 
 
 
-
-static getScriptUrls(dependencyGraph,condition){
-const scriptUrls=new Set();
-
-dependencyGraph.traverse(node=>{
-if(node.type===Node.TYPES.CPU)return;
-if(node.record._resourceType!==WebInspector.resourceTypes.Script)return;
-if(condition&&!condition(node))return;
-scriptUrls.add(node.record.url);
-});
-
-return scriptUrls;
-}
-
-
-
-
-
-
-static getOptimisticFCPGraph(dependencyGraph,traceOfTab){
-const fcp=traceOfTab.timestamps.firstContentfulPaint;
-const blockingScriptUrls=PredictivePerf.getScriptUrls(dependencyGraph,node=>{
-return(
-node.endTime<=fcp&&node.hasRenderBlockingPriority()&&node.initiatorType!=='script');
-
-});
-
-return dependencyGraph.cloneWithRelationships(node=>{
-if(node.endTime>fcp)return false;
-
-if(node.type===Node.TYPES.CPU)return node.isEvaluateScriptFor(blockingScriptUrls);
-
-return node.hasRenderBlockingPriority()&&node.initiatorType!=='script';
-});
-}
-
-
-
-
-
-
-static getPessimisticFCPGraph(dependencyGraph,traceOfTab){
-const fcp=traceOfTab.timestamps.firstContentfulPaint;
-const blockingScriptUrls=PredictivePerf.getScriptUrls(dependencyGraph,node=>{
-return node.endTime<=fcp&&node.hasRenderBlockingPriority();
-});
-
-return dependencyGraph.cloneWithRelationships(node=>{
-if(node.endTime>fcp)return false;
-
-if(node.type===Node.TYPES.CPU)return node.isEvaluateScriptFor(blockingScriptUrls);
-
-return node.hasRenderBlockingPriority();
-});
-}
-
-
-
-
-
-
-static getOptimisticFMPGraph(dependencyGraph,traceOfTab){
-const fmp=traceOfTab.timestamps.firstMeaningfulPaint;
-const requiredScriptUrls=PredictivePerf.getScriptUrls(dependencyGraph,node=>{
-return(
-node.endTime<=fmp&&node.hasRenderBlockingPriority()&&node.initiatorType!=='script');
-
-});
-
-return dependencyGraph.cloneWithRelationships(node=>{
-if(node.endTime>fmp)return false;
-
-if(node.type===Node.TYPES.CPU)return node.isEvaluateScriptFor(requiredScriptUrls);
-
-return node.hasRenderBlockingPriority()&&node.initiatorType!=='script';
-});
-}
-
-
-
-
-
-
-static getPessimisticFMPGraph(dependencyGraph,traceOfTab){
-const fmp=traceOfTab.timestamps.firstMeaningfulPaint;
-const requiredScriptUrls=PredictivePerf.getScriptUrls(dependencyGraph,node=>{
-return node.endTime<=fmp&&node.hasRenderBlockingPriority();
-});
-
-return dependencyGraph.cloneWithRelationships(node=>{
-if(node.endTime>fmp)return false;
-
-
-if(node.type===Node.TYPES.CPU){
-return node.didPerformLayout()||node.isEvaluateScriptFor(requiredScriptUrls);
-}
-
-
-return node.hasRenderBlockingPriority();
-});
-}
-
-
-
-
-
-static getOptimisticTTCIGraph(dependencyGraph){
-
-const minimumCpuTaskDuration=CRITICAL_LONG_TASK_THRESHOLD*1000;
-
-return dependencyGraph.cloneWithRelationships(node=>{
-
-if(node.type===Node.TYPES.CPU)return node.event.dur>minimumCpuTaskDuration;
-
-const isImage=node.record._resourceType===WebInspector.resourceTypes.Image;
-const isScript=node.record._resourceType===WebInspector.resourceTypes.Script;
-return!isImage&&(isScript||
-node.record.priority()==='High'||
-node.record.priority()==='VeryHigh');
-});
-}
-
-
-
-
-
-static getPessimisticTTCIGraph(dependencyGraph){
-return dependencyGraph;
-}
-
-
-
-
-
-static getLastLongTaskEndTime(nodeTiming){
-return Array.from(nodeTiming.entries()).
-filter(([node,timing])=>node.type===Node.TYPES.CPU&&
-timing.endTime-timing.startTime>50).
-map(([_,timing])=>timing.endTime).
-reduce((max,x)=>Math.max(max,x),0);
-}
-
-
-
-
-
-static audit(artifacts){
+static async audit(artifacts){
 const trace=artifacts.traces[Audit.DEFAULT_PASS];
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-return Promise.all([
-artifacts.requestPageDependencyGraph(trace,devtoolsLogs),
-artifacts.requestTraceOfTab(trace)]).
-then(([graph,traceOfTab])=>{
-const graphs={
-optimisticFCP:PredictivePerf.getOptimisticFCPGraph(graph,traceOfTab),
-pessimisticFCP:PredictivePerf.getPessimisticFCPGraph(graph,traceOfTab),
-optimisticFMP:PredictivePerf.getOptimisticFMPGraph(graph,traceOfTab),
-pessimisticFMP:PredictivePerf.getPessimisticFMPGraph(graph,traceOfTab),
-optimisticTTCI:PredictivePerf.getOptimisticTTCIGraph(graph,traceOfTab),
-pessimisticTTCI:PredictivePerf.getPessimisticTTCIGraph(graph,traceOfTab)};
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
 
 
-const values={};
-Object.keys(graphs).forEach(key=>{
-const estimate=new LoadSimulator(graphs[key]).simulate();
-const lastLongTaskEnd=PredictivePerf.getLastLongTaskEndTime(estimate.nodeTiming);
+const settings={};
+const fcp=await artifacts.requestLanternFirstContentfulPaint({trace,devtoolsLog,settings});
+const fmp=await artifacts.requestLanternFirstMeaningfulPaint({trace,devtoolsLog,settings});
+const tti=await artifacts.requestLanternInteractive({trace,devtoolsLog,settings});
+const ttfcpui=await artifacts.requestLanternFirstCPUIdle({trace,devtoolsLog,settings});
+const si=await artifacts.requestLanternSpeedIndex({trace,devtoolsLog,settings});
+const eil=await artifacts.requestLanternEstimatedInputLatency({trace,devtoolsLog,settings});
 
-switch(key){
-case'optimisticFCP':
-case'pessimisticFCP':
-case'optimisticFMP':
-case'pessimisticFMP':
-values[key]=estimate.timeInMs;
-break;
-case'optimisticTTCI':
-values[key]=Math.max(values.optimisticFMP,lastLongTaskEnd);
-break;
-case'pessimisticTTCI':
-values[key]=Math.max(values.pessimisticFMP,lastLongTaskEnd);
-break;}
+const values={
+roughEstimateOfFCP:fcp.timing,
+optimisticFCP:fcp.optimisticEstimate.timeInMs,
+pessimisticFCP:fcp.pessimisticEstimate.timeInMs,
 
-});
+roughEstimateOfFMP:fmp.timing,
+optimisticFMP:fmp.optimisticEstimate.timeInMs,
+pessimisticFMP:fmp.pessimisticEstimate.timeInMs,
 
-values.roughEstimateOfFCP=COEFFICIENTS.FCP.intercept+
-COEFFICIENTS.FCP.optimistic*values.optimisticFCP+
-COEFFICIENTS.FCP.pessimistic*values.pessimisticFCP;
-values.roughEstimateOfFMP=COEFFICIENTS.FMP.intercept+
-COEFFICIENTS.FMP.optimistic*values.optimisticFMP+
-COEFFICIENTS.FMP.pessimistic*values.pessimisticFMP;
-values.roughEstimateOfTTCI=COEFFICIENTS.TTCI.intercept+
-COEFFICIENTS.TTCI.optimistic*values.optimisticTTCI+
-COEFFICIENTS.TTCI.pessimistic*values.pessimisticTTCI;
+roughEstimateOfTTI:tti.timing,
+optimisticTTI:tti.optimisticEstimate.timeInMs,
+pessimisticTTI:tti.pessimisticEstimate.timeInMs,
 
+roughEstimateOfTTFCPUI:ttfcpui.timing,
+optimisticTTFCPUI:ttfcpui.optimisticEstimate.timeInMs,
+pessimisticTTFCPUI:ttfcpui.pessimisticEstimate.timeInMs,
 
+roughEstimateOfSI:si.timing,
+optimisticSI:si.optimisticEstimate.timeInMs,
+pessimisticSI:si.pessimisticEstimate.timeInMs,
 
-values.roughEstimateOfFMP=Math.max(values.roughEstimateOfFCP,values.roughEstimateOfFMP);
-values.roughEstimateOfTTCI=Math.max(values.roughEstimateOfFMP,values.roughEstimateOfTTCI);
+roughEstimateOfEIL:eil.timing,
+optimisticEIL:eil.optimisticEstimate.timeInMs,
+pessimisticEIL:eil.pessimisticEstimate.timeInMs};
+
 
 const score=Audit.computeLogNormalScore(
-values.roughEstimateOfTTCI,
+values.roughEstimateOfTTI,
 SCORING_POINT_OF_DIMINISHING_RETURNS,
 SCORING_MEDIAN);
 
 
 return{
 score,
-rawValue:values.roughEstimateOfTTCI,
-displayValue:Util.formatMilliseconds(values.roughEstimateOfTTCI),
-extendedInfo:{value:values}};
+rawValue:values.roughEstimateOfTTI,
+displayValue:Util.formatMilliseconds(values.roughEstimateOfTTI),
+details:{items:[values]}};
 
-});
 }}
 
 
 module.exports=PredictivePerf;
 
-},{"../lib/dependency-graph/node.js":22,"../lib/dependency-graph/simulator/simulator.js":23,"../lib/web-inspector":42,"../report/v2/renderer/util.js":43,"./audit":2}],"../audits/redirects-http":[function(require,module,exports){
+},{"../report/html/renderer/util":48,"./audit":2}],"../audits/redirects-http":[function(require,module,exports){
 
 
 
@@ -6271,8 +6396,7 @@
 
 static audit(artifacts){
 return{
-rawValue:artifacts.HTTPRedirect.value,
-debugString:artifacts.HTTPRedirect.debugString};
+rawValue:artifacts.HTTPRedirect.value};
 
 }}
 
@@ -6288,7 +6412,6 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
 const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
 
 class Redirects extends Audit{
@@ -6298,10 +6421,10 @@
 static get meta(){
 return{
 name:'redirects',
-description:'Avoids page redirects',
-failureDescription:'Has multiple page redirects',
+description:'Avoid multiple page redirects',
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
 helpText:'Redirects introduce additional delays before the page can be loaded. [Learn more](https://developers.google.com/speed/docs/insights/AvoidRedirects).',
-requiredArtifacts:['URL','devtoolsLogs']};
+requiredArtifacts:['URL','devtoolsLogs','traces']};
 
 }
 
@@ -6309,9 +6432,28 @@
 
 
 
-static audit(artifacts){
-return artifacts.requestMainResource(artifacts.devtoolsLogs[Audit.DEFAULT_PASS]).
-then(mainResource=>{
+
+static async audit(artifacts,context){
+const settings=context.settings;
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+
+const traceOfTab=await artifacts.requestTraceOfTab(trace);
+const networkRecords=await artifacts.requestNetworkRecords(devtoolsLog);
+const mainResource=await artifacts.requestMainResource({URL:artifacts.URL,devtoolsLog});
+
+const metricComputationData={trace,devtoolsLog,traceOfTab,networkRecords,settings};
+const metricResult=await artifacts.requestLanternInteractive(metricComputationData);
+
+
+const nodeTimingsByUrl=new Map();
+for(const[node,timing]of metricResult.pessimisticEstimate.nodeTimings.entries()){
+if(node.type==='network'){
+const networkNode=node;
+nodeTimingsByUrl.set(networkNode.record.url,timing);
+}
+}
+
 
 const redirectRequests=Array.from(mainResource.redirects||[]);
 
@@ -6325,7 +6467,7 @@
 if(redirectRequests.length>1){
 pageRedirects.push({
 url:`(Initial: ${redirectRequests[0].url})`,
-wastedMs:'n/a'});
+wastedMs:0});
 
 }
 
@@ -6333,26 +6475,34 @@
 const initialRequest=redirectRequests[i-1];
 const redirectedRequest=redirectRequests[i];
 
-const wastedMs=(redirectedRequest.startTime-initialRequest.startTime)*1000;
+const initialTiming=nodeTimingsByUrl.get(initialRequest.url);
+const redirectedTiming=nodeTimingsByUrl.get(redirectedRequest.url);
+if(!initialTiming||!redirectedTiming){
+throw new Error('Could not find redirects in graph');
+}
+
+
+const wastedMs=redirectedTiming.startTime-initialTiming.startTime;
 totalWastedMs+=wastedMs;
 
 pageRedirects.push({
 url:redirectedRequest.url,
-wastedMs:Util.formatMilliseconds(wastedMs,1)});
+wastedMs});
 
 }
 
 const headings=[
 {key:'url',itemType:'text',text:'Redirected URL'},
-{key:'wastedMs',itemType:'text',text:'Time for Redirect'}];
+{key:'wastedMs',itemType:'ms',text:'Time for Redirect'}];
 
-const details=Audit.makeTableDetails(headings,pageRedirects);
+const summary={wastedMs:totalWastedMs};
+const details=Audit.makeTableDetails(headings,pageRedirects,summary);
 
 return{
 
-score:redirectRequests.length<=2?100:UnusedBytes.scoreForWastedMs(totalWastedMs),
+score:redirectRequests.length<=2?1:UnusedBytes.scoreForWastedMs(totalWastedMs),
 rawValue:totalWastedMs,
-displayValue:Util.formatMilliseconds(totalWastedMs,1),
+displayValue:['%d\xa0ms',totalWastedMs],
 extendedInfo:{
 value:{
 wastedMs:totalWastedMs}},
@@ -6360,13 +6510,12 @@
 
 details};
 
-});
 }}
 
 
 module.exports=Redirects;
 
-},{"../report/v2/renderer/util":43,"./audit":2,"./byte-efficiency/byte-efficiency-audit":3}],"../audits/screenshot-thumbnails":[function(require,module,exports){
+},{"./audit":2,"./byte-efficiency/byte-efficiency-audit":3}],"../audits/screenshot-thumbnails":[function(require,module,exports){
 
 
 
@@ -6375,13 +6524,14 @@
 'use strict';
 
 const Audit=require('./audit');
-const TTFI=require('./first-interactive');
-const TTCI=require('./consistently-interactive');
+const LHError=require('../lib/errors');
 const jpeg=require('jpeg-js');
 
 const NUMBER_OF_THUMBNAILS=10;
 const THUMBNAIL_WIDTH=120;
 
+
+
 class ScreenshotThumbnails extends Audit{
 
 
@@ -6389,10 +6539,10 @@
 static get meta(){
 return{
 name:'screenshot-thumbnails',
-informative:true,
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
 description:'Screenshot Thumbnails',
 helpText:'This is what the load of your site looked like.',
-requiredArtifacts:['traces']};
+requiredArtifacts:['traces','devtoolsLogs']};
 
 }
 
@@ -6436,27 +6586,42 @@
 
 
 
-static audit(artifacts){
+
+static async audit(artifacts,context){
 const trace=artifacts.traces[Audit.DEFAULT_PASS];
+
 const cachedThumbnails=new Map();
 
-return Promise.all([
-artifacts.requestSpeedline(trace),
-TTFI.audit(artifacts).catch(()=>({rawValue:0})),
-TTCI.audit(artifacts).catch(()=>({rawValue:0}))]).
-then(([speedline,ttfi,ttci])=>{
+const speedline=await artifacts.requestSpeedline(trace);
+
+
+let minimumTimelineDuration=context.options.minimumTimelineDuration||3000;
+
+if(context.settings.throttlingMethod!=='simulate'){
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const tti=artifacts.requestInteractive(metricComputationData);
+try{
+minimumTimelineDuration=Math.max((await tti).timing,minimumTimelineDuration);
+}catch(_){}
+}
+
 const thumbnails=[];
 const analyzedFrames=speedline.frames.filter(frame=>!frame.isProgressInterpolated());
 const maxFrameTime=
 speedline.complete||
 Math.max(...speedline.frames.map(frame=>frame.getTimeStamp()-speedline.beginning));
+const timelineEnd=Math.max(maxFrameTime,minimumTimelineDuration);
 
-
-const timelineEnd=Math.max(maxFrameTime,ttfi.rawValue,ttci.rawValue);
+if(!analyzedFrames.length||!Number.isFinite(timelineEnd)){
+throw new LHError(LHError.errors.INVALID_SPEEDLINE);
+}
 
 for(let i=1;i<=NUMBER_OF_THUMBNAILS;i++){
 const targetTimestamp=speedline.beginning+timelineEnd*i/NUMBER_OF_THUMBNAILS;
 
+
+
 let frameForTimestamp=null;
 if(i===NUMBER_OF_THUMBNAILS){
 frameForTimestamp=analyzedFrames[analyzedFrames.length-1];
@@ -6483,7 +6648,7 @@
 }
 
 return{
-score:100,
+score:1,
 rawValue:thumbnails.length>0,
 details:{
 type:'filmstrip',
@@ -6491,13 +6656,12 @@
 items:thumbnails}};
 
 
-});
 }}
 
 
 module.exports=ScreenshotThumbnails;
 
-},{"./audit":2,"./consistently-interactive":"../audits/consistently-interactive","./first-interactive":"../audits/first-interactive","jpeg-js":134}],"../audits/seo/canonical":[function(require,module,exports){
+},{"../lib/errors":33,"./audit":2,"jpeg-js":140}],"../audits/seo/canonical":[function(require,module,exports){
 
 
 
@@ -6564,9 +6728,8 @@
 description:'Document has a valid `rel=canonical`',
 failureDescription:'Document does not have a valid `rel=canonical`',
 helpText:'Canonical links suggest which URL to show in search results. '+
-'Read more in [Use canonical URLs]'+
-'(https://support.google.com/webmasters/answer/139066).',
-requiredArtifacts:['Canonical','Hreflang']};
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/canonical).',
+requiredArtifacts:['Canonical','Hreflang','URL']};
 
 }
 
@@ -6575,22 +6738,31 @@
 
 
 static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
 
-return artifacts.requestMainResource(devtoolsLogs).
+return artifacts.requestMainResource({devtoolsLog,URL:artifacts.URL}).
 then(mainResource=>{
 const baseURL=new URL(mainResource.url);
+
 let canonicals=[];
+
 let hreflangs=[];
 
-mainResource.responseHeaders.
+mainResource._responseHeaders&&mainResource._responseHeaders.
 filter(h=>h.name.toLowerCase()===LINK_HEADER).
 forEach(h=>{
 canonicals=canonicals.concat(getCanonicalLinksFromHeader(h.value));
 hreflangs=hreflangs.concat(getHreflangsFromHeader(h.value));
 });
 
-canonicals=canonicals.concat(artifacts.Canonical);
+for(const canonical of artifacts.Canonical){
+if(canonical!==null){
+canonicals.push(canonical);
+}
+}
+
+
+canonicals=Array.from(new Set(canonicals));
 
 artifacts.Hreflang.forEach(({href})=>hreflangs.push(href));
 
@@ -6608,7 +6780,7 @@
 if(canonicals.length>1){
 return{
 rawValue:false,
-debugString:`Multiple URLs (${canonicals.join(', ')})`};
+explanation:`Multiple conflicting URLs (${canonicals.join(', ')})`};
 
 }
 
@@ -6617,14 +6789,14 @@
 if(!isValidRelativeOrAbsoluteURL(canonical)){
 return{
 rawValue:false,
-debugString:`Invalid URL (${canonical})`};
+explanation:`Invalid URL (${canonical})`};
 
 }
 
 if(!URL.isValid(canonical)){
 return{
 rawValue:false,
-debugString:`Relative URL (${canonical})`};
+explanation:`Relative URL (${canonical})`};
 
 }
 
@@ -6635,7 +6807,7 @@
 baseURL.href!==canonicalURL.href){
 return{
 rawValue:false,
-debugString:`Points to another hreflang location (${baseURL.href})`};
+explanation:`Points to another hreflang location (${baseURL.href})`};
 
 }
 
@@ -6644,7 +6816,7 @@
 if(getPrimaryDomain(canonicalURL)!==getPrimaryDomain(baseURL)){
 return{
 rawValue:false,
-debugString:`Points to a different domain (${canonicalURL})`};
+explanation:`Points to a different domain (${canonicalURL})`};
 
 }
 
@@ -6653,7 +6825,7 @@
 canonicalURL.pathname==='/'&&baseURL.pathname!=='/'){
 return{
 rawValue:false,
-debugString:'Points to a root of the same origin'};
+explanation:'Points to a root of the same origin'};
 
 }
 
@@ -6666,8 +6838,7 @@
 
 module.exports=Canonical;
 
-},{"../../lib/url-shim":41,"../audit":2,"http-link-header":131}],"../audits/seo/font-size":[function(require,module,exports){
-(function(global){
+},{"../../lib/url-shim":"url","../audit":2,"http-link-header":137}],"../audits/seo/font-size":[function(require,module,exports){
 
 
 
@@ -6675,17 +6846,22 @@
 
 'use strict';
 
+
+
+
 const URL=require('../../lib/url-shim');
 const Audit=require('../audit');
 const ViewportAudit=require('../viewport');
-const CSSStyleDeclaration=require('../../lib/web-inspector').CSSStyleDeclaration;
-const MINIMAL_PERCENTAGE_OF_LEGIBLE_TEXT=75;
+const WebInspector=require('../../lib/web-inspector');
+const CSSStyleDeclaration=WebInspector.CSSStyleDeclaration;
+const MINIMAL_PERCENTAGE_OF_LEGIBLE_TEXT=60;
 
 
 
 
 
 function getUniqueFailingRules(fontSizeArtifact){
+
 const failingRules=new Map();
 
 fontSizeArtifact.forEach(({cssRule,fontSize,textLength,node})=>{
@@ -6704,14 +6880,14 @@
 }
 });
 
-return failingRules.valuesArray();
+return[...failingRules.values()];
 }
 
 
 
 
 
-function getAttributeMap(attributes){
+function getAttributeMap(attributes=[]){
 const map=new Map();
 
 for(let i=0;i<attributes.length;i+=2){
@@ -6736,8 +6912,11 @@
 
 if(attributeMap.has('id')){
 return'#'+attributeMap.get('id');
-}else if(attributeMap.has('class')){
-return'.'+attributeMap.get('class').split(/\s+/).join('.');
+}else{
+const attrClass=attributeMap.get('class');
+if(attrClass){
+return'.'+attrClass.split(/\s+/).join('.');
+}
 }
 
 return node.localName.toLowerCase();
@@ -6748,7 +6927,8 @@
 
 
 function nodeToTableNode(node){
-const attributesString=node.attributes.map((value,idx)=>
+const attributes=node.attributes||[];
+const attributesString=attributes.map((value,idx)=>
 idx%2===0?` ${value}`:`="${value}"`).
 join('');
 
@@ -6772,13 +6952,13 @@
 styleDeclaration.type===CSSStyleDeclaration.Type.Inline)
 {
 return{
-source:baseURL,
-selector:nodeToTableNode(node)};
+selector:nodeToTableNode(node),
+source:baseURL};
 
 }
 
 if(styleDeclaration.parentRule&&
-styleDeclaration.parentRule.origin===global.CSSAgent.StyleSheetOrigin.USER_AGENT){
+styleDeclaration.parentRule.origin==='user-agent'){
 return{
 selector:styleDeclaration.parentRule.selectors.map(item=>item.text).join(', '),
 source:'User Agent Stylesheet'};
@@ -6819,6 +6999,7 @@
 }
 
 return{
+selector:'',
 source:'Unknown'};
 
 }
@@ -6847,9 +7028,9 @@
 name:'font-size',
 description:'Document uses legible font sizes',
 failureDescription:'Document doesn\'t use legible font sizes',
-helpText:'Font sizes less than 16px are too small to be legible and require mobile '+
-'visitors to “pinch to zoom” in order to read. Strive to have >75% of page text ≥16px. '+
-'[Learn more](https://developers.google.com/speed/docs/insights/UseLegibleFontSizes).',
+helpText:'Font sizes less than 12px are too small to be legible and require mobile '+
+'visitors to “pinch to zoom” in order to read. Strive to have >60% of page text ≥12px. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/font-sizes).',
 requiredArtifacts:['FontSize','URL','Viewport']};
 
 }
@@ -6863,7 +7044,7 @@
 if(!hasViewportSet){
 return{
 rawValue:false,
-debugString:'Text is illegible because of a missing viewport config'};
+explanation:'Text is illegible because of a missing viewport config'};
 
 }
 
@@ -6913,25 +7094,27 @@
 
 tableData.push({
 source:'Add\'l illegible text',
-selector:null,
+selector:'',
 coverage:`${percentageOfUnanalyzedFailingText.toFixed(2)}%`,
-fontSize:'< 16px'});
+fontSize:'< 12px'});
 
 }
 
 if(percentageOfPassingText>0){
 tableData.push({
 source:'Legible text',
-selector:null,
+selector:'',
 coverage:`${percentageOfPassingText.toFixed(2)}%`,
-fontSize:'≥ 16px'});
+fontSize:'≥ 12px'});
 
 }
 
+
+const displayValue=['%.1d% legible text',percentageOfPassingText];
 const details=Audit.makeTableDetails(headings,tableData);
 const passed=percentageOfPassingText>=MINIMAL_PERCENTAGE_OF_LEGIBLE_TEXT;
-let debugString=null;
 
+let explanation;
 if(!passed){
 const percentageOfFailingText=parseFloat((100-percentageOfPassingText).toFixed(2));
 let disclaimer='';
@@ -6942,21 +7125,21 @@
 disclaimer=` (based on ${percentageOfVisitedText.toFixed()}% sample)`;
 }
 
-debugString=`${percentageOfFailingText}% of text is too small${disclaimer}.`;
+explanation=`${percentageOfFailingText}% of text is too small${disclaimer}.`;
 }
 
 return{
 rawValue:passed,
 details,
-debugString};
+displayValue,
+explanation};
 
 }}
 
 
 module.exports=FontSize;
 
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"../../lib/url-shim":41,"../../lib/web-inspector":42,"../audit":2,"../viewport":"../audits/viewport"}],"../audits/seo/hreflang":[function(require,module,exports){
+},{"../../lib/url-shim":"url","../../lib/web-inspector":47,"../audit":2,"../viewport":"../audits/viewport"}],"../audits/seo/hreflang":[function(require,module,exports){
 (function(global){
 
 
@@ -6976,11 +7159,17 @@
 
 
 
+
 function importValidLangs(){
+
 const axeCache=global.axe;
+
 global.axe={utils:{}};
+
 require('axe-core/lib/commons/utils/valid-langs.js');
+
 const validLangs=global.axe.utils.validLangs();
+
 global.axe=axeCache;
 
 return validLangs;
@@ -7008,7 +7197,7 @@
 const linkHeader=LinkHeader.parse(headerValue);
 
 return linkHeader.get('rel','alternate').
-every(link=>link.hreflang&&isValidHreflang(link.hreflang));
+every(link=>!!link.hreflang&&isValidHreflang(link.hreflang));
 }
 
 class Hreflang extends Audit{
@@ -7020,10 +7209,10 @@
 name:'hreflang',
 description:'Document has a valid `hreflang`',
 failureDescription:'Document doesn\'t have a valid `hreflang`',
-helpText:'hreflang allows crawlers to discover alternate translations of the '+
-'page content. [Learn more]'+
-'(https://support.google.com/webmasters/answer/189077).',
-requiredArtifacts:['Hreflang']};
+helpText:'hreflang links tell search engines what version of a page they should '+
+'list in search results for a given language or region. [Learn more]'+
+'(https://developers.google.com/web/tools/lighthouse/audits/hreflang).',
+requiredArtifacts:['Hreflang','URL']};
 
 }
 
@@ -7032,9 +7221,10 @@
 
 
 static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const URL=artifacts.URL;
 
-return artifacts.requestMainResource(devtoolsLogs).
+return artifacts.requestMainResource({devtoolsLog,URL}).
 then(mainResource=>{
 
 const invalidHreflangs=[];
@@ -7052,7 +7242,7 @@
 });
 }
 
-mainResource.responseHeaders.
+mainResource._responseHeaders&&mainResource._responseHeaders.
 filter(h=>h.name.toLowerCase()===LINK_HEADER&&!headerHasValidHreflangs(h.value)).
 forEach(h=>invalidHreflangs.push({source:`${h.name}: ${h.value}`}));
 
@@ -7072,7 +7262,7 @@
 module.exports=Hreflang;
 
 }).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"../audit":2,"axe-core/lib/commons/utils/valid-langs.js":92,"http-link-header":131}],"../audits/seo/http-status-code":[function(require,module,exports){
+},{"../audit":2,"axe-core/lib/commons/utils/valid-langs.js":98,"http-link-header":137}],"../audits/seo/http-status-code":[function(require,module,exports){
 
 
 
@@ -7096,7 +7286,7 @@
 helpText:'Pages with unsuccessful HTTP status codes may not be indexed properly. '+
 '[Learn more]'+
 '(https://developers.google.com/web/tools/lighthouse/audits/successful-http-code).',
-requiredArtifacts:['devtoolsLogs']};
+requiredArtifacts:['devtoolsLogs','URL']};
 
 }
 
@@ -7105,9 +7295,10 @@
 
 
 static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const URL=artifacts.URL;
 
-return artifacts.requestMainResource(devtoolsLogs).
+return artifacts.requestMainResource({devtoolsLog,URL}).
 then(mainResource=>{
 const statusCode=mainResource.statusCode;
 
@@ -7137,6 +7328,8 @@
 'use strict';
 
 const Audit=require('../audit');
+const robotsParser=require('robots-parser');
+const URL=require('../../lib/url-shim');
 const BLOCKLIST=new Set([
 'noindex',
 'none']);
@@ -7194,9 +7387,10 @@
 name:'is-crawlable',
 description:'Page isn’t blocked from indexing',
 failureDescription:'Page is blocked from indexing',
-helpText:'The "Robots" directives tell crawlers how your content should be indexed. '+
-'[Learn more](https://developers.google.com/search/reference/robots_meta_tag).',
-requiredArtifacts:['MetaRobots']};
+helpText:'Search engines are unable to include your pages in search results '+
+'if they don\'t have permission to crawl them. [Learn '+
+'more](https://developers.google.com/web/tools/lighthouse/audits/indexing).',
+requiredArtifacts:['MetaRobots','RobotsTxt','URL']};
 
 }
 
@@ -7205,8 +7399,11 @@
 
 
 static audit(artifacts){
-return artifacts.requestMainResource(artifacts.devtoolsLogs[Audit.DEFAULT_PASS]).
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+
+return artifacts.requestMainResource({devtoolsLog,URL:artifacts.URL}).
 then(mainResource=>{
+
 const blockingDirectives=[];
 
 if(artifacts.MetaRobots){
@@ -7222,13 +7419,27 @@
 }
 }
 
-mainResource.responseHeaders.
+mainResource._responseHeaders&&mainResource._responseHeaders.
 filter(h=>h.name.toLowerCase()===ROBOTS_HEADER&&!hasUserAgent(h.value)&&
 hasBlockingDirective(h.value)).
 forEach(h=>blockingDirectives.push({source:`${h.name}: ${h.value}`}));
 
+if(artifacts.RobotsTxt.content){
+const robotsFileUrl=new URL('/robots.txt',mainResource.url);
+const robotsTxt=robotsParser(robotsFileUrl.href,artifacts.RobotsTxt.content);
+
+if(!robotsTxt.isAllowed(mainResource.url)){
+blockingDirectives.push({
+source:{
+type:'url',
+value:robotsFileUrl.href}});
+
+
+}
+}
+
 const headings=[
-{key:'source',itemType:'code',text:'Source'}];
+{key:'source',itemType:'code',text:'Blocking Directive Source'}];
 
 const details=Audit.makeTableDetails(headings,blockingDirectives);
 
@@ -7242,7 +7453,7 @@
 
 module.exports=IsCrawlable;
 
-},{"../audit":2}],"../audits/seo/link-text":[function(require,module,exports){
+},{"../../lib/url-shim":"url","../audit":2,"robots-parser":149}],"../audits/seo/link-text":[function(require,module,exports){
 
 
 
@@ -7270,12 +7481,11 @@
 
 static get meta(){
 return{
-category:'Content Best Practices',
 name:'link-text',
 description:'Links have descriptive text',
 failureDescription:'Links do not have descriptive text',
 helpText:'Descriptive link text helps search engines understand your content. '+
-'[Learn more](https://webmasters.googleblog.com/2008/10/importance-of-link-architecture.html).',
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/descriptive-link-text).',
 requiredArtifacts:['URL','CrawlableLinks']};
 
 }
@@ -7302,7 +7512,7 @@
 {key:'text',itemType:'text',text:'Link Text'}];
 
 
-const details=Audit.makeTableDetails(headings,failingLinks);
+const details=Audit.makeTableDetails(headings,failingLinks,{});
 let displayValue;
 
 if(failingLinks.length){
@@ -7320,7 +7530,7 @@
 
 module.exports=LinkText;
 
-},{"../../lib/url-shim":41,"../audit":2}],"../audits/seo/manual/mobile-friendly":[function(require,module,exports){
+},{"../../lib/url-shim":"url","../audit":2}],"../audits/seo/manual/mobile-friendly":[function(require,module,exports){
 
 
 
@@ -7343,7 +7553,7 @@
 name:'mobile-friendly',
 helpText:'Take the [Mobile-Friendly Test](https://search.google.com/test/mobile-friendly) to check for audits not covered by Lighthouse, like sizing tap targets appropriately. [Learn more](https://developers.google.com/search/mobile-sites/).',
 description:'Page is mobile friendly'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -7372,7 +7582,7 @@
 name:'structured-data',
 helpText:'Run the [Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool/) and the [Structured Data Linter](http://linter.structured-data.org/) to validate structured data. [Learn more](https://developers.google.com/search/docs/guides/mark-up-content).',
 description:'Structured data is valid'},
-super.meta);
+super.partialMeta);
 }}
 
 
@@ -7399,7 +7609,7 @@
 failureDescription:'Document does not have a meta description',
 helpText:'Meta descriptions may be included in search results to concisely summarize '+
 'page content. '+
-'[Learn more](https://support.google.com/webmasters/answer/35624?hl=en#1).',
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/description).',
 requiredArtifacts:['MetaDescription']};
 
 }
@@ -7418,7 +7628,7 @@
 if(artifacts.MetaDescription.trim().length===0){
 return{
 rawValue:false,
-debugString:'Description text is empty.'};
+explanation:'Description text is empty.'};
 
 }
 
@@ -7469,6 +7679,7 @@
 
 
 
+
 function isPluginType(type){
 type=type.trim().toLowerCase();
 
@@ -7481,13 +7692,18 @@
 
 
 
+
 function isPluginURL(url){
 try{
 
 const filePath=new URL(url,'http://example.com').pathname;
 const parts=filePath.split('.');
 
-return parts.length>1&&FILE_EXTENSION_BLOCKLIST.has(parts.pop().trim().toLowerCase());
+if(parts.length<2){
+return false;
+}
+const part=parts.pop();
+return FILE_EXTENSION_BLOCKLIST.has(part.trim().toLowerCase());
 }catch(e){
 return false;
 }
@@ -7502,8 +7718,9 @@
 name:'plugins',
 description:'Document avoids plugins',
 failureDescription:'Document uses plugins',
-helpText:'Most mobile devices do not support plugins, and many desktop browsers restrict '+
-'them.',
+helpText:'Search engines can\'t index plugin content, and '+
+'many devices restrict plugins or don\'t support them. '+
+'[Learn more](https://developers.google.com/web/tools/lighthouse/audits/plugins).',
 requiredArtifacts:['EmbeddedContent']};
 
 }
@@ -7544,7 +7761,9 @@
 }).
 map(plugin=>{
 const tagName=plugin.tagName.toLowerCase();
-const attributes=['src','data','code','type'].
+
+const attributeKeys=['src','data','code','type'];
+const attributes=attributeKeys.
 reduce((result,attr)=>{
 if(plugin[attr]!==null){
 result+=` ${attr}="${plugin[attr]}"`;
@@ -7579,7 +7798,239 @@
 
 module.exports=Plugins;
 
-},{"../../lib/url-shim":41,"../audit":2}],"../audits/service-worker":[function(require,module,exports){
+},{"../../lib/url-shim":"url","../audit":2}],"../audits/seo/robots-txt":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+const Audit=require('../audit');
+const URL=require('../../lib/url-shim');
+
+const HTTP_CLIENT_ERROR_CODE_LOW=400;
+const HTTP_SERVER_ERROR_CODE_LOW=500;
+
+const DIRECTIVE_SITEMAP='sitemap';
+const DIRECTIVE_USER_AGENT='user-agent';
+const DIRECTIVE_ALLOW='allow';
+const DIRECTIVE_DISALLOW='disallow';
+const DIRECTIVES_GROUP_MEMBERS=new Set([DIRECTIVE_ALLOW,DIRECTIVE_DISALLOW]);
+const DIRECTIVE_SAFELIST=new Set([
+DIRECTIVE_USER_AGENT,DIRECTIVE_DISALLOW,
+DIRECTIVE_ALLOW,DIRECTIVE_SITEMAP,
+'crawl-delay',
+'clean-param','host',
+'request-rate','visit-time','noindex']);
+
+const SITEMAP_VALID_PROTOCOLS=new Set(['https:','http:','ftp:']);
+
+
+
+
+
+
+function verifyDirective(directiveName,directiveValue){
+if(!DIRECTIVE_SAFELIST.has(directiveName)){
+throw new Error('Unknown directive');
+}
+
+if(directiveName===DIRECTIVE_SITEMAP){
+let sitemapUrl;
+
+try{
+sitemapUrl=new URL(directiveValue);
+}catch(e){
+throw new Error('Invalid sitemap URL');
+}
+
+if(!SITEMAP_VALID_PROTOCOLS.has(sitemapUrl.protocol)){
+throw new Error('Invalid sitemap URL protocol');
+}
+}
+
+if(directiveName===DIRECTIVE_USER_AGENT&&!directiveValue){
+throw new Error('No user-agent specified');
+}
+
+if(directiveName===DIRECTIVE_ALLOW||directiveName===DIRECTIVE_DISALLOW){
+if(directiveValue!==''&&directiveValue[0]!=='/'&&directiveValue[0]!=='*'){
+throw new Error('Pattern should either be empty, start with "/" or "*"');
+}
+
+const dollarIndex=directiveValue.indexOf('$');
+
+if(dollarIndex!==-1&&dollarIndex!==directiveValue.length-1){
+throw new Error('"$" should only be used at the end of the pattern');
+}
+}
+}
+
+
+
+
+
+
+function parseLine(line){
+const hashIndex=line.indexOf('#');
+
+if(hashIndex!==-1){
+line=line.substr(0,hashIndex);
+}
+
+line=line.trim();
+
+if(line.length===0){
+return null;
+}
+
+const colonIndex=line.indexOf(':');
+
+if(colonIndex===-1){
+throw new Error('Syntax not understood');
+}
+
+const directiveName=line.slice(0,colonIndex).trim().toLowerCase();
+const directiveValue=line.slice(colonIndex+1).trim();
+
+verifyDirective(directiveName,directiveValue);
+
+return{
+directive:directiveName,
+value:directiveValue};
+
+}
+
+
+
+
+
+function validateRobots(content){
+
+
+
+const errors=[];
+let inGroup=false;
+
+content.
+split(/\r\n|\r|\n/).
+forEach((line,index)=>{
+let parsedLine;
+
+try{
+parsedLine=parseLine(line);
+}catch(e){
+errors.push({
+index:(index+1).toString(),
+line:line,
+message:e.message.toString()});
+
+}
+
+if(!parsedLine){
+return;
+}
+
+
+
+if(parsedLine.directive===DIRECTIVE_USER_AGENT){
+inGroup=true;
+}else if(!inGroup&&DIRECTIVES_GROUP_MEMBERS.has(parsedLine.directive)){
+errors.push({
+index:(index+1).toString(),
+line:line,
+message:'No user-agent specified'});
+
+}
+});
+
+return errors;
+}
+
+class RobotsTxt extends Audit{
+
+
+
+static get meta(){
+return{
+name:'robots-txt',
+description:'robots.txt is valid',
+failureDescription:'robots.txt is not valid',
+helpText:'If your robots.txt file is malformed, crawlers may not be able to understand '+
+'how you want your website to be crawled or indexed.',
+requiredArtifacts:['RobotsTxt']};
+
+}
+
+
+
+
+
+static audit(artifacts){
+const{
+status,
+content}=
+artifacts.RobotsTxt;
+
+if(!status){
+return{
+rawValue:false,
+explanation:'Lighthouse was unable to download your robots.txt file'};
+
+}
+
+if(status>=HTTP_SERVER_ERROR_CODE_LOW){
+return{
+rawValue:false,
+displayValue:`request for robots.txt returned HTTP${status}`};
+
+}else if(status>=HTTP_CLIENT_ERROR_CODE_LOW||content===''){
+return{
+rawValue:true,
+notApplicable:true};
+
+}
+
+
+if(content===null){
+throw new Error(`Status ${status} was valid, but content was null`);
+}
+
+const validationErrors=validateRobots(content);
+
+const headings=[
+{key:'index',itemType:'text',text:'Line #'},
+{key:'line',itemType:'code',text:'Content'},
+{key:'message',itemType:'code',text:'Error'}];
+
+
+const details=Audit.makeTableDetails(headings,validationErrors,{});
+let displayValue;
+
+if(validationErrors.length){
+displayValue=validationErrors.length>1?
+`${validationErrors.length} errors found`:'1 error found';
+}
+
+return{
+rawValue:validationErrors.length===0,
+details,
+displayValue};
+
+}}
+
+
+module.exports=RobotsTxt;
+
+},{"../../lib/url-shim":"url","../audit":2}],"../audits/service-worker":[function(require,module,exports){
 
 
 
@@ -7628,7 +8079,7 @@
 
 module.exports=ServiceWorker;
 
-},{"../lib/url-shim":41,"./audit":2}],"../audits/speed-index-metric":[function(require,module,exports){
+},{"../lib/url-shim":"url","./audit":2}],"../audits/speed-index":[function(require,module,exports){
 
 
 
@@ -7637,105 +8088,64 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
-const LHError=require('../lib/errors');
+const Util=require('../report/html/renderer/util');
 
-
-
-const SCORING_POINT_OF_DIMINISHING_RETURNS=1250;
-const SCORING_MEDIAN=5500;
-
-class SpeedIndexMetric extends Audit{
+class SpeedIndex extends Audit{
 
 
 
 static get meta(){
 return{
-name:'speed-index-metric',
-description:'Perceptual Speed Index',
+name:'speed-index',
+description:'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).',
-scoringMode:Audit.SCORING_MODES.NUMERIC,
-requiredArtifacts:['traces']};
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC,
+requiredArtifacts:['traces','devtoolsLogs']};
 
 }
 
 
 
 
-
-
-
-static audit(artifacts){
-const trace=artifacts.traces[this.DEFAULT_PASS];
-
-
-return artifacts.requestSpeedline(trace).then(speedline=>{
-if(speedline.frames.length===0){
-throw new LHError(LHError.errors.NO_SPEEDLINE_FRAMES);
-}
-
-if(speedline.perceptualSpeedIndex===0){
-throw new LHError(LHError.errors.SPEEDINDEX_OF_ZERO);
-}
-
-let visuallyReadyInMs=undefined;
-speedline.frames.forEach(frame=>{
-if(frame.getPerceptualProgress()>=85&&typeof visuallyReadyInMs==='undefined'){
-visuallyReadyInMs=frame.getTimeStamp()-speedline.beginning;
-}
-});
-
-
-
-
-
-
-
-const score=Audit.computeLogNormalScore(
-speedline.perceptualSpeedIndex,
-SCORING_POINT_OF_DIMINISHING_RETURNS,
-SCORING_MEDIAN);
-
-
-const extendedInfo={
-timings:{
-firstVisualChange:speedline.first,
-visuallyReady:visuallyReadyInMs,
-visuallyComplete:speedline.complete,
-perceptualSpeedIndex:speedline.perceptualSpeedIndex},
-
-timestamps:{
-firstVisualChange:(speedline.first+speedline.beginning)*1000,
-visuallyReady:(visuallyReadyInMs+speedline.beginning)*1000,
-visuallyComplete:(speedline.complete+speedline.beginning)*1000,
-perceptualSpeedIndex:(speedline.perceptualSpeedIndex+speedline.beginning)*1000},
-
-frames:speedline.frames.map(frame=>{
+static get defaultOptions(){
 return{
-timestamp:frame.getTimeStamp(),
-progress:frame.getPerceptualProgress()};
-
-})};
 
 
-const rawValue=Math.round(speedline.perceptualSpeedIndex);
+
+scorePODR:2900,
+scoreMedian:5800};
+
+}
+
+
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+const metricComputationData={trace,devtoolsLog,settings:context.settings};
+const metricResult=await artifacts.requestSpeedIndex(metricComputationData);
 
 return{
-score,
-rawValue,
-displayValue:Util.formatNumber(rawValue),
-extendedInfo:{
-value:extendedInfo}};
+score:Audit.computeLogNormalScore(
+metricResult.timing,
+context.options.scorePODR,
+context.options.scoreMedian),
 
+rawValue:metricResult.timing,
+displayValue:[Util.MS_DISPLAY_VALUE,metricResult.timing]};
 
-});
 }}
 
 
-module.exports=SpeedIndexMetric;
+module.exports=SpeedIndex;
 
-},{"../lib/errors":28,"../report/v2/renderer/util":43,"./audit":2}],"../audits/splash-screen":[function(require,module,exports){
+},{"../report/html/renderer/util":48,"./audit":2}],"../audits/splash-screen":[function(require,module,exports){
 
 
 
@@ -7774,8 +8184,12 @@
 
 }
 
+
+
+
+
 static assessManifest(manifestValues,failures){
-if(manifestValues.isParseFailure){
+if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
 failures.push(manifestValues.parseFailureReason);
 return;
 }
@@ -7797,7 +8211,11 @@
 }
 
 
+
+
+
 static audit_(artifacts){
+
 const failures=[];
 
 return artifacts.requestManifestValues(artifacts.Manifest).then(manifestValues=>{
@@ -7849,6 +8267,10 @@
 
 }
 
+
+
+
+
 static assessMetaThemecolor(themeColorMeta,failures){
 if(themeColorMeta===null){
 failures.push('No `<meta name="theme-color">` tag found');
@@ -7857,19 +8279,28 @@
 }
 }
 
+
+
+
+
 static assessManifest(manifestValues,failures){
-if(manifestValues.isParseFailure){
+if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
 failures.push(manifestValues.parseFailureReason);
 return;
 }
 
 const themeColorCheck=manifestValues.allChecks.find(i=>i.id==='hasThemeColor');
-if(!themeColorCheck.passing){
+if(themeColorCheck&&!themeColorCheck.passing){
 failures.push(themeColorCheck.failureText);
 }
 }
 
+
+
+
+
 static audit_(artifacts){
+
 const failures=[];
 
 return artifacts.requestManifestValues(artifacts.Manifest).then(manifestValues=>{
@@ -7887,7 +8318,7 @@
 
 module.exports=ThemedOmnibox;
 
-},{"../lib/web-inspector":42,"./multi-check-audit":5}],"../audits/time-to-first-byte":[function(require,module,exports){
+},{"../lib/web-inspector":47,"./multi-check-audit":5}],"../audits/time-to-first-byte":[function(require,module,exports){
 
 
 
@@ -7896,7 +8327,7 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
+const Util=require('../report/html/renderer/util');
 
 const TTFB_THRESHOLD=600;
 
@@ -7908,13 +8339,15 @@
 return{
 name:'time-to-first-byte',
 description:'Keep server response times low (TTFB)',
-informative:true,
 helpText:'Time To First Byte identifies the time at which your server sends a response.'+
 ' [Learn more](https://developers.google.com/web/tools/chrome-devtools/network-performance/issues).',
 requiredArtifacts:['devtoolsLogs','URL']};
 
 }
 
+
+
+
 static caclulateTTFB(record){
 const timing=record._timing;
 
@@ -7930,28 +8363,34 @@
 
 return artifacts.requestNetworkRecords(devtoolsLogs).
 then(networkRecords=>{
-let debugString='';
+let displayValue='';
 
 const finalUrl=artifacts.URL.finalUrl;
 const finalUrlRequest=networkRecords.find(record=>record._url===finalUrl);
+if(!finalUrlRequest){
+throw new Error(`finalUrl '${finalUrl} not found in network records.`);
+}
 const ttfb=TTFBMetric.caclulateTTFB(finalUrlRequest);
 const passed=ttfb<TTFB_THRESHOLD;
 
 if(!passed){
-debugString=`Root document took ${Util.formatMilliseconds(ttfb,1)} `+
-'to get the first byte.';
+displayValue=`Root document took ${Util.formatMilliseconds(ttfb,1)} `;
 }
 
 return{
 rawValue:ttfb,
-score:passed,
-displayValue:Util.formatMilliseconds(ttfb),
-extendedInfo:{
-value:{
+score:Number(passed),
+displayValue,
+details:{
+summary:{
 wastedMs:ttfb-TTFB_THRESHOLD}},
 
 
-debugString};
+extendedInfo:{
+value:{
+wastedMs:ttfb-TTFB_THRESHOLD}}};
+
+
 
 });
 }}
@@ -7959,7 +8398,7 @@
 
 module.exports=TTFBMetric;
 
-},{"../report/v2/renderer/util":43,"./audit":2}],"../audits/user-timings":[function(require,module,exports){
+},{"../report/html/renderer/util":48,"./audit":2}],"../audits/user-timings":[function(require,module,exports){
 
 
 
@@ -7968,7 +8407,9 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
+
+
+
 
 class UserTimings extends Audit{
 
@@ -7977,12 +8418,12 @@
 static get meta(){
 return{
 name:'user-timings',
+scoreDisplayMode:Audit.SCORING_MODES.INFORMATIVE,
 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).',
-requiredArtifacts:['traces'],
-informative:true};
+requiredArtifacts:['traces']};
 
 }
 
@@ -7991,6 +8432,7 @@
 
 
 static filterTrace(tabTrace){
+
 const userTimings=[];
 const measuresStartTimes={};
 
@@ -8031,7 +8473,8 @@
 isMark:false,
 args:ut.args,
 startTime:measuresStartTimes[ut.name],
-endTime:ut.ts});
+endTime:ut.ts,
+duration:ut.ts-measuresStartTimes[ut.name]});
 
 }
 });
@@ -8041,7 +8484,7 @@
 ut.startTime=(ut.startTime-tabTrace.navigationStartEvt.ts)/1000;
 if(!ut.isMark){
 ut.endTime=(ut.endTime-tabTrace.navigationStartEvt.ts)/1000;
-ut.duration=ut.endTime-ut.startTime;
+ut.duration=ut.duration/1000;
 }
 });
 
@@ -8060,8 +8503,8 @@
 
 
 
-static excludeBlacklisted(timing){
-return UserTimings.blacklistedPrefixes.every(prefix=>!timing.name.startsWith(prefix));
+static excludeBlacklisted(evt){
+return UserTimings.blacklistedPrefixes.every(prefix=>!evt.name.startsWith(prefix));
 }
 
 
@@ -8077,13 +8520,12 @@
 return{
 name:item.name,
 timingType:item.isMark?'Mark':'Measure',
-time:Util.formatMilliseconds(time,0.001),
-timeAsNumber:time};
+time};
 
 }).sort((itemA,itemB)=>{
 if(itemA.timingType===itemB.timingType){
 
-return itemA.timeAsNumber-itemB.timeAsNumber;
+return itemA.time-itemB.time;
 }else if(itemA.timingType==='Measure'){
 
 return-1;
@@ -8095,7 +8537,7 @@
 const headings=[
 {key:'name',itemType:'text',text:'Name'},
 {key:'timingType',itemType:'text',text:'Type'},
-{key:'time',itemType:'text',text:'Time'}];
+{key:'time',itemType:'ms',granularity:0.01,text:'Time'}];
 
 
 const details=Audit.makeTableDetails(headings,tableRows);
@@ -8103,7 +8545,8 @@
 return{
 
 rawValue:userTimings.length===0,
-displayValue:userTimings.length,
+notApplicable:userTimings.length===0,
+displayValue:userTimings.length?`${userTimings.length}`:'',
 extendedInfo:{
 value:userTimings},
 
@@ -8115,7 +8558,7 @@
 
 module.exports=UserTimings;
 
-},{"../report/v2/renderer/util":43,"./audit":2}],"../audits/uses-rel-preload":[function(require,module,exports){
+},{"./audit":2}],"../audits/uses-rel-preconnect":[function(require,module,exports){
 
 
 
@@ -8125,7 +8568,175 @@
 'use strict';
 
 const Audit=require('./audit');
-const Util=require('../report/v2/renderer/util');
+const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
+
+
+
+
+const PRECONNECT_SOCKET_MAX_IDLE=15;
+
+const IGNORE_THRESHOLD_IN_MS=50;
+
+class UsesRelPreconnectAudit extends Audit{
+
+
+
+static get meta(){
+return{
+name:'uses-rel-preconnect',
+description:'Avoid multiple, costly round trips to any origin',
+helpText:
+'Consider adding preconnect or dns-prefetch resource hints to establish early '+
+`connections to important third-party origins. [Learn more](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect).`,
+requiredArtifacts:['devtoolsLogs','URL'],
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC};
+
+}
+
+
+
+
+
+
+static hasValidTiming(record){
+return record._timing&&record._timing.connectEnd>0&&record._timing.connectStart>0;
+}
+
+
+
+
+
+
+static hasAlreadyConnectedToOrigin(record){
+return(
+record._timing.dnsEnd-record._timing.dnsStart===0&&
+record._timing.connectEnd-record._timing.connectStart===0);
+
+}
+
+
+
+
+
+
+
+static socketStartTimeIsBelowThreshold(record,mainResource){
+return Math.max(0,record.startTime-mainResource.endTime)<PRECONNECT_SOCKET_MAX_IDLE;
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const devtoolsLog=artifacts.devtoolsLogs[UsesRelPreconnectAudit.DEFAULT_PASS];
+const URL=artifacts.URL;
+const settings=context.settings;
+let maxWasted=0;
+
+const[networkRecords,mainResource,loadSimulator]=await Promise.all([
+artifacts.requestNetworkRecords(devtoolsLog),
+artifacts.requestMainResource({devtoolsLog,URL}),
+artifacts.requestLoadSimulator({devtoolsLog,settings})]);
+
+
+const{rtt,additionalRttByOrigin}=loadSimulator.getOptions();
+
+
+const origins=new Map();
+networkRecords.
+forEach(record=>{
+if(
+
+!UsesRelPreconnectAudit.hasValidTiming(record)||
+
+record.initiatorRequest()===mainResource||
+
+!record.parsedURL||!record.parsedURL.securityOrigin()||
+
+mainResource.parsedURL.securityOrigin()===record.parsedURL.securityOrigin()||
+
+UsesRelPreconnectAudit.hasAlreadyConnectedToOrigin(record)||
+
+!UsesRelPreconnectAudit.socketStartTimeIsBelowThreshold(record,mainResource))
+{
+return;
+}
+
+const securityOrigin=record.parsedURL.securityOrigin();
+const records=origins.get(securityOrigin)||[];
+records.push(record);
+origins.set(securityOrigin,records);
+});
+
+
+let results=[];
+origins.forEach(records=>{
+
+
+const firstRecordOfOrigin=records.reduce((firstRecord,record)=>{
+return record.startTime<firstRecord.startTime?record:firstRecord;
+});
+
+const securityOrigin=firstRecordOfOrigin.parsedURL.securityOrigin();
+
+
+
+
+const additionalRtt=additionalRttByOrigin.get(securityOrigin)||0;
+let connectionTime=rtt+additionalRtt;
+
+if(firstRecordOfOrigin.parsedURL.scheme==='https')connectionTime=connectionTime*2;
+
+const timeBetweenMainResourceAndDnsStart=
+firstRecordOfOrigin.startTime*1000-
+mainResource.endTime*1000+
+firstRecordOfOrigin._timing.dnsStart;
+
+const wastedMs=Math.min(connectionTime,timeBetweenMainResourceAndDnsStart);
+if(wastedMs<IGNORE_THRESHOLD_IN_MS)return;
+
+maxWasted=Math.max(wastedMs,maxWasted);
+results.push({
+url:securityOrigin,
+wastedMs:wastedMs});
+
+});
+
+results=results.
+sort((a,b)=>b.wastedMs-a.wastedMs);
+
+const headings=[
+{key:'url',itemType:'url',text:'Origin'},
+{key:'wastedMs',itemType:'ms',text:'Potential Savings'}];
+
+const summary={wastedMs:maxWasted};
+const details=Audit.makeTableDetails(headings,results,summary);
+
+return{
+score:UnusedBytes.scoreForWastedMs(maxWasted),
+rawValue:maxWasted,
+displayValue:['Potential savings of %10d\xa0ms',maxWasted],
+extendedInfo:{
+value:results},
+
+details};
+
+}}
+
+
+module.exports=UsesRelPreconnectAudit;
+
+},{"./audit":2,"./byte-efficiency/byte-efficiency-audit":3}],"../audits/uses-rel-preload":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Audit=require('./audit');
 const UnusedBytes=require('./byte-efficiency/byte-efficiency-audit');
 const THRESHOLD_IN_MS=100;
 
@@ -8135,19 +8746,28 @@
 
 static get meta(){
 return{
-category:'Performance',
 name:'uses-rel-preload',
 description:'Preload key requests',
-informative:true,
 helpText:'Consider using <link rel=preload> to prioritize fetching late-discovered '+
-'resources sooner [Learn more](https://developers.google.com/web/updates/2016/03/link-rel-preload).',
-requiredArtifacts:['devtoolsLogs','traces'],
-scoringMode:Audit.SCORING_MODES.NUMERIC};
+'resources sooner. [Learn more](https://developers.google.com/web/updates/2016/03/link-rel-preload).',
+requiredArtifacts:['devtoolsLogs','traces','URL'],
+scoreDisplayMode:Audit.SCORING_MODES.NUMERIC};
 
 }
 
+
+
+
+
+
 static _flattenRequests(chains,maxLevel,minLevel=0){
+
 const requests=[];
+
+
+
+
+
 const flatten=(chains,level)=>{
 Object.keys(chains).forEach(chain=>{
 if(chains[chain]){
@@ -8172,62 +8792,134 @@
 
 
 
-static audit(artifacts){
-const devtoolsLogs=artifacts.devtoolsLogs[UsesRelPreloadAudit.DEFAULT_PASS];
 
-return Promise.all([
-artifacts.requestCriticalRequestChains(devtoolsLogs),
-artifacts.requestMainResource(devtoolsLogs)]).
-then(([critChains,mainResource])=>{
+
+
+static computeWasteWithGraph(urls,graph,simulator){
+if(!urls.size){
+return{wastedMs:0,results:[]};
+}
+
+
+
+const simulationBeforeChanges=simulator.simulate(graph,{flexibleOrdering:true});
+const modifiedGraph=graph.cloneWithRelationships();
+
+
+const nodesToPreload=[];
+
+let mainDocumentNode=null;
+modifiedGraph.traverse(node=>{
+if(node.type!=='network')return;
+
+const networkNode=node;
+if(node.isMainDocument()){
+mainDocumentNode=networkNode;
+}else if(networkNode.record&&urls.has(networkNode.record.url)){
+nodesToPreload.push(networkNode);
+}
+});
+
+if(!mainDocumentNode){
+
+throw new Error('Could not find main document node');
+}
+
+
+
+for(const node of nodesToPreload){
+node.removeAllDependencies();
+node.addDependency(mainDocumentNode);
+}
+
+
+const simulationAfterChanges=simulator.simulate(modifiedGraph,{flexibleOrdering:true});
+const originalNodesByRecord=Array.from(simulationBeforeChanges.nodeTimings.keys()).
+
+reduce((map,node)=>map.set(node.record,node),new Map());
+
 const results=[];
-let maxWasted=0;
+for(const node of nodesToPreload){
+const originalNode=originalNodesByRecord.get(node.record);
+const timingAfter=simulationAfterChanges.nodeTimings.get(node);
+const timingBefore=simulationBeforeChanges.nodeTimings.get(originalNode);
+
+const wastedMs=Math.round(timingBefore.endTime-timingAfter.endTime);
+if(wastedMs<THRESHOLD_IN_MS)continue;
+results.push({url:node.record.url,wastedMs});
+}
+
+if(!results.length){
+return{wastedMs:0,results};
+}
+
+return{
+
+
+wastedMs:Math.max(...results.map(item=>item.wastedMs)),
+results};
+
+}
+
+
+
+
+
+
+static async audit(artifacts,context){
+const trace=artifacts.traces[UsesRelPreloadAudit.DEFAULT_PASS];
+const devtoolsLog=artifacts.devtoolsLogs[UsesRelPreloadAudit.DEFAULT_PASS];
+const URL=artifacts.URL;
+const simulatorOptions={trace,devtoolsLog,settings:context.settings};
+
+const[critChains,mainResource,graph,simulator]=await Promise.all([
+
+artifacts.requestCriticalRequestChains({devtoolsLog,URL}),
+artifacts.requestMainResource({devtoolsLog,URL}),
+artifacts.requestPageDependencyGraph({trace,devtoolsLog}),
+artifacts.requestLoadSimulator(simulatorOptions)]);
+
+
 
 const mainResourceIndex=mainResource.redirects?mainResource.redirects.length:0;
 
 const criticalRequests=UsesRelPreloadAudit._flattenRequests(critChains,
 3+mainResourceIndex,2+mainResourceIndex);
-criticalRequests.forEach(request=>{
-const networkRecord=request;
+
+
+const urls=new Set();
+for(const networkRecord of criticalRequests){
 if(!networkRecord._isLinkPreload&&networkRecord.protocol!=='data'){
-
-const wastedMs=Math.min(request._startTime-mainResource._endTime,
-request._endTime-request._startTime)*1000;
-
-if(wastedMs>=THRESHOLD_IN_MS){
-maxWasted=Math.max(wastedMs,maxWasted);
-results.push({
-url:request.url,
-wastedMs:Util.formatMilliseconds(wastedMs)});
-
+urls.add(networkRecord._url);
 }
 }
-});
 
+const{results,wastedMs}=UsesRelPreloadAudit.computeWasteWithGraph(urls,graph,simulator);
 
 results.sort((a,b)=>b.wastedMs-a.wastedMs);
 
 const headings=[
 {key:'url',itemType:'url',text:'URL'},
-{key:'wastedMs',itemType:'text',text:'Potential Savings'}];
+{key:'wastedMs',itemType:'ms',text:'Potential Savings',granularity:10}];
 
-const details=Audit.makeTableDetails(headings,results);
+const summary={wastedMs};
+const details=Audit.makeTableDetails(headings,results,summary);
 
 return{
-score:UnusedBytes.scoreForWastedMs(maxWasted),
-rawValue:maxWasted,
-displayValue:Util.formatMilliseconds(maxWasted),
+score:UnusedBytes.scoreForWastedMs(wastedMs),
+rawValue:wastedMs,
+displayValue:['Potential savings of %10d\xa0ms',wastedMs],
 extendedInfo:{
 value:results},
 
 details};
 
-});
 }}
 
 
 module.exports=UsesRelPreloadAudit;
 
-},{"../report/v2/renderer/util":43,"./audit":2,"./byte-efficiency/byte-efficiency-audit":3}],"../audits/viewport":[function(require,module,exports){
+},{"./audit":2,"./byte-efficiency/byte-efficiency-audit":3}],"../audits/viewport":[function(require,module,exports){
 
 
 
@@ -8261,35 +8953,34 @@
 static audit(artifacts){
 if(artifacts.Viewport===null){
 return{
-debugString:'No viewport meta tag found',
+explanation:'No viewport meta tag found',
 rawValue:false};
 
 }
 
-let debugString='';
+const warnings=[];
 const parsedProps=Parser.parseMetaViewPortContent(artifacts.Viewport);
 
 if(Object.keys(parsedProps.unknownProperties).length){
-debugString+=`Invalid properties found: ${JSON.stringify(parsedProps.unknownProperties)}. `;
+warnings.push(`Invalid properties found: ${JSON.stringify(parsedProps.unknownProperties)}`);
 }
 if(Object.keys(parsedProps.invalidValues).length){
-debugString+=`Invalid values found: ${JSON.stringify(parsedProps.invalidValues)}. `;
+warnings.push(`Invalid values found: ${JSON.stringify(parsedProps.invalidValues)}`);
 }
-debugString=debugString.trim();
 
 const viewportProps=parsedProps.validProperties;
 const hasMobileViewport=viewportProps.width||viewportProps['initial-scale'];
 
 return{
 rawValue:!!hasMobileViewport,
-debugString};
+warnings};
 
 }}
 
 
 module.exports=Viewport;
 
-},{"./audit":2,"metaviewport-parser":139}],"../audits/webapp-install-banner":[function(require,module,exports){
+},{"./audit":2,"metaviewport-parser":145}],"../audits/webapp-install-banner":[function(require,module,exports){
 
 
 
@@ -8336,13 +9027,17 @@
 
 }
 
-static assessManifest(artifacts,result){
-const{manifestValues,failures}=result;
-if(manifestValues.isParseFailure){
-failures.push(manifestValues.parseFailureReason);
-return;
+
+
+
+
+static assessManifest(manifestValues){
+if(manifestValues.isParseFailure&&manifestValues.parseFailureReason){
+return[manifestValues.parseFailureReason];
 }
 
+
+const failures=[];
 const bannerCheckIds=[
 'hasName',
 'hasShortName',
@@ -8357,40 +9052,76 @@
 failures.push(item.failureText);
 }
 });
+
+return failures;
 }
 
 
-static assessServiceWorker(artifacts,result){
+
+
+
+static assessServiceWorker(artifacts){
+const failures=[];
 const hasServiceWorker=SWAudit.audit(artifacts).rawValue;
 if(!hasServiceWorker){
-result.failures.push('Site does not register a service worker');
-}
+failures.push('Site does not register a service worker');
 }
 
-static assessOfflineStartUrl(artifacts,result){
+return failures;
+}
+
+
+
+
+
+static assessOfflineStartUrl(artifacts){
+const failures=[];
+const warnings=[];
 const hasOfflineStartUrl=artifacts.StartUrl.statusCode===200;
 
 if(!hasOfflineStartUrl){
-result.failures.push('Service worker does not successfully serve the manifest\'s start_url');
-if(artifacts.StartUrl.debugString)result.failures.push(artifacts.StartUrl.debugString);
+failures.push('Service worker does not successfully serve the manifest\'s start_url');
+
+if(artifacts.StartUrl.debugString){
+failures.push(artifacts.StartUrl.debugString);
+}
 }
 
 if(artifacts.StartUrl.debugString){
-result.warnings.push(artifacts.StartUrl.debugString);
+warnings.push(artifacts.StartUrl.debugString);
 }
+
+return{failures,warnings};
 }
 
+
+
+
+
 static audit_(artifacts){
-const failures=[];
-const warnings=[];
+
+let offlineFailures=[];
+
+let offlineWarnings=[];
 
 return artifacts.requestManifestValues(artifacts.Manifest).then(manifestValues=>{
-const result={warnings,failures,manifestValues};
-WebappInstallBanner.assessManifest(artifacts,result);
-WebappInstallBanner.assessServiceWorker(artifacts,result);
-WebappInstallBanner.assessOfflineStartUrl(artifacts,result);
+const manifestFailures=WebappInstallBanner.assessManifest(manifestValues);
+const swFailures=WebappInstallBanner.assessServiceWorker(artifacts);
+if(!swFailures.length){
+const{failures,warnings}=WebappInstallBanner.assessOfflineStartUrl(artifacts);
+offlineFailures=failures;
+offlineWarnings=warnings;
+}
 
-return result;
+return{
+warnings:offlineWarnings,
+failures:[
+...manifestFailures,
+...swFailures,
+...offlineFailures],
+
+manifestValues};
+
 });
 }}
 
@@ -8433,7 +9164,7 @@
 if(artifact.value.trim()===''){
 return{
 rawValue:false,
-debugString:'The page body should render some content if its scripts are not available.'};
+explanation:'The page body should render some content if its scripts are not available.'};
 
 }
 
@@ -8477,1328 +9208,25 @@
 
 
 static audit(artifacts){
-let debugString;
+const warnings=[];
 const passed=artifacts.Offline===200;
 if(!passed&&
-!URL.equalWithExcludedFragments(artifacts.URL.initialUrl,artifacts.URL.finalUrl)){
-debugString='WARNING: You may be failing this check because your test URL '+
-`(${artifacts.URL.initialUrl}) was redirected to "${artifacts.URL.finalUrl}". `+
-'Try testing the second URL directly.';
+!URL.equalWithExcludedFragments(artifacts.URL.requestedUrl,artifacts.URL.finalUrl)){
+warnings.push('You may be not loading offline because your test URL '+
+`(${artifacts.URL.requestedUrl}) was redirected to "${artifacts.URL.finalUrl}". `+
+'Try testing the second URL directly.');
 }
 
 return{
 rawValue:passed,
-debugString};
+warnings};
 
 }}
 
 
 module.exports=WorksOffline;
 
-},{"../lib/url-shim":41,"./audit":2}],"./gather/computed/computed-artifact":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ArbitraryEqualityMap=require('../../lib/arbitrary-equality-map');
-
-class ComputedArtifact{
-
-
-
-constructor(allComputedArtifacts){
-
-this._cache=new ArbitraryEqualityMap();
-this._cache.setEqualityFn(ArbitraryEqualityMap.deepEquals);
-
-
-this._allComputedArtifacts=allComputedArtifacts;
-}
-
-get requiredNumberOfArtifacts(){
-return 1;
-}
-
-
-
-
-
-
-
-
-
-
-
-compute_(artifact,allComputedArtifacts){
-throw new Error('compute_() not implemented for computed artifact '+this.name);
-}
-
-
-
-
-
-_assertCorrectNumberOfArtifacts(artifacts){
-const actual=artifacts.length;
-const expected=this.requiredNumberOfArtifacts;
-if(actual!==expected){
-const className=this.constructor.name;
-throw new Error(`${className} requires ${expected} artifacts but ${actual} were given`);
-}
-}
-
-
-
-
-
-
-
-
-request(...artifacts){
-this._assertCorrectNumberOfArtifacts(artifacts);
-if(this._cache.has(artifacts)){
-return Promise.resolve(this._cache.get(artifacts));
-}
-
-const artifactPromise=Promise.resolve().
-then(_=>this.compute_(...artifacts,this._allComputedArtifacts));
-this._cache.set(artifacts,artifactPromise);
-
-return artifactPromise;
-}}
-
-
-module.exports=ComputedArtifact;
-
-},{"../../lib/arbitrary-equality-map":17}],"./gather/computed/critical-request-chains":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const WebInspector=require('../../lib/web-inspector');
-const assert=require('assert');
-
-class CriticalRequestChains extends ComputedArtifact{
-get name(){
-return'CriticalRequestChains';
-}
-
-
-
-
-
-
-
-
-static isCritical(request,mainResource){
-assert.ok(mainResource,'mainResource not provided');
-const resourceTypeCategory=request._resourceType&&request._resourceType._category;
-
-
-const isIframe=request._resourceType===WebInspector.resourceTypes.Document&&
-request.frameId!==mainResource.frameId;
-
-
-
-const nonCriticalResourceTypes=[
-WebInspector.resourceTypes.Image._category,
-WebInspector.resourceTypes.XHR._category];
-
-if(nonCriticalResourceTypes.includes(resourceTypeCategory)||
-isIframe||
-request.mimeType&&request.mimeType.startsWith('image/')){
-return false;
-}
-
-return['VeryHigh','High','Medium'].includes(request.priority());
-}
-
-static extractChain([networkRecords,mainResource]){
-networkRecords=networkRecords.filter(req=>req.finished);
-
-
-const requestIdToRequests=new Map();
-for(const request of networkRecords){
-requestIdToRequests.set(request.requestId,request);
-}
-
-
-
-const criticalRequests=networkRecords.filter(request=>
-CriticalRequestChains.isCritical(request,mainResource));
-
-
-const criticalRequestChains={};
-for(const request of criticalRequests){
-
-
-
-const ancestors=[];
-let ancestorRequest=request.initiatorRequest();
-let node=criticalRequestChains;
-while(ancestorRequest){
-const ancestorIsCritical=CriticalRequestChains.isCritical(ancestorRequest,mainResource);
-
-
-
-
-
-if(!ancestorIsCritical||ancestors.includes(ancestorRequest.requestId)){
-
-
-ancestors.length=0;
-node=undefined;
-break;
-}
-ancestors.push(ancestorRequest.requestId);
-ancestorRequest=ancestorRequest.initiatorRequest();
-}
-
-
-
-let ancestor=ancestors.pop();
-while(ancestor){
-const parentRequest=requestIdToRequests.get(ancestor);
-const parentRequestId=parentRequest.requestId;
-if(!node[parentRequestId]){
-node[parentRequestId]={
-request:parentRequest,
-children:{}};
-
-}
-
-
-ancestor=ancestors.pop();
-node=node[parentRequestId].children;
-}
-
-if(!node){
-continue;
-}
-
-
-if(node[request.requestId]){
-continue;
-}
-
-
-node[request.requestId]={
-request,
-children:{}};
-
-}
-
-return criticalRequestChains;
-}
-
-
-
-
-
-
-compute_(devtoolsLog,artifacts){
-return Promise.all([
-artifacts.requestNetworkRecords(devtoolsLog),
-artifacts.requestMainResource(devtoolsLog)]).
-
-then(CriticalRequestChains.extractChain);
-}}
-
-
-module.exports=CriticalRequestChains;
-
-},{"../../lib/web-inspector":42,"./computed-artifact":"./gather/computed/computed-artifact","assert":47}],"./gather/computed/dtm-model":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const DTM=require('../../lib/traces/devtools-timeline-model');
-
-class DevtoolsTimelineModel extends ComputedArtifact{
-get name(){
-return'DevtoolsTimelineModel';
-}
-
-
-
-
-
-compute_(trace){
-return Promise.resolve(new DTM(trace));
-}}
-
-
-module.exports=DevtoolsTimelineModel;
-
-},{"../../lib/traces/devtools-timeline-model":37,"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/first-interactive":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const TracingProcessor=require('../../lib/traces/tracing-processor');
-const LHError=require('../../lib/errors');
-
-const LONG_TASK_THRESHOLD=50;
-
-const MAX_TASK_CLUSTER_DURATION=250;
-const MIN_TASK_CLUSTER_PADDING=1000;
-const MIN_TASK_CLUSTER_FMP_DISTANCE=5000;
-
-const MAX_QUIET_WINDOW_SIZE=5000;
-
-
-const EXPONENTIATION_COEFFICIENT=-Math.log(3-1)/15;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class FirstInteractive extends ComputedArtifact{
-get name(){
-return'FirstInteractive';
-}
-
-
-
-
-
-static getRequiredWindowSizeInMs(t){
-const tInSeconds=t/1000;
-const exponentiationComponent=Math.exp(EXPONENTIATION_COEFFICIENT*tInSeconds);
-return(4*exponentiationComponent+1)*1000;
-}
-
-
-
-
-
-
-
-
-
-
-static getTaskClustersInWindow(tasks,startIndex,windowEnd){
-const clusters=[];
-
-let previousTaskEndTime=-Infinity;
-let currentCluster=null;
-
-
-
-
-
-const clusteringWindowEnd=windowEnd+MIN_TASK_CLUSTER_PADDING;
-const isInClusteringWindow=task=>task.start<clusteringWindowEnd;
-for(let i=startIndex;i<tasks.length;i++){
-if(!isInClusteringWindow(tasks[i])){
-break;
-}
-
-const task=tasks[i];
-
-
-if(task.start-previousTaskEndTime>MIN_TASK_CLUSTER_PADDING){
-currentCluster=[];
-clusters.push(currentCluster);
-}
-
-currentCluster.push(task);
-previousTaskEndTime=task.end;
-}
-
-return clusters.
-
-map(tasks=>{
-const start=tasks[0].start;
-const end=tasks[tasks.length-1].end;
-const duration=end-start;
-return{start,end,duration};
-}).
-
-filter(cluster=>cluster.start<windowEnd);
-}
-
-
-
-
-
-
-
-
-
-
-static findQuietWindow(FMP,traceEnd,longTasks){
-
-if(longTasks.length===0||
-longTasks[0].start>FMP+FirstInteractive.getRequiredWindowSizeInMs(0)){
-return FMP;
-}
-
-const isTooCloseToFMP=cluster=>cluster.start<FMP+MIN_TASK_CLUSTER_FMP_DISTANCE;
-const isTooLong=cluster=>cluster.duration>MAX_TASK_CLUSTER_DURATION;
-const isBadCluster=cluster=>isTooCloseToFMP(cluster)||isTooLong(cluster);
-
-
-
-for(let i=0;i<longTasks.length;i++){
-const windowStart=longTasks[i].end;
-const windowSize=FirstInteractive.getRequiredWindowSizeInMs(windowStart-FMP);
-const windowEnd=windowStart+windowSize;
-
-
-if(windowEnd>traceEnd){
-throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
-}
-
-
-if(i+1<longTasks.length&&
-longTasks[i+1].start-windowStart<=MIN_TASK_CLUSTER_PADDING){
-continue;
-}
-
-const taskClusters=FirstInteractive.getTaskClustersInWindow(longTasks,i+1,windowEnd);
-const hasBadTaskClusters=taskClusters.some(isBadCluster);
-
-if(!hasBadTaskClusters){
-return windowStart;
-}
-}
-
-throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
-}
-
-
-
-
-
-computeWithArtifacts(traceOfTab){
-const navStart=traceOfTab.timestamps.navigationStart;
-const FMP=traceOfTab.timings.firstMeaningfulPaint;
-const DCL=traceOfTab.timings.domContentLoaded;
-const traceEnd=traceOfTab.timings.traceEnd;
-
-if(traceEnd-FMP<MAX_QUIET_WINDOW_SIZE){
-throw new LHError(LHError.errors.FMP_TOO_LATE_FOR_FCPUI);
-}
-
-if(!FMP||!DCL){
-throw new LHError(FMP?LHError.errors.NO_DCL:LHError.errors.NO_FMP);
-}
-
-const longTasksAfterFMP=TracingProcessor.getMainThreadTopLevelEvents(traceOfTab,FMP).
-filter(evt=>evt.duration>=LONG_TASK_THRESHOLD);
-const firstInteractive=FirstInteractive.findQuietWindow(FMP,traceEnd,longTasksAfterFMP);
-
-const valueInMs=Math.max(firstInteractive,DCL);
-return{
-timeInMs:valueInMs,
-timestamp:valueInMs*1000+navStart};
-
-}
-
-
-
-
-
-
-compute_(trace,artifacts){
-return artifacts.requestTraceOfTab(trace).then(traceOfTab=>{
-return this.computeWithArtifacts(traceOfTab);
-});
-}}
-
-
-module.exports=FirstInteractive;
-
-},{"../../lib/errors":28,"../../lib/traces/tracing-processor":40,"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/main-resource":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const HTTP_REDIRECT_CODE_LOW=300;
-const HTTP_REDIRECT_CODE_HIGH=399;
-
-
-
-
-
-class MainResource extends ComputedArtifact{
-get name(){
-return'MainResource';
-}
-
-
-
-
-
-isMainResource(request){
-return request.statusCode<HTTP_REDIRECT_CODE_LOW||
-request.statusCode>HTTP_REDIRECT_CODE_HIGH;
-}
-
-
-
-
-
-
-compute_(devtoolsLog,artifacts){
-return artifacts.requestNetworkRecords(devtoolsLog).
-then(requests=>{
-const mainResource=requests.find(this.isMainResource);
-
-if(!mainResource){
-throw new Error('Unable to identify the main resource');
-}
-
-return mainResource;
-});
-}}
-
-
-module.exports=MainResource;
-
-},{"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/manifest-values":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const icons=require('../../lib/icons');
-
-const PWA_DISPLAY_VALUES=['minimal-ui','fullscreen','standalone'];
-
-
-
-const SUGGESTED_SHORTNAME_LENGTH=12;
-
-class ManifestValues extends ComputedArtifact{
-get name(){
-return'ManifestValues';
-}
-
-static get validityIds(){
-return['hasManifest','hasParseableManifest'];
-}
-
-static get manifestChecks(){
-return[
-{
-id:'hasStartUrl',
-failureText:'Manifest does not contain a `start_url`',
-validate:manifest=>!!manifest.value.start_url.value},
-
-{
-id:'hasIconsAtLeast192px',
-failureText:'Manifest does not have icons at least 192px',
-validate:manifest=>icons.doExist(manifest.value)&&
-icons.sizeAtLeast(192,manifest.value).length>0},
-
-{
-id:'hasIconsAtLeast512px',
-failureText:'Manifest does not have icons at least 512px',
-validate:manifest=>icons.doExist(manifest.value)&&
-icons.sizeAtLeast(512,manifest.value).length>0},
-
-{
-id:'hasPWADisplayValue',
-failureText:'Manifest\'s `display` value is not one of: '+PWA_DISPLAY_VALUES.join(' | '),
-validate:manifest=>PWA_DISPLAY_VALUES.includes(manifest.value.display.value)},
-
-{
-id:'hasBackgroundColor',
-failureText:'Manifest does not have `background_color`',
-validate:manifest=>!!manifest.value.background_color.value},
-
-{
-id:'hasThemeColor',
-failureText:'Manifest does not have `theme_color`',
-validate:manifest=>!!manifest.value.theme_color.value},
-
-{
-id:'hasShortName',
-failureText:'Manifest does not have `short_name`',
-validate:manifest=>!!manifest.value.short_name.value},
-
-{
-id:'shortNameLength',
-failureText:'Manifest `short_name` will be truncated when displayed on the homescreen',
-validate:manifest=>!!manifest.value.short_name.value&&
-manifest.value.short_name.value.length<=SUGGESTED_SHORTNAME_LENGTH},
-
-{
-id:'hasName',
-failureText:'Manifest does not have `name`',
-validate:manifest=>!!manifest.value.name.value}];
-
-
-}
-
-
-
-
-
-
-compute_(manifest){
-
-let parseFailureReason;
-
-if(manifest===null){
-parseFailureReason='No manifest was fetched';
-}
-if(manifest&&manifest.value===undefined){
-parseFailureReason='Manifest failed to parse as valid JSON';
-}
-if(parseFailureReason){
-return{
-isParseFailure:true,
-parseFailureReason,
-allChecks:[]};
-
-}
-
-
-const remainingChecks=ManifestValues.manifestChecks.map(item=>{
-item.passing=item.validate(manifest);
-return item;
-});
-
-return{
-isParseFailure:false,
-parseFailureReason,
-allChecks:remainingChecks};
-
-}}
-
-
-module.exports=ManifestValues;
-
-},{"../../lib/icons":30,"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/network-records":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const NetworkRecorder=require('../../lib/network-recorder');
-
-class NetworkRecords extends ComputedArtifact{
-get name(){
-return'NetworkRecords';
-}
-
-
-
-
-
-compute_(devtoolsLog){
-return NetworkRecorder.recordsFromLogs(devtoolsLog);
-}}
-
-
-module.exports=NetworkRecords;
-
-},{"../../lib/network-recorder":32,"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/network-throughput":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-
-class NetworkThroughput extends ComputedArtifact{
-get name(){
-return'NetworkThroughput';
-}
-
-
-
-
-
-
-
-
-
-static getThroughput(networkRecords){
-let totalBytes=0;
-const timeBoundaries=networkRecords.reduce((boundaries,record)=>{
-const scheme=record.parsedURL&&record.parsedURL.scheme;
-if(scheme==='data'||record.failed||!record.finished||
-record.statusCode>300||!record.transferSize){
-return boundaries;
-}
-
-totalBytes+=record.transferSize;
-boundaries.push({time:record.responseReceivedTime,isStart:true});
-boundaries.push({time:record.endTime,isStart:false});
-return boundaries;
-},[]).sort((a,b)=>a.time-b.time);
-
-if(!timeBoundaries.length){
-return Infinity;
-}
-
-let inflight=0;
-let currentStart=0;
-let totalDuration=0;
-timeBoundaries.forEach(boundary=>{
-if(boundary.isStart){
-if(inflight===0){
-currentStart=boundary.time;
-}
-inflight++;
-}else{
-inflight--;
-if(inflight===0){
-totalDuration+=boundary.time-currentStart;
-}
-}
-});
-
-return totalBytes/totalDuration;
-}
-
-
-
-
-
-
-compute_(devtoolsLog,artifacts){
-return artifacts.requestNetworkRecords(devtoolsLog).
-then(NetworkThroughput.getThroughput);
-}}
-
-
-module.exports=NetworkThroughput;
-
-},{"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/page-dependency-graph":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const NetworkNode=require('../../lib/dependency-graph/network-node');
-const CPUNode=require('../../lib/dependency-graph/cpu-node');
-const TracingProcessor=require('../../lib/traces/tracing-processor');
-const WebInspector=require('../../lib/web-inspector');
-
-
-const MINIMUM_TASK_DURATION_OF_INTEREST=10;
-
-
-const IGNORED_MIME_TYPES_REGEX=/^video/;
-
-class PageDependencyGraphArtifact extends ComputedArtifact{
-get name(){
-return'PageDependencyGraph';
-}
-
-get requiredNumberOfArtifacts(){
-return 2;
-}
-
-
-
-
-
-static getNetworkInitiators(record){
-if(!record._initiator)return[];
-if(record._initiator.url)return[record._initiator.url];
-if(record._initiator.type==='script'){
-const frames=record._initiator.stack.callFrames;
-return Array.from(new Set(frames.map(frame=>frame.url))).filter(Boolean);
-}
-
-return[];
-}
-
-
-
-
-
-static getNetworkNodeOutput(networkRecords){
-const nodes=[];
-const idToNodeMap=new Map();
-const urlToNodeMap=new Map();
-
-networkRecords.forEach(record=>{
-if(IGNORED_MIME_TYPES_REGEX.test(record.mimeType))return;
-const node=new NetworkNode(record);
-nodes.push(node);
-
-const list=urlToNodeMap.get(record.url)||[];
-list.push(node);
-
-idToNodeMap.set(record.requestId,node);
-urlToNodeMap.set(record.url,list);
-});
-
-return{nodes,idToNodeMap,urlToNodeMap};
-}
-
-
-
-
-
-static getCPUNodes(traceOfTab){
-const nodes=[];
-let i=0;
-
-const minimumEvtDur=MINIMUM_TASK_DURATION_OF_INTEREST*1000;
-while(i<traceOfTab.mainThreadEvents.length){
-const evt=traceOfTab.mainThreadEvents[i];
-
-
-if(
-!TracingProcessor.isScheduleableTask(evt)||
-!evt.dur||
-evt.dur<minimumEvtDur)
-{
-i++;
-continue;
-}
-
-
-const children=[];
-i++;
-for(
-const endTime=evt.ts+evt.dur;
-i<traceOfTab.mainThreadEvents.length&&traceOfTab.mainThreadEvents[i].ts<endTime;
-i++)
-{
-children.push(traceOfTab.mainThreadEvents[i]);
-}
-
-nodes.push(new CPUNode(evt,children));
-}
-
-return nodes;
-}
-
-
-
-
-
-static linkNetworkNodes(rootNode,networkNodeOutput){
-networkNodeOutput.nodes.forEach(node=>{
-const initiators=PageDependencyGraphArtifact.getNetworkInitiators(node.record);
-if(initiators.length){
-initiators.forEach(initiator=>{
-const parentCandidates=networkNodeOutput.urlToNodeMap.get(initiator)||[rootNode];
-
-const parent=parentCandidates.length===1?parentCandidates[0]:rootNode;
-node.addDependency(parent);
-});
-}else if(node!==rootNode){
-rootNode.addDependent(node);
-}
-
-const redirects=Array.from(node.record.redirects||[]);
-redirects.push(node.record);
-
-for(let i=1;i<redirects.length;i++){
-const redirectNode=networkNodeOutput.idToNodeMap.get(redirects[i-1].requestId);
-const actualNode=networkNodeOutput.idToNodeMap.get(redirects[i].requestId);
-actualNode.addDependency(redirectNode);
-}
-});
-}
-
-
-
-
-
-
-static linkCPUNodes(rootNode,networkNodeOutput,cpuNodes){
-function addDependentNetworkRequest(cpuNode,reqId){
-const networkNode=networkNodeOutput.idToNodeMap.get(reqId);
-if(!networkNode||
-networkNode.record._resourceType!==WebInspector.resourceTypes.XHR)return;
-cpuNode.addDependent(networkNode);
-}
-
-function addDependencyOnUrl(cpuNode,url){
-if(!url)return;
-const candidates=networkNodeOutput.urlToNodeMap.get(url)||[];
-
-let minCandidate=null;
-let minDistance=Infinity;
-
-candidates.forEach(candidate=>{
-const distance=cpuNode.startTime-candidate.endTime;
-if(distance>0&&distance<minDistance){
-minCandidate=candidate;
-minDistance=distance;
-}
-});
-
-if(!minCandidate)return;
-cpuNode.addDependency(minCandidate);
-}
-
-const timers=new Map();
-for(const node of cpuNodes){
-for(const evt of node.childEvents){
-if(!evt.args.data)continue;
-
-const url=evt.args.data.url;
-const stackTraceUrls=(evt.args.data.stackTrace||[]).map(l=>l.url).filter(Boolean);
-
-switch(evt.name){
-case'TimerInstall':
-timers.set(evt.args.data.timerId,node);
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;
-case'TimerFire':{
-const installer=timers.get(evt.args.data.timerId);
-if(!installer)break;
-installer.addDependent(node);
-break;
-}
-
-case'InvalidateLayout':
-case'ScheduleStyleRecalculation':
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;
-
-case'EvaluateScript':
-addDependencyOnUrl(node,url);
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;
-
-case'XHRReadyStateChange':
-
-if(evt.args.data.readyState!==4)break;
-
-addDependencyOnUrl(node,url);
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;
-
-case'FunctionCall':
-case'v8.compile':
-addDependencyOnUrl(node,url);
-break;
-
-case'ParseAuthorStyleSheet':
-addDependencyOnUrl(node,evt.args.data.styleSheetUrl);
-break;
-
-case'ResourceSendRequest':
-addDependentNetworkRequest(node,evt.args.data.requestId,evt);
-stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
-break;}
-
-}
-
-if(node.getNumberOfDependencies()===0){
-node.addDependency(rootNode);
-}
-}
-}
-
-
-
-
-
-
-static createGraph(traceOfTab,networkRecords){
-const networkNodeOutput=PageDependencyGraphArtifact.getNetworkNodeOutput(networkRecords);
-const cpuNodes=PageDependencyGraphArtifact.getCPUNodes(traceOfTab);
-
-const rootRequest=networkRecords.reduce((min,r)=>min.startTime<r.startTime?min:r);
-const rootNode=networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
-
-PageDependencyGraphArtifact.linkNetworkNodes(rootNode,networkNodeOutput,networkRecords);
-PageDependencyGraphArtifact.linkCPUNodes(rootNode,networkNodeOutput,cpuNodes);
-
-if(NetworkNode.hasCycle(rootNode)){
-throw new Error('Invalid dependency graph created, cycle detected');
-}
-
-return rootNode;
-}
-
-
-
-
-
-static printGraph(rootNode,widthInCharacters=100){
-function padRight(str,target,padChar=' '){
-return str+padChar.repeat(Math.max(target-str.length,0));
-}
-
-const nodes=[];
-rootNode.traverse(node=>nodes.push(node));
-nodes.sort((a,b)=>a.startTime-b.startTime);
-
-const min=nodes[0].startTime;
-const max=nodes.reduce((max,node)=>Math.max(max,node.endTime),0);
-
-const totalTime=max-min;
-const timePerCharacter=totalTime/widthInCharacters;
-nodes.forEach(node=>{
-const offset=Math.round((node.startTime-min)/timePerCharacter);
-const length=Math.ceil((node.endTime-node.startTime)/timePerCharacter);
-const bar=padRight('',offset)+padRight('',length,'=');
-
-const displayName=node.record?node.record._url:node.type;
-
-console.log(padRight(bar,widthInCharacters),`| ${displayName.slice(0,30)}`);
-});
-}
-
-
-
-
-
-
-
-compute_(trace,devtoolsLog,artifacts){
-const promises=[
-artifacts.requestTraceOfTab(trace),
-artifacts.requestNetworkRecords(devtoolsLog)];
-
-
-return Promise.all(promises).then(([traceOfTab,networkRecords])=>{
-return PageDependencyGraphArtifact.createGraph(traceOfTab,networkRecords);
-});
-}}
-
-
-module.exports=PageDependencyGraphArtifact;
-
-
-
-
-
-
-
-
-PageDependencyGraphArtifact.NetworkNodeOutput;
-
-},{"../../lib/dependency-graph/cpu-node":20,"../../lib/dependency-graph/network-node":21,"../../lib/traces/tracing-processor":40,"../../lib/web-inspector":42,"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/pushed-requests":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-
-class PushedRequests extends ComputedArtifact{
-get name(){
-return'PushedRequests';
-}
-
-
-
-
-
-
-
-compute_(devtoolsLog,artifacts){
-return artifacts.requestNetworkRecords(devtoolsLog).then(records=>{
-const pushedRecords=records.filter(r=>r._timing&&!!r._timing.pushStart);
-return pushedRecords;
-});
-}}
-
-
-module.exports=PushedRequests;
-
-},{"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/screenshots":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-
-class ScreenshotFilmstrip extends ComputedArtifact{
-get name(){
-return'Screenshots';
-}
-
-fetchScreenshot(frame){
-return frame.
-imageDataPromise().
-then(data=>'data:image/jpg;base64,'+data);
-}
-
-
-
-
-
-
-compute_(trace,artifacts){
-return artifacts.requestDevtoolsTimelineModel(trace).then(model=>{
-const filmStripFrames=model.filmStripModel().frames();
-const frameFetches=filmStripFrames.map(frame=>this.fetchScreenshot(frame));
-
-return Promise.all(frameFetches).then(images=>{
-const result=filmStripFrames.map((frame,i)=>({
-timestamp:frame.timestamp,
-datauri:images[i]}));
-
-return result;
-});
-});
-}}
-
-
-module.exports=ScreenshotFilmstrip;
-
-},{"./computed-artifact":"./gather/computed/computed-artifact"}],"./gather/computed/speedline":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const ComputedArtifact=require('./computed-artifact');
-const speedline=require('speedline');
-const LHError=require('../../lib/errors');
-
-class Speedline extends ComputedArtifact{
-get name(){
-return'Speedline';
-}
-
-
-
-
-compute_(trace,computedArtifacts){
-
-
-return computedArtifacts.requestTraceOfTab(trace).then(traceOfTab=>{
-
-
-const traceEvents=trace.traceEvents.slice();
-
-
-const navStart=traceOfTab.timestamps.navigationStart;
-return speedline(traceEvents,{
-timeOrigin:navStart,
-fastMode:true,
-include:'perceptualSpeedIndex'});
-
-}).catch(err=>{
-if(/No screenshots found in trace/.test(err.message)){
-throw new LHError(LHError.errors.NO_SCREENSHOTS);
-}
-
-throw err;
-});
-}}
-
-
-module.exports=Speedline;
-
-},{"../../lib/errors":28,"./computed-artifact":"./gather/computed/computed-artifact","speedline":144}],"./gather/computed/trace-of-tab":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-const ComputedArtifact=require('./computed-artifact');
-const log=require('lighthouse-logger');
-const LHError=require('../../lib/errors');
-const Sentry=require('../../lib/sentry');
-
-
-
-
-const WebInspector=require('../../lib/web-inspector');
-
-class TraceOfTab extends ComputedArtifact{
-get name(){
-return'TraceOfTab';
-}
-
-
-
-
-
-
-
-compute_(trace){
-
-
-const keyEvents=trace.traceEvents.
-filter(e=>{
-return e.cat.includes('blink.user_timing')||
-e.cat.includes('loading')||
-e.cat.includes('devtools.timeline')||
-e.name==='TracingStartedInPage';
-}).
-stableSort((event0,event1)=>event0.ts-event1.ts);
-
-
-
-const startedInPageEvt=keyEvents.find(e=>e.name==='TracingStartedInPage');
-if(!startedInPageEvt)throw new LHError(LHError.errors.NO_TRACING_STARTED);
-
-const frameEvents=keyEvents.filter(e=>e.args.frame===startedInPageEvt.args.data.page);
-
-
-const navigationStart=frameEvents.filter(e=>e.name==='navigationStart').pop();
-if(!navigationStart)throw new LHError(LHError.errors.NO_NAVSTART);
-
-
-const firstPaint=frameEvents.find(e=>e.name==='firstPaint'&&e.ts>navigationStart.ts);
-
-
-const firstContentfulPaint=frameEvents.find(
-e=>e.name==='firstContentfulPaint'&&e.ts>navigationStart.ts);
-
-
-
-let firstMeaningfulPaint=frameEvents.find(
-e=>e.name==='firstMeaningfulPaint'&&e.ts>navigationStart.ts);
-
-let fmpFellBack=false;
-
-
-
-
-
-if(!firstMeaningfulPaint){
-
-Sentry.captureMessage('No firstMeaningfulPaint found, using fallback',{level:'warning'});
-
-const fmpCand='firstMeaningfulPaintCandidate';
-fmpFellBack=true;
-log.verbose('trace-of-tab',`No firstMeaningfulPaint found, falling back to last ${fmpCand}`);
-const lastCandidate=frameEvents.filter(e=>e.name===fmpCand).pop();
-if(!lastCandidate){
-log.verbose('trace-of-tab','No `firstMeaningfulPaintCandidate` events found in trace');
-}
-firstMeaningfulPaint=lastCandidate;
-}
-
-const onLoad=frameEvents.find(e=>e.name==='loadEventEnd'&&e.ts>navigationStart.ts);
-const domContentLoaded=frameEvents.find(
-e=>e.name==='domContentLoadedEventEnd'&&e.ts>navigationStart.ts);
-
-
-
-
-const processEvents=trace.traceEvents.
-filter(e=>e.pid===startedInPageEvt.pid).
-stableSort((event0,event1)=>event0.ts-event1.ts);
-
-const mainThreadEvents=processEvents.
-filter(e=>e.tid===startedInPageEvt.tid);
-
-const traceEnd=trace.traceEvents.reduce((max,evt)=>{
-return max.ts>evt.ts?max:evt;
-});
-
-const metrics={
-navigationStart,
-firstPaint,
-firstContentfulPaint,
-firstMeaningfulPaint,
-traceEnd:{ts:traceEnd.ts+(traceEnd.dur||0)},
-onLoad,
-domContentLoaded};
-
-
-const timings={};
-const timestamps={};
-
-Object.keys(metrics).forEach(metric=>{
-timestamps[metric]=metrics[metric]&&metrics[metric].ts;
-timings[metric]=(timestamps[metric]-navigationStart.ts)/1000;
-});
-
-return{
-timings,
-timestamps,
-processEvents,
-mainThreadEvents,
-startedInPageEvt,
-navigationStartEvt:navigationStart,
-firstPaintEvt:firstPaint,
-firstContentfulPaintEvt:firstContentfulPaint,
-firstMeaningfulPaintEvt:firstMeaningfulPaint,
-onLoadEvt:onLoad,
-fmpFellBack};
-
-}}
-
-
-module.exports=TraceOfTab;
-
-},{"../../lib/errors":28,"../../lib/sentry":33,"../../lib/web-inspector":42,"./computed-artifact":"./gather/computed/computed-artifact","lighthouse-logger":137}],"./gatherers/accessibility":[function(require,module,exports){
+},{"../lib/url-shim":"url","./audit":2}],"../gather/gatherers/accessibility":[function(require,module,exports){
 
 
 
@@ -9810,13 +9238,17 @@
 
 const Gatherer=require('./gatherer');
 
-const axeLibSource="/*! aXe v2.6.1\n * Copyright (c) 2017 Deque Systems, Inc.\n *\n * Your use of this Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This entire copyright notice must appear in every copy of this file you\n * distribute or in any file that contains substantial portions of this source\n * code.\n */\n!function a(window){function b(a){this.name=\"SupportError\",this.cause=a.cause,this.message=\"`\"+a.cause+\"` - feature unsupported in your environment.\",a.ruleId&&(this.ruleId=a.ruleId,this.message+=\" Skipping \"+this.ruleId+\" rule.\"),this.stack=(new Error).stack}function c(a){\"use strict\";var b;return a?(b=axe.utils.clone(a),b.commons=a.commons):b={},b.reporter=b.reporter||null,b.rules=b.rules||[],b.checks=b.checks||[],b.data=Object.assign({checks:{},rules:{}},b.data),b}function d(a,b,c){\"use strict\";var d,e;for(d=0,e=a.length;d<e;d++)b[c](a[d])}function e(a){this.brand=\"axe\",this.application=\"axeAPI\",this.tagExclude=[\"experimental\"],this.defaultConfig=a,this._init()}function f(a,b,c){var d=a.brand,e=a.application;return axe.constants.helpUrlBase+d+\"/\"+(c||axe.version.substring(0,axe.version.lastIndexOf(\".\")))+\"/\"+b+\"?application=\"+e}function g(a){\"use strict\";this.id=a.id,this.data=null,this.relatedNodes=[],this.result=null}function h(a){\"use strict\";return\"string\"==typeof a?new Function(\"return \"+a+\";\")():a}function i(a){a&&(this.id=a.id,this.configure(a))}function j(a,b){\"use strict\";if(!axe.utils.isHidden(b)){axe.utils.findBy(a,\"node\",b)||a.push({node:b,include:[],exclude:[]})}}function k(a,b,c){\"use strict\";a.frames=a.frames||[];var d,e,f=document.querySelectorAll(c.shift());a:for(var g=0,h=f.length;g<h;g++){e=f[g];for(var i=0,j=a.frames.length;i<j;i++)if(a.frames[i].node===e){a.frames[i][b].push(c);break a}d={node:e,include:[],exclude:[]},c&&d[b].push(c),a.frames.push(d)}}function l(a){\"use strict\";if(a&&\"object\"===(void 0===a?\"undefined\":ha(a))||a instanceof NodeList){if(a instanceof Node)return{include:[a],exclude:[]};if(a.hasOwnProperty(\"include\")||a.hasOwnProperty(\"exclude\"))return{include:a.include&&+a.include.length?a.include:[document],exclude:a.exclude||[]};if(a.length===+a.length)return{include:a,exclude:[]}}return\"string\"==typeof a?{include:[a],exclude:[]}:{include:[document],exclude:[]}}function m(a,b){\"use strict\";for(var c,d=[],e=0,f=a[b].length;e<f;e++){if(\"string\"==typeof(c=a[b][e])){d=d.concat(axe.utils.toArray(document.querySelectorAll(c)));break}!c||!c.length||c instanceof Node?d.push(c):c.length>1?k(a,b,c):d=d.concat(axe.utils.toArray(document.querySelectorAll(c[0])))}return d.filter(function(a){return a})}function n(a){\"use strict\";if(0===a.include.length){if(0===a.frames.length){var b=axe.utils.respondable.isInFrame()?\"frame\":\"page\";return new Error(\"No elements found for include in \"+b+\" Context\")}a.frames.forEach(function(a,b){if(0===a.include.length)return new Error(\"No elements found for include in Context of frame \"+b)})}}function o(a){\"use strict\";var b=this;this.frames=[],this.initiator=!a||\"boolean\"!=typeof a.initiator||a.initiator,this.page=!1,a=l(a),this.exclude=a.exclude,this.include=a.include,this.include=m(this,\"include\"),this.exclude=m(this,\"exclude\"),axe.utils.select(\"frame, iframe\",this).forEach(function(a){fa(a,b)&&j(b.frames,a)}),1===this.include.length&&this.include[0]===document&&(this.page=!0);var c=n(this);if(c instanceof Error)throw c}function p(a){\"use strict\";this.id=a.id,this.result=axe.constants.NA,this.pageLevel=a.pageLevel,this.impact=null,this.nodes=[]}function q(a,b){\"use strict\";this._audit=b,this.id=a.id,this.selector=a.selector||\"*\",this.excludeHidden=\"boolean\"!=typeof a.excludeHidden||a.excludeHidden,this.enabled=\"boolean\"!=typeof a.enabled||a.enabled,this.pageLevel=\"boolean\"==typeof a.pageLevel&&a.pageLevel,this.any=a.any||[],this.all=a.all||[],this.none=a.none||[],this.tags=a.tags||[],a.matches&&(this.matches=h(a.matches))}function r(a){\"use strict\";return axe.utils.getAllChecks(a).map(function(b){var c=a._audit.checks[b.id||b];return c&&\"function\"==typeof c.after?c:null}).filter(Boolean)}function s(a,b){\"use strict\";var c=[];return a.forEach(function(a){axe.utils.getAllChecks(a).forEach(function(a){a.id===b&&c.push(a)})}),c}function t(a){\"use strict\";return a.filter(function(a){return!0!==a.filtered})}function u(a){\"use strict\";var b=[\"any\",\"all\",\"none\"],c=a.nodes.filter(function(a){var c=0;return b.forEach(function(b){a[b]=t(a[b]),c+=a[b].length}),c>0});return a.pageLevel&&c.length&&(c=[c.reduce(function(a,c){if(a)return b.forEach(function(b){a[b].push.apply(a[b],c[b])}),a})]),c}function v(a,b){\"use strict\";if(!axe._audit)throw new Error(\"No audit configured\");var c=axe.utils.queue(),d=[];Object.keys(axe.plugins).forEach(function(a){c.defer(function(b){var c=function(a){d.push(a),b()};try{axe.plugins[a].cleanup(b,c)}catch(a){c(a)}})}),axe.utils.toArray(document.querySelectorAll(\"frame, iframe\")).forEach(function(a){c.defer(function(b,c){return axe.utils.sendCommandToFrame(a,{command:\"cleanup-plugin\"},b,c)})}),c.then(function(c){0===d.length?a(c):b(d)}).catch(b)}function w(a){\"use strict\";var b;if(!(b=axe._audit))throw new Error(\"No audit configured\");a.reporter&&(\"function\"==typeof a.reporter||ka[a.reporter])&&(b.reporter=a.reporter),a.checks&&a.checks.forEach(function(a){b.addCheck(a)}),a.rules&&a.rules.forEach(function(a){b.addRule(a)}),void 0!==a.branding?b.setBranding(a.branding):b._constructHelpUrls(),a.tagExclude&&(b.tagExclude=a.tagExclude)}function x(a,b,c){\"use strict\";var d=c,e=function(a){a instanceof Error==!1&&(a=new Error(a)),c(a)},f=a&&a.context||{};f.hasOwnProperty(\"include\")&&!f.include.length&&(f.include=[document]);var g=a&&a.options||{};switch(a.command){case\"rules\":return A(f,g,d,e);case\"cleanup-plugin\":return v(d,e);default:if(axe._audit&&axe._audit.commands&&axe._audit.commands[a.command])return axe._audit.commands[a.command](a,c)}}function y(a){\"use strict\";this._run=a.run,this._collect=a.collect,this._registry={},a.commands.forEach(function(a){axe._audit.registerCommand(a)})}function z(){\"use strict\";var a=axe._audit;if(!a)throw new Error(\"No audit configured\");a.resetRulesAndChecks()}function A(a,b,c,d){\"use strict\";try{a=new o(a)}catch(a){return d(a)}var e=axe.utils.queue(),f=axe._audit;b.performanceTimer&&axe.utils.performanceTimer.auditStart(),a.frames.length&&!1!==b.iframes&&e.defer(function(c,d){axe.utils.collectResultsFromFrames(a,b,\"rules\",null,c,d)});var g=void 0;e.defer(function(c,d){b.restoreScroll&&(g=axe.utils.getScrollState()),f.run(a,b,c,d)}),e.then(function(e){try{g&&axe.utils.setScrollState(g),b.performanceTimer&&axe.utils.performanceTimer.auditEnd();var h=axe.utils.mergeResults(e.map(function(a){return{results:a}}));a.initiator&&(h=f.after(h,b),h.forEach(axe.utils.publishMetaData),h=h.map(axe.utils.finalizeRuleResult));try{c(h)}catch(a){axe.log(a)}}catch(a){d(a)}}).catch(d)}function B(a){\"use strict\";switch(!0){case\"string\"==typeof a:case Array.isArray(a):case Node&&a instanceof Node:case NodeList&&a instanceof NodeList:return!0;case\"object\"!==(void 0===a?\"undefined\":ha(a)):return!1;case void 0!==a.include:case void 0!==a.exclude:case\"number\"==typeof a.length:return!0;default:return!1}}function C(a,b,c){\"use strict\";var d=new TypeError(\"axe.run arguments are invalid\");if(!B(a)){if(void 0!==c)throw d;c=b,b=a,a=document}if(\"object\"!==(void 0===b?\"undefined\":ha(b))){if(void 0!==c)throw d;c=b,b={}}if(\"function\"!=typeof c&&void 0!==c)throw d;return{context:a,options:b,callback:c||la}}function D(a,b){\"use strict\";[\"any\",\"all\",\"none\"].forEach(function(c){Array.isArray(a[c])&&a[c].filter(function(a){return Array.isArray(a.relatedNodes)}).forEach(function(a){a.relatedNodes=a.relatedNodes.map(function(a){var c={html:a.source};return b.elementRef&&!a.fromFrame&&(c.element=a.element),(!1!==b.selectors||a.fromFrame)&&(c.target=a.selector),b.xpath&&(c.xpath=a.xpath),c})})})}function E(a,b){return ra.reduce(function(c,d){return c[d]=(a[d]||[]).map(function(a){return b(a,d)}),c},{})}function F(a,b,c){var d=Object.assign({},b);d.nodes=(d[c]||[]).concat(),axe.constants.resultGroups.forEach(function(a){delete d[a]}),a[c].push(d)}function G(a,b,c){\"use strict\";var d=window.getComputedStyle(a,null),e=!1;return!!d&&(b.forEach(function(a){d.getPropertyValue(a.property)===a.value&&(e=!0)}),!!e||!(a.nodeName.toUpperCase()===c.toUpperCase()||!a.parentNode)&&G(a.parentNode,b,c))}function H(a,b){\"use strict\";return new Error(a+\": \"+axe.utils.getSelector(b))}function I(a,b,c,d,e,f){\"use strict\";var g=axe.utils.queue();a.frames.forEach(function(e){var f={options:b,command:c,parameter:d,context:{initiator:!1,page:a.page,include:e.include||[],exclude:e.exclude||[]}};g.defer(function(a,b){var c=e.node;axe.utils.sendCommandToFrame(c,f,function(b){if(b)return a({results:b,frameElement:c,frame:axe.utils.getSelector(c)});a(null)},b)})}),g.then(function(a){e(axe.utils.mergeResults(a,b))}).catch(f)}function J(a,b){if(b=b||300,a.length>b){var c=a.indexOf(\">\");a=a.substring(0,c+1)}return a}function K(a){var b=a.outerHTML;return b||\"function\"!=typeof XMLSerializer||(b=(new XMLSerializer).serializeToString(a)),J(b||\"\")}function L(a,b,c){this._fromFrame=!!c,this.spec=c||{},b&&b.absolutePaths&&(this._options={toRoot:!0}),this.source=void 0!==this.spec.source?this.spec.source:K(a),this._element=a}function M(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\";return 0!==a.length&&(a.match(/[0-9]/g)||\"\").length>=a.length/2}function N(a,b){return[a.substring(0,b),a.substring(b)]}function O(a){var b=a,c=\"\",d=\"\",e=\"\",f=\"\",g=\"\",h=\"\";if(a.includes(\"#\")){var i=N(a,a.indexOf(\"#\")),j=sa(i,2);a=j[0],h=j[1]}if(a.includes(\"?\")){var k=N(a,a.indexOf(\"?\")),l=sa(k,2);a=l[0],g=l[1]}if(a.includes(\"://\")){var m=a.split(\"://\"),n=sa(m,2);c=n[0],a=n[1];var o=N(a,a.indexOf(\"/\")),p=sa(o,2);d=p[0],a=p[1]}else if(\"//\"===a.substr(0,2)){a=a.substr(2);var q=N(a,a.indexOf(\"/\")),r=sa(q,2);d=r[0],a=r[1]}if(\"www.\"===d.substr(0,4)&&(d=d.substr(4)),d&&d.includes(\":\")){var s=N(d,d.indexOf(\":\")),t=sa(s,2);d=t[0],e=t[1]}return f=a,{original:b,protocol:c,domain:d,port:e,path:f,query:g,hash:h}}function P(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b<a.length;b++)c[b]=a[b];return c}return Array.from(a)}function Q(a){return![\"focus\",\"hover\",\"hidden\",\"visible\",\"dirty\",\"touched\",\"valid\",\"disable\",\"enable\",\"active\",\"col-\"].find(function(b){return a.includes(b)})}function R(a){return a.classList&&0!==a.classList.length?(a.parentNode&&Array.from(a.parentNode.children||\"\")||[]).reduce(function(b,c){return a===c?b:b.filter(function(a){return!c.classList.contains(a)})},Array.from(a.classList).filter(Q)):[]}function S(a,b){var c=a.parentNode&&Array.from(a.parentNode.children||\"\")||[];if(c.find(function(c){return c!==a&&axe.utils.matchesSelector(c,b)}))return\":nth-child(\"+(1+c.indexOf(a))+\")\";return\"\"}function T(a,b){void 0===ua&&(ua=axe.utils.isXHTML(document));var c=ta(ua?a.localName:a.nodeName.toLowerCase()),d=Array.from(a.classList)||[],e={nodeName:c,classList:d,isCustomElm:c.includes(\"-\"),isCommonElm:va.includes(c),distinctClassList:R(a)};return[wa.getCustomElm,wa.getElmRoleProp,wa.getUncommonElm,wa.getElmNameProp,wa.getDistinctClass,wa.getFileRefProp,wa.getCommonName].reduce(function(c,d){if(c.length===b)return c;var f=d(a,e);return f&&(f[0].match(/[a-z]/)?c.unshift(f):c.push(f)),c},[])}function U(a,b){var c,d;if(!a)return[];if(!b&&9===a.nodeType)return b=[{str:\"html\"}];if(b=b||[],a.parentNode&&a.parentNode!==a&&(b=U(a.parentNode,b)),a.previousSibling){d=1,c=a.previousSibling;do{1===c.nodeType&&c.nodeName===a.nodeName&&d++,c=c.previousSibling}while(c);1===d&&(d=null)}else if(a.nextSibling){c=a.nextSibling;do{1===c.nodeType&&c.nodeName===a.nodeName?(d=1,c=null):(d=null,c=c.previousSibling)}while(c)}if(1===a.nodeType){var e={};e.str=a.nodeName.toLowerCase();var f=a.getAttribute&&axe.utils.escapeSelector(a.getAttribute(\"id\"));f&&1===a.ownerDocument.querySelectorAll(\"#\"+f).length&&(e.id=a.getAttribute(\"id\")),d>1&&(e.count=d),b.push(e)}return b}function V(a){return a.reduce(function(a,b){return b.id?\"/\"+b.str+\"[@id='\"+b.id+\"']\":a+\"/\"+b.str+(b.count>0?\"[\"+b.count+\"]\":\"\")},\"\")}function W(a){\"use strict\";if(xa&&xa.parentNode)return void 0===xa.styleSheet?xa.appendChild(document.createTextNode(a)):xa.styleSheet.cssText+=a,xa;if(a){var b=document.head||document.getElementsByTagName(\"head\")[0];return xa=document.createElement(\"style\"),xa.type=\"text/css\",void 0===xa.styleSheet?xa.appendChild(document.createTextNode(a)):xa.styleSheet.cssText=a,b.appendChild(xa),xa}}function X(a,b,c,d){\"use strict\";var e=axe.utils.getXpath(c),f={element:c,selector:d,xpath:e};a.forEach(function(a){a.node=axe.utils.DqElement.fromFrame(a.node,b,f);var c=axe.utils.getAllChecks(a);c.length&&c.forEach(function(a){a.relatedNodes=a.relatedNodes.map(function(a){return axe.utils.DqElement.fromFrame(a,b,f)})})})}function Y(a,b){\"use strict\";for(var c,d,e=b[0].node,f=0,g=a.length;f<g;f++)if(d=a[f].node,(c=axe.utils.nodeSorter(d.element,e.element))>0||0===c&&e.selector.length<d.selector.length)return void a.splice.apply(a,[f,0].concat(b));a.push.apply(a,b)}function Z(a){\"use strict\";return a&&a.results?Array.isArray(a.results)?a.results.length?a.results:null:[a.results]:null}function $(a,b){function c(a){return a.incomplete&&a.incomplete.default?a.incomplete.default:ia.incompleteFallbackMessage()}if(!a||!a.missingData)return c(b);try{var d=b.incomplete[a.missingData[0].reason];if(!d)throw new Error;return d}catch(d){return\"string\"==typeof a.missingData?b.incomplete[a.missingData]:c(b)}}function _(a,b){\"use strict\";return function(c){var d=a[c.id]||{},e=d.messages||{},f=Object.assign({},d);delete f.messages,void 0===c.result?\"object\"===ha(e.incomplete)?f.message=function(){return $(c.data,e)}:f.message=e.incomplete:f.message=c.result===b?e.pass:e.fail,axe.utils.extendMetaData(c,f)}}function aa(a,b){\"use strict\";var c,d,e=axe._audit&&axe._audit.tagExclude?axe._audit.tagExclude:[];return b.hasOwnProperty(\"include\")||b.hasOwnProperty(\"exclude\")?(c=b.include||[],c=Array.isArray(c)?c:[c],d=b.exclude||[],d=Array.isArray(d)?d:[d],d=d.concat(e.filter(function(a){return-1===c.indexOf(a)}))):(c=Array.isArray(b)?b:[b],d=e.filter(function(a){return-1===c.indexOf(a)})),!!(c.some(function(b){return-1!==a.tags.indexOf(b)})||0===c.length&&!1!==a.enabled)&&d.every(function(b){return-1===a.tags.indexOf(b)})}function ba(a){var b=window.getComputedStyle(a),c=\"visible\"===b.getPropertyValue(\"overflow-y\"),d=\"visible\"===b.getPropertyValue(\"overflow-x\");if(!c&&a.scrollHeight>a.clientHeight||!d&&a.scrollWidth>a.clientWidth)return{elm:a,top:a.scrollTop,left:a.scrollLeft}}function ca(a,b,c){if(a===window)return a.scroll(b,c);a.scrollTop=b,a.scrollLeft=c}function da(a){return Array.from(a.children).reduce(function(a,b){var c=ba(b);return c&&a.push(c),a.concat(da(b))},[])}function ea(a){\"use strict\";return a.sort(function(a,b){return axe.utils.contains(a,b)?1:-1})[0]}function fa(a,b){\"use strict\";var c=b.include&&ea(b.include.filter(function(b){return axe.utils.contains(b,a)})),d=b.exclude&&ea(b.exclude.filter(function(b){return axe.utils.contains(b,a)}));return!!(!d&&c||d&&axe.utils.contains(d,c))}function ga(a,b,c){\"use strict\";for(var d=0,e=b.length;d<e;d++)-1===a.indexOf(b[d])&&fa(b[d],c)&&a.push(b[d])}var document=window.document,ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},axe=axe||{};axe.version=\"2.6.1\",\"function\"==typeof define&&define.amd&&define([],function(){\"use strict\";return axe}),\"object\"===(\"undefined\"==typeof module?\"undefined\":ha(module))&&module.exports&&\"function\"==typeof a.toString&&(axe.source=\"(\"+a.toString()+')(typeof window === \"object\" ? window : this);',module.exports=axe),\"function\"==typeof window.getComputedStyle&&(window.axe=axe);var commons;b.prototype=Object.create(Error.prototype),b.prototype.constructor=b;var utils=axe.utils={},ia={},ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};e.prototype._init=function(){var a=c(this.defaultConfig);axe.commons=commons=a.commons,this.reporter=a.reporter,this.commands={},this.rules=[],this.checks={},d(a.rules,this,\"addRule\"),d(a.checks,this,\"addCheck\"),this.data={},this.data.checks=a.data&&a.data.checks||{},this.data.rules=a.data&&a.data.rules||{},this.data.failureSummaries=a.data&&a.data.failureSummaries||{},this.data.incompleteFallbackMessage=a.data&&a.data.incompleteFallbackMessage||\"\",this._constructHelpUrls()},e.prototype.registerCommand=function(a){\"use strict\";this.commands[a.id]=a.callback},e.prototype.addRule=function(a){\"use strict\";a.metadata&&(this.data.rules[a.id]=a.metadata);var b=this.getRule(a.id);b?b.configure(a):this.rules.push(new q(a,this))},e.prototype.addCheck=function(a){\"use strict\";var b=a.metadata;\"object\"===(void 0===b?\"undefined\":ha(b))&&(this.data.checks[a.id]=b,\"object\"===ha(b.messages)&&Object.keys(b.messages).filter(function(a){return b.messages.hasOwnProperty(a)&&\"string\"==typeof b.messages[a]}).forEach(function(a){0===b.messages[a].indexOf(\"function\")&&(b.messages[a]=new Function(\"return \"+b.messages[a]+\";\")())})),this.checks[a.id]?this.checks[a.id].configure(a):this.checks[a.id]=new i(a)},e.prototype.run=function(a,b,c,d){\"use strict\";this.validateOptions(b);var e=axe.utils.queue();this.rules.forEach(function(c){if(axe.utils.ruleShouldRun(c,a,b)){if(b.performanceTimer){var d=\"mark_rule_end_\"+c.id,f=\"mark_rule_start_\"+c.id;axe.utils.performanceTimer.mark(f)}e.defer(function(e,g){c.run(a,b,function(a){b.performanceTimer&&(axe.utils.performanceTimer.mark(d),axe.utils.performanceTimer.measure(\"rule_\"+c.id,f,d)),e(a)},function(a){if(b.debug)g(a);else{var d=Object.assign(new p(c),{result:axe.constants.CANTTELL,description:\"An error occured while running this rule\",message:a.message,stack:a.stack,error:a});e(d)}})})}}),e.then(function(a){c(a.filter(function(a){return!!a}))}).catch(d)},e.prototype.after=function(a,b){\"use strict\";var c=this.rules;return a.map(function(a){return axe.utils.findBy(c,\"id\",a.id).after(a,b)})},e.prototype.getRule=function(a){return this.rules.find(function(b){return b.id===a})},e.prototype.validateOptions=function(a){\"use strict\";var b=this;if(\"object\"===ha(a.runOnly)){var c=a.runOnly;if(\"rule\"===c.type&&Array.isArray(c.value))c.value.forEach(function(a){if(!b.getRule(a))throw new Error(\"unknown rule `\"+a+\"` in options.runOnly\")});else if(Array.isArray(c.value)&&c.value.length>0){var d=[].concat(c.value);if(b.rules.forEach(function(a){var b,c,e;if(d)for(c=0,e=a.tags.length;c<e;c++)-1!==(b=d.indexOf(a.tags[c]))&&d.splice(b,1)}),0!==d.length)throw new Error(\"could not find tags `\"+d.join(\"`, `\")+\"`\")}}return\"object\"===ha(a.rules)&&Object.keys(a.rules).forEach(function(a){if(!b.getRule(a))throw new Error(\"unknown rule `\"+a+\"` in options.rules\")}),a},e.prototype.setBranding=function(a){\"use strict\";var b={brand:this.brand,application:this.application};a&&a.hasOwnProperty(\"brand\")&&a.brand&&\"string\"==typeof a.brand&&(this.brand=a.brand),a&&a.hasOwnProperty(\"application\")&&a.application&&\"string\"==typeof a.application&&(this.application=a.application),this._constructHelpUrls(b)},e.prototype._constructHelpUrls=function(){var a=this,b=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,c=(axe.version.match(/^[1-9][0-9]*\\.[0-9]+/)||[\"x.y\"])[0];this.rules.forEach(function(d){a.data.rules[d.id]||(a.data.rules[d.id]={});var e=a.data.rules[d.id];(\"string\"!=typeof e.helpUrl||b&&e.helpUrl===f(b,d.id,c))&&(e.helpUrl=f(a,d.id,c))})},e.prototype.resetRulesAndChecks=function(){\"use strict\";this._init()},i.prototype.enabled=!0,i.prototype.run=function(a,b,c,d){\"use strict\";b=b||{};var e=b.hasOwnProperty(\"enabled\")?b.enabled:this.enabled,f=b.options||this.options;if(e){var h,i=new g(this),j=axe.utils.checkHelper(i,b,c,d);try{h=this.evaluate.call(j,a,f)}catch(a){return void d(a)}j.isAsync||(i.result=h,setTimeout(function(){c(i)},0))}else c(null)},i.prototype.configure=function(a){var b=this;[\"options\",\"enabled\"].filter(function(b){return a.hasOwnProperty(b)}).forEach(function(c){return b[c]=a[c]}),[\"evaluate\",\"after\"].filter(function(b){return a.hasOwnProperty(b)}).forEach(function(c){return b[c]=h(a[c])})};var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};q.prototype.matches=function(){\"use strict\";return!0},q.prototype.gather=function(a){\"use strict\";var b=axe.utils.select(this.selector,a);return this.excludeHidden?b.filter(function(a){return!axe.utils.isHidden(a)}):b},q.prototype.runChecks=function(a,b,c,d,e){\"use strict\";var f=this,g=axe.utils.queue();this[a].forEach(function(a){var d=f._audit.checks[a.id||a],e=axe.utils.getCheckOption(d,f.id,c);g.defer(function(a,c){d.run(b,e,a,c)})}),g.then(function(b){b=b.filter(function(a){return a}),d({type:a,results:b})}).catch(e)},q.prototype.run=function(a,c,d,e){var f=this,g=axe.utils.queue(),h=new p(this),i=void 0;try{i=this.gather(a).filter(function(a){return f.matches(a)})}catch(a){return void e(new b({cause:a,ruleId:this.id}))}c.performanceTimer&&axe.log(\"gather (\",i.length,\"):\",axe.utils.performanceTimer.timeElapsed()+\"ms\"),i.forEach(function(a){g.defer(function(b,d){var e=axe.utils.queue();e.defer(function(b,d){f.runChecks(\"any\",a,c,b,d)}),e.defer(function(b,d){f.runChecks(\"all\",a,c,b,d)}),e.defer(function(b,d){f.runChecks(\"none\",a,c,b,d)}),e.then(function(d){if(d.length){var e=!1,f={};d.forEach(function(a){var b=a.results.filter(function(a){return a});f[a.type]=b,b.length&&(e=!0)}),e&&(f.node=new axe.utils.DqElement(a,c),h.nodes.push(f))}b()}).catch(function(a){return d(a)})})}),g.then(function(){return d(h)}).catch(function(a){return e(a)})},q.prototype.after=function(a,b){\"use strict\";var c=r(this),d=this.id;return c.forEach(function(c){var e=s(a.nodes,c.id),f=axe.utils.getCheckOption(c,d,b),g=c.after(e,f);e.forEach(function(a){-1===g.indexOf(a)&&(a.filtered=!0)})}),a.nodes=u(a),a},q.prototype.configure=function(a){\"use strict\";a.hasOwnProperty(\"selector\")&&(this.selector=a.selector),a.hasOwnProperty(\"excludeHidden\")&&(this.excludeHidden=\"boolean\"!=typeof a.excludeHidden||a.excludeHidden),a.hasOwnProperty(\"enabled\")&&(this.enabled=\"boolean\"!=typeof a.enabled||a.enabled),a.hasOwnProperty(\"pageLevel\")&&(this.pageLevel=\"boolean\"==typeof a.pageLevel&&a.pageLevel),a.hasOwnProperty(\"any\")&&(this.any=a.any),a.hasOwnProperty(\"all\")&&(this.all=a.all),a.hasOwnProperty(\"none\")&&(this.none=a.none),a.hasOwnProperty(\"tags\")&&(this.tags=a.tags),a.hasOwnProperty(\"matches\")&&(\"string\"==typeof a.matches?this.matches=new Function(\"return \"+a.matches+\";\")():this.matches=a.matches)},function(axe){var a=[{name:\"NA\",value:\"inapplicable\",priority:0,group:\"inapplicable\"},{name:\"PASS\",value:\"passed\",priority:1,group:\"passes\"},{name:\"CANTTELL\",value:\"cantTell\",priority:2,group:\"incomplete\"},{name:\"FAIL\",value:\"failed\",priority:3,group:\"violations\"}],b={helpUrlBase:\"https://dequeuniversity.com/rules/\",results:[],resultGroups:[],resultGroupMap:{},impact:Object.freeze([\"minor\",\"moderate\",\"serious\",\"critical\"])};a.forEach(function(a){var c=a.name,d=a.value,e=a.priority,f=a.group;b[c]=d,b[c+\"_PRIO\"]=e,b[c+\"_GROUP\"]=f,b.results[e]=d,b.resultGroups[e]=f,b.resultGroupMap[d]=f}),Object.freeze(b.results),Object.freeze(b.resultGroups),Object.freeze(b.resultGroupMap),Object.freeze(b),Object.defineProperty(axe,\"constants\",{value:b,enumerable:!0,configurable:!1,writable:!1})}(axe);var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.log=function(){\"use strict\";\"object\"===(\"undefined\"==typeof console?\"undefined\":ha(console))&&console.log&&Function.prototype.apply.call(console.log,console,arguments)};var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.a11yCheck=function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={}),b&&\"object\"===(void 0===b?\"undefined\":ha(b))||(b={});var d=axe._audit;if(!d)throw new Error(\"No audit configured\");b.reporter=b.reporter||d.reporter||\"v2\",b.performanceTimer&&axe.utils.performanceTimer.start();var e=axe.getReporter(b.reporter);axe._runRules(a,b,function(a){var d=e(a,b,c);void 0!==d&&(b.performanceTimer&&axe.utils.performanceTimer.end(),c(d))},axe.log)},axe.cleanup=v,axe.configure=w,axe.getRules=function(a){\"use strict\";a=a||[];var b=a.length?axe._audit.rules.filter(function(b){return!!a.filter(function(a){return-1!==b.tags.indexOf(a)}).length}):axe._audit.rules,c=axe._audit.data.rules||{};return b.map(function(a){var b=c[a.id]||{};return{ruleId:a.id,description:b.description,help:b.help,helpUrl:b.helpUrl,tags:a.tags}})},axe._load=function(a){\"use strict\";axe.utils.respondable.subscribe(\"axe.ping\",function(a,b,c){c({axe:!0})}),axe.utils.respondable.subscribe(\"axe.start\",x),axe._audit=new e(a)};var axe=axe||{};axe.plugins={},y.prototype.run=function(){\"use strict\";return this._run.apply(this,arguments)},y.prototype.collect=function(){\"use strict\";return this._collect.apply(this,arguments)},y.prototype.cleanup=function(a){\"use strict\";var b=axe.utils.queue(),c=this;Object.keys(this._registry).forEach(function(a){b.defer(function(b){c._registry[a].cleanup(b)})}),b.then(function(){a()})},y.prototype.add=function(a){\"use strict\";this._registry[a.id]=a},axe.registerPlugin=function(a){\"use strict\";axe.plugins[a.id]=new y(a)};var ja,ka={};axe.getReporter=function(a){\"use strict\";return\"string\"==typeof a&&ka[a]?ka[a]:\"function\"==typeof a?a:ja},axe.addReporter=function(a,b,c){\"use strict\";ka[a]=b,c&&(ja=b)},axe.reset=z,axe._runRules=A;var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},la=function(){};axe.run=function(a,b,c){\"use strict\";if(!axe._audit)throw new Error(\"No audit configured\");var d=C(a,b,c);a=d.context,b=d.options,c=d.callback,b.reporter=b.reporter||axe._audit.reporter||\"v1\",b.performanceTimer&&axe.utils.performanceTimer.start();var e=void 0,f=la,g=la;return window.Promise&&c===la&&(e=new Promise(function(a,b){f=b,g=a})),axe._runRules(a,b,function(a){var d=function(a){try{c(null,a)}catch(a){axe.log(a)}g(a)};b.performanceTimer&&axe.utils.performanceTimer.end();try{var e=axe.getReporter(b.reporter),h=e(a,b,d);void 0!==h&&d(h)}catch(a){c(a),f(a)}},function(a){c(a),f(a)}),e},ia.failureSummary=function(a){\"use strict\";var b={};return b.none=a.none.concat(a.all),b.any=a.any,Object.keys(b).map(function(a){if(b[a].length){var c=axe._audit.data.failureSummaries[a];return c&&\"function\"==typeof c.failureMessage?c.failureMessage(b[a].map(function(a){return a.message||\"\"})):void 0}}).filter(function(a){return void 0!==a}).join(\"\\n\\n\")},ia.incompleteFallbackMessage=function(){\"use strict\";return axe._audit.data.incompleteFallbackMessage()};var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},ma=axe.constants.resultGroups;ia.processAggregate=function(a,b){var c=axe.utils.aggregateResult(a);return c.timestamp=(new Date).toISOString(),c.url=window.location.href,ma.forEach(function(a){b.resultTypes&&!b.resultTypes.includes(a)&&(c[a]||[]).forEach(function(a){Array.isArray(a.nodes)&&a.nodes.length>0&&(a.nodes=[a.nodes[0]])}),c[a]=(c[a]||[]).map(function(a){return a=Object.assign({},a),Array.isArray(a.nodes)&&a.nodes.length>0&&(a.nodes=a.nodes.map(function(a){return\"object\"===ha(a.node)&&(a.html=a.node.source,b.elementRef&&!a.node.fromFrame&&(a.element=a.node.element),(!1!==b.selectors||a.node.fromFrame)&&(a.target=a.node.selector),b.xpath&&(a.xpath=a.node.xpath)),delete a.result,delete a.node,D(a,b),a})),ma.forEach(function(b){return delete a[b]}),delete a.pageLevel,delete a.result,a})}),c},axe.addReporter(\"na\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=ia.processAggregate(a,b);c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"no-passes\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={}),b.resultTypes=[\"violations\"];var d=ia.processAggregate(a,b);c({violations:d.violations,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"raw\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={}),c(a)}),axe.addReporter(\"v1\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=ia.processAggregate(a,b);d.violations.forEach(function(a){return a.nodes.forEach(function(a){a.failureSummary=ia.failureSummary(a)})}),c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"v2\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=ia.processAggregate(a,b);c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})},!0),axe.utils.aggregate=function(a,b,c){b=b.slice(),c&&b.push(c);var d=b.map(function(b){return a.indexOf(b)}).sort();return a[d.pop()]};var na=axe.constants,oa=na.CANTTELL_PRIO,pa=na.FAIL_PRIO,qa=[];qa[axe.constants.PASS_PRIO]=!0,qa[axe.constants.CANTTELL_PRIO]=null,qa[axe.constants.FAIL_PRIO]=!1;var ra=[\"any\",\"all\",\"none\"];axe.utils.aggregateChecks=function(a){var b=Object.assign({},a);E(b,function(a,b){var c=qa.indexOf(a.result);a.priority=-1!==c?c:axe.constants.CANTTELL_PRIO,\"none\"===b&&(a.priority=4-a.priority)});var c={all:b.all.reduce(function(a,b){return Math.max(a,b.priority)},0),none:b.none.reduce(function(a,b){return Math.max(a,b.priority)},0),any:b.any.reduce(function(a,b){return Math.min(a,b.priority)},4)%4};b.priority=Math.max(c.all,c.none,c.any);var d=[];return ra.forEach(function(a){b[a]=b[a].filter(function(d){return d.priority===b.priority&&d.priority===c[a]}),b[a].forEach(function(a){return d.push(a.impact)})}),[oa,pa].includes(b.priority)?b.impact=axe.utils.aggregate(axe.constants.impact,d):b.impact=null,E(b,function(a){delete a.result,delete a.priority}),b.result=axe.constants.results[b.priority],delete b.priority,b},function(){axe.utils.aggregateNodeResults=function(a){var b={};if((a=a.map(function(a){if(a.any&&a.all&&a.none)return axe.utils.aggregateChecks(a);if(Array.isArray(a.node))return axe.utils.finalizeRuleResult(a);throw new TypeError(\"Invalid Result type\")}))&&a.length){var c=a.map(function(a){return a.result});b.result=axe.utils.aggregate(axe.constants.results,c,b.result)}else b.result=\"inapplicable\";axe.constants.resultGroups.forEach(function(a){return b[a]=[]}),a.forEach(function(a){var c=axe.constants.resultGroupMap[a.result];b[c].push(a)});var d=axe.constants.FAIL_GROUP;if(0===b[d].length&&(d=axe.constants.CANTTELL_GROUP),b[d].length>0){var e=b[d].map(function(a){return a.impact});b.impact=axe.utils.aggregate(axe.constants.impact,e)||null}else b.impact=null;return b}}(),axe.utils.aggregateResult=function(a){var b={};return axe.constants.resultGroups.forEach(function(a){return b[a]=[]}),a.forEach(function(a){a.error?F(b,a,axe.constants.CANTTELL_GROUP):a.result===axe.constants.NA?F(b,a,axe.constants.NA_GROUP):axe.constants.resultGroups.forEach(function(c){Array.isArray(a[c])&&a[c].length>0&&F(b,a,c)})}),b},axe.utils.areStylesSet=G,axe.utils.checkHelper=function(a,b,c,d){\"use strict\";return{isAsync:!1,async:function(){return this.isAsync=!0,function(b){b instanceof Error==!1?(a.result=b,c(a)):d(b)}},data:function(b){a.data=b},relatedNodes:function(c){c=c instanceof Node?[c]:axe.utils.toArray(c),a.relatedNodes=c.map(function(a){return new axe.utils.DqElement(a,b)})}}};var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.clone=function(a){\"use strict\";var b,c,d=a\n;if(null!==a&&\"object\"===(void 0===a?\"undefined\":ha(a)))if(Array.isArray(a))for(d=[],b=0,c=a.length;b<c;b++)d[b]=axe.utils.clone(a[b]);else{d={};for(b in a)d[b]=axe.utils.clone(a[b])}return d},axe.utils.sendCommandToFrame=function(a,b,c,d){\"use strict\";var e=a.contentWindow;if(!e)return axe.log(\"Frame does not have a content window\",a),void c(null);var f=setTimeout(function(){f=setTimeout(function(){var e=H(\"No response from frame\",a);b.debug?d(e):(axe.log(e),c(null))},0)},500);axe.utils.respondable(e,\"axe.ping\",null,void 0,function(){clearTimeout(f),f=setTimeout(function(){d(H(\"Axe in frame timed out\",a))},3e4),axe.utils.respondable(e,\"axe.start\",b,void 0,function(a){clearTimeout(f),a instanceof Error==!1?c(a):d(a)})})},axe.utils.collectResultsFromFrames=I,axe.utils.contains=function(a,b){\"use strict\";return\"function\"==typeof a.contains?a.contains(b):!!(16&a.compareDocumentPosition(b))},L.prototype={get selector(){return this.spec.selector||[axe.utils.getSelector(this.element,this._options)]},get xpath(){return this.spec.xpath||[axe.utils.getXpath(this.element)]},get element(){return this._element},get fromFrame(){return this._fromFrame},toJSON:function(){\"use strict\";return{selector:this.selector,source:this.source,xpath:this.xpath}}},L.fromFrame=function(a,b,c){return a.selector.unshift(c.selector),a.xpath.unshift(c.xpath),new axe.utils.DqElement(c.element,b,a)},axe.utils.DqElement=L,axe.utils.matchesSelector=function(){\"use strict\";function a(a){var b,c,d=a.Element.prototype,e=[\"matches\",\"matchesSelector\",\"mozMatchesSelector\",\"webkitMatchesSelector\",\"msMatchesSelector\"],f=e.length;for(b=0;b<f;b++)if(c=e[b],d[c])return c}var b;return function(c,d){return b&&c[b]||(b=a(c.ownerDocument.defaultView)),c[b](d)}}(),axe.utils.escapeSelector=function(a){\"use strict\";for(var b,c=String(a),d=c.length,e=-1,f=\"\",g=c.charCodeAt(0);++e<d;){if(0==(b=c.charCodeAt(e)))throw new Error(\"INVALID_CHARACTER_ERR\");b>=1&&b<=31||b>=127&&b<=159||0==e&&b>=48&&b<=57||1==e&&b>=48&&b<=57&&45==g?f+=\"\\\\\"+b.toString(16)+\" \":f+=(1!=e||45!=b||45!=g)&&(b>=128||45==b||95==b||b>=48&&b<=57||b>=65&&b<=90||b>=97&&b<=122)?c.charAt(e):\"\\\\\"+c.charAt(e)}return f},axe.utils.extendMetaData=function(a,b){Object.assign(a,b),Object.keys(b).filter(function(a){return\"function\"==typeof b[a]}).forEach(function(c){a[c]=null;try{a[c]=b[c](a)}catch(a){}})},axe.utils.finalizeRuleResult=function(a){return Object.assign(a,axe.utils.aggregateNodeResults(a.nodes)),delete a.nodes,a};var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.findBy=function(a,b,c){if(Array.isArray(a))return a.find(function(a){return\"object\"===(void 0===a?\"undefined\":ha(a))&&a[b]===c})},axe.utils.getAllChecks=function(a){\"use strict\";return[].concat(a.any||[]).concat(a.all||[]).concat(a.none||[])},axe.utils.getCheckOption=function(a,b,c){var d=((c.rules&&c.rules[b]||{}).checks||{})[a.id],e=(c.checks||{})[a.id],f=a.enabled,g=a.options;return e&&(e.hasOwnProperty(\"enabled\")&&(f=e.enabled),e.hasOwnProperty(\"options\")&&(g=e.options)),d&&(d.hasOwnProperty(\"enabled\")&&(f=d.enabled),d.hasOwnProperty(\"options\")&&(g=d.options)),{enabled:f,options:g,absolutePaths:c.absolutePaths}};var sa=function(){function a(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g,h=a[Symbol.iterator]();!(d=(g=h.next()).done)&&(c.push(g.value),!b||c.length!==b);d=!0);}catch(a){e=!0,f=a}finally{try{!d&&h.return&&h.return()}finally{if(e)throw f}}return c}return function(b,c){if(Array.isArray(b))return b;if(Symbol.iterator in Object(b))return a(b,c);throw new TypeError(\"Invalid attempt to destructure non-iterable instance\")}}();axe.utils.getFriendlyUriEnd=function(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\",b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!(a.length<=1||\"data:\"===a.substr(0,5)||\"javascript:\"===a.substr(0,11)||a.includes(\"?\"))){var c=b.currentDomain,d=b.maxLength,e=void 0===d?25:d,f=O(a),g=f.path,h=f.domain,i=f.hash,j=g.substr(g.substr(0,g.length-2).lastIndexOf(\"/\")+1);if(i)return j&&(j+i).length<=e?j+i:j.length<2&&i.length>2&&i.length<=e?i:void 0;if(h&&h.length<e&&g.length<=1)return h+g;if(g===\"/\"+j&&h&&c&&h!==c&&(h+g).length<=e)return h+g;var k=j.lastIndexOf(\".\");return(-1===k||k>1)&&(-1!==k||j.length>2)&&j.length<=e&&!j.match(/index(\\.[a-zA-Z]{2-4})?/)&&!M(j)?j:void 0}};var ta=axe.utils.escapeSelector,ua=void 0,va=[\"div\",\"span\",\"p\",\"b\",\"i\",\"u\",\"strong\",\"em\",\"h2\",\"h3\"],wa={getElmId:function(a){if(a.getAttribute(\"id\")){var b=\"#\"+ta(a.getAttribute(\"id\")||\"\");return b.match(/player_uid_/)||1!==document.querySelectorAll(b).length?void 0:b}},getCustomElm:function(a,b){var c=b.isCustomElm,d=b.nodeName;if(c)return d},getElmRoleProp:function(a){if(a.hasAttribute(\"role\"))return'[role=\"'+ta(a.getAttribute(\"role\"))+'\"]'},getUncommonElm:function(a,b){var c=b.isCommonElm,d=b.isCustomElm,e=b.nodeName;if(!c&&!d)return\"input\"===e&&a.hasAttribute(\"type\")&&(e+='[type=\"'+a.type+'\"]'),e},getElmNameProp:function(a){if(!a.hasAttribute(\"id\")&&a.name)return'[name=\"'+ta(a.name)+'\"]'},getDistinctClass:function(a,b){var c=b.distinctClassList;if(c.length>0&&c.length<3)return\".\"+c.map(ta).join(\".\")},getFileRefProp:function(a){var b=void 0;if(a.hasAttribute(\"href\"))b=\"href\";else{if(!a.hasAttribute(\"src\"))return;b=\"src\"}var c=axe.utils.getFriendlyUriEnd(a.getAttribute(b));if(c)return\"[\"+b+'$=\"'+encodeURI(c)+'\"]'},getCommonName:function(a,b){var c=b.nodeName;if(b.isCommonElm)return c}};axe.utils.getSelector=function a(b){var c=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!b)return\"\";var d=void 0,e=void 0,f=c.isUnique,g=void 0!==f&&f,h=wa.getElmId(b),i=c.featureCount,j=void 0===i?2:i,k=c.minDepth,l=void 0===k?1:k,m=c.toRoot,n=void 0!==m&&m,o=c.childSelectors,p=void 0===o?[]:o;h?(d=h,g=!0):(d=T(b,j).join(\"\"),d+=S(b,d),g=c.isUnique||1===document.querySelectorAll(d).length,g||b!==document.documentElement||(d+=\":root\"),e=0!==l||!g);var q=[d].concat(P(p));return b.parentElement&&(n||e)?a(b.parentNode,{toRoot:n,isUnique:g,childSelectors:q,featureCount:1,minDepth:l-1}):q.join(\" > \")},axe.utils.getXpath=function(a){return V(U(a))};var xa;axe.utils.injectStyle=W,axe.utils.isHidden=function(a,b){\"use strict\";if(9===a.nodeType)return!1;var c=window.getComputedStyle(a,null);return!c||!a.parentNode||\"none\"===c.getPropertyValue(\"display\")||!b&&\"hidden\"===c.getPropertyValue(\"visibility\")||\"true\"===a.getAttribute(\"aria-hidden\")||axe.utils.isHidden(a.parentNode,!0)},axe.utils.isXHTML=function(a){\"use strict\";return!!a.createElement&&\"A\"===a.createElement(\"A\").localName},axe.utils.mergeResults=function(a,b){\"use strict\";var c=[];return a.forEach(function(a){var d=Z(a);d&&d.length&&d.forEach(function(d){d.nodes&&a.frame&&X(d.nodes,b,a.frameElement,a.frame);var e=axe.utils.findBy(c,\"id\",d.id);e?d.nodes.length&&Y(e.nodes,d.nodes):c.push(d)})}),c},axe.utils.nodeSorter=function(a,b){\"use strict\";return a===b?0:4&a.compareDocumentPosition(b)?-1:1},utils.performanceTimer=function(){\"use strict\";function a(){if(window.performance&&window.performance)return window.performance.now()}var b=null,c=a();return{start:function(){this.mark(\"mark_axe_start\")},end:function(){this.mark(\"mark_axe_end\"),this.measure(\"axe\",\"mark_axe_start\",\"mark_axe_end\"),this.logMeasures(\"axe\")},auditStart:function(){this.mark(\"mark_audit_start\")},auditEnd:function(){this.mark(\"mark_audit_end\"),this.measure(\"audit_start_to_end\",\"mark_audit_start\",\"mark_audit_end\"),this.logMeasures()},mark:function(a){window.performance&&void 0!==window.performance.mark&&window.performance.mark(a)},measure:function(a,b,c){window.performance&&void 0!==window.performance.measure&&window.performance.measure(a,b,c)},logMeasures:function(a){function b(a){axe.log(\"Measure \"+a.name+\" took \"+a.duration+\"ms\")}if(window.performance&&void 0!==window.performance.getEntriesByType)for(var c=window.performance.getEntriesByType(\"measure\"),d=0;d<c.length;++d){var e=c[d];if(e.name===a)return void b(e);b(e)}},timeElapsed:function(){return a()-c},reset:function(){b||(b=a()),c=a()}}}(),\"function\"!=typeof Object.assign&&function(){Object.assign=function(a){\"use strict\";if(void 0===a||null===a)throw new TypeError(\"Cannot convert undefined or null to object\");for(var b=Object(a),c=1;c<arguments.length;c++){var d=arguments[c];if(void 0!==d&&null!==d)for(var e in d)d.hasOwnProperty(e)&&(b[e]=d[e])}return b}}(),Array.prototype.find||Object.defineProperty(Array.prototype,\"find\",{value:function(a){if(null===this)throw new TypeError(\"Array.prototype.find called on null or undefined\");if(\"function\"!=typeof a)throw new TypeError(\"predicate must be a function\");for(var b,c=Object(this),d=c.length>>>0,e=arguments[1],f=0;f<d;f++)if(b=c[f],a.call(e,b,f,c))return b}}),axe.utils.pollyfillElementsFromPoint=function(){if(document.elementsFromPoint)return document.elementsFromPoint;if(document.msElementsFromPoint)return document.msElementsFromPoint;var a=function(){var a=document.createElement(\"x\");return a.style.cssText=\"pointer-events:auto\",\"auto\"===a.style.pointerEvents}(),b=a?\"pointer-events\":\"visibility\",c=a?\"none\":\"hidden\",d=document.createElement(\"style\");return d.innerHTML=a?\"* { pointer-events: all }\":\"* { visibility: visible }\",function(a,e){var f,g,h,i=[],j=[];for(document.head.appendChild(d);(f=document.elementFromPoint(a,e))&&-1===i.indexOf(f);)i.push(f),j.push({value:f.style.getPropertyValue(b),priority:f.style.getPropertyPriority(b)}),f.style.setProperty(b,c,\"important\");for(g=j.length;h=j[--g];)i[g].style.setProperty(b,h.value?h.value:\"\",h.priority);return document.head.removeChild(d),i}},\"function\"==typeof window.addEventListener&&(document.elementsFromPoint=axe.utils.pollyfillElementsFromPoint()),Array.prototype.includes||Object.defineProperty(Array.prototype,\"includes\",{value:function(a){\"use strict\";var b=Object(this),c=parseInt(b.length,10)||0;if(0===c)return!1;var d,e=parseInt(arguments[1],10)||0;e>=0?d=e:(d=c+e)<0&&(d=0);for(var f;d<c;){if(f=b[d],a===f||a!==a&&f!==f)return!0;d++}return!1}}),Array.prototype.some||Object.defineProperty(Array.prototype,\"some\",{value:function(a){\"use strict\";if(null==this)throw new TypeError(\"Array.prototype.some called on null or undefined\");if(\"function\"!=typeof a)throw new TypeError;for(var b=Object(this),c=b.length>>>0,d=arguments.length>=2?arguments[1]:void 0,e=0;e<c;e++)if(e in b&&a.call(d,b[e],e,b))return!0;return!1}}),Array.from||Object.defineProperty(Array,\"from\",{value:function(){var a=Object.prototype.toString,b=function(b){return\"function\"==typeof b||\"[object Function]\"===a.call(b)},c=function(a){var b=Number(a);return isNaN(b)?0:0!==b&&isFinite(b)?(b>0?1:-1)*Math.floor(Math.abs(b)):b},d=Math.pow(2,53)-1,e=function(a){var b=c(a);return Math.min(Math.max(b,0),d)};return function(a){var c=this,d=Object(a);if(null==a)throw new TypeError(\"Array.from requires an array-like object - not null or undefined\");var f,g=arguments.length>1?arguments[1]:void 0;if(void 0!==g){if(!b(g))throw new TypeError(\"Array.from: when provided, the second argument must be a function\");arguments.length>2&&(f=arguments[2])}for(var h,i=e(d.length),j=b(c)?Object(new c(i)):new Array(i),k=0;k<i;)h=d[k],j[k]=g?void 0===f?g(h,k):g.call(f,h,k):h,k+=1;return j.length=i,j}}()}),String.prototype.includes||(String.prototype.includes=function(a,b){return\"number\"!=typeof b&&(b=0),!(b+a.length>this.length)&&-1!==this.indexOf(a,b)});var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.publishMetaData=function(a){\"use strict\";var b=axe._audit.data.checks||{},c=axe._audit.data.rules||{},d=axe.utils.findBy(axe._audit.rules,\"id\",a.id)||{};a.tags=axe.utils.clone(d.tags||[]);var e=_(b,!0),f=_(b,!1);a.nodes.forEach(function(a){a.any.forEach(e),a.all.forEach(e),a.none.forEach(f)}),axe.utils.extendMetaData(a,axe.utils.clone(c[a.id]||{}))};var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};!function(){\"use strict\";function a(){}function b(a){if(\"function\"!=typeof a)throw new TypeError(\"Queue methods require functions as arguments\")}function c(){function c(b){return function(c){g[b]=c,(i-=1)||j===a||(k=!0,j(g))}}function d(b){return j=a,m(b),g}function e(){for(var a=g.length;h<a;h++){var b=g[h];try{b.call(null,c(h),d)}catch(a){d(a)}}}var f,g=[],h=0,i=0,j=a,k=!1,l=function(a){f=a,setTimeout(function(){void 0!==f&&null!==f&&axe.log(\"Uncaught error (of queue)\",f)},1)},m=l,n={defer:function(a){if(\"object\"===(void 0===a?\"undefined\":ha(a))&&a.then&&a.catch){var c=a;a=function(a,b){c.then(a).catch(b)}}if(b(a),void 0===f){if(k)throw new Error(\"Queue already completed\");return g.push(a),++i,e(),n}},then:function(c){if(b(c),j!==a)throw new Error(\"queue `then` already set\");return f||(j=c,i||(k=!0,j(g))),n},catch:function(a){if(b(a),m!==l)throw new Error(\"queue `catch` already set\");return f?(a(f),f=null):m=a,n},abort:d};return n}axe.utils.queue=c}();var ha=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};!function(a){\"use strict\";function b(){var a=\"axe\",b=\"\";return void 0!==axe&&axe._audit&&!axe._audit.application&&(a=axe._audit.application),void 0!==axe&&(b=axe.version),a+\".\"+b}function c(a){if(\"object\"===(void 0===a?\"undefined\":ha(a))&&\"string\"==typeof a.uuid&&!0===a._respondable){var c=b();return a._source===c||\"axe.x.y.z\"===a._source||\"axe.x.y.z\"===c}return!1}function d(a,c,d,e,f,g){var h;d instanceof Error&&(h={name:d.name,message:d.message,stack:d.stack},d=void 0);var i={uuid:e,topic:c,message:d,error:h,_respondable:!0,_source:b(),_keepalive:f};\"function\"==typeof g&&(j[e]=g),a.postMessage(JSON.stringify(i),\"*\")}function e(a,b,c,e,f){d(a,b,c,ya.v1(),e,f)}function f(a,b,c){return function(e,f,g){d(a,b,e,c,f,g)}}function g(a,b,c){var d=b.topic,e=k[d];if(e){var g=f(a,null,b.uuid);e(b.message,c,g)}}function h(a){var b=a.message||\"Unknown error occurred\",c=l.includes(a.name)?a.name:\"Error\",d=window[c]||Error;return a.stack&&(b+=\"\\n\"+a.stack.replace(a.message,\"\")),new d(b)}function i(a){var b;if(\"string\"==typeof a){try{b=JSON.parse(a)}catch(a){}if(c(b))return\"object\"===ha(b.error)?b.error=h(b.error):b.error=void 0,b}}var j={},k={},l=Object.freeze([\"EvalError\",\"RangeError\",\"ReferenceError\",\"SyntaxError\",\"TypeError\",\"URIError\"]);e.subscribe=function(a,b){k[a]=b},e.isInFrame=function(a){return a=a||window,!!a.frameElement},\"function\"==typeof window.addEventListener&&window.addEventListener(\"message\",function(a){var b=i(a.data);if(b){var c=b.uuid,e=b._keepalive,h=j[c];if(h){h(b.error||b.message,e,f(a.source,b.topic,c)),e||delete j[c]}if(!b.error)try{g(a.source,b,e)}catch(e){d(a.source,b.topic,e,c,!1)}}},!1),a.respondable=e}(utils),axe.utils.ruleShouldRun=function(a,b,c){\"use strict\";var d=c.runOnly||{},e=(c.rules||{})[a.id];return!(a.pageLevel&&!b.page)&&(\"rule\"===d.type?-1!==d.values.indexOf(a.id):e&&\"boolean\"==typeof e.enabled?e.enabled:\"tag\"===d.type&&d.values?aa(a,d.values):aa(a,[]))},axe.utils.getScrollState=function(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window,b=a.document.documentElement;return[void 0!==a.pageXOffset?{elm:a,top:a.pageYOffset,left:a.pageXOffset}:{elm:b,top:b.scrollTop,left:b.scrollLeft}].concat(da(document.body))},axe.utils.setScrollState=function(a){a.forEach(function(a){return ca(a.elm,a.top,a.left)})},axe.utils.select=function(a,b){\"use strict\";for(var c,d=[],e=0,f=b.include.length;e<f;e++)c=b.include[e],c.nodeType===c.ELEMENT_NODE&&axe.utils.matchesSelector(c,a)&&ga(d,[c],b),ga(d,c.querySelectorAll(a),b);return d.sort(axe.utils.nodeSorter)},axe.utils.toArray=function(a){\"use strict\";return Array.prototype.slice.call(a)};var ya;!function(a){function b(a,b,c){var d=b&&c||0,e=0;for(b=b||[],a.toLowerCase().replace(/[0-9a-f]{2}/g,function(a){e<16&&(b[d+e++]=l[a])});e<16;)b[d+e++]=0;return b}function c(a,b){var c=b||0,d=k;return d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]}function d(a,b,d){var e=b&&d||0,f=b||[];a=a||{};var g=null!=a.clockseq?a.clockseq:p,h=null!=a.msecs?a.msecs:(new Date).getTime(),i=null!=a.nsecs?a.nsecs:r+1,j=h-q+(i-r)/1e4;if(j<0&&null==a.clockseq&&(g=g+1&16383),(j<0||h>q)&&null==a.nsecs&&(i=0),i>=1e4)throw new Error(\"uuid.v1(): Can't create more than 10M uuids/sec\");q=h,r=i,p=g,h+=122192928e5;var k=(1e4*(268435455&h)+i)%4294967296;f[e++]=k>>>24&255,f[e++]=k>>>16&255,f[e++]=k>>>8&255,f[e++]=255&k;var l=h/4294967296*1e4&268435455;f[e++]=l>>>8&255,f[e++]=255&l,f[e++]=l>>>24&15|16,f[e++]=l>>>16&255,f[e++]=g>>>8|128,f[e++]=255&g;for(var m=a.node||o,n=0;n<6;n++)f[e+n]=m[n];return b||c(f)}function e(a,b,d){var e=b&&d||0;\"string\"==typeof a&&(b=\"binary\"==a?new j(16):null,a=null),a=a||{};var g=a.random||(a.rng||f)();if(g[6]=15&g[6]|64,g[8]=63&g[8]|128,b)for(var h=0;h<16;h++)b[e+h]=g[h];return b||c(g)}var f,g=a.crypto||a.msCrypto;if(!f&&g&&g.getRandomValues){var h=new Uint8Array(16);f=function(){return g.getRandomValues(h),h}}if(!f){var i=new Array(16);f=function(){for(var a,b=0;b<16;b++)0==(3&b)&&(a=4294967296*Math.random()),i[b]=a>>>((3&b)<<3)&255;return i}}for(var j=\"function\"==typeof a.Buffer?a.Buffer:Array,k=[],l={},m=0;m<256;m++)k[m]=(m+256).toString(16).substr(1),l[k[m]]=m;var n=f(),o=[1|n[0],n[1],n[2],n[3],n[4],n[5]],p=16383&(n[6]<<8|n[7]),q=0,r=0;ya=e,ya.v1=d,ya.v4=e,ya.parse=b,ya.unparse=c,ya.BufferClass=j}(window),axe._load({data:{rules:{accesskeys:{description:\"Ensures every accesskey attribute value is unique\",help:\"accesskey attribute value must be unique\"},\"area-alt\":{description:\"Ensures <area> elements of image maps have alternate text\",help:\"Active <area> elements must have alternate text\"},\"aria-allowed-attr\":{description:\"Ensures ARIA attributes are allowed for an element's role\",help:\"Elements must only use allowed ARIA attributes\"},\"aria-hidden-body\":{description:\"Ensures aria-hidden='true' is not present on the document body.\",help:\"aria-hidden='true' must not be present on the document body\"},\"aria-required-attr\":{description:\"Ensures elements with ARIA roles have all required ARIA attributes\",help:\"Required ARIA attributes must be provided\"},\"aria-required-children\":{description:\"Ensures elements with an ARIA role that require child roles contain them\",help:\"Certain ARIA roles must contain particular children\"},\"aria-required-parent\":{description:\"Ensures elements with an ARIA role that require parent roles are contained by them\",help:\"Certain ARIA roles must be contained by particular parents\"},\"aria-roles\":{description:\"Ensures all elements with a role attribute use a valid value\",help:\"ARIA roles used must conform to valid values\"},\"aria-valid-attr-value\":{description:\"Ensures all ARIA attributes have valid values\",help:\"ARIA attributes must conform to valid values\"},\"aria-valid-attr\":{description:\"Ensures attributes that begin with aria- are valid ARIA attributes\",help:\"ARIA attributes must conform to valid names\"},\"audio-caption\":{description:\"Ensures <audio> elements have captions\",help:\"<audio> elements must have a captions track\"},blink:{description:\"Ensures <blink> elements are not used\",help:\"<blink> elements are deprecated and must not be used\"},\"button-name\":{description:\"Ensures buttons have discernible text\",help:\"Buttons must have discernible text\"},bypass:{description:\"Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content\",help:\"Page must have means to bypass repeated blocks\"},checkboxgroup:{description:'Ensures related <input type=\"checkbox\"> elements have a group and that that group designation is consistent',help:\"Checkbox inputs with the same name attribute value must be part of a group\"},\"color-contrast\":{description:\"Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds\",help:\"Elements must have sufficient color contrast\"},\"definition-list\":{description:\"Ensures <dl> elements are structured correctly\",help:\"<dl> elements must only directly contain properly-ordered <dt> and <dd> groups, <script> or <template> elements\"},dlitem:{description:\"Ensures <dt> and <dd> elements are contained by a <dl>\",help:\"<dt> and <dd> elements must be contained by a <dl>\"},\"document-title\":{description:\"Ensures each HTML document contains a non-empty <title> element\",help:\"Documents must have <title> element to aid in navigation\"},\"duplicate-id\":{description:\"Ensures every id attribute value is unique\",help:\"id attribute value must be unique\"},\"empty-heading\":{description:\"Ensures headings have discernible text\",help:\"Headings must not be empty\"},\"frame-title-unique\":{description:\"Ensures <iframe> and <frame> elements contain a unique title attribute\",help:\"Frames must have a unique title attribute\"},\"frame-title\":{description:\"Ensures <iframe> and <frame> elements contain a non-empty title attribute\",help:\"Frames must have title attribute\"},\"heading-order\":{description:\"Ensures the order of headings is semantically correct\",help:\"Heading levels should only increase by one\"},\"hidden-content\":{description:\"Informs users about hidden content.\",help:\"Hidden content on the page cannot be analyzed\"},\"href-no-hash\":{description:\"Ensures that href values are valid link references to promote only using anchors as links\",help:\"Anchors must only be used as links with valid URLs or URL fragments\"},\"html-has-lang\":{description:\"Ensures every HTML document has a lang attribute\",help:\"<html> element must have a lang attribute\"},\"html-lang-valid\":{description:\"Ensures the lang attribute of the <html> element has a valid value\",help:\"<html> element must have a valid value for the lang attribute\"},\"image-alt\":{description:\"Ensures <img> elements have alternate text or a role of none or presentation\",help:\"Images must have alternate text\"},\"image-redundant-alt\":{description:\"Ensure button and link text is not repeated as image alternative\",help:\"Text of buttons and links should not be repeated in the image alternative\"},\"input-image-alt\":{description:'Ensures <input type=\"image\"> elements have alternate text',help:\"Image buttons must have alternate text\"},\"label-title-only\":{description:\"Ensures that every form element is not solely labeled using the title or aria-describedby attributes\",help:\"Form elements should have a visible label\"},label:{description:\"Ensures every form element has a label\",help:\"Form elements must have labels\"},\"landmark-main-is-top-level\":{description:\"The main landmark should not be contained in another landmark\",help:\"Main landmark is not at top level\"},\"landmark-one-main\":{description:\"Ensures a navigation point to the primary content of the page. If the page contains iframes, each iframe should contain either no main landmarks or just one.\",help:\"Page must contain one main landmark.\"},\"layout-table\":{description:\"Ensures presentational <table> elements do not use <th>, <caption> elements or the summary attribute\",help:\"Layout tables must not use data table elements\"},\"link-in-text-block\":{description:\"Links can be distinguished without relying on color\",help:\"Links must be distinguished from surrounding text in a way that does not rely on color\"},\"link-name\":{description:\"Ensures links have discernible text\",help:\"Links must have discernible text\"},list:{description:\"Ensures that lists are structured correctly\",help:\"<ul> and <ol> must only directly contain <li>, <script> or <template> elements\"},listitem:{description:\"Ensures <li> elements are used semantically\",help:\"<li> elements must be contained in a <ul> or <ol>\"},marquee:{description:\"Ensures <marquee> elements are not used\",help:\"<marquee> elements are deprecated and must not be used\"},\"meta-refresh\":{description:'Ensures <meta http-equiv=\"refresh\"> is not used',help:\"Timed refresh must not exist\"},\"meta-viewport-large\":{description:'Ensures <meta name=\"viewport\"> can scale a significant amount',help:\"Users should be able to zoom and scale the text up to 500%\"},\"meta-viewport\":{description:'Ensures <meta name=\"viewport\"> does not disable text scaling and zooming',help:\"Zooming and scaling must not be disabled\"},\"object-alt\":{description:\"Ensures <object> elements have alternate text\",help:\"<object> elements must have alternate text\"},\"p-as-heading\":{description:\"Ensure p elements are not used to style headings\",help:\"Bold, italic text and font-size are not used to style p elements as a heading\"},radiogroup:{description:'Ensures related <input type=\"radio\"> elements have a group and that the group designation is consistent',help:\"Radio inputs with the same name attribute value must be part of a group\"},region:{description:\"Ensures all content is contained within a landmark region\",help:\"Content should be contained in a landmark region\"},\"scope-attr-valid\":{description:\"Ensures the scope attribute is used correctly on tables\",help:\"scope attribute should be used correctly\"},\"server-side-image-map\":{description:\"Ensures that server-side image maps are not used\",help:\"Server-side image maps must not be used\"},\"skip-link\":{description:\"Ensures the first link on the page is a skip link\",help:\"The page should have a skip link as its first link\"},tabindex:{description:\"Ensures tabindex attribute values are not greater than 0\",help:\"Elements should not have tabindex greater than zero\"},\"table-duplicate-name\":{description:\"Ensure that tables do not have the same summary and caption\",help:\"The <caption> element should not contain the same text as the summary attribute\"},\"table-fake-caption\":{description:\"Ensure that tables with a caption use the <caption> element.\",help:\"Data or header cells should not be used to give caption to a data table.\"},\"td-has-header\":{description:\"Ensure that each non-empty data cell in a large table has one or more table headers\",help:\"All non-empty td element in table larger than 3 by 3 must have an associated table header\"},\"td-headers-attr\":{description:\"Ensure that each cell in a table using the headers refers to another cell in that table\",help:\"All cells in a table element that use the headers attribute must only refer to other cells of that same table\"},\"th-has-data-cells\":{description:\"Ensure that each table header in a data table refers to data cells\",help:\"All th elements and elements with role=columnheader/rowheader must have data cells they describe\"},\"valid-lang\":{description:\"Ensures lang attributes have valid values\",help:\"lang attribute must have a valid value\"},\"video-caption\":{description:\"Ensures <video> elements have captions\",help:\"<video> elements must have captions\"},\"video-description\":{description:\"Ensures <video> elements have audio descriptions\",help:\"<video> elements must have an audio description track\"}},checks:{accesskeys:{impact:\"serious\",messages:{pass:function(a){return\"Accesskey attribute value is unique\"},fail:function(a){return\"Document has multiple elements with the same accesskey\"}}},\"non-empty-alt\":{impact:\"critical\",messages:{pass:function(a){return\"Element has a non-empty alt attribute\"},fail:function(a){return\"Element has no alt attribute or the alt attribute is empty\"}}},\"non-empty-title\":{impact:\"serious\",messages:{pass:function(a){return\"Element has a title attribute\"},fail:function(a){return\"Element has no title attribute or the title attribute is empty\"}}},\"aria-label\":{impact:\"serious\",messages:{pass:function(a){return\"aria-label attribute exists and is not empty\"},fail:function(a){return\"aria-label attribute does not exist or is empty\"}}},\"aria-labelledby\":{impact:\"serious\",messages:{pass:function(a){return\"aria-labelledby attribute exists and references elements that are visible to screen readers\"},fail:function(a){return\"aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty or not visible\"}}},\"aria-allowed-attr\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attributes are used correctly for the defined role\"},fail:function(a){var b=\"ARIA attribute\"+(a.data&&a.data.length>1?\"s are\":\" is\")+\" not allowed:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-hidden-body\":{impact:\"critical\",messages:{pass:function(a){return\"No aria-hidden attribute is present on document body\"},fail:function(a){return\"aria-hidden=true should not be present on the document body\"}}},\"aria-required-attr\":{impact:\"critical\",messages:{pass:function(a){return\"All required ARIA attributes are present\"},fail:function(a){var b=\"Required ARIA attribute\"+(a.data&&a.data.length>1?\"s\":\"\")+\" not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-required-children\":{impact:\"critical\",messages:{pass:function(a){return\"Required ARIA children are present\"},fail:function(a){var b=\"Required ARIA \"+(a.data&&a.data.length>1?\"children\":\"child\")+\" role not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-required-parent\":{impact:\"critical\",messages:{pass:function(a){return\"Required ARIA parent role present\"},fail:function(a){var b=\"Required ARIA parent\"+(a.data&&a.data.length>1?\"s\":\"\")+\" role not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},invalidrole:{impact:\"critical\",messages:{pass:function(a){return\"ARIA role is valid\"},fail:function(a){return\"Role must be one of the valid ARIA roles\"}}},abstractrole:{impact:\"serious\",messages:{pass:function(a){return\"Abstract roles are not used\"},fail:function(a){return\"Abstract roles cannot be directly used\"}}},\"aria-valid-attr-value\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attribute values are valid\"},fail:function(a){var b=\"Invalid ARIA attribute value\"+(a.data&&a.data.length>1?\"s\":\"\")+\":\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-errormessage\":{impact:\"critical\",messages:{pass:function(a){return\"Uses a supported aria-errormessage technique\"},fail:function(a){var b=\"aria-errormessage value\"+(a.data&&a.data.length>1?\"s\":\"\")+\" \",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" `\"+d;return b+=\"` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)\"}}},\"aria-valid-attr\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attribute name\"+(a.data&&a.data.length>1?\"s\":\"\")+\" are valid\"},fail:function(a){var b=\"Invalid ARIA attribute name\"+(a.data&&a.data.length>1?\"s\":\"\")+\":\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},caption:{impact:\"critical\",messages:{pass:function(a){return\"The multimedia element has a captions track\"},fail:function(a){return\"The multimedia element does not have a captions track\"},incomplete:function(a){return\"A captions track for this element could not be found\"}}},\"is-on-screen\":{impact:\"serious\",messages:{pass:function(a){return\"Element is not visible\"},fail:function(a){return\"Element is visible\"}}},\"non-empty-if-present\":{impact:\"critical\",messages:{pass:function(a){var b=\"Element \";return a.data?b+=\"has a non-empty value attribute\":b+=\"does not have a value attribute\",b},fail:function(a){return\"Element has a value attribute and the value attribute is empty\"}}},\"non-empty-value\":{impact:\"critical\",messages:{pass:function(a){return\"Element has a non-empty value attribute\"},fail:function(a){return\"Element has no value attribute or the value attribute is empty\"}}},\"button-has-visible-text\":{impact:\"critical\",messages:{pass:function(a){return\"Element has inner text that is visible to screen readers\"},fail:function(a){return\"Element does not have inner text that is visible to screen readers\"}}},\n\"role-presentation\":{impact:\"minor\",messages:{pass:function(a){return'Element\\'s default semantics were overriden with role=\"presentation\"'},fail:function(a){return'Element\\'s default semantics were not overridden with role=\"presentation\"'}}},\"role-none\":{impact:\"minor\",messages:{pass:function(a){return'Element\\'s default semantics were overriden with role=\"none\"'},fail:function(a){return'Element\\'s default semantics were not overridden with role=\"none\"'}}},\"focusable-no-name\":{impact:\"serious\",messages:{pass:function(a){return\"Element is not in tab order or has accessible text\"},fail:function(a){return\"Element is in tab order and does not have accessible text\"}}},\"internal-link-present\":{impact:\"serious\",messages:{pass:function(a){return\"Valid skip link found\"},fail:function(a){return\"No valid skip link found\"}}},\"header-present\":{impact:\"serious\",messages:{pass:function(a){return\"Page has a header\"},fail:function(a){return\"Page does not have a header\"}}},landmark:{impact:\"serious\",messages:{pass:function(a){return\"Page has a landmark region\"},fail:function(a){return\"Page does not have a landmark region\"}}},\"group-labelledby\":{impact:\"critical\",messages:{pass:function(a){return'All elements with the name \"'+a.data.name+'\" reference the same element with aria-labelledby'},fail:function(a){return'All elements with the name \"'+a.data.name+'\" do not reference the same element with aria-labelledby'}}},fieldset:{impact:\"critical\",messages:{pass:function(a){return\"Element is contained in a fieldset\"},fail:function(a){var b=\"\",c=a.data&&a.data.failureCode;return b+=\"no-legend\"===c?\"Fieldset does not have a legend as its first child\":\"empty-legend\"===c?\"Legend does not have text that is visible to screen readers\":\"mixed-inputs\"===c?\"Fieldset contains unrelated inputs\":\"no-group-label\"===c?\"ARIA group does not have aria-label or aria-labelledby\":\"group-mixed-inputs\"===c?\"ARIA group contains unrelated inputs\":\"Element does not have a containing fieldset or ARIA group\"}}},\"color-contrast\":{impact:\"serious\",messages:{pass:function(a){return\"Element has sufficient color contrast of \"+a.data.contrastRatio},fail:function(a){return\"Element has insufficient color contrast of \"+a.data.contrastRatio+\" (foreground color: \"+a.data.fgColor+\", background color: \"+a.data.bgColor+\", font size: \"+a.data.fontSize+\", font weight: \"+a.data.fontWeight+\"). Expected contrast ratio of \"+a.data.expectedContrastRatio},incomplete:{bgImage:\"Element's background color could not be determined due to a background image\",bgGradient:\"Element's background color could not be determined due to a background gradient\",imgNode:\"Element's background color could not be determined because element contains an image node\",bgOverlap:\"Element's background color could not be determined because it is overlapped by another element\",fgAlpha:\"Element's foreground color could not be determined because of alpha transparency\",elmPartiallyObscured:\"Element's background color could not be determined because it's partially obscured by another element\",elmPartiallyObscuring:\"Element's background color could not be determined because it partially overlaps other elements\",outsideViewport:\"Element's background color could not be determined because it's outside the viewport\",equalRatio:\"Element has a 1:1 contrast ratio with the background\",default:\"Unable to determine contrast ratio\"}}},\"structured-dlitems\":{impact:\"serious\",messages:{pass:function(a){return\"When not empty, element has both <dt> and <dd> elements\"},fail:function(a){return\"When not empty, element does not have at least one <dt> element followed by at least one <dd> element\"}}},\"only-dlitems\":{impact:\"serious\",messages:{pass:function(a){return\"List element only has direct children that are allowed inside <dt> or <dd> elements\"},fail:function(a){return\"List element has direct children that are not allowed inside <dt> or <dd> elements\"}}},dlitem:{impact:\"serious\",messages:{pass:function(a){return\"Description list item has a <dl> parent element\"},fail:function(a){return\"Description list item does not have a <dl> parent element\"}}},\"doc-has-title\":{impact:\"serious\",messages:{pass:function(a){return\"Document has a non-empty <title> element\"},fail:function(a){return\"Document does not have a non-empty <title> element\"}}},\"duplicate-id\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has no elements that share the same id attribute\"},fail:function(a){return\"Document has multiple elements with the same id attribute: \"+a.data}}},\"has-visible-text\":{impact:\"minor\",messages:{pass:function(a){return\"Element has text that is visible to screen readers\"},fail:function(a){return\"Element does not have text that is visible to screen readers\"}}},\"unique-frame-title\":{impact:\"serious\",messages:{pass:function(a){return\"Element's title attribute is unique\"},fail:function(a){return\"Element's title attribute is not unique\"}}},\"heading-order\":{impact:\"moderate\",messages:{pass:function(a){return\"Heading order valid\"},fail:function(a){return\"Heading order invalid\"}}},\"hidden-content\":{impact:\"minor\",messages:{pass:function(a){return\"All content on the page has been analyzed.\"},fail:function(a){return\"There were problems analyzing the content on this page.\"},incomplete:function(a){return\"There is hidden content on the page that was not analyzed. You will need to trigger the display of this content in order to analyze it.\"}}},\"href-no-hash\":{impact:\"moderate\",messages:{pass:function(a){return\"Anchor does not have an href value of #\"},fail:function(a){return\"Anchor has an href value of #\"}}},\"has-lang\":{impact:\"serious\",messages:{pass:function(a){return\"The <html> element has a lang attribute\"},fail:function(a){return\"The <html> element does not have a lang attribute\"}}},\"valid-lang\":{impact:\"serious\",messages:{pass:function(a){return\"Value of lang attribute is included in the list of valid languages\"},fail:function(a){return\"Value of lang attribute not included in the list of valid languages\"}}},\"has-alt\":{impact:\"critical\",messages:{pass:function(a){return\"Element has an alt attribute\"},fail:function(a){return\"Element does not have an alt attribute\"}}},\"duplicate-img-label\":{impact:\"minor\",messages:{pass:function(a){return\"Element does not duplicate existing text in <img> alt text\"},fail:function(a){return\"Element contains <img> element with alt text that duplicates existing text\"}}},\"title-only\":{impact:\"serious\",messages:{pass:function(a){return\"Form element does not solely use title attribute for its label\"},fail:function(a){return\"Only title used to generate label for form element\"}}},\"implicit-label\":{impact:\"critical\",messages:{pass:function(a){return\"Form element has an implicit (wrapped) <label>\"},fail:function(a){return\"Form element does not have an implicit (wrapped) <label>\"}}},\"explicit-label\":{impact:\"critical\",messages:{pass:function(a){return\"Form element has an explicit <label>\"},fail:function(a){return\"Form element does not have an explicit <label>\"}}},\"help-same-as-label\":{impact:\"minor\",messages:{pass:function(a){return\"Help text (title or aria-describedby) does not duplicate label text\"},fail:function(a){return\"Help text (title or aria-describedby) text is the same as the label text\"}}},\"multiple-label\":{impact:\"serious\",messages:{pass:function(a){return\"Form element does not have multiple <label> elements\"},fail:function(a){return\"Form element has multiple <label> elements\"}}},\"main-is-top-level\":{impact:\"moderate\",messages:{pass:function(a){return\"The main landmark is at the top level.\"},fail:function(a){return\"The main landmark is contained in another landmark.\"}}},\"has-at-least-one-main\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has at least one main landmark\"},fail:function(a){return\"Document has no main landmarks\"}}},\"has-no-more-than-one-main\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has no more than one main landmark\"},fail:function(a){return\"Document has more than one main landmark\"}}},\"has-th\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use <th> elements\"},fail:function(a){return\"Layout table uses <th> elements\"}}},\"has-caption\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use <caption> element\"},fail:function(a){return\"Layout table uses <caption> element\"}}},\"has-summary\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use summary attribute\"},fail:function(a){return\"Layout table uses summary attribute\"}}},\"link-in-text-block\":{impact:\"serious\",messages:{pass:function(a){return\"Links can be distinguished from surrounding text in a way that does not rely on color\"},fail:function(a){return\"Links can not be distinguished from surrounding text in a way that does not rely on color\"},incomplete:{bgContrast:\"Element's contrast ratio could not be determined. Check for a distinct hover/focus style\",bgImage:\"Element's contrast ratio could not be determined due to a background image\",bgGradient:\"Element's contrast ratio could not be determined due to a background gradient\",imgNode:\"Element's contrast ratio could not be determined because element contains an image node\",bgOverlap:\"Element's contrast ratio could not be determined because of element overlap\",default:\"Unable to determine contrast ratio\"}}},\"only-listitems\":{impact:\"serious\",messages:{pass:function(a){return\"List element only has direct children that are allowed inside <li> elements\"},fail:function(a){return\"List element has direct children that are not allowed inside <li> elements\"}}},listitem:{impact:\"serious\",messages:{pass:function(a){return'List item has a <ul>, <ol> or role=\"list\" parent element'},fail:function(a){return'List item does not have a <ul>, <ol> or role=\"list\" parent element'}}},\"meta-refresh\":{impact:\"critical\",messages:{pass:function(a){return\"<meta> tag does not immediately refresh the page\"},fail:function(a){return\"<meta> tag forces timed refresh of page\"}}},\"meta-viewport-large\":{impact:\"minor\",messages:{pass:function(a){return\"<meta> tag does not prevent significant zooming on mobile devices\"},fail:function(a){return\"<meta> tag limits zooming on mobile devices\"}}},\"meta-viewport\":{impact:\"critical\",messages:{pass:function(a){return\"<meta> tag does not disable zooming on mobile devices\"},fail:function(a){return\"<meta> tag disables zooming on mobile devices\"}}},\"p-as-heading\":{impact:\"serious\",messages:{pass:function(a){return\"<p> elements are not styled as headings\"},fail:function(a){return\"Heading elements should be used instead of styled p elements\"}}},region:{impact:\"moderate\",messages:{pass:function(a){return\"Content contained by ARIA landmark\"},fail:function(a){return\"Content not contained by an ARIA landmark\"}}},\"html5-scope\":{impact:\"moderate\",messages:{pass:function(a){return\"Scope attribute is only used on table header elements (<th>)\"},fail:function(a){return\"In HTML 5, scope attributes may only be used on table header elements (<th>)\"}}},\"scope-value\":{impact:\"critical\",messages:{pass:function(a){return\"Scope attribute is used correctly\"},fail:function(a){return\"The value of the scope attribute may only be 'row' or 'col'\"}}},exists:{impact:\"minor\",messages:{pass:function(a){return\"Element does not exist\"},fail:function(a){return\"Element exists\"}}},\"skip-link\":{impact:\"moderate\",messages:{pass:function(a){return\"Valid skip link found\"},fail:function(a){return\"No valid skip link found\"}}},tabindex:{impact:\"serious\",messages:{pass:function(a){return\"Element does not have a tabindex greater than 0\"},fail:function(a){return\"Element has a tabindex greater than 0\"}}},\"same-caption-summary\":{impact:\"minor\",messages:{pass:function(a){return\"Content of summary attribute and <caption> are not duplicated\"},fail:function(a){return\"Content of summary attribute and <caption> element are identical\"}}},\"caption-faked\":{impact:\"serious\",messages:{pass:function(a){return\"The first row of a table is not used as a caption\"},fail:function(a){return\"The first row of the table should be a caption instead of a table cell\"}}},\"td-has-header\":{impact:\"critical\",messages:{pass:function(a){return\"All non-empty data cells have table headers\"},fail:function(a){return\"Some non-empty data cells do not have table headers\"}}},\"td-headers-attr\":{impact:\"serious\",messages:{pass:function(a){return\"The headers attribute is exclusively used to refer to other cells in the table\"},fail:function(a){return\"The headers attribute is not exclusively used to refer to other cells in the table\"}}},\"th-has-data-cells\":{impact:\"serious\",messages:{pass:function(a){return\"All table header cells refer to data cells\"},fail:function(a){return\"Not all table header cells refer to data cells\"},incomplete:function(a){return\"Table data cells are missing or empty\"}}},description:{impact:\"critical\",messages:{pass:function(a){return\"The multimedia element has an audio description track\"},fail:function(a){return\"The multimedia element does not have an audio description track\"},incomplete:function(a){return\"An audio description track for this element could not be found\"}}}},failureSummaries:{any:{failureMessage:function(a){var b=\"Fix any of the following:\",c=a;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\"\\n  \"+d.split(\"\\n\").join(\"\\n  \");return b}},none:{failureMessage:function(a){var b=\"Fix all of the following:\",c=a;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\"\\n  \"+d.split(\"\\n\").join(\"\\n  \");return b}}},incompleteFallbackMessage:function(a){return\"aXe couldn't tell the reason. Time to break out the element inspector!\"}},rules:[{id:\"accesskeys\",selector:\"[accesskey]\",excludeHidden:!1,tags:[\"wcag2a\",\"wcag211\",\"cat.keyboard\"],all:[],any:[],none:[\"accesskeys\"]},{id:\"area-alt\",selector:\"map area[href]\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-alt\",\"non-empty-title\",\"aria-label\",\"aria-labelledby\"],none:[]},{id:\"aria-allowed-attr\",matches:function(a){var b=a.getAttribute(\"role\");b||(b=axe.commons.aria.implicitRole(a));var c=axe.commons.aria.allowedAttr(b);if(b&&c){var d=/^aria-/;if(a.hasAttributes())for(var e=a.attributes,f=0,g=e.length;f<g;f++)if(d.test(e[f].name))return!0}return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag411\",\"wcag412\"],all:[],any:[\"aria-allowed-attr\"],none:[]},{id:\"aria-hidden-body\",selector:\"body\",excludeHidden:!1,tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[],any:[\"aria-hidden-body\"],none:[]},{id:\"aria-required-attr\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag411\",\"wcag412\"],all:[],any:[\"aria-required-attr\"],none:[]},{id:\"aria-required-children\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[],any:[\"aria-required-children\"],none:[]},{id:\"aria-required-parent\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[],any:[\"aria-required-parent\"],none:[]},{id:\"aria-roles\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"wcag411\",\"wcag412\"],all:[],any:[],none:[\"invalidrole\",\"abstractrole\"]},{id:\"aria-valid-attr-value\",matches:function(a){var b=/^aria-/;if(a.hasAttributes())for(var c=a.attributes,d=0,e=c.length;d<e;d++)if(b.test(c[d].name))return!0;return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"wcag411\",\"wcag412\"],all:[{options:[],id:\"aria-valid-attr-value\"},\"aria-errormessage\"],any:[],none:[]},{id:\"aria-valid-attr\",matches:function(a){var b=/^aria-/;if(a.hasAttributes())for(var c=a.attributes,d=0,e=c.length;d<e;d++)if(b.test(c[d].name))return!0;return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag411\"],all:[],any:[{options:[],id:\"aria-valid-attr\"}],none:[]},{id:\"audio-caption\",selector:\"audio\",excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag122\",\"section508\",\"section508.22.a\"],all:[],any:[],none:[\"caption\"]},{id:\"blink\",selector:\"blink\",excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag222\",\"section508\",\"section508.22.j\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"button-name\",selector:'button, [role=\"button\"], input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"]',tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-if-present\",\"non-empty-value\",\"button-has-visible-text\",\"aria-label\",\"aria-labelledby\",\"role-presentation\",\"role-none\"],none:[\"focusable-no-name\"]},{id:\"bypass\",selector:\"html\",pageLevel:!0,matches:function(a){return!!a.querySelector(\"a[href]\")},tags:[\"cat.keyboard\",\"wcag2a\",\"wcag241\",\"section508\",\"section508.22.o\"],all:[],any:[\"internal-link-present\",\"header-present\",\"landmark\"],none:[]},{id:\"checkboxgroup\",selector:\"input[type=checkbox][name]\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[\"group-labelledby\",\"fieldset\"],none:[]},{id:\"color-contrast\",matches:function(a){var b=a.nodeName.toUpperCase(),c=a.type,d=document;if(\"true\"===a.getAttribute(\"aria-disabled\")||axe.commons.dom.findUp(a,'[aria-disabled=\"true\"]'))return!1;if(\"INPUT\"===b)return-1===[\"hidden\",\"range\",\"color\",\"checkbox\",\"radio\",\"image\"].indexOf(c)&&!a.disabled;if(\"SELECT\"===b)return!!a.options.length&&!a.disabled;if(\"TEXTAREA\"===b)return!a.disabled;if(\"OPTION\"===b)return!1;if(\"BUTTON\"===b&&a.disabled||axe.commons.dom.findUp(a,\"button[disabled]\"))return!1;if(\"FIELDSET\"===b&&a.disabled||axe.commons.dom.findUp(a,\"fieldset[disabled]\"))return!1;var e=axe.commons.dom.findUp(a,\"label\");if(\"LABEL\"===b||e){var f=a;e&&(f=e);var g=f.htmlFor&&d.getElementById(f.htmlFor);if(g&&g.disabled)return!1;var g=f.querySelector('input:not([type=\"hidden\"]):not([type=\"image\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]), select, textarea');if(g&&g.disabled)return!1}if(a.getAttribute(\"id\")){var h=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),i=d.querySelector('[aria-labelledby~=\"'+h+'\"]');if(i&&i.hasAttribute(\"disabled\"))return!1}if(\"\"===axe.commons.text.visible(a,!1,!0))return!1;var j,k,l=document.createRange(),m=a.childNodes,n=m.length;for(k=0;k<n;k++)j=m[k],3===j.nodeType&&\"\"!==axe.commons.text.sanitize(j.nodeValue)&&l.selectNodeContents(j);var o=l.getClientRects();for(n=o.length,k=0;k<n;k++)if(axe.commons.dom.visuallyOverlaps(o[k],a))return!0;return!1},excludeHidden:!1,options:{noScroll:!1},tags:[\"cat.color\",\"wcag2aa\",\"wcag143\"],all:[],any:[\"color-contrast\"],none:[]},{id:\"definition-list\",selector:\"dl:not([role])\",tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"structured-dlitems\",\"only-dlitems\"]},{id:\"dlitem\",selector:\"dd:not([role]), dt:not([role])\",tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[\"dlitem\"],none:[]},{id:\"document-title\",selector:\"html\",matches:function(a){return a.ownerDocument.defaultView.self===a.ownerDocument.defaultView.top},tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag242\"],all:[],any:[\"doc-has-title\"],none:[]},{id:\"duplicate-id\",selector:\"[id]\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag411\"],all:[],any:[\"duplicate-id\"],none:[]},{id:\"empty-heading\",selector:'h1, h2, h3, h4, h5, h6, [role=\"heading\"]',enabled:!0,tags:[\"cat.name-role-value\",\"best-practice\"],all:[],any:[\"has-visible-text\",\"role-presentation\",\"role-none\"],none:[]},{id:\"frame-title-unique\",selector:\"frame[title]:not([title='']), iframe[title]:not([title=''])\",matches:function(a){var b=a.getAttribute(\"title\");return!!(b?axe.commons.text.sanitize(b).trim():\"\")},tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[\"unique-frame-title\"]},{id:\"frame-title\",selector:\"frame, iframe\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag241\",\"section508\",\"section508.22.i\"],all:[],any:[\"aria-label\",\"aria-labelledby\",\"non-empty-title\",\"role-presentation\",\"role-none\"],none:[]},{id:\"heading-order\",selector:\"h1,h2,h3,h4,h5,h6,[role=heading]\",enabled:!1,tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"heading-order\"],none:[]},{id:\"hidden-content\",selector:\"*\",excludeHidden:!1,tags:[\"experimental\",\"review-item\"],all:[],any:[\"hidden-content\"],none:[],enabled:!1},{id:\"href-no-hash\",selector:\"a[href]\",enabled:!1,tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"href-no-hash\"],none:[]},{id:\"html-has-lang\",selector:\"html\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[],any:[\"has-lang\"],none:[]},{id:\"html-lang-valid\",selector:\"html[lang]\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[],any:[],none:[\"valid-lang\"]},{id:\"image-alt\",selector:\"img, [role='img']\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-alt\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\",\"role-presentation\",\"role-none\"],none:[]},{id:\"image-redundant-alt\",selector:'button, [role=\"button\"], a[href], p, li, td, th',tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[\"duplicate-img-label\"]},{id:\"input-image-alt\",selector:'input[type=\"image\"]',tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-alt\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\"],none:[]},{id:\"label-title-only\",selector:\"input:not([type='hidden']):not([type='image']):not([type='button']):not([type='submit']):not([type='reset']), select, textarea\",enabled:!1,tags:[\"cat.forms\",\"best-practice\"],all:[],any:[],none:[\"title-only\"]},{id:\"label\",selector:\"input:not([type='hidden']):not([type='image']):not([type='button']):not([type='submit']):not([type='reset']), select, textarea\",tags:[\"cat.forms\",\"wcag2a\",\"wcag332\",\"wcag131\",\"section508\",\"section508.22.n\"],all:[],any:[\"aria-label\",\"aria-labelledby\",\"implicit-label\",\"explicit-label\",\"non-empty-title\"],none:[\"help-same-as-label\",\"multiple-label\"]},{id:\"landmark-main-is-top-level\",selector:\"main,[role=main]\",tags:[\"best-practice\"],all:[],any:[\"main-is-top-level\"],none:[]},{id:\"landmark-one-main\",selector:\"html\",tags:[\"best-practice\"],all:[\"has-at-least-one-main\",\"has-no-more-than-one-main\"],any:[],none:[]},{id:\"layout-table\",selector:\"table\",matches:function(a){return!axe.commons.table.isDataTable(a)},tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"has-th\",\"has-caption\",\"has-summary\"]},{id:\"link-in-text-block\",selector:\"a[href]:not([role]), *[role=link]\",matches:function(a){return!!axe.commons.text.sanitize(a.textContent)&&!!axe.commons.dom.isVisible(a,!1)&&axe.commons.dom.isInTextBlock(a)},excludeHidden:!1,tags:[\"cat.color\",\"experimental\",\"wcag2a\",\"wcag141\"],all:[\"link-in-text-block\"],any:[],none:[]},{id:\"link-name\",selector:'a[href]:not([role=\"button\"]), [role=link][href]',tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag111\",\"wcag412\",\"wcag244\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",\"role-presentation\",\"role-none\"],none:[\"focusable-no-name\"]},{id:\"list\",selector:\"ul:not([role]), ol:not([role])\",tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"only-listitems\"]},{id:\"listitem\",selector:\"li:not([role])\",tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[\"listitem\"],none:[]},{id:\"marquee\",selector:\"marquee\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag222\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"meta-refresh\",selector:'meta[http-equiv=\"refresh\"]',excludeHidden:!1,tags:[\"cat.time\",\"wcag2a\",\"wcag2aaa\",\"wcag221\",\"wcag224\",\"wcag325\"],all:[],any:[\"meta-refresh\"],none:[]},{id:\"meta-viewport-large\",selector:'meta[name=\"viewport\"]',excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"best-practice\"],all:[],any:[{options:{scaleMinimum:5,lowerBound:2},id:\"meta-viewport-large\"}],none:[]},{id:\"meta-viewport\",selector:'meta[name=\"viewport\"]',excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"wcag2aa\",\"wcag144\"],all:[],any:[{options:{scaleMinimum:2},id:\"meta-viewport\"}],none:[]},{id:\"object-alt\",selector:\"object\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\"],none:[]},{id:\"p-as-heading\",selector:\"p\",matches:function(a){var b=Array.from(a.parentNode.childNodes),c=a.textContent.trim(),d=/[.!?:;](?![.!?:;])/g;return!(0===c.length||(c.match(d)||[]).length>=2)&&0!==b.slice(b.indexOf(a)+1).filter(function(a){return\"P\"===a.nodeName.toUpperCase()&&\"\"!==a.textContent.trim()}).length},tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\",\"experimental\"],all:[{options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}]},id:\"p-as-heading\"}],any:[],none:[]},{id:\"radiogroup\",selector:\"input[type=radio][name]\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[\"group-labelledby\",\"fieldset\"],none:[]},{id:\"region\",selector:\"html\",pageLevel:!0,enabled:!1,tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"region\"],none:[]},{id:\"scope-attr-valid\",selector:\"td[scope], th[scope]\",enabled:!0,tags:[\"cat.tables\",\"best-practice\"],all:[\"html5-scope\",\"scope-value\"],any:[],none:[]},{id:\"server-side-image-map\",selector:\"img[ismap]\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag211\",\"section508\",\"section508.22.f\"],all:[],any:[],none:[\"exists\"]},{id:\"skip-link\",selector:\"a[href]\",pageLevel:!0,enabled:!1,tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"skip-link\"],none:[]},{id:\"tabindex\",selector:\"[tabindex]\",tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"tabindex\"],none:[]},{id:\"table-duplicate-name\",selector:\"table\",tags:[\"cat.tables\",\"best-practice\"],all:[],any:[],none:[\"same-caption-summary\"]},{id:\"table-fake-caption\",selector:\"table\",matches:function(a){return axe.commons.table.isDataTable(a)},tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"caption-faked\"],any:[],none:[]},{id:\"td-has-header\",selector:\"table\",matches:function(a){if(axe.commons.table.isDataTable(a)){var b=axe.commons.table.toArray(a);return b.length>=3&&b[0].length>=3&&b[1].length>=3&&b[2].length>=3}return!1},tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"td-has-header\"],any:[],none:[]},{id:\"td-headers-attr\",selector:\"table\",tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"td-headers-attr\"],any:[],none:[]},{id:\"th-has-data-cells\",selector:\"table\",matches:function(a){return axe.commons.table.isDataTable(a)},tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"th-has-data-cells\"],any:[],none:[]},{id:\"valid-lang\",selector:\"[lang]:not(html), [xml\\\\:lang]:not(html)\",tags:[\"cat.language\",\"wcag2aa\",\"wcag312\"],all:[],any:[],none:[\"valid-lang\"]},{id:\"video-caption\",selector:\"video\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag122\",\"wcag123\",\"section508\",\"section508.22.a\"],all:[],any:[],none:[\"caption\"]},{id:\"video-description\",selector:\"video\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2aa\",\"wcag125\",\"section508\",\"section508.22.b\"],all:[],any:[],none:[\"description\"]}],checks:[{id:\"abstractrole\",evaluate:function(a,b){return\"abstract\"===axe.commons.aria.getRoleType(a.getAttribute(\"role\"))}},{id:\"aria-allowed-attr\",evaluate:function(a,b){var c,d,e,f=[],g=a.getAttribute(\"role\"),h=a.attributes;if(g||(g=axe.commons.aria.implicitRole(a)),e=axe.commons.aria.allowedAttr(g),g&&e)for(var i=0,j=h.length;i<j;i++)c=h[i],d=c.name,axe.commons.aria.validateAttr(d)&&-1===e.indexOf(d)&&f.push(d+'=\"'+c.nodeValue+'\"');return!f.length||(this.data(f),!1)}},{id:\"aria-hidden-body\",evaluate:function(a,b){return\"true\"!==a.getAttribute(\"aria-hidden\")}},{id:\"aria-errormessage\",evaluate:function(a,b){b=Array.isArray(b)?b:[];var c=a.getAttribute(\"aria-errormessage\"),d=a.hasAttribute(\"aria-errormessage\"),e=document;return!(-1===b.indexOf(c)&&d&&!function(){var b=c&&e.getElementById(c);if(b)return\"alert\"===b.getAttribute(\"role\")||\"assertive\"===b.getAttribute(\"aria-live\")||axe.utils.tokenList(a.getAttribute(\"aria-describedby\")||\"\").indexOf(c)>-1}())||(this.data(c),!1)}},{id:\"invalidrole\",evaluate:function(a,b){return!axe.commons.aria.isValidRole(a.getAttribute(\"role\"))}},{id:\"aria-required-attr\",evaluate:function(a,b){var c=[];if(a.hasAttributes()){var d,e=a.getAttribute(\"role\"),f=axe.commons.aria.requiredAttr(e);if(e&&f)for(var g=0,h=f.length;g<h;g++)d=f[g],a.getAttribute(d)||c.push(d)}return!c.length||(this.data(c),!1)}},{id:\"aria-required-children\",evaluate:function(a,b){function c(a,b,c){if(null===a)return!1;var d=f(b),e=['[role=\"'+b+'\"]'];return d&&(e=e.concat(d)),e=e.join(\",\"),c?g(a,e)||!!a.querySelector(e):!!a.querySelector(e)}function d(a,b){var d,e;for(d=0,e=a.length;d<e;d++)if(null!==a[d]&&c(a[d],b,!0))return!0;return!1}var e=axe.commons.aria.requiredOwned,f=axe.commons.aria.implicitNodes,g=axe.commons.utils.matchesSelector,h=axe.commons.dom.idrefs,i=a.getAttribute(\"role\"),j=e(i);if(!j)return!0;var k=!1,l=j.one;if(!l){var k=!0;l=j.all}var m=function(a,b,e,f){var g,i=b.length,j=[],k=h(a,\"aria-owns\");for(g=0;g<i;g++){var l=b[g];if(c(a,l)||d(k,l)){if(!e)return null}else e&&j.push(l)}if(\"combobox\"===f){var m=j.indexOf(\"textbox\"),n=[\"text\",\"search\",\"email\",\"url\",\"tel\"];m>=0&&\"INPUT\"===a.tagName&&n.includes(a.type)&&j.splice(m,1);var o=j.indexOf(\"listbox\"),p=a.getAttribute(\"aria-expanded\");o>=0&&(!p||\"false\"===p)&&j.splice(o,1)}return j.length?j:!e&&b.length?b:null}(a,l,k,i);return!m||(this.data(m),!1)}},{id:\"aria-required-parent\",evaluate:function(a,b){function c(a){return(axe.commons.aria.implicitNodes(a)||[]).concat('[role=\"'+a+'\"]').join(\",\")}function d(a,b,d){var e,f,g=a.getAttribute(\"role\"),h=[];if(b||(b=axe.commons.aria.requiredContext(g)),!b)return null;for(e=0,f=b.length;e<f;e++){if(d&&axe.utils.matchesSelector(a,c(b[e])))return null;if(axe.commons.dom.findUp(a,c(b[e])))return null;h.push(b[e])}return h}var e=d(a);if(!e)return!0;var f=function(a){for(var b=[],c=null;a;){if(a.getAttribute(\"id\")){var d=axe.commons.utils.escapeSelector(a.getAttribute(\"id\"));c=document.querySelector(\"[aria-owns~=\"+d+\"]\"),c&&b.push(c)}a=a.parentElement}return b.length?b:null}(a);if(f)for(var g=0,h=f.length;g<h;g++)if(!(e=d(f[g],e,!0)))return!0;return this.data(e),!1}},{id:\"aria-valid-attr-value\",evaluate:function(a,b){b=Array.isArray(b)?b:[];for(var c,d,e=[],f=/^aria-/,g=a.attributes,h=[\"aria-errormessage\"],i=0,j=g.length;i<j;i++)c=g[i],d=c.name,h.includes(d)||-1===b.indexOf(d)&&f.test(d)&&!axe.commons.aria.validateAttrValue(a,d)&&e.push(d+'=\"'+c.nodeValue+'\"');return!e.length||(this.data(e),!1)},options:[]},{id:\"aria-valid-attr\",evaluate:function(a,b){b=Array.isArray(b)?b:[];for(var c,d=[],e=/^aria-/,f=a.attributes,g=0,h=f.length;g<h;g++)c=f[g].name,-1===b.indexOf(c)&&e.test(c)&&!axe.commons.aria.validateAttr(c)&&d.push(c);return!d.length||(this.data(d),!1)},options:[]},{id:\"color-contrast\",evaluate:function(a,b){if(!axe.commons.dom.isVisible(a,!1))return!0;var c,d=!!(b||{}).noScroll,e=[],f=axe.commons.color.getBackgroundColor(a,e,d),g=axe.commons.color.getForegroundColor(a,d),h=window.getComputedStyle(a),i=parseFloat(h.getPropertyValue(\"font-size\")),j=h.getPropertyValue(\"font-weight\"),k=-1!==[\"bold\",\"bolder\",\"600\",\"700\",\"800\",\"900\"].indexOf(j),l=axe.commons.color.hasValidContrastRatio(f,g,i,k),m=Math.floor(100*l.contrastRatio)/100;null===f&&(c=axe.commons.color.incompleteData.get(\"bgColor\"));var n=!1;1===m&&(n=!0,c=axe.commons.color.incompleteData.set(\"bgColor\",\"equalRatio\"));var o={fgColor:g?g.toHexString():void 0,bgColor:f?f.toHexString():void 0,contrastRatio:l?m:void 0,fontSize:(72*i/96).toFixed(1)+\"pt\",fontWeight:k?\"bold\":\"normal\",missingData:c,expectedContrastRatio:l.expectedContrastRatio+\":1\"};return this.data(o),null===g||null===f||n?(c=null,axe.commons.color.incompleteData.clear(),void this.relatedNodes(e)):(l.isValid||this.relatedNodes(e),l.isValid)}},{id:\"link-in-text-block\",evaluate:function(a,b){function c(a,b){var c=a.getRelativeLuminance(),d=b.getRelativeLuminance();return(Math.max(c,d)+.05)/(Math.min(c,d)+.05)}function d(a){var b=window.getComputedStyle(a).getPropertyValue(\"display\");return-1!==f.indexOf(b)||\"table-\"===b.substr(0,6)}var e=axe.commons.color,f=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];if(d(a))return!1;for(var g=a.parentNode;1===g.nodeType&&!d(g);)g=g.parentNode;if(this.relatedNodes([g]),e.elementIsDistinct(a,g))return!0;var h,i;if(h=e.getForegroundColor(a),i=e.getForegroundColor(g),h&&i){var j=c(h,i);if(1===j)return!0;if(j>=3)return axe.commons.color.incompleteData.set(\"fgColor\",\"bgContrast\"),this.data({\nmissingData:axe.commons.color.incompleteData.get(\"fgColor\")}),void axe.commons.color.incompleteData.clear();if(h=e.getBackgroundColor(a),i=e.getBackgroundColor(g),!h||!i||c(h,i)>=3){var k=void 0;return k=h&&i?\"bgContrast\":axe.commons.color.incompleteData.get(\"bgColor\"),axe.commons.color.incompleteData.set(\"fgColor\",k),this.data({missingData:axe.commons.color.incompleteData.get(\"fgColor\")}),void axe.commons.color.incompleteData.clear()}return!1}}},{id:\"fieldset\",evaluate:function(a,b){function c(a,b){return axe.commons.utils.toArray(a.querySelectorAll('select,textarea,button,input:not([name=\"'+b+'\"]):not([type=\"hidden\"])'))}function d(a,b){var d=a.firstElementChild;if(!d||\"LEGEND\"!==d.nodeName.toUpperCase())return h.relatedNodes([a]),g=\"no-legend\",!1;if(!axe.commons.text.accessibleText(d))return h.relatedNodes([d]),g=\"empty-legend\",!1;var e=c(a,b);return!e.length||(h.relatedNodes(e),g=\"mixed-inputs\",!1)}function e(a,b){var d=axe.commons.dom.idrefs(a,\"aria-labelledby\").some(function(a){return a&&axe.commons.text.accessibleText(a)}),e=a.getAttribute(\"aria-label\");if(!(d||e&&axe.commons.text.sanitize(e)))return h.relatedNodes(a),g=\"no-group-label\",!1;var f=c(a,b);return!f.length||(h.relatedNodes(f),g=\"group-mixed-inputs\",!1)}function f(a,b){return axe.commons.utils.toArray(a).filter(function(a){return a!==b})}var g,h=this,i={name:a.getAttribute(\"name\"),type:a.getAttribute(\"type\")},j=function(b){var c=axe.commons.utils.escapeSelector(a.name),i=document.querySelectorAll('input[type=\"'+axe.commons.utils.escapeSelector(a.type)+'\"][name=\"'+c+'\"]');if(i.length<2)return!0;var j=axe.commons.dom.findUp(b,\"fieldset\"),k=axe.commons.dom.findUp(b,'[role=\"group\"]'+(\"radio\"===a.type?',[role=\"radiogroup\"]':\"\"));return k||j?j?d(j,c):e(k,c):(g=\"no-group\",h.relatedNodes(f(i,b)),!1)}(a);return j||(i.failureCode=g),this.data(i),j},after:function(a,b){var c={};return a.filter(function(a){if(a.result)return!0;var b=a.data;if(b){if(c[b.type]=c[b.type]||{},!c[b.type][b.name])return c[b.type][b.name]=[b],!0;var d=c[b.type][b.name].some(function(a){return a.failureCode===b.failureCode});return d||c[b.type][b.name].push(b),!d}return!1})}},{id:\"group-labelledby\",evaluate:function(a,b){this.data({name:a.getAttribute(\"name\"),type:a.getAttribute(\"type\")});var c=document.querySelectorAll('input[type=\"'+axe.commons.utils.escapeSelector(a.type)+'\"][name=\"'+axe.commons.utils.escapeSelector(a.name)+'\"]');return c.length<=1||0!==[].map.call(c,function(a){var b=a.getAttribute(\"aria-labelledby\");return b?b.split(/\\s+/):[]}).reduce(function(a,b){return a.filter(function(a){return-1!==b.indexOf(a)})}).filter(function(a){var b=document.getElementById(a);return b&&axe.commons.text.accessibleText(b)}).length},after:function(a,b){var c={};return a.filter(function(a){var b=a.data;return!(!b||(c[b.type]=c[b.type]||{},c[b.type][b.name]))&&(c[b.type][b.name]=!0,!0)})}},{id:\"accesskeys\",evaluate:function(a,b){return axe.commons.dom.isVisible(a,!1)&&(this.data(a.getAttribute(\"accesskey\")),this.relatedNodes([a])),!0},after:function(a,b){var c={};return a.filter(function(a){if(!a.data)return!1;var b=a.data.toUpperCase();return c[b]?(c[b].relatedNodes.push(a.relatedNodes[0]),!1):(c[b]=a,a.relatedNodes=[],!0)}).map(function(a){return a.result=!!a.relatedNodes.length,a})}},{id:\"focusable-no-name\",evaluate:function(a,b){var c=a.getAttribute(\"tabindex\");return!!(axe.commons.dom.isFocusable(a)&&c>-1)&&!axe.commons.text.accessibleText(a)}},{id:\"has-at-least-one-main\",evaluate:function(a,b){var c=document.querySelectorAll(\"main,[role=main]\");return this.data(!!c[0]),!!c[0]},after:function(a,b){for(var c=!1,d=0;d<a.length&&!c;d++)c=a[d].data;for(var d=0;d<a.length;d++)a[d].result=c;return a}},{id:\"has-no-more-than-one-main\",evaluate:function(a,b){return document.querySelectorAll(\"main,[role=main]\").length<=1}},{id:\"main-is-top-level\",evaluate:function(a,b){for(var c=axe.commons.aria.getRolesByType(\"landmark\"),d=a.parentNode;d;){if(1===d.nodeType){var e=d.getAttribute(\"role\");if(e||\"form\"===d.tagName.toLowerCase()||(e=axe.commons.aria.implicitRole(d)),e&&c.includes(e))return!1}d=d.parentNode}return!0}},{id:\"tabindex\",evaluate:function(a,b){return a.tabIndex<=0}},{id:\"duplicate-img-label\",evaluate:function(a,b){var c=a.querySelectorAll(\"img\"),d=axe.commons.text.visible(a,!0).toLowerCase();if(\"\"===d)return!1;for(var e=0,f=c.length;e<f;e++){var g=c[e];if(axe.commons.text.accessibleText(g).toLowerCase()===d&&\"presentation\"!==g.getAttribute(\"role\")&&axe.commons.dom.isVisible(g))return!0}return!1}},{id:\"explicit-label\",evaluate:function(a,b){if(a.getAttribute(\"id\")){var c=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),d=document.querySelector('label[for=\"'+c+'\"]');if(d)return!!axe.commons.text.accessibleText(d)}return!1}},{id:\"help-same-as-label\",evaluate:function(a,b){var c=axe.commons.text.label(a),d=a.getAttribute(\"title\");if(!c)return!1;if(!d&&(d=\"\",a.getAttribute(\"aria-describedby\"))){d=axe.commons.dom.idrefs(a,\"aria-describedby\").map(function(a){return a?axe.commons.text.accessibleText(a):\"\"}).join(\"\")}return axe.commons.text.sanitize(d)===axe.commons.text.sanitize(c)},enabled:!1},{id:\"implicit-label\",evaluate:function(a,b){var c=axe.commons.dom.findUp(a,\"label\");return!!c&&!!axe.commons.text.accessibleText(c)}},{id:\"multiple-label\",evaluate:function(a,b){var c=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),d=Array.from(document.querySelectorAll('label[for=\"'+c+'\"]')),e=a.parentNode;for(d.length&&(d=d.filter(function(a,b){if(0===b&&!axe.commons.dom.isVisible(a,!0)||axe.commons.dom.isVisible(a,!0))return a}));e;)\"LABEL\"===e.tagName&&-1===d.indexOf(e)&&d.push(e),e=e.parentNode;return this.relatedNodes(d),d.length>1}},{id:\"title-only\",evaluate:function(a,b){return!(axe.commons.text.label(a)||!a.getAttribute(\"title\")&&!a.getAttribute(\"aria-describedby\"))}},{id:\"has-lang\",evaluate:function(a,b){return!!(a.getAttribute(\"lang\")||a.getAttribute(\"xml:lang\")||\"\").trim()}},{id:\"valid-lang\",evaluate:function(a,b){function c(a){return a.trim().split(\"-\")[0].toLowerCase()}var d,e;return d=(b||axe.commons.utils.validLangs()).map(c),e=[\"lang\",\"xml:lang\"].reduce(function(b,e){var f=a.getAttribute(e);if(\"string\"!=typeof f)return b;var g=c(f);return\"\"!==g&&-1===d.indexOf(g)&&b.push(e+'=\"'+a.getAttribute(e)+'\"'),b},[]),!!e.length&&(this.data(e),!0)}},{id:\"dlitem\",evaluate:function(a,b){return\"DL\"===a.parentNode.tagName.toUpperCase()}},{id:\"has-listitem\",evaluate:function(a,b){var c=a.children;if(0===c.length)return!0;for(var d=0;d<c.length;d++)if(\"LI\"===c[d].nodeName.toUpperCase())return!1;return!0}},{id:\"listitem\",evaluate:function(a,b){return-1!==[\"UL\",\"OL\"].indexOf(a.parentNode.nodeName.toUpperCase())||\"list\"===a.parentNode.getAttribute(\"role\")}},{id:\"only-dlitems\",evaluate:function(a,b){for(var c,d,e=[],f=a.childNodes,g=[\"STYLE\",\"META\",\"LINK\",\"MAP\",\"AREA\",\"SCRIPT\",\"DATALIST\",\"TEMPLATE\"],h=!1,i=0;i<f.length;i++){c=f[i];var d=c.nodeName.toUpperCase();1===c.nodeType&&\"DT\"!==d&&\"DD\"!==d&&-1===g.indexOf(d)?e.push(c):3===c.nodeType&&\"\"!==c.nodeValue.trim()&&(h=!0)}return e.length&&this.relatedNodes(e),!!e.length||h}},{id:\"only-listitems\",evaluate:function(a,b){for(var c,d,e=[],f=a.childNodes,g=[\"STYLE\",\"META\",\"LINK\",\"MAP\",\"AREA\",\"SCRIPT\",\"DATALIST\",\"TEMPLATE\"],h=!1,i=0;i<f.length;i++)c=f[i],d=c.nodeName.toUpperCase(),1===c.nodeType&&\"LI\"!==d&&-1===g.indexOf(d)?e.push(c):3===c.nodeType&&\"\"!==c.nodeValue.trim()&&(h=!0);return e.length&&this.relatedNodes(e),!!e.length||h}},{id:\"structured-dlitems\",evaluate:function(a,b){var c=a.children;if(!c||!c.length)return!1;for(var d,e=!1,f=!1,g=0;g<c.length;g++){if(d=c[g].nodeName.toUpperCase(),\"DT\"===d&&(e=!0),e&&\"DD\"===d)return!1;\"DD\"===d&&(f=!0)}return e||f}},{id:\"caption\",evaluate:function(a,b){var c=a.querySelectorAll(\"track\");if(c.length){for(var d=0;d<c.length;d++){var e=c[d].getAttribute(\"kind\");if(e&&\"captions\"===e)return!1}return!0}}},{id:\"description\",evaluate:function(a,b){var c=a.querySelectorAll(\"track\");if(c.length){for(var d=0;d<c.length;d++){var e=c[d].getAttribute(\"kind\");if(e&&\"descriptions\"===e)return!1}return!0}}},{id:\"meta-viewport-large\",evaluate:function(a,b){b=b||{};for(var c,d=a.getAttribute(\"content\")||\"\",e=d.split(/[;,]/),f={},g=b.scaleMinimum||2,h=b.lowerBound||!1,i=0,j=e.length;i<j;i++){c=e[i].split(\"=\");var k=c.shift().toLowerCase();k&&c.length&&(f[k.trim()]=c.shift().trim().toLowerCase())}return!!(h&&f[\"maximum-scale\"]&&parseFloat(f[\"maximum-scale\"])<h)||!(!h&&\"no\"===f[\"user-scalable\"])&&!(f[\"maximum-scale\"]&&parseFloat(f[\"maximum-scale\"])<g)},options:{scaleMinimum:5,lowerBound:2}},{id:\"meta-viewport\",evaluate:function(a,b){b=b||{};for(var c,d=a.getAttribute(\"content\")||\"\",e=d.split(/[;,]/),f={},g=b.scaleMinimum||2,h=b.lowerBound||!1,i=0,j=e.length;i<j;i++){c=e[i].split(\"=\");var k=c.shift().toLowerCase();k&&c.length&&(f[k.trim()]=c.shift().trim().toLowerCase())}return!!(h&&f[\"maximum-scale\"]&&parseFloat(f[\"maximum-scale\"])<h)||!(!h&&\"no\"===f[\"user-scalable\"])&&!(f[\"maximum-scale\"]&&parseFloat(f[\"maximum-scale\"])<g)},options:{scaleMinimum:2}},{id:\"header-present\",evaluate:function(a,b){return!!a.querySelector('h1, h2, h3, h4, h5, h6, [role=\"heading\"]')}},{id:\"heading-order\",evaluate:function(a,b){var c=a.getAttribute(\"aria-level\");if(null!==c)return this.data(parseInt(c,10)),!0;var d=a.tagName.match(/H(\\d)/);return!d||(this.data(parseInt(d[1],10)),!0)},after:function(a,b){if(a.length<2)return a;for(var c=a[0].data,d=1;d<a.length;d++)a[d].result&&a[d].data>c+1&&(a[d].result=!1),c=a[d].data;return a}},{id:\"href-no-hash\",evaluate:function(a,b){return\"#\"!==a.getAttribute(\"href\")}},{id:\"internal-link-present\",evaluate:function(a,b){return!!a.querySelector('a[href^=\"#\"]')}},{id:\"landmark\",evaluate:function(a,b){return a.getElementsByTagName(\"main\").length>0||!!a.querySelector('[role=\"main\"]')}},{id:\"meta-refresh\",evaluate:function(a,b){var c=a.getAttribute(\"content\")||\"\",d=c.split(/[;,]/);return\"\"===c||\"0\"===d[0]}},{id:\"p-as-heading\",evaluate:function(a,b){function c(a){for(var b=a,c=a.textContent.trim(),d=c;d===c&&void 0!==b;){var e=-1;if(a=b,0===a.children.length)return a;do{e++,d=a.children[e].textContent.trim()}while(\"\"===d&&e+1<a.children.length);b=a.children[e]}return a}function d(a){switch(a){case\"lighter\":return 100;case\"normal\":return 400;case\"bold\":return 700;case\"bolder\":return 900}return a=parseInt(a),isNaN(a)?400:a}function e(a){var b=window.getComputedStyle(c(a));return{fontWeight:d(b.getPropertyValue(\"font-weight\")),fontSize:parseInt(b.getPropertyValue(\"font-size\")),isItalic:\"italic\"===b.getPropertyValue(\"font-style\")}}function f(a,b,c){return c.reduce(function(c,d){return c||(!d.size||a.fontSize/d.size>b.fontSize)&&(!d.weight||a.fontWeight-d.weight>b.fontWeight)&&(!d.italic||a.isItalic&&!b.isItalic)},!1)}var g=Array.from(a.parentNode.children),h=g.indexOf(a);b=b||{};var i=b.margins||[],j=g.slice(h+1).find(function(a){return\"P\"===a.nodeName.toUpperCase()}),k=g.slice(0,h).reverse().find(function(a){return\"P\"===a.nodeName.toUpperCase()}),l=e(a),m=j?e(j):null,n=k?e(k):null;if(!m||!f(l,m,i))return!0;var o=axe.commons.dom.findUp(a,\"blockquote\");return!!(o&&\"BLOCKQUOTE\"===o.nodeName.toUpperCase()||n&&!f(l,n,i))&&void 0},options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}]}},{id:\"region\",evaluate:function(a,b){function c(a){return h&&axe.commons.dom.getElementByReference(h,\"href\")&&h===a}function d(a){return a.hasAttribute(\"role\")?g.includes(a.getAttribute(\"role\").toLowerCase()):i.some(function(b){return axe.utils.matchesSelector(a,b)})}function e(a){return d(a)?null:c(a)?f(a):axe.commons.dom.isVisible(a,!0)&&(axe.commons.text.visible(a,!0,!0)||axe.commons.dom.isVisualContent(a))?a:f(a)}function f(a){var b=axe.commons.utils.toArray(a.children);return 0===b.length?[]:b.map(e).filter(function(a){return null!==a}).reduce(function(a,b){return a.concat(b)},[])}var g=axe.commons.aria.getRolesByType(\"landmark\"),h=a.querySelector(\"a[href]\"),i=g.reduce(function(a,b){return a.concat(axe.commons.aria.implicitNodes(b))},[]).filter(function(a){return null!==a}),j=f(a);return this.relatedNodes(j),!j.length},after:function(a,b){return[a[0]]}},{id:\"skip-link\",evaluate:function(a,b){var c=axe.commons.dom.getElementByReference(a,\"href\");return!!c&&axe.commons.dom.isFocusable(c)},after:function(a,b){return[a[0]]}},{id:\"unique-frame-title\",evaluate:function(a,b){var c=axe.commons.text.sanitize(a.title).trim().toLowerCase();return this.data(c),!0},after:function(a,b){var c={};return a.forEach(function(a){c[a.data]=void 0!==c[a.data]?++c[a.data]:0}),a.forEach(function(a){a.result=!!c[a.data]}),a}},{id:\"aria-label\",evaluate:function(a,b){var c=a.getAttribute(\"aria-label\");return!!(c?axe.commons.text.sanitize(c).trim():\"\")}},{id:\"aria-labelledby\",evaluate:function(a,b){return(0,axe.commons.dom.idrefs)(a,\"aria-labelledby\").some(function(a){return a&&axe.commons.text.accessibleText(a,!0)})}},{id:\"button-has-visible-text\",evaluate:function(a,b){var c=a.nodeName.toUpperCase(),d=a.getAttribute(\"role\"),e=void 0;return(\"BUTTON\"===c||\"button\"===d&&\"INPUT\"!==c)&&(e=axe.commons.text.accessibleText(a),this.data(e),!!e)}},{id:\"doc-has-title\",evaluate:function(a,b){var c=document.title;return!!(c?axe.commons.text.sanitize(c).trim():\"\")}},{id:\"duplicate-id\",evaluate:function(a,b){if(!a.getAttribute(\"id\").trim())return!0;for(var c=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),d=document.querySelectorAll('[id=\"'+c+'\"]'),e=[],f=0;f<d.length;f++)d[f]!==a&&e.push(d[f]);return e.length&&this.relatedNodes(e),this.data(a.getAttribute(\"id\")),d.length<=1},after:function(a,b){var c=[];return a.filter(function(a){return-1===c.indexOf(a.data)&&(c.push(a.data),!0)})}},{id:\"exists\",evaluate:function(a,b){return!0}},{id:\"has-alt\",evaluate:function(a,b){var c=a.nodeName.toLowerCase();return a.hasAttribute(\"alt\")&&(\"img\"===c||\"input\"===c||\"area\"===c)}},{id:\"has-visible-text\",evaluate:function(a,b){return axe.commons.text.accessibleText(a).length>0}},{id:\"is-on-screen\",evaluate:function(a,b){return axe.commons.dom.isVisible(a,!1)&&!axe.commons.dom.isOffscreen(a)}},{id:\"non-empty-alt\",evaluate:function(a,b){var c=a.getAttribute(\"alt\");return!!(c?axe.commons.text.sanitize(c).trim():\"\")}},{id:\"non-empty-if-present\",evaluate:function(a,b){var c=a.nodeName.toUpperCase(),d=(a.getAttribute(\"type\")||\"\").toLowerCase(),e=a.getAttribute(\"value\");return this.data(e),\"INPUT\"===c&&-1!==[\"submit\",\"reset\"].indexOf(d)&&null===e}},{id:\"non-empty-title\",evaluate:function(a,b){var c=a.getAttribute(\"title\");return!!(c?axe.commons.text.sanitize(c).trim():\"\")}},{id:\"non-empty-value\",evaluate:function(a,b){var c=a.getAttribute(\"value\");return!!(c?axe.commons.text.sanitize(c).trim():\"\")}},{id:\"role-none\",evaluate:function(a,b){return\"none\"===a.getAttribute(\"role\")}},{id:\"role-presentation\",evaluate:function(a,b){return\"presentation\"===a.getAttribute(\"role\")}},{id:\"caption-faked\",evaluate:function(a,b){var c=axe.commons.table.toGrid(a),d=c[0];return c.length<=1||d.length<=1||a.rows.length<=1||d.reduce(function(a,b,c){return a||b!==d[c+1]&&void 0!==d[c+1]},!1)}},{id:\"has-caption\",evaluate:function(a,b){return!!a.caption}},{id:\"has-summary\",evaluate:function(a,b){return!!a.summary}},{id:\"has-th\",evaluate:function(a,b){for(var c,d,e=[],f=0,g=a.rows.length;f<g;f++){c=a.rows[f];for(var h=0,i=c.cells.length;h<i;h++)d=c.cells[h],\"TH\"!==d.nodeName.toUpperCase()&&-1===[\"rowheader\",\"columnheader\"].indexOf(d.getAttribute(\"role\"))||e.push(d)}return!!e.length&&(this.relatedNodes(e),!0)}},{id:\"html5-scope\",evaluate:function(a,b){return!axe.commons.dom.isHTML5(document)||\"TH\"===a.nodeName.toUpperCase()}},{id:\"same-caption-summary\",evaluate:function(a,b){return!(!a.summary||!a.caption)&&a.summary===axe.commons.text.accessibleText(a.caption)}},{id:\"scope-value\",evaluate:function(a,b){b=b||{};var c=a.getAttribute(\"scope\").toLowerCase();return-1!==([\"row\",\"col\",\"rowgroup\",\"colgroup\"]||b.values).indexOf(c)}},{id:\"td-has-header\",evaluate:function(a,b){var c=axe.commons.table,d=[];return c.getAllCells(a).forEach(function(a){if(axe.commons.dom.hasContent(a)&&c.isDataCell(a)&&!axe.commons.aria.label(a)){var b=c.getHeaders(a);(b=b.reduce(function(a,b){return a||null!==b&&!!axe.commons.dom.hasContent(b)},!1))||d.push(a)}}),!d.length||(this.relatedNodes(d),!1)}},{id:\"td-headers-attr\",evaluate:function(a,b){for(var c=[],d=0,e=a.rows.length;d<e;d++)for(var f=a.rows[d],g=0,h=f.cells.length;g<h;g++)c.push(f.cells[g]);var i=c.reduce(function(a,b){return b.getAttribute(\"id\")&&a.push(b.getAttribute(\"id\")),a},[]),j=c.reduce(function(a,b){var c,d,e=(b.getAttribute(\"headers\")||\"\").split(/\\s/).reduce(function(a,b){return b=b.trim(),b&&a.push(b),a},[]);return 0!==e.length&&(b.getAttribute(\"id\")&&(c=-1!==e.indexOf(b.getAttribute(\"id\").trim())),d=e.reduce(function(a,b){return a||-1===i.indexOf(b)},!1),(c||d)&&a.push(b)),a},[]);return!(j.length>0)||(this.relatedNodes(j),!1)}},{id:\"th-has-data-cells\",evaluate:function(a,b){var c=axe.commons.table,d=c.getAllCells(a),e=this,f=[];d.forEach(function(a){var b=a.getAttribute(\"headers\");b&&(f=f.concat(b.split(/\\s+/)));var c=a.getAttribute(\"aria-labelledby\");c&&(f=f.concat(c.split(/\\s+/)))});var g=d.filter(function(a){return\"\"!==axe.commons.text.sanitize(a.textContent)&&(\"TH\"===a.nodeName.toUpperCase()||-1!==[\"rowheader\",\"columnheader\"].indexOf(a.getAttribute(\"role\")))}),h=c.toGrid(a);return!!g.reduce(function(a,b){if(b.getAttribute(\"id\")&&f.includes(b.getAttribute(\"id\")))return!!a||a;var d=!1,g=c.getCellPosition(b,h);return c.isColumnHeader(b)&&(d=c.traverse(\"down\",g,h).reduce(function(a,b){return a||axe.commons.dom.hasContent(b)&&!c.isColumnHeader(b)},!1)),!d&&c.isRowHeader(b)&&(d=c.traverse(\"right\",g,h).reduce(function(a,b){return a||axe.commons.dom.hasContent(b)&&!c.isRowHeader(b)},!1)),d||e.relatedNodes(b),a&&d},!0)||void 0}},{id:\"hidden-content\",evaluate:function(a,b){var c=window.getComputedStyle(a);if(![\"SCRIPT\",\"HEAD\",\"TITLE\",\"NOSCRIPT\",\"STYLE\",\"TEMPLATE\"].includes(a.tagName.toUpperCase())&&axe.commons.dom.hasContent(a)){if(\"none\"===c.getPropertyValue(\"display\"))return;if(\"hidden\"===c.getPropertyValue(\"visibility\")){if(a.parentNode)var d=window.getComputedStyle(a.parentNode);if(!d||\"hidden\"!==d.getPropertyValue(\"visibility\"))return}}return!0}}],commons:function(){function a(a){return a.getPropertyValue(\"font-family\").split(/[,;]/g).map(function(a){return a.trim().toLowerCase()})}function b(b,c){var d=window.getComputedStyle(b);if(\"none\"!==d.getPropertyValue(\"background-image\"))return!0;if([\"border-bottom\",\"border-top\",\"outline\"].reduce(function(a,b){var c=new y.Color;return c.parseRgbString(d.getPropertyValue(b+\"-color\")),a||\"none\"!==d.getPropertyValue(b+\"-style\")&&parseFloat(d.getPropertyValue(b+\"-width\"))>0&&0!==c.alpha},!1))return!0;var e=window.getComputedStyle(c);if(a(d)[0]!==a(e)[0])return!0;var f=[\"text-decoration-line\",\"text-decoration-style\",\"font-weight\",\"font-style\",\"font-size\"].reduce(function(a,b){return a||d.getPropertyValue(b)!==e.getPropertyValue(b)},!1),g=d.getPropertyValue(\"text-decoration\");return g.split(\" \").length<3&&(f=f||g!==e.getPropertyValue(\"text-decoration\")),f}function c(a,b){var c=a.nodeName.toUpperCase();if(C.includes(c))return axe.commons.color.incompleteData.set(\"bgColor\",\"imgNode\"),!0;b=b||window.getComputedStyle(a);var d=b.getPropertyValue(\"background-image\"),e=\"none\"!==d;if(e){var f=/gradient/.test(d);axe.commons.color.incompleteData.set(\"bgColor\",f?\"bgGradient\":\"bgImage\")}return e}function d(a,b){b=b||window.getComputedStyle(a);var c=new y.Color;if(c.parseRgbString(b.getPropertyValue(\"background-color\")),0!==c.alpha){var d=b.getPropertyValue(\"opacity\");c.alpha=c.alpha*d}return c}function e(a,b){var c=a.getClientRects()[0],d=document.elementsFromPoint(c.left,c.top);if(d)for(var e=0;e<d.length;e++)if(d[e]!==a&&d[e]===b)return!0;return!1}function f(a,b,c){var f=0;if(a>0)for(var g=a-1;g>=0;g--){var h=b[g],i=window.getComputedStyle(h),j=d(h,i);j.alpha&&e(c,h)?f+=j.alpha:b.splice(g,1)}return f}function g(a,b,c){var d=a!==b&&!z.visuallyContains(a,b)&&0!==c.alpha;return d&&axe.commons.color.incompleteData.set(\"bgColor\",\"elmPartiallyObscured\"),d}function h(a,b){var c={TD:[\"TR\",\"TBODY\"],TH:[\"TR\",\"THEAD\"],INPUT:[\"LABEL\"]},d=a.map(function(a){return a.tagName}),e=a;for(var f in c)if(d.includes(f))for(var g in c[f])if(f.hasOwnProperty(g)){var h=axe.commons.dom.findUp(b,c[f][g]);if(h&&-1===a.indexOf(h)){var i=axe.commons.dom.visuallyOverlaps(b.getBoundingClientRect(),h);i&&e.splice(d.indexOf(f)+1,0,h)}b.tagName===c[f][g]&&-1===d.indexOf(b.tagName)&&e.splice(d.indexOf(f)+1,0,b)}return e}function i(a){var b=a.indexOf(document.body),e=a;return b>1&&!c(document.documentElement)&&0===d(document.documentElement).alpha&&(e.splice(b,1),e.splice(a.indexOf(document.documentElement),1),e.push(document.body)),e}function j(a,b){\"use strict\";var c=b(a);for(a=a.firstChild;a;)!1!==c&&j(a,b),a=a.nextSibling}function k(a){\"use strict\";var b=window.getComputedStyle(a).getPropertyValue(\"display\");return-1!==D.indexOf(b)||\"table-\"===b.substr(0,6)}function l(a){\"use strict\";var b=a.match(/rect\\s*\\(([0-9]+)px,?\\s*([0-9]+)px,?\\s*([0-9]+)px,?\\s*([0-9]+)px\\s*\\)/);return!(!b||5!==b.length)&&(b[3]-b[1]<=0&&b[2]-b[4]<=0)}function m(a){var b=null;if(a.getAttribute(\"id\")){var c=axe.utils.escapeSelector(a.getAttribute(\"id\"));if(b=document.querySelector('label[for=\"'+c+'\"]'))return b}return b=z.findUp(a,\"label\")}function n(a){return-1!==[\"button\",\"reset\",\"submit\"].indexOf(a.type)}function o(a){var b=a.nodeName.toUpperCase();return\"TEXTAREA\"===b||\"SELECT\"===b||\"INPUT\"===b&&\"hidden\"!==a.type.toLowerCase()}function p(a){return-1!==[\"BUTTON\",\"SUMMARY\",\"A\"].indexOf(a.nodeName.toUpperCase())}function q(a){return-1!==[\"TABLE\",\"FIGURE\"].indexOf(a.nodeName.toUpperCase())}function r(a){var b=a.nodeName.toUpperCase();if(\"INPUT\"===b)return!a.hasAttribute(\"type\")||-1!==G.indexOf(a.getAttribute(\"type\").toLowerCase())&&a.value?a.value:\"\";if(\"SELECT\"===b){var c=a.options;if(c&&c.length){for(var d=\"\",e=0;e<c.length;e++)c[e].selected&&(d+=\" \"+c[e].text);return B.sanitize(d)}return\"\"}return\"TEXTAREA\"===b&&a.value?a.value:\"\"}function s(a,b){var c=a.querySelector(b.toLowerCase());return c?B.accessibleText(c):\"\"}function t(a){if(!a)return!1;switch(a.nodeName.toUpperCase()){case\"SELECT\":case\"TEXTAREA\":return!0;case\"INPUT\":return!a.hasAttribute(\"type\")||-1!==G.indexOf(a.getAttribute(\"type\").toLowerCase());default:return!1}}function u(a){var b=a.nodeName.toUpperCase();return\"INPUT\"===b&&\"image\"===a.type.toLowerCase()||-1!==[\"IMG\",\"APPLET\",\"AREA\"].indexOf(b)}function v(a){return!!B.sanitize(a)}var commons={},w=commons.aria={},x=w.lookupTable={};x.attributes={\"aria-activedescendant\":{type:\"idref\"},\"aria-atomic\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-autocomplete\":{type:\"nmtoken\",values:[\"inline\",\"list\",\"both\",\"none\"]},\"aria-busy\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-checked\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"]},\"aria-colcount\":{type:\"int\"},\"aria-colindex\":{type:\"int\"},\"aria-colspan\":{type:\"int\"},\"aria-controls\":{type:\"idrefs\"},\"aria-current\":{type:\"nmtoken\",values:[\"page\",\"step\",\"location\",\"date\",\"time\",\"true\",\"false\"]},\"aria-describedby\":{type:\"idrefs\"},\"aria-disabled\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-dropeffect\":{type:\"nmtokens\",values:[\"copy\",\"move\",\"reference\",\"execute\",\"popup\",\"none\"]},\"aria-errormessage\":{type:\"idref\"},\"aria-expanded\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-flowto\":{type:\"idrefs\"},\"aria-grabbed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-haspopup\":{type:\"nmtoken\",values:[\"true\",\"false\",\"menu\",\"listbox\",\"tree\",\"grid\",\"dialog\"]},\"aria-hidden\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-invalid\":{type:\"nmtoken\",values:[\"true\",\"false\",\"spelling\",\"grammar\"]},\"aria-keyshortcuts\":{type:\"string\"},\"aria-label\":{type:\"string\"},\"aria-labelledby\":{type:\"idrefs\"},\"aria-level\":{type:\"int\"},\"aria-live\":{type:\"nmtoken\",values:[\"off\",\"polite\",\"assertive\"]},\"aria-modal\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-multiline\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-multiselectable\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-orientation\":{type:\"nmtoken\",values:[\"horizontal\",\"vertical\"]},\"aria-owns\":{type:\"idrefs\"},\"aria-placeholder\":{type:\"string\"},\"aria-posinset\":{type:\"int\"},\"aria-pressed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"]},\"aria-readonly\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-relevant\":{type:\"nmtokens\",values:[\"additions\",\"removals\",\"text\",\"all\"]},\"aria-required\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-rowcount\":{type:\"int\"},\"aria-rowindex\":{type:\"int\"},\"aria-rowspan\":{type:\"int\"},\"aria-selected\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-setsize\":{type:\"int\"},\"aria-sort\":{type:\"nmtoken\",values:[\"ascending\",\"descending\",\"other\",\"none\"]},\"aria-valuemax\":{type:\"decimal\"},\"aria-valuemin\":{type:\"decimal\"},\"aria-valuenow\":{type:\"decimal\"},\"aria-valuetext\":{type:\"string\"}},x.globalAttributes=[\"aria-atomic\",\"aria-busy\",\"aria-controls\",\"aria-current\",\"aria-describedby\",\"aria-disabled\",\"aria-dropeffect\",\"aria-flowto\",\"aria-grabbed\",\"aria-haspopup\",\"aria-hidden\",\"aria-invalid\",\"aria-keyshortcuts\",\"aria-label\",\"aria-labelledby\",\"aria-live\",\"aria-owns\",\"aria-relevant\"],x.role={alert:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},alertdialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\"]},owned:null,nameFrom:[\"author\"],context:null},application:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},article:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"article\"]},banner:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"header\"]},button:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-pressed\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"button\",'input[type=\"button\"]','input[type=\"image\"]','input[type=\"reset\"]','input[type=\"submit\"]',\"summary\"]},cell:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-rowindex\",\"aria-rowspan\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"]},checkbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"checkbox\"]']},columnheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"]},combobox:{type:\"composite\",attributes:{allowed:[\"aria-expanded\",\"aria-autocomplete\",\"aria-required\",\"aria-activedescendant\",\"aria-orientation\"]},owned:{all:[\"listbox\",\"textbox\"]},nameFrom:[\"author\"],context:null},command:{nameFrom:[\"author\"],type:\"abstract\"},complementary:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"aside\"]},composite:{nameFrom:[\"author\"],type:\"abstract\"},contentinfo:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"footer\"]},definition:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dd\",\"dfn\"]},dialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dialog\"]},directory:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},document:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"body\"]},feed:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:{one:[\"article\"]},nameFrom:[\"author\"],context:null},form:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"form\"]},grid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-colcount\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-rowcount\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"]},gridcell:{type:\"widget\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-selected\",\"aria-readonly\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"]},group:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"details\",\"optgroup\"]},heading:{type:\"structure\",attributes:{allowed:[\"aria-level\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"]},img:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"img\"]},input:{nameFrom:[\"author\"],type:\"abstract\"},landmark:{nameFrom:[\"author\"],type:\"abstract\"},link:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"a[href]\"]},list:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:{all:[\"listitem\"]},nameFrom:[\"author\"],context:null,implicit:[\"ol\",\"ul\",\"dl\"]},listbox:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\"]},owned:{all:[\"option\"]},nameFrom:[\"author\"],context:null,implicit:[\"select\"]},listitem:{type:\"structure\",attributes:{allowed:[\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"list\"],implicit:[\"li\",\"dt\"]},log:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},main:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"main\"]},marquee:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},math:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"math\"]},menu:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"]},owned:{one:[\"menuitem\",\"menuitemradio\",\"menuitemcheckbox\"]},nameFrom:[\"author\"],context:null,implicit:['menu[type=\"context\"]']},menubar:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null},menuitem:{type:\"widget\",attributes:{allowed:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"command\"]']},menuitemcheckbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"checkbox\"]']},menuitemradio:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"radio\"]']},navigation:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"nav\"]},none:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null},note:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},option:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"listbox\"],implicit:[\"option\"]},presentation:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null},progressbar:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],\ncontext:null,implicit:[\"progress\"]},radio:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"radio\"]']},radiogroup:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-required\",\"aria-expanded\"]},owned:{all:[\"radio\"]},nameFrom:[\"author\"],context:null},range:{nameFrom:[\"author\"],type:\"abstract\"},region:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"section[aria-label]\",\"section[aria-labelledby]\",\"section[title]\"]},roletype:{type:\"abstract\"},row:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colindex\",\"aria-expanded\",\"aria-level\",\"aria-selected\",\"aria-rowindex\"]},owned:{one:[\"cell\",\"columnheader\",\"rowheader\",\"gridcell\"]},nameFrom:[\"author\",\"contents\"],context:[\"rowgroup\",\"grid\",\"treegrid\",\"table\"],implicit:[\"tr\"]},rowgroup:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:{all:[\"row\"]},nameFrom:[\"author\",\"contents\"],context:[\"grid\",\"table\"],implicit:[\"tbody\",\"thead\",\"tfoot\"]},rowheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"]},scrollbar:{type:\"widget\",attributes:{required:[\"aria-controls\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"],allowed:[\"aria-valuetext\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null},search:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},searchbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"search\"]']},section:{nameFrom:[\"author\",\"contents\"],type:\"abstract\"},sectionhead:{nameFrom:[\"author\",\"contents\"],type:\"abstract\"},select:{nameFrom:[\"author\"],type:\"abstract\"},separator:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"hr\"]},slider:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-orientation\"],required:[\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"range\"]']},spinbutton:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-required\"],required:[\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"number\"]']},status:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"output\"]},structure:{type:\"abstract\"},switch:{type:\"widget\",attributes:{required:[\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},tab:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-expanded\",\"aria-setsize\",\"aria-posinset\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"tablist\"]},table:{type:\"structure\",attributes:{allowed:[\"aria-colcount\",\"aria-rowcount\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"]},tablist:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-orientation\"]},owned:{all:[\"tab\"]},nameFrom:[\"author\"],context:null},tabpanel:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},term:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"dt\"]},text:{type:\"structure\",owned:null,nameFrom:[\"author\",\"contents\"],context:null},textbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"text\"]','input[type=\"email\"]','input[type=\"password\"]','input[type=\"tel\"]','input[type=\"url\"]',\"input:not([type])\",\"textarea\"]},timer:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},toolbar:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['menu[type=\"toolbar\"]']},tooltip:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},tree:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\"]},owned:{all:[\"treeitem\"]},nameFrom:[\"author\"],context:null},treegrid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colcount\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-required\",\"aria-rowcount\",\"aria-orientation\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null},treeitem:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"group\",\"tree\"]},widget:{type:\"abstract\"},window:{nameFrom:[\"author\"],type:\"abstract\"}};var y={};commons.color=y;var z=commons.dom={},A=commons.table={},B=commons.text={};commons.utils=axe.utils;w.requiredAttr=function(a){\"use strict\";var b=w.lookupTable.role[a];return b&&b.attributes&&b.attributes.required||[]},w.allowedAttr=function(a){\"use strict\";var b=w.lookupTable.role[a],c=b&&b.attributes&&b.attributes.allowed||[],d=b&&b.attributes&&b.attributes.required||[];return c.concat(w.lookupTable.globalAttributes).concat(d)},w.validateAttr=function(a){\"use strict\";return!!w.lookupTable.attributes[a]},w.validateAttrValue=function(a,b){\"use strict\";var c,d,e=document,f=a.getAttribute(b),g=w.lookupTable.attributes[b];if(!g)return!0;switch(g.type){case\"boolean\":case\"nmtoken\":return\"string\"==typeof f&&-1!==g.values.indexOf(f.toLowerCase());case\"nmtokens\":return d=axe.utils.tokenList(f),d.reduce(function(a,b){return a&&-1!==g.values.indexOf(b)},0!==d.length);case\"idref\":return!(!f||!e.getElementById(f));case\"idrefs\":return d=axe.utils.tokenList(f),d.reduce(function(a,b){return!(!a||!e.getElementById(b))},0!==d.length);case\"string\":return!0;case\"decimal\":return!(!(c=f.match(/^[-+]?([0-9]*)\\.?([0-9]*)$/))||!c[1]&&!c[2]);case\"int\":return/^[-+]?[0-9]+$/.test(f)}},w.label=function(a){var b,c;return a.getAttribute(\"aria-labelledby\")&&(b=z.idrefs(a,\"aria-labelledby\"),c=b.map(function(a){return a?B.visible(a,!0):\"\"}).join(\" \").trim())?c:(c=a.getAttribute(\"aria-label\"),c&&(c=B.sanitize(c).trim())?c:null)},w.isValidRole=function(a){\"use strict\";return!!w.lookupTable.role[a]},w.getRolesWithNameFromContents=function(){return Object.keys(w.lookupTable.role).filter(function(a){return w.lookupTable.role[a].nameFrom&&-1!==w.lookupTable.role[a].nameFrom.indexOf(\"contents\")})},w.getRolesByType=function(a){return Object.keys(w.lookupTable.role).filter(function(b){return w.lookupTable.role[b].type===a})},w.getRoleType=function(a){var b=w.lookupTable.role[a];return b&&b.type||null},w.requiredOwned=function(a){\"use strict\";var b=null,c=w.lookupTable.role[a];return c&&(b=axe.utils.clone(c.owned)),b},w.requiredContext=function(a){\"use strict\";var b=null,c=w.lookupTable.role[a];return c&&(b=axe.utils.clone(c.context)),b},w.implicitNodes=function(a){\"use strict\";var b=null,c=w.lookupTable.role[a];return c&&c.implicit&&(b=axe.utils.clone(c.implicit)),b},w.implicitRole=function(a){\"use strict\";var b=function(b,c){var d=function(b){return axe.utils.matchesSelector(a,b)};return c.implicit&&c.implicit.some(d)&&b.push(c.name),b},c=Object.keys(w.lookupTable.role).map(function(a){var b=w.lookupTable.role[a];return{name:a,implicit:b&&b.implicit}}),d=c.reduce(b,[]);if(!d.length)return null;for(var e=a.attributes,f=[],g=0,h=e.length;g<h;g++){var i=e[g];i.name.match(/^aria-/)&&f.push(i.name)}return function(a,b){var c=function(a){return w.allowedAttr(a).reduce(function(a,c){return a+(b.indexOf(c)>-1?1:0)},0)};return a.map(function(a){return{score:c(a),name:a}}).sort(function(a,b){return b.score-a.score}).map(function(a){return a.name})}(d,f).shift()},y.Color=function(a,b,c,d){this.red=a,this.green=b,this.blue=c,this.alpha=d,this.toHexString=function(){var a=Math.round(this.red).toString(16),b=Math.round(this.green).toString(16),c=Math.round(this.blue).toString(16);return\"#\"+(this.red>15.5?a:\"0\"+a)+(this.green>15.5?b:\"0\"+b)+(this.blue>15.5?c:\"0\"+c)};var e=/^rgb\\((\\d+), (\\d+), (\\d+)\\)$/,f=/^rgba\\((\\d+), (\\d+), (\\d+), (\\d*(\\.\\d+)?)\\)/;this.parseRgbString=function(a){if(\"transparent\"===a)return this.red=0,this.green=0,this.blue=0,void(this.alpha=0);var b=a.match(e);return b?(this.red=parseInt(b[1],10),this.green=parseInt(b[2],10),this.blue=parseInt(b[3],10),void(this.alpha=1)):(b=a.match(f),b?(this.red=parseInt(b[1],10),this.green=parseInt(b[2],10),this.blue=parseInt(b[3],10),void(this.alpha=parseFloat(b[4]))):void 0)},this.getRelativeLuminance=function(){var a=this.red/255,b=this.green/255,c=this.blue/255;return.2126*(a<=.03928?a/12.92:Math.pow((a+.055)/1.055,2.4))+.7152*(b<=.03928?b/12.92:Math.pow((b+.055)/1.055,2.4))+.0722*(c<=.03928?c/12.92:Math.pow((c+.055)/1.055,2.4))}},y.flattenColors=function(a,b){var c=a.alpha,d=(1-c)*b.red+c*a.red,e=(1-c)*b.green+c*a.green,f=(1-c)*b.blue+c*a.blue,g=a.alpha+b.alpha*(1-a.alpha);return new y.Color(d,e,f,g)},y.getContrast=function(a,b){if(!b||!a)return null;b.alpha<1&&(b=y.flattenColors(b,a));var c=a.getRelativeLuminance(),d=b.getRelativeLuminance();return(Math.max(d,c)+.05)/(Math.min(d,c)+.05)},y.hasValidContrastRatio=function(a,b,c,d){var e=y.getContrast(a,b),f=d&&Math.ceil(72*c)/96<14||!d&&Math.ceil(72*c)/96<18,g=f?4.5:3;return{isValid:e>g,contrastRatio:e,expectedContrastRatio:g}},y.elementIsDistinct=b;var C=[\"IMG\",\"CANVAS\",\"OBJECT\",\"IFRAME\",\"VIDEO\",\"SVG\"];y.getCoords=function(a){var b=void 0,c=void 0;if(!(a.left>window.innerWidth||a.top>window.innerHeight))return b=Math.min(Math.ceil(a.left+a.width/2),window.innerWidth-1),c=Math.min(Math.ceil(a.top+a.height/2),window.innerHeight-1),{x:b,y:c}},y.getRectStack=function(a){var b=y.getCoords(a.getBoundingClientRect());if(b){var c=Array.from(a.getClientRects()),d=Array.from(document.elementsFromPoint(b.x,b.y));if(c&&c.length>1){var e=c.filter(function(a){return a.width&&a.width>0}).map(function(a){var b=y.getCoords(a);if(b)return Array.from(document.elementsFromPoint(b.x,b.y))});return e.splice(0,0,d),e}return[d]}return null},y.filteredRectStack=function(a){var b=y.getRectStack(a);if(b&&1===b.length)return b[0];if(b&&b.length>1){var c=b.shift(),d=void 0;return b.forEach(function(e,f){if(0!==f){var g=b[f-1],h=b[f];d=g.every(function(a,b){return a===h[b]})||c.includes(a)}}),d?b[0]:(axe.commons.color.incompleteData.set(\"bgColor\",\"elmPartiallyObscuring\"),null)}return axe.commons.color.incompleteData.set(\"bgColor\",\"outsideViewport\"),null},y.getBackgroundStack=function(a){var b=y.filteredRectStack(a);if(null===b)return null;b=h(b,a),b=z.reduceToElementsBelowFloating(b,a),b=i(b);var c=b.indexOf(a);return f(c,b,a)>=.99?(axe.commons.color.incompleteData.set(\"bgColor\",\"bgOverlap\"),null):-1!==c?b:null},y.getBackgroundColor=function(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];if(!0!==(arguments.length>2&&void 0!==arguments[2]&&arguments[2])){var e=a.clientHeight-2>=2*window.innerHeight;a.scrollIntoView(e)}var f=[],h=y.getBackgroundStack(a);if((h||[]).some(function(e){var h=window.getComputedStyle(e),i=d(e,h);return g(a,e,i)||c(e,h)?(f=null,b.push(e),!0):0!==i.alpha&&(b.push(e),f.push(i),1===i.alpha)}),null!==f&&null!==h){f.push(new y.Color(255,255,255,1));return f.reduce(y.flattenColors)}return null},z.isOpaque=function(a){var b=window.getComputedStyle(a);return c(a,b)||1===d(a,b).alpha},y.getForegroundColor=function(a,b){var c=window.getComputedStyle(a),d=new y.Color;d.parseRgbString(c.getPropertyValue(\"color\"));var e=c.getPropertyValue(\"opacity\");if(d.alpha=d.alpha*e,1===d.alpha)return d;var f=y.getBackgroundColor(a,[],b);if(null===f){var g=axe.commons.color.incompleteData.get(\"bgColor\");return axe.commons.color.incompleteData.set(\"fgColor\",g),null}return y.flattenColors(d,f)},y.incompleteData=function(){var a={};return{set:function(b,c){if(\"string\"!=typeof b)throw new Error(\"Incomplete data: key must be a string\");return c&&(a[b]=c),a[b]},get:function(b){return a[b]},clear:function(){a={}}}}(),z.reduceToElementsBelowFloating=function(a,b){var c,d,e,f=[\"fixed\",\"sticky\"],g=[],h=!1;for(c=0;c<a.length;++c)d=a[c],d===b&&(h=!0),e=window.getComputedStyle(d),h||-1===f.indexOf(e.position)?g.push(d):g=[];return g},z.findUp=function(a,b){\"use strict\";var c,d=document.querySelectorAll(b);if(!d.length)return null;for(d=axe.utils.toArray(d),c=a.parentNode;c&&-1===d.indexOf(c);)c=c.parentNode;return c},z.getElementByReference=function(a,b){\"use strict\";var c,d=a.getAttribute(b),e=document;if(d&&\"#\"===d.charAt(0)){if(d=d.substring(1),c=e.getElementById(d))return c;if(c=e.getElementsByName(d),c.length)return c[0]}return null},z.getElementCoordinates=function(a){\"use strict\";var b=z.getScrollOffset(document),c=b.left,d=b.top,e=a.getBoundingClientRect();return{top:e.top+d,right:e.right+c,bottom:e.bottom+d,left:e.left+c,width:e.right-e.left,height:e.bottom-e.top}},z.getScrollOffset=function(a){\"use strict\";if(!a.nodeType&&a.document&&(a=a.document),9===a.nodeType){var b=a.documentElement,c=a.body;return{left:b&&b.scrollLeft||c&&c.scrollLeft||0,top:b&&b.scrollTop||c&&c.scrollTop||0}}return{left:a.scrollLeft,top:a.scrollTop}},z.getViewportSize=function(a){\"use strict\";var b,c=a.document,d=c.documentElement;return a.innerWidth?{width:a.innerWidth,height:a.innerHeight}:d?{width:d.clientWidth,height:d.clientHeight}:(b=c.body,{width:b.clientWidth,height:b.clientHeight})},z.hasContent=function(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];if(a.textContent.trim()||w.label(a))return!0;for(var c=a.querySelectorAll(\"*\"),d=0;d<c.length;d++)if(-1===b.indexOf(c[d])&&w.label(c[d])||z.isVisualContent(c[d]))return!0;return!1},z.idrefs=function(a,b){\"use strict\";var c,d,e=document,f=[],g=a.getAttribute(b);if(g)for(g=axe.utils.tokenList(g),c=0,d=g.length;c<d;c++)f.push(e.getElementById(g[c]));return f},z.isFocusable=function(a){\"use strict\";if(z.isNativelyFocusable(a))return!0;var b=a.getAttribute(\"tabindex\");return!(!b||isNaN(parseInt(b,10)))},z.isNativelyFocusable=function(a){\"use strict\";if(!a||a.disabled||!z.isVisible(a)&&\"AREA\"!==a.nodeName.toUpperCase())return!1;switch(a.nodeName.toUpperCase()){case\"A\":case\"AREA\":if(a.href)return!0;break;case\"INPUT\":return\"hidden\"!==a.type;case\"TEXTAREA\":case\"SELECT\":case\"DETAILS\":case\"BUTTON\":return!0}return!1},z.isHTML5=function(a){var b=a.doctype;return null!==b&&(\"html\"===b.name&&!b.publicId&&!b.systemId)};var D=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];z.isInTextBlock=function(a){\"use strict\";if(k(a))return!1;for(var b=a.parentNode;1===b.nodeType&&!k(b);)b=b.parentNode;var c=\"\",d=\"\",e=0;return j(b,function(b){if(2===e)return!1;if(3===b.nodeType&&(c+=b.nodeValue),1===b.nodeType){var f=(b.nodeName||\"\").toUpperCase();if(-1!==[\"BR\",\"HR\"].indexOf(f))0===e?(c=\"\",d=\"\"):e=2;else{if(\"none\"===b.style.display||\"hidden\"===b.style.overflow||-1===[\"\",null,\"none\"].indexOf(b.style.float)||-1===[\"\",null,\"relative\"].indexOf(b.style.position))return!1;if(\"A\"===f&&b.href||\"link\"===(b.getAttribute(\"role\")||\"\").toLowerCase())return b===a&&(e=1),d+=b.textContent,!1}}}),c=axe.commons.text.sanitize(c),d=axe.commons.text.sanitize(d),c.length>d.length},z.isNode=function(a){\"use strict\";return a instanceof Node},z.isOffscreen=function(a){\"use strict\";var b,c=document.documentElement,d=window.getComputedStyle(document.body||c).getPropertyValue(\"direction\"),e=z.getElementCoordinates(a);if(e.bottom<0&&function(a,b){for(a=a.parentNode;\"html\"!==a.nodeName.toLowerCase();){if(a.scrollTop&&(b+=a.scrollTop)>=0)return!1;a=a.parentNode}return!0}(a,e.bottom))return!0;if(0===e.left&&0===e.right)return!1;if(\"ltr\"===d){if(e.right<=0)return!0}else if(b=Math.max(c.scrollWidth,z.getViewportSize(window).width),e.left>=b)return!0;return!1},z.isVisible=function(a,b,c){\"use strict\";var d,e=a.nodeName.toUpperCase(),f=a.parentNode;return 9===a.nodeType||null!==(d=window.getComputedStyle(a,null))&&(!(\"none\"===d.getPropertyValue(\"display\")||\"STYLE\"===e.toUpperCase()||\"SCRIPT\"===e.toUpperCase()||!b&&l(d.getPropertyValue(\"clip\"))||!c&&(\"hidden\"===d.getPropertyValue(\"visibility\")||!b&&z.isOffscreen(a))||b&&\"true\"===a.getAttribute(\"aria-hidden\"))&&(!!f&&z.isVisible(f,b,!0)))};var E=[\"checkbox\",\"img\",\"radio\",\"range\",\"slider\",\"spinbutton\",\"textbox\"];z.isVisualContent=function(a){var b=a.getAttribute(\"role\");if(b)return-1!==E.indexOf(b);switch(a.tagName.toUpperCase()){case\"IMG\":case\"IFRAME\":case\"OBJECT\":case\"VIDEO\":case\"AUDIO\":case\"CANVAS\":case\"SVG\":case\"MATH\":case\"BUTTON\":case\"SELECT\":case\"TEXTAREA\":case\"KEYGEN\":case\"PROGRESS\":case\"METER\":return!0;case\"INPUT\":return\"hidden\"!==a.type;default:return!1}},z.visuallyContains=function(a,b){var c=a.getBoundingClientRect(),d={top:c.top+.01,bottom:c.bottom-.01,left:c.left+.01,right:c.right-.01},e=b.getBoundingClientRect(),f=e.top,g=e.left,h={top:f-b.scrollTop,bottom:f-b.scrollTop+b.scrollHeight,left:g-b.scrollLeft,right:g-b.scrollLeft+b.scrollWidth},i=window.getComputedStyle(b);return\"inline\"===i.getPropertyValue(\"display\")||!(d.left<h.left&&d.left<e.left||d.top<h.top&&d.top<e.top||d.right>h.right&&d.right>e.right||d.bottom>h.bottom&&d.bottom>e.bottom)&&(!(d.right>e.right||d.bottom>e.bottom)||(\"scroll\"===i.overflow||\"auto\"===i.overflow||\"hidden\"===i.overflow||b instanceof HTMLBodyElement||b instanceof HTMLHtmlElement))},z.visuallyOverlaps=function(a,b){var c=b.getBoundingClientRect(),d=c.top,e=c.left,f={top:d-b.scrollTop,bottom:d-b.scrollTop+b.scrollHeight,left:e-b.scrollLeft,right:e-b.scrollLeft+b.scrollWidth};if(a.left>f.right&&a.left>c.right||a.top>f.bottom&&a.top>c.bottom||a.right<f.left&&a.right<c.left||a.bottom<f.top&&a.bottom<c.top)return!1;var g=window.getComputedStyle(b);return!(a.left>c.right||a.top>c.bottom)||(\"scroll\"===g.overflow||\"auto\"===g.overflow||b instanceof HTMLBodyElement||b instanceof HTMLHtmlElement)},A.getAllCells=function(a){var b,c,d,e,f=[];for(b=0,d=a.rows.length;b<d;b++)for(c=0,e=a.rows[b].cells.length;c<e;c++)f.push(a.rows[b].cells[c]);return f},A.getCellPosition=function(a,b){var c,d;for(b||(b=A.toGrid(z.findUp(a,\"table\"))),c=0;c<b.length;c++)if(b[c]&&-1!==(d=b[c].indexOf(a)))return{x:d,y:c}},A.getHeaders=function(a){if(a.hasAttribute(\"headers\"))return commons.dom.idrefs(a,\"headers\");var b=commons.table.toGrid(commons.dom.findUp(a,\"table\")),c=commons.table.getCellPosition(a,b);return[].concat(A.traverse(\"left\",c,b).filter(function(a){return A.isRowHeader(a)}),A.traverse(\"up\",c,b).filter(function(a){return A.isColumnHeader(a)})).reverse()},A.getScope=function(a){var b=a.getAttribute(\"scope\"),c=a.getAttribute(\"role\");if(a instanceof Element==!1||-1===[\"TD\",\"TH\"].indexOf(a.nodeName.toUpperCase()))throw new TypeError(\"Expected TD or TH element\");if(\"columnheader\"===c)return\"col\";if(\"rowheader\"===c)return\"row\";if(\"col\"===b||\"row\"===b)return b;if(\"TH\"!==a.nodeName.toUpperCase())return!1;var d=A.toGrid(z.findUp(a,\"table\")),e=A.getCellPosition(a);return d[e.y].reduce(function(a,b){return a&&\"TH\"===b.nodeName.toUpperCase()},!0)?\"col\":d.map(function(a){return a[e.x]}).reduce(function(a,b){return a&&\"TH\"===b.nodeName.toUpperCase()},!0)?\"row\":\"auto\"},A.isColumnHeader=function(a){return-1!==[\"col\",\"auto\"].indexOf(A.getScope(a))},A.isDataCell=function(a){return!(!a.children.length&&!a.textContent.trim())&&\"TD\"===a.nodeName.toUpperCase()},A.isDataTable=function(a){var b=a.getAttribute(\"role\");if((\"presentation\"===b||\"none\"===b)&&!z.isFocusable(a))return!1;if(\"true\"===a.getAttribute(\"contenteditable\")||z.findUp(a,'[contenteditable=\"true\"]'))return!0;if(\"grid\"===b||\"treegrid\"===b||\"table\"===b)return!0;if(\"landmark\"===commons.aria.getRoleType(b))return!0;if(\"0\"===a.getAttribute(\"datatable\"))return!1;if(a.getAttribute(\"summary\"))return!0;if(a.tHead||a.tFoot||a.caption)return!0;for(var c=0,d=a.children.length;c<d;c++)if(\"COLGROUP\"===a.children[c].nodeName.toUpperCase())return!0;for(var e,f,g=0,h=a.rows.length,i=!1,j=0;j<h;j++){e=a.rows[j];for(var k=0,l=e.cells.length;k<l;k++){if(f=e.cells[k],\"TH\"===f.nodeName.toUpperCase())return!0;if(i||f.offsetWidth===f.clientWidth&&f.offsetHeight===f.clientHeight||(i=!0),f.getAttribute(\"scope\")||f.getAttribute(\"headers\")||f.getAttribute(\"abbr\"))return!0;if(-1!==[\"columnheader\",\"rowheader\"].indexOf(f.getAttribute(\"role\")))return!0;if(1===f.children.length&&\"ABBR\"===f.children[0].nodeName.toUpperCase())return!0;g++}}if(a.getElementsByTagName(\"table\").length)return!1;if(h<2)return!1;var m=a.rows[Math.ceil(h/2)];if(1===m.cells.length&&1===m.cells[0].colSpan)return!1;if(m.cells.length>=5)return!0;if(i)return!0;var n,o;for(j=0;j<h;j++){if(e=a.rows[j],n&&n!==window.getComputedStyle(e).getPropertyValue(\"background-color\"))return!0;if(n=window.getComputedStyle(e).getPropertyValue(\"background-color\"),o&&o!==window.getComputedStyle(e).getPropertyValue(\"background-image\"))return!0;o=window.getComputedStyle(e).getPropertyValue(\"background-image\")}return h>=20||!(z.getElementCoordinates(a).width>.95*z.getViewportSize(window).width)&&(!(g<10)&&!a.querySelector(\"object, embed, iframe, applet\"))},A.isHeader=function(a){if(A.isColumnHeader(a)||A.isRowHeader(a))return!0;if(a.getAttribute(\"id\")){var b=axe.utils.escapeSelector(a.getAttribute(\"id\"));return!!document.querySelector('[headers~=\"'+b+'\"]')}return!1},A.isRowHeader=function(a){return[\"row\",\"auto\"].includes(A.getScope(a))},A.toGrid=function(a){for(var b=[],c=a.rows,d=0,e=c.length;d<e;d++){var f=c[d].cells;b[d]=b[d]||[];for(var g=0,h=0,i=f.length;h<i;h++)for(var j=0;j<f[h].colSpan;j++){for(var k=0;k<f[h].rowSpan;k++){for(b[d+k]=b[d+k]||[];b[d+k][g];)g++;b[d+k][g]=f[h]}g++}}return b},A.toArray=A.toGrid,function(a){var b=function a(b,c,d,e){var f,g=d[c.y]?d[c.y][c.x]:void 0;return g?\"function\"==typeof e&&!0===(f=e(g,c,d))?[g]:(f=a(b,{x:c.x+b.x,y:c.y+b.y},d,e),f.unshift(g),f):[]};a.traverse=function(a,c,d,e){if(Array.isArray(c)&&(e=d,d=c,c={x:0,y:0}),\"string\"==typeof a)switch(a){case\"left\":a={x:-1,y:0};break;case\"up\":a={x:0,y:-1};break;case\"right\":a={x:1,y:0};break;case\"down\":a={x:0,y:1}}return b(a,{x:c.x+a.x,y:c.y+a.y},d,e)}}(A);var F={submit:\"Submit\",reset:\"Reset\"},G=[\"text\",\"search\",\"tel\",\"url\",\"email\",\"date\",\"time\",\"number\",\"range\",\"color\"],H=[\"A\",\"EM\",\"STRONG\",\"SMALL\",\"MARK\",\"ABBR\",\"DFN\",\"I\",\"B\",\"S\",\"U\",\"CODE\",\"VAR\",\"SAMP\",\"KBD\",\"SUP\",\"SUB\",\"Q\",\"CITE\",\"SPAN\",\"BDO\",\"BDI\",\"BR\",\"WBR\",\"INS\",\"DEL\",\"IMG\",\"EMBED\",\"OBJECT\",\"IFRAME\",\"MAP\",\"AREA\",\"SCRIPT\",\"NOSCRIPT\",\"RUBY\",\"VIDEO\",\"AUDIO\",\"INPUT\",\"TEXTAREA\",\"SELECT\",\"BUTTON\",\"LABEL\",\"OUTPUT\",\"DATALIST\",\"KEYGEN\",\"PROGRESS\",\"COMMAND\",\"CANVAS\",\"TIME\",\"METER\"];B.accessibleText=function(a,b){function c(a,b,c){for(var d,e=a.childNodes,f=\"\",h=0;h<e.length;h++)d=e[h],3===d.nodeType?f+=d.textContent:1===d.nodeType&&(-1===H.indexOf(d.nodeName.toUpperCase())&&(f+=\" \"),f+=g(e[h],b,c));return f}function d(a){return axe.commons.table.isDataTable(a)||1!==axe.commons.table.getAllCells(a).length?\"\":c(a,!1,!1).trim()}function e(a,b,e){var f=\"\",h=a.nodeName.toUpperCase();if(p(a)&&(f=c(a,!1,!1)||\"\",v(f)))return f;if(\"FIGURE\"===h&&(f=s(a,\"figcaption\"),v(f)))return f;if(\"TABLE\"===h){if(f=s(a,\"caption\"),v(f))return f;if(f=a.getAttribute(\"title\")||a.getAttribute(\"summary\")||d(a)||\"\",v(f))return f}if(u(a))return a.getAttribute(\"alt\")||\"\";if(o(a)&&!e){if(n(a))return a.value||a.title||F[a.type]||\"\";var i=m(a);if(i)return g(i,b,!0)}return\"\"}function f(a,b,c){return!b&&a.hasAttribute(\"aria-labelledby\")?B.sanitize(z.idrefs(a,\"aria-labelledby\").map(function(b){return a===b&&h.pop(),g(b,!0,a!==b)}).join(\" \")):c&&t(a)||!a.hasAttribute(\"aria-label\")?\"\":B.sanitize(a.getAttribute(\"aria-label\"))}var g,h=[];return g=function(a,b,d){\"use strict\";var g;if(null===a||-1!==h.indexOf(a))return\"\";if(!b&&!z.isVisible(a,!0))return\"\";h.push(a);var i=a.getAttribute(\"role\");return g=f(a,b,d),v(g)?g:(g=e(a,b,d),v(g)?g:d&&(g=r(a),v(g))?g:q(a)||i&&-1===w.getRolesWithNameFromContents().indexOf(i)||(g=c(a,b,d),!v(g))?a.hasAttribute(\"title\")?a.getAttribute(\"title\"):\"\":g)},B.sanitize(g(a,b))},B.label=function(a){var b,c;if(c=w.label(a))return c;if(a.getAttribute(\"id\")){var d=axe.commons.utils.escapeSelector(a.getAttribute(\"id\"));if(b=document.querySelector('label[for=\"'+d+'\"]'),c=b&&B.visible(b,!0))return c}return b=z.findUp(a,\"label\"),(c=b&&B.visible(b,!0))||null},B.sanitize=function(a){\"use strict\";return a.replace(/\\r\\n/g,\"\\n\").replace(/\\u00A0/g,\" \").replace(/[\\s]{2,}/g,\" \").trim()},B.visible=function(a,b,c){\"use strict\";var d,e,f=a.childNodes,g=f.length,h=\"\";for(d=0;d<g;d++)e=f[d],3===e.nodeType?e.nodeValue&&z.isVisible(a,b)&&(h+=e.nodeValue):c||(h+=B.visible(e,b));return B.sanitize(h)},axe.utils.toArray=function(a){\"use strict\";return Array.prototype.slice.call(a)},axe.utils.tokenList=function(a){\"use strict\";return a.trim().replace(/\\s{2,}/g,\" \").split(\" \")}\n;var I=[\"aa\",\"ab\",\"ae\",\"af\",\"ak\",\"am\",\"an\",\"ar\",\"as\",\"av\",\"ay\",\"az\",\"ba\",\"be\",\"bg\",\"bh\",\"bi\",\"bm\",\"bn\",\"bo\",\"br\",\"bs\",\"ca\",\"ce\",\"ch\",\"co\",\"cr\",\"cs\",\"cu\",\"cv\",\"cy\",\"da\",\"de\",\"dv\",\"dz\",\"ee\",\"el\",\"en\",\"eo\",\"es\",\"et\",\"eu\",\"fa\",\"ff\",\"fi\",\"fj\",\"fo\",\"fr\",\"fy\",\"ga\",\"gd\",\"gl\",\"gn\",\"gu\",\"gv\",\"ha\",\"he\",\"hi\",\"ho\",\"hr\",\"ht\",\"hu\",\"hy\",\"hz\",\"ia\",\"id\",\"ie\",\"ig\",\"ii\",\"ik\",\"in\",\"io\",\"is\",\"it\",\"iu\",\"iw\",\"ja\",\"ji\",\"jv\",\"jw\",\"ka\",\"kg\",\"ki\",\"kj\",\"kk\",\"kl\",\"km\",\"kn\",\"ko\",\"kr\",\"ks\",\"ku\",\"kv\",\"kw\",\"ky\",\"la\",\"lb\",\"lg\",\"li\",\"ln\",\"lo\",\"lt\",\"lu\",\"lv\",\"mg\",\"mh\",\"mi\",\"mk\",\"ml\",\"mn\",\"mo\",\"mr\",\"ms\",\"mt\",\"my\",\"na\",\"nb\",\"nd\",\"ne\",\"ng\",\"nl\",\"nn\",\"no\",\"nr\",\"nv\",\"ny\",\"oc\",\"oj\",\"om\",\"or\",\"os\",\"pa\",\"pi\",\"pl\",\"ps\",\"pt\",\"qu\",\"rm\",\"rn\",\"ro\",\"ru\",\"rw\",\"sa\",\"sc\",\"sd\",\"se\",\"sg\",\"sh\",\"si\",\"sk\",\"sl\",\"sm\",\"sn\",\"so\",\"sq\",\"sr\",\"ss\",\"st\",\"su\",\"sv\",\"sw\",\"ta\",\"te\",\"tg\",\"th\",\"ti\",\"tk\",\"tl\",\"tn\",\"to\",\"tr\",\"ts\",\"tt\",\"tw\",\"ty\",\"ug\",\"uk\",\"ur\",\"uz\",\"ve\",\"vi\",\"vo\",\"wa\",\"wo\",\"xh\",\"yi\",\"yo\",\"za\",\"zh\",\"zu\",\"aaa\",\"aab\",\"aac\",\"aad\",\"aae\",\"aaf\",\"aag\",\"aah\",\"aai\",\"aak\",\"aal\",\"aam\",\"aan\",\"aao\",\"aap\",\"aaq\",\"aas\",\"aat\",\"aau\",\"aav\",\"aaw\",\"aax\",\"aaz\",\"aba\",\"abb\",\"abc\",\"abd\",\"abe\",\"abf\",\"abg\",\"abh\",\"abi\",\"abj\",\"abl\",\"abm\",\"abn\",\"abo\",\"abp\",\"abq\",\"abr\",\"abs\",\"abt\",\"abu\",\"abv\",\"abw\",\"abx\",\"aby\",\"abz\",\"aca\",\"acb\",\"acd\",\"ace\",\"acf\",\"ach\",\"aci\",\"ack\",\"acl\",\"acm\",\"acn\",\"acp\",\"acq\",\"acr\",\"acs\",\"act\",\"acu\",\"acv\",\"acw\",\"acx\",\"acy\",\"acz\",\"ada\",\"adb\",\"add\",\"ade\",\"adf\",\"adg\",\"adh\",\"adi\",\"adj\",\"adl\",\"adn\",\"ado\",\"adp\",\"adq\",\"adr\",\"ads\",\"adt\",\"adu\",\"adw\",\"adx\",\"ady\",\"adz\",\"aea\",\"aeb\",\"aec\",\"aed\",\"aee\",\"aek\",\"ael\",\"aem\",\"aen\",\"aeq\",\"aer\",\"aes\",\"aeu\",\"aew\",\"aey\",\"aez\",\"afa\",\"afb\",\"afd\",\"afe\",\"afg\",\"afh\",\"afi\",\"afk\",\"afn\",\"afo\",\"afp\",\"afs\",\"aft\",\"afu\",\"afz\",\"aga\",\"agb\",\"agc\",\"agd\",\"age\",\"agf\",\"agg\",\"agh\",\"agi\",\"agj\",\"agk\",\"agl\",\"agm\",\"agn\",\"ago\",\"agp\",\"agq\",\"agr\",\"ags\",\"agt\",\"agu\",\"agv\",\"agw\",\"agx\",\"agy\",\"agz\",\"aha\",\"ahb\",\"ahg\",\"ahh\",\"ahi\",\"ahk\",\"ahl\",\"ahm\",\"ahn\",\"aho\",\"ahp\",\"ahr\",\"ahs\",\"aht\",\"aia\",\"aib\",\"aic\",\"aid\",\"aie\",\"aif\",\"aig\",\"aih\",\"aii\",\"aij\",\"aik\",\"ail\",\"aim\",\"ain\",\"aio\",\"aip\",\"aiq\",\"air\",\"ais\",\"ait\",\"aiw\",\"aix\",\"aiy\",\"aja\",\"ajg\",\"aji\",\"ajn\",\"ajp\",\"ajt\",\"aju\",\"ajw\",\"ajz\",\"akb\",\"akc\",\"akd\",\"ake\",\"akf\",\"akg\",\"akh\",\"aki\",\"akj\",\"akk\",\"akl\",\"akm\",\"ako\",\"akp\",\"akq\",\"akr\",\"aks\",\"akt\",\"aku\",\"akv\",\"akw\",\"akx\",\"aky\",\"akz\",\"ala\",\"alc\",\"ald\",\"ale\",\"alf\",\"alg\",\"alh\",\"ali\",\"alj\",\"alk\",\"all\",\"alm\",\"aln\",\"alo\",\"alp\",\"alq\",\"alr\",\"als\",\"alt\",\"alu\",\"alv\",\"alw\",\"alx\",\"aly\",\"alz\",\"ama\",\"amb\",\"amc\",\"ame\",\"amf\",\"amg\",\"ami\",\"amj\",\"amk\",\"aml\",\"amm\",\"amn\",\"amo\",\"amp\",\"amq\",\"amr\",\"ams\",\"amt\",\"amu\",\"amv\",\"amw\",\"amx\",\"amy\",\"amz\",\"ana\",\"anb\",\"anc\",\"and\",\"ane\",\"anf\",\"ang\",\"anh\",\"ani\",\"anj\",\"ank\",\"anl\",\"anm\",\"ann\",\"ano\",\"anp\",\"anq\",\"anr\",\"ans\",\"ant\",\"anu\",\"anv\",\"anw\",\"anx\",\"any\",\"anz\",\"aoa\",\"aob\",\"aoc\",\"aod\",\"aoe\",\"aof\",\"aog\",\"aoh\",\"aoi\",\"aoj\",\"aok\",\"aol\",\"aom\",\"aon\",\"aor\",\"aos\",\"aot\",\"aou\",\"aox\",\"aoz\",\"apa\",\"apb\",\"apc\",\"apd\",\"ape\",\"apf\",\"apg\",\"aph\",\"api\",\"apj\",\"apk\",\"apl\",\"apm\",\"apn\",\"apo\",\"app\",\"apq\",\"apr\",\"aps\",\"apt\",\"apu\",\"apv\",\"apw\",\"apx\",\"apy\",\"apz\",\"aqa\",\"aqc\",\"aqd\",\"aqg\",\"aql\",\"aqm\",\"aqn\",\"aqp\",\"aqr\",\"aqt\",\"aqz\",\"arb\",\"arc\",\"ard\",\"are\",\"arh\",\"ari\",\"arj\",\"ark\",\"arl\",\"arn\",\"aro\",\"arp\",\"arq\",\"arr\",\"ars\",\"art\",\"aru\",\"arv\",\"arw\",\"arx\",\"ary\",\"arz\",\"asa\",\"asb\",\"asc\",\"asd\",\"ase\",\"asf\",\"asg\",\"ash\",\"asi\",\"asj\",\"ask\",\"asl\",\"asn\",\"aso\",\"asp\",\"asq\",\"asr\",\"ass\",\"ast\",\"asu\",\"asv\",\"asw\",\"asx\",\"asy\",\"asz\",\"ata\",\"atb\",\"atc\",\"atd\",\"ate\",\"atg\",\"ath\",\"ati\",\"atj\",\"atk\",\"atl\",\"atm\",\"atn\",\"ato\",\"atp\",\"atq\",\"atr\",\"ats\",\"att\",\"atu\",\"atv\",\"atw\",\"atx\",\"aty\",\"atz\",\"aua\",\"aub\",\"auc\",\"aud\",\"aue\",\"auf\",\"aug\",\"auh\",\"aui\",\"auj\",\"auk\",\"aul\",\"aum\",\"aun\",\"auo\",\"aup\",\"auq\",\"aur\",\"aus\",\"aut\",\"auu\",\"auw\",\"aux\",\"auy\",\"auz\",\"avb\",\"avd\",\"avi\",\"avk\",\"avl\",\"avm\",\"avn\",\"avo\",\"avs\",\"avt\",\"avu\",\"avv\",\"awa\",\"awb\",\"awc\",\"awd\",\"awe\",\"awg\",\"awh\",\"awi\",\"awk\",\"awm\",\"awn\",\"awo\",\"awr\",\"aws\",\"awt\",\"awu\",\"awv\",\"aww\",\"awx\",\"awy\",\"axb\",\"axe\",\"axg\",\"axk\",\"axl\",\"axm\",\"axx\",\"aya\",\"ayb\",\"ayc\",\"ayd\",\"aye\",\"ayg\",\"ayh\",\"ayi\",\"ayk\",\"ayl\",\"ayn\",\"ayo\",\"ayp\",\"ayq\",\"ayr\",\"ays\",\"ayt\",\"ayu\",\"ayx\",\"ayy\",\"ayz\",\"aza\",\"azb\",\"azc\",\"azd\",\"azg\",\"azj\",\"azm\",\"azn\",\"azo\",\"azt\",\"azz\",\"baa\",\"bab\",\"bac\",\"bad\",\"bae\",\"baf\",\"bag\",\"bah\",\"bai\",\"baj\",\"bal\",\"ban\",\"bao\",\"bap\",\"bar\",\"bas\",\"bat\",\"bau\",\"bav\",\"baw\",\"bax\",\"bay\",\"baz\",\"bba\",\"bbb\",\"bbc\",\"bbd\",\"bbe\",\"bbf\",\"bbg\",\"bbh\",\"bbi\",\"bbj\",\"bbk\",\"bbl\",\"bbm\",\"bbn\",\"bbo\",\"bbp\",\"bbq\",\"bbr\",\"bbs\",\"bbt\",\"bbu\",\"bbv\",\"bbw\",\"bbx\",\"bby\",\"bbz\",\"bca\",\"bcb\",\"bcc\",\"bcd\",\"bce\",\"bcf\",\"bcg\",\"bch\",\"bci\",\"bcj\",\"bck\",\"bcl\",\"bcm\",\"bcn\",\"bco\",\"bcp\",\"bcq\",\"bcr\",\"bcs\",\"bct\",\"bcu\",\"bcv\",\"bcw\",\"bcy\",\"bcz\",\"bda\",\"bdb\",\"bdc\",\"bdd\",\"bde\",\"bdf\",\"bdg\",\"bdh\",\"bdi\",\"bdj\",\"bdk\",\"bdl\",\"bdm\",\"bdn\",\"bdo\",\"bdp\",\"bdq\",\"bdr\",\"bds\",\"bdt\",\"bdu\",\"bdv\",\"bdw\",\"bdx\",\"bdy\",\"bdz\",\"bea\",\"beb\",\"bec\",\"bed\",\"bee\",\"bef\",\"beg\",\"beh\",\"bei\",\"bej\",\"bek\",\"bem\",\"beo\",\"bep\",\"beq\",\"ber\",\"bes\",\"bet\",\"beu\",\"bev\",\"bew\",\"bex\",\"bey\",\"bez\",\"bfa\",\"bfb\",\"bfc\",\"bfd\",\"bfe\",\"bff\",\"bfg\",\"bfh\",\"bfi\",\"bfj\",\"bfk\",\"bfl\",\"bfm\",\"bfn\",\"bfo\",\"bfp\",\"bfq\",\"bfr\",\"bfs\",\"bft\",\"bfu\",\"bfw\",\"bfx\",\"bfy\",\"bfz\",\"bga\",\"bgb\",\"bgc\",\"bgd\",\"bge\",\"bgf\",\"bgg\",\"bgi\",\"bgj\",\"bgk\",\"bgl\",\"bgm\",\"bgn\",\"bgo\",\"bgp\",\"bgq\",\"bgr\",\"bgs\",\"bgt\",\"bgu\",\"bgv\",\"bgw\",\"bgx\",\"bgy\",\"bgz\",\"bha\",\"bhb\",\"bhc\",\"bhd\",\"bhe\",\"bhf\",\"bhg\",\"bhh\",\"bhi\",\"bhj\",\"bhk\",\"bhl\",\"bhm\",\"bhn\",\"bho\",\"bhp\",\"bhq\",\"bhr\",\"bhs\",\"bht\",\"bhu\",\"bhv\",\"bhw\",\"bhx\",\"bhy\",\"bhz\",\"bia\",\"bib\",\"bic\",\"bid\",\"bie\",\"bif\",\"big\",\"bij\",\"bik\",\"bil\",\"bim\",\"bin\",\"bio\",\"bip\",\"biq\",\"bir\",\"bit\",\"biu\",\"biv\",\"biw\",\"bix\",\"biy\",\"biz\",\"bja\",\"bjb\",\"bjc\",\"bjd\",\"bje\",\"bjf\",\"bjg\",\"bjh\",\"bji\",\"bjj\",\"bjk\",\"bjl\",\"bjm\",\"bjn\",\"bjo\",\"bjp\",\"bjq\",\"bjr\",\"bjs\",\"bjt\",\"bju\",\"bjv\",\"bjw\",\"bjx\",\"bjy\",\"bjz\",\"bka\",\"bkb\",\"bkc\",\"bkd\",\"bkf\",\"bkg\",\"bkh\",\"bki\",\"bkj\",\"bkk\",\"bkl\",\"bkm\",\"bkn\",\"bko\",\"bkp\",\"bkq\",\"bkr\",\"bks\",\"bkt\",\"bku\",\"bkv\",\"bkw\",\"bkx\",\"bky\",\"bkz\",\"bla\",\"blb\",\"blc\",\"bld\",\"ble\",\"blf\",\"blg\",\"blh\",\"bli\",\"blj\",\"blk\",\"bll\",\"blm\",\"bln\",\"blo\",\"blp\",\"blq\",\"blr\",\"bls\",\"blt\",\"blv\",\"blw\",\"blx\",\"bly\",\"blz\",\"bma\",\"bmb\",\"bmc\",\"bmd\",\"bme\",\"bmf\",\"bmg\",\"bmh\",\"bmi\",\"bmj\",\"bmk\",\"bml\",\"bmm\",\"bmn\",\"bmo\",\"bmp\",\"bmq\",\"bmr\",\"bms\",\"bmt\",\"bmu\",\"bmv\",\"bmw\",\"bmx\",\"bmy\",\"bmz\",\"bna\",\"bnb\",\"bnc\",\"bnd\",\"bne\",\"bnf\",\"bng\",\"bni\",\"bnj\",\"bnk\",\"bnl\",\"bnm\",\"bnn\",\"bno\",\"bnp\",\"bnq\",\"bnr\",\"bns\",\"bnt\",\"bnu\",\"bnv\",\"bnw\",\"bnx\",\"bny\",\"bnz\",\"boa\",\"bob\",\"boe\",\"bof\",\"bog\",\"boh\",\"boi\",\"boj\",\"bok\",\"bol\",\"bom\",\"bon\",\"boo\",\"bop\",\"boq\",\"bor\",\"bot\",\"bou\",\"bov\",\"bow\",\"box\",\"boy\",\"boz\",\"bpa\",\"bpb\",\"bpd\",\"bpg\",\"bph\",\"bpi\",\"bpj\",\"bpk\",\"bpl\",\"bpm\",\"bpn\",\"bpo\",\"bpp\",\"bpq\",\"bpr\",\"bps\",\"bpt\",\"bpu\",\"bpv\",\"bpw\",\"bpx\",\"bpy\",\"bpz\",\"bqa\",\"bqb\",\"bqc\",\"bqd\",\"bqf\",\"bqg\",\"bqh\",\"bqi\",\"bqj\",\"bqk\",\"bql\",\"bqm\",\"bqn\",\"bqo\",\"bqp\",\"bqq\",\"bqr\",\"bqs\",\"bqt\",\"bqu\",\"bqv\",\"bqw\",\"bqx\",\"bqy\",\"bqz\",\"bra\",\"brb\",\"brc\",\"brd\",\"brf\",\"brg\",\"brh\",\"bri\",\"brj\",\"brk\",\"brl\",\"brm\",\"brn\",\"bro\",\"brp\",\"brq\",\"brr\",\"brs\",\"brt\",\"bru\",\"brv\",\"brw\",\"brx\",\"bry\",\"brz\",\"bsa\",\"bsb\",\"bsc\",\"bse\",\"bsf\",\"bsg\",\"bsh\",\"bsi\",\"bsj\",\"bsk\",\"bsl\",\"bsm\",\"bsn\",\"bso\",\"bsp\",\"bsq\",\"bsr\",\"bss\",\"bst\",\"bsu\",\"bsv\",\"bsw\",\"bsx\",\"bsy\",\"bta\",\"btb\",\"btc\",\"btd\",\"bte\",\"btf\",\"btg\",\"bth\",\"bti\",\"btj\",\"btk\",\"btl\",\"btm\",\"btn\",\"bto\",\"btp\",\"btq\",\"btr\",\"bts\",\"btt\",\"btu\",\"btv\",\"btw\",\"btx\",\"bty\",\"btz\",\"bua\",\"bub\",\"buc\",\"bud\",\"bue\",\"buf\",\"bug\",\"buh\",\"bui\",\"buj\",\"buk\",\"bum\",\"bun\",\"buo\",\"bup\",\"buq\",\"bus\",\"but\",\"buu\",\"buv\",\"buw\",\"bux\",\"buy\",\"buz\",\"bva\",\"bvb\",\"bvc\",\"bvd\",\"bve\",\"bvf\",\"bvg\",\"bvh\",\"bvi\",\"bvj\",\"bvk\",\"bvl\",\"bvm\",\"bvn\",\"bvo\",\"bvp\",\"bvq\",\"bvr\",\"bvt\",\"bvu\",\"bvv\",\"bvw\",\"bvx\",\"bvy\",\"bvz\",\"bwa\",\"bwb\",\"bwc\",\"bwd\",\"bwe\",\"bwf\",\"bwg\",\"bwh\",\"bwi\",\"bwj\",\"bwk\",\"bwl\",\"bwm\",\"bwn\",\"bwo\",\"bwp\",\"bwq\",\"bwr\",\"bws\",\"bwt\",\"bwu\",\"bww\",\"bwx\",\"bwy\",\"bwz\",\"bxa\",\"bxb\",\"bxc\",\"bxd\",\"bxe\",\"bxf\",\"bxg\",\"bxh\",\"bxi\",\"bxj\",\"bxk\",\"bxl\",\"bxm\",\"bxn\",\"bxo\",\"bxp\",\"bxq\",\"bxr\",\"bxs\",\"bxu\",\"bxv\",\"bxw\",\"bxx\",\"bxz\",\"bya\",\"byb\",\"byc\",\"byd\",\"bye\",\"byf\",\"byg\",\"byh\",\"byi\",\"byj\",\"byk\",\"byl\",\"bym\",\"byn\",\"byo\",\"byp\",\"byq\",\"byr\",\"bys\",\"byt\",\"byv\",\"byw\",\"byx\",\"byy\",\"byz\",\"bza\",\"bzb\",\"bzc\",\"bzd\",\"bze\",\"bzf\",\"bzg\",\"bzh\",\"bzi\",\"bzj\",\"bzk\",\"bzl\",\"bzm\",\"bzn\",\"bzo\",\"bzp\",\"bzq\",\"bzr\",\"bzs\",\"bzt\",\"bzu\",\"bzv\",\"bzw\",\"bzx\",\"bzy\",\"bzz\",\"caa\",\"cab\",\"cac\",\"cad\",\"cae\",\"caf\",\"cag\",\"cah\",\"cai\",\"caj\",\"cak\",\"cal\",\"cam\",\"can\",\"cao\",\"cap\",\"caq\",\"car\",\"cas\",\"cau\",\"cav\",\"caw\",\"cax\",\"cay\",\"caz\",\"cba\",\"cbb\",\"cbc\",\"cbd\",\"cbe\",\"cbg\",\"cbh\",\"cbi\",\"cbj\",\"cbk\",\"cbl\",\"cbn\",\"cbo\",\"cbq\",\"cbr\",\"cbs\",\"cbt\",\"cbu\",\"cbv\",\"cbw\",\"cby\",\"cca\",\"ccc\",\"ccd\",\"cce\",\"ccg\",\"cch\",\"ccj\",\"ccl\",\"ccm\",\"ccn\",\"cco\",\"ccp\",\"ccq\",\"ccr\",\"ccs\",\"cda\",\"cdc\",\"cdd\",\"cde\",\"cdf\",\"cdg\",\"cdh\",\"cdi\",\"cdj\",\"cdm\",\"cdn\",\"cdo\",\"cdr\",\"cds\",\"cdy\",\"cdz\",\"cea\",\"ceb\",\"ceg\",\"cek\",\"cel\",\"cen\",\"cet\",\"cfa\",\"cfd\",\"cfg\",\"cfm\",\"cga\",\"cgc\",\"cgg\",\"cgk\",\"chb\",\"chc\",\"chd\",\"chf\",\"chg\",\"chh\",\"chj\",\"chk\",\"chl\",\"chm\",\"chn\",\"cho\",\"chp\",\"chq\",\"chr\",\"cht\",\"chw\",\"chx\",\"chy\",\"chz\",\"cia\",\"cib\",\"cic\",\"cid\",\"cie\",\"cih\",\"cik\",\"cim\",\"cin\",\"cip\",\"cir\",\"ciw\",\"ciy\",\"cja\",\"cje\",\"cjh\",\"cji\",\"cjk\",\"cjm\",\"cjn\",\"cjo\",\"cjp\",\"cjr\",\"cjs\",\"cjv\",\"cjy\",\"cka\",\"ckb\",\"ckh\",\"ckl\",\"ckn\",\"cko\",\"ckq\",\"ckr\",\"cks\",\"ckt\",\"cku\",\"ckv\",\"ckx\",\"cky\",\"ckz\",\"cla\",\"clc\",\"cld\",\"cle\",\"clh\",\"cli\",\"clj\",\"clk\",\"cll\",\"clm\",\"clo\",\"clt\",\"clu\",\"clw\",\"cly\",\"cma\",\"cmc\",\"cme\",\"cmg\",\"cmi\",\"cmk\",\"cml\",\"cmm\",\"cmn\",\"cmo\",\"cmr\",\"cms\",\"cmt\",\"cna\",\"cnb\",\"cnc\",\"cng\",\"cnh\",\"cni\",\"cnk\",\"cnl\",\"cno\",\"cns\",\"cnt\",\"cnu\",\"cnw\",\"cnx\",\"coa\",\"cob\",\"coc\",\"cod\",\"coe\",\"cof\",\"cog\",\"coh\",\"coj\",\"cok\",\"col\",\"com\",\"con\",\"coo\",\"cop\",\"coq\",\"cot\",\"cou\",\"cov\",\"cow\",\"cox\",\"coy\",\"coz\",\"cpa\",\"cpb\",\"cpc\",\"cpe\",\"cpf\",\"cpg\",\"cpi\",\"cpn\",\"cpo\",\"cpp\",\"cps\",\"cpu\",\"cpx\",\"cpy\",\"cqd\",\"cqu\",\"cra\",\"crb\",\"crc\",\"crd\",\"crf\",\"crg\",\"crh\",\"cri\",\"crj\",\"crk\",\"crl\",\"crm\",\"crn\",\"cro\",\"crp\",\"crq\",\"crr\",\"crs\",\"crt\",\"crv\",\"crw\",\"crx\",\"cry\",\"crz\",\"csa\",\"csb\",\"csc\",\"csd\",\"cse\",\"csf\",\"csg\",\"csh\",\"csi\",\"csj\",\"csk\",\"csl\",\"csm\",\"csn\",\"cso\",\"csq\",\"csr\",\"css\",\"cst\",\"csu\",\"csv\",\"csw\",\"csy\",\"csz\",\"cta\",\"ctc\",\"ctd\",\"cte\",\"ctg\",\"cth\",\"ctl\",\"ctm\",\"ctn\",\"cto\",\"ctp\",\"cts\",\"ctt\",\"ctu\",\"ctz\",\"cua\",\"cub\",\"cuc\",\"cug\",\"cuh\",\"cui\",\"cuj\",\"cuk\",\"cul\",\"cum\",\"cuo\",\"cup\",\"cuq\",\"cur\",\"cus\",\"cut\",\"cuu\",\"cuv\",\"cuw\",\"cux\",\"cvg\",\"cvn\",\"cwa\",\"cwb\",\"cwd\",\"cwe\",\"cwg\",\"cwt\",\"cya\",\"cyb\",\"cyo\",\"czh\",\"czk\",\"czn\",\"czo\",\"czt\",\"daa\",\"dac\",\"dad\",\"dae\",\"daf\",\"dag\",\"dah\",\"dai\",\"daj\",\"dak\",\"dal\",\"dam\",\"dao\",\"dap\",\"daq\",\"dar\",\"das\",\"dau\",\"dav\",\"daw\",\"dax\",\"day\",\"daz\",\"dba\",\"dbb\",\"dbd\",\"dbe\",\"dbf\",\"dbg\",\"dbi\",\"dbj\",\"dbl\",\"dbm\",\"dbn\",\"dbo\",\"dbp\",\"dbq\",\"dbr\",\"dbt\",\"dbu\",\"dbv\",\"dbw\",\"dby\",\"dcc\",\"dcr\",\"dda\",\"ddd\",\"dde\",\"ddg\",\"ddi\",\"ddj\",\"ddn\",\"ddo\",\"ddr\",\"dds\",\"ddw\",\"dec\",\"ded\",\"dee\",\"def\",\"deg\",\"deh\",\"dei\",\"dek\",\"del\",\"dem\",\"den\",\"dep\",\"deq\",\"der\",\"des\",\"dev\",\"dez\",\"dga\",\"dgb\",\"dgc\",\"dgd\",\"dge\",\"dgg\",\"dgh\",\"dgi\",\"dgk\",\"dgl\",\"dgn\",\"dgo\",\"dgr\",\"dgs\",\"dgt\",\"dgu\",\"dgw\",\"dgx\",\"dgz\",\"dha\",\"dhd\",\"dhg\",\"dhi\",\"dhl\",\"dhm\",\"dhn\",\"dho\",\"dhr\",\"dhs\",\"dhu\",\"dhv\",\"dhw\",\"dhx\",\"dia\",\"dib\",\"dic\",\"did\",\"dif\",\"dig\",\"dih\",\"dii\",\"dij\",\"dik\",\"dil\",\"dim\",\"din\",\"dio\",\"dip\",\"diq\",\"dir\",\"dis\",\"dit\",\"diu\",\"diw\",\"dix\",\"diy\",\"diz\",\"dja\",\"djb\",\"djc\",\"djd\",\"dje\",\"djf\",\"dji\",\"djj\",\"djk\",\"djl\",\"djm\",\"djn\",\"djo\",\"djr\",\"dju\",\"djw\",\"dka\",\"dkk\",\"dkl\",\"dkr\",\"dks\",\"dkx\",\"dlg\",\"dlk\",\"dlm\",\"dln\",\"dma\",\"dmb\",\"dmc\",\"dmd\",\"dme\",\"dmg\",\"dmk\",\"dml\",\"dmm\",\"dmn\",\"dmo\",\"dmr\",\"dms\",\"dmu\",\"dmv\",\"dmw\",\"dmx\",\"dmy\",\"dna\",\"dnd\",\"dne\",\"dng\",\"dni\",\"dnj\",\"dnk\",\"dnn\",\"dnr\",\"dnt\",\"dnu\",\"dnv\",\"dnw\",\"dny\",\"doa\",\"dob\",\"doc\",\"doe\",\"dof\",\"doh\",\"doi\",\"dok\",\"dol\",\"don\",\"doo\",\"dop\",\"doq\",\"dor\",\"dos\",\"dot\",\"dov\",\"dow\",\"dox\",\"doy\",\"doz\",\"dpp\",\"dra\",\"drb\",\"drc\",\"drd\",\"dre\",\"drg\",\"drh\",\"dri\",\"drl\",\"drn\",\"dro\",\"drq\",\"drr\",\"drs\",\"drt\",\"dru\",\"drw\",\"dry\",\"dsb\",\"dse\",\"dsh\",\"dsi\",\"dsl\",\"dsn\",\"dso\",\"dsq\",\"dta\",\"dtb\",\"dtd\",\"dth\",\"dti\",\"dtk\",\"dtm\",\"dtn\",\"dto\",\"dtp\",\"dtr\",\"dts\",\"dtt\",\"dtu\",\"dty\",\"dua\",\"dub\",\"duc\",\"dud\",\"due\",\"duf\",\"dug\",\"duh\",\"dui\",\"duj\",\"duk\",\"dul\",\"dum\",\"dun\",\"duo\",\"dup\",\"duq\",\"dur\",\"dus\",\"duu\",\"duv\",\"duw\",\"dux\",\"duy\",\"duz\",\"dva\",\"dwa\",\"dwl\",\"dwr\",\"dws\",\"dwu\",\"dww\",\"dwy\",\"dya\",\"dyb\",\"dyd\",\"dyg\",\"dyi\",\"dym\",\"dyn\",\"dyo\",\"dyu\",\"dyy\",\"dza\",\"dzd\",\"dze\",\"dzg\",\"dzl\",\"dzn\",\"eaa\",\"ebg\",\"ebk\",\"ebo\",\"ebr\",\"ebu\",\"ecr\",\"ecs\",\"ecy\",\"eee\",\"efa\",\"efe\",\"efi\",\"ega\",\"egl\",\"ego\",\"egx\",\"egy\",\"ehu\",\"eip\",\"eit\",\"eiv\",\"eja\",\"eka\",\"ekc\",\"eke\",\"ekg\",\"eki\",\"ekk\",\"ekl\",\"ekm\",\"eko\",\"ekp\",\"ekr\",\"eky\",\"ele\",\"elh\",\"eli\",\"elk\",\"elm\",\"elo\",\"elp\",\"elu\",\"elx\",\"ema\",\"emb\",\"eme\",\"emg\",\"emi\",\"emk\",\"emm\",\"emn\",\"emo\",\"emp\",\"ems\",\"emu\",\"emw\",\"emx\",\"emy\",\"ena\",\"enb\",\"enc\",\"end\",\"enf\",\"enh\",\"enl\",\"enm\",\"enn\",\"eno\",\"enq\",\"enr\",\"enu\",\"env\",\"enw\",\"enx\",\"eot\",\"epi\",\"era\",\"erg\",\"erh\",\"eri\",\"erk\",\"ero\",\"err\",\"ers\",\"ert\",\"erw\",\"ese\",\"esg\",\"esh\",\"esi\",\"esk\",\"esl\",\"esm\",\"esn\",\"eso\",\"esq\",\"ess\",\"esu\",\"esx\",\"esy\",\"etb\",\"etc\",\"eth\",\"etn\",\"eto\",\"etr\",\"ets\",\"ett\",\"etu\",\"etx\",\"etz\",\"euq\",\"eve\",\"evh\",\"evn\",\"ewo\",\"ext\",\"eya\",\"eyo\",\"eza\",\"eze\",\"faa\",\"fab\",\"fad\",\"faf\",\"fag\",\"fah\",\"fai\",\"faj\",\"fak\",\"fal\",\"fam\",\"fan\",\"fap\",\"far\",\"fat\",\"fau\",\"fax\",\"fay\",\"faz\",\"fbl\",\"fcs\",\"fer\",\"ffi\",\"ffm\",\"fgr\",\"fia\",\"fie\",\"fil\",\"fip\",\"fir\",\"fit\",\"fiu\",\"fiw\",\"fkk\",\"fkv\",\"fla\",\"flh\",\"fli\",\"fll\",\"fln\",\"flr\",\"fly\",\"fmp\",\"fmu\",\"fnb\",\"fng\",\"fni\",\"fod\",\"foi\",\"fom\",\"fon\",\"for\",\"fos\",\"fox\",\"fpe\",\"fqs\",\"frc\",\"frd\",\"frk\",\"frm\",\"fro\",\"frp\",\"frq\",\"frr\",\"frs\",\"frt\",\"fse\",\"fsl\",\"fss\",\"fub\",\"fuc\",\"fud\",\"fue\",\"fuf\",\"fuh\",\"fui\",\"fuj\",\"fum\",\"fun\",\"fuq\",\"fur\",\"fut\",\"fuu\",\"fuv\",\"fuy\",\"fvr\",\"fwa\",\"fwe\",\"gaa\",\"gab\",\"gac\",\"gad\",\"gae\",\"gaf\",\"gag\",\"gah\",\"gai\",\"gaj\",\"gak\",\"gal\",\"gam\",\"gan\",\"gao\",\"gap\",\"gaq\",\"gar\",\"gas\",\"gat\",\"gau\",\"gav\",\"gaw\",\"gax\",\"gay\",\"gaz\",\"gba\",\"gbb\",\"gbc\",\"gbd\",\"gbe\",\"gbf\",\"gbg\",\"gbh\",\"gbi\",\"gbj\",\"gbk\",\"gbl\",\"gbm\",\"gbn\",\"gbo\",\"gbp\",\"gbq\",\"gbr\",\"gbs\",\"gbu\",\"gbv\",\"gbw\",\"gbx\",\"gby\",\"gbz\",\"gcc\",\"gcd\",\"gce\",\"gcf\",\"gcl\",\"gcn\",\"gcr\",\"gct\",\"gda\",\"gdb\",\"gdc\",\"gdd\",\"gde\",\"gdf\",\"gdg\",\"gdh\",\"gdi\",\"gdj\",\"gdk\",\"gdl\",\"gdm\",\"gdn\",\"gdo\",\"gdq\",\"gdr\",\"gds\",\"gdt\",\"gdu\",\"gdx\",\"gea\",\"geb\",\"gec\",\"ged\",\"geg\",\"geh\",\"gei\",\"gej\",\"gek\",\"gel\",\"gem\",\"geq\",\"ges\",\"gev\",\"gew\",\"gex\",\"gey\",\"gez\",\"gfk\",\"gft\",\"gfx\",\"gga\",\"ggb\",\"ggd\",\"gge\",\"ggg\",\"ggk\",\"ggl\",\"ggn\",\"ggo\",\"ggr\",\"ggt\",\"ggu\",\"ggw\",\"gha\",\"ghc\",\"ghe\",\"ghh\",\"ghk\",\"ghl\",\"ghn\",\"gho\",\"ghr\",\"ghs\",\"ght\",\"gia\",\"gib\",\"gic\",\"gid\",\"gie\",\"gig\",\"gih\",\"gil\",\"gim\",\"gin\",\"gio\",\"gip\",\"giq\",\"gir\",\"gis\",\"git\",\"giu\",\"giw\",\"gix\",\"giy\",\"giz\",\"gji\",\"gjk\",\"gjm\",\"gjn\",\"gjr\",\"gju\",\"gka\",\"gke\",\"gkn\",\"gko\",\"gkp\",\"gku\",\"glc\",\"gld\",\"glh\",\"gli\",\"glj\",\"glk\",\"gll\",\"glo\",\"glr\",\"glu\",\"glw\",\"gly\",\"gma\",\"gmb\",\"gmd\",\"gme\",\"gmg\",\"gmh\",\"gml\",\"gmm\",\"gmn\",\"gmq\",\"gmu\",\"gmv\",\"gmw\",\"gmx\",\"gmy\",\"gmz\",\"gna\",\"gnb\",\"gnc\",\"gnd\",\"gne\",\"gng\",\"gnh\",\"gni\",\"gnk\",\"gnl\",\"gnm\",\"gnn\",\"gno\",\"gnq\",\"gnr\",\"gnt\",\"gnu\",\"gnw\",\"gnz\",\"goa\",\"gob\",\"goc\",\"god\",\"goe\",\"gof\",\"gog\",\"goh\",\"goi\",\"goj\",\"gok\",\"gol\",\"gom\",\"gon\",\"goo\",\"gop\",\"goq\",\"gor\",\"gos\",\"got\",\"gou\",\"gow\",\"gox\",\"goy\",\"goz\",\"gpa\",\"gpe\",\"gpn\",\"gqa\",\"gqi\",\"gqn\",\"gqr\",\"gqu\",\"gra\",\"grb\",\"grc\",\"grd\",\"grg\",\"grh\",\"gri\",\"grj\",\"grk\",\"grm\",\"gro\",\"grq\",\"grr\",\"grs\",\"grt\",\"gru\",\"grv\",\"grw\",\"grx\",\"gry\",\"grz\",\"gse\",\"gsg\",\"gsl\",\"gsm\",\"gsn\",\"gso\",\"gsp\",\"gss\",\"gsw\",\"gta\",\"gti\",\"gtu\",\"gua\",\"gub\",\"guc\",\"gud\",\"gue\",\"guf\",\"gug\",\"guh\",\"gui\",\"guk\",\"gul\",\"gum\",\"gun\",\"guo\",\"gup\",\"guq\",\"gur\",\"gus\",\"gut\",\"guu\",\"guv\",\"guw\",\"gux\",\"guz\",\"gva\",\"gvc\",\"gve\",\"gvf\",\"gvj\",\"gvl\",\"gvm\",\"gvn\",\"gvo\",\"gvp\",\"gvr\",\"gvs\",\"gvy\",\"gwa\",\"gwb\",\"gwc\",\"gwd\",\"gwe\",\"gwf\",\"gwg\",\"gwi\",\"gwj\",\"gwm\",\"gwn\",\"gwr\",\"gwt\",\"gwu\",\"gww\",\"gwx\",\"gxx\",\"gya\",\"gyb\",\"gyd\",\"gye\",\"gyf\",\"gyg\",\"gyi\",\"gyl\",\"gym\",\"gyn\",\"gyr\",\"gyy\",\"gza\",\"gzi\",\"gzn\",\"haa\",\"hab\",\"hac\",\"had\",\"hae\",\"haf\",\"hag\",\"hah\",\"hai\",\"haj\",\"hak\",\"hal\",\"ham\",\"han\",\"hao\",\"hap\",\"haq\",\"har\",\"has\",\"hav\",\"haw\",\"hax\",\"hay\",\"haz\",\"hba\",\"hbb\",\"hbn\",\"hbo\",\"hbu\",\"hca\",\"hch\",\"hdn\",\"hds\",\"hdy\",\"hea\",\"hed\",\"heg\",\"heh\",\"hei\",\"hem\",\"hgm\",\"hgw\",\"hhi\",\"hhr\",\"hhy\",\"hia\",\"hib\",\"hid\",\"hif\",\"hig\",\"hih\",\"hii\",\"hij\",\"hik\",\"hil\",\"him\",\"hio\",\"hir\",\"hit\",\"hiw\",\"hix\",\"hji\",\"hka\",\"hke\",\"hkk\",\"hks\",\"hla\",\"hlb\",\"hld\",\"hle\",\"hlt\",\"hlu\",\"hma\",\"hmb\",\"hmc\",\"hmd\",\"hme\",\"hmf\",\"hmg\",\"hmh\",\"hmi\",\"hmj\",\"hmk\",\"hml\",\"hmm\",\"hmn\",\"hmp\",\"hmq\",\"hmr\",\"hms\",\"hmt\",\"hmu\",\"hmv\",\"hmw\",\"hmx\",\"hmy\",\"hmz\",\"hna\",\"hnd\",\"hne\",\"hnh\",\"hni\",\"hnj\",\"hnn\",\"hno\",\"hns\",\"hnu\",\"hoa\",\"hob\",\"hoc\",\"hod\",\"hoe\",\"hoh\",\"hoi\",\"hoj\",\"hok\",\"hol\",\"hom\",\"hoo\",\"hop\",\"hor\",\"hos\",\"hot\",\"hov\",\"how\",\"hoy\",\"hoz\",\"hpo\",\"hps\",\"hra\",\"hrc\",\"hre\",\"hrk\",\"hrm\",\"hro\",\"hrp\",\"hrr\",\"hrt\",\"hru\",\"hrw\",\"hrx\",\"hrz\",\"hsb\",\"hsh\",\"hsl\",\"hsn\",\"hss\",\"hti\",\"hto\",\"hts\",\"htu\",\"htx\",\"hub\",\"huc\",\"hud\",\"hue\",\"huf\",\"hug\",\"huh\",\"hui\",\"huj\",\"huk\",\"hul\",\"hum\",\"huo\",\"hup\",\"huq\",\"hur\",\"hus\",\"hut\",\"huu\",\"huv\",\"huw\",\"hux\",\"huy\",\"huz\",\"hvc\",\"hve\",\"hvk\",\"hvn\",\"hvv\",\"hwa\",\"hwc\",\"hwo\",\"hya\",\"hyx\",\"iai\",\"ian\",\"iap\",\"iar\",\"iba\",\"ibb\",\"ibd\",\"ibe\",\"ibg\",\"ibh\",\"ibi\",\"ibl\",\"ibm\",\"ibn\",\"ibr\",\"ibu\",\"iby\",\"ica\",\"ich\",\"icl\",\"icr\",\"ida\",\"idb\",\"idc\",\"idd\",\"ide\",\"idi\",\"idr\",\"ids\",\"idt\",\"idu\",\"ifa\",\"ifb\",\"ife\",\"iff\",\"ifk\",\"ifm\",\"ifu\",\"ify\",\"igb\",\"ige\",\"igg\",\"igl\",\"igm\",\"ign\",\"igo\",\"igs\",\"igw\",\"ihb\",\"ihi\",\"ihp\",\"ihw\",\"iin\",\"iir\",\"ijc\",\"ije\",\"ijj\",\"ijn\",\"ijo\",\"ijs\",\"ike\",\"iki\",\"ikk\",\"ikl\",\"iko\",\"ikp\",\"ikr\",\"iks\",\"ikt\",\"ikv\",\"ikw\",\"ikx\",\"ikz\",\"ila\",\"ilb\",\"ilg\",\"ili\",\"ilk\",\"ill\",\"ilm\",\"ilo\",\"ilp\",\"ils\",\"ilu\",\"ilv\",\"ilw\",\"ima\",\"ime\",\"imi\",\"iml\",\"imn\",\"imo\",\"imr\",\"ims\",\"imy\",\"inb\",\"inc\",\"ine\",\"ing\",\"inh\",\"inj\",\"inl\",\"inm\",\"inn\",\"ino\",\"inp\",\"ins\",\"int\",\"inz\",\"ior\",\"iou\",\"iow\",\"ipi\",\"ipo\",\"iqu\",\"iqw\",\"ira\",\"ire\",\"irh\",\"iri\",\"irk\",\"irn\",\"iro\",\"irr\",\"iru\",\"irx\",\"iry\",\"isa\",\"isc\",\"isd\",\"ise\",\"isg\",\"ish\",\"isi\",\"isk\",\"ism\",\"isn\",\"iso\",\"isr\",\"ist\",\"isu\",\"itb\",\"itc\",\"itd\",\"ite\",\"iti\",\"itk\",\"itl\",\"itm\",\"ito\",\"itr\",\"its\",\"itt\",\"itv\",\"itw\",\"itx\",\"ity\",\"itz\",\"ium\",\"ivb\",\"ivv\",\"iwk\",\"iwm\",\"iwo\",\"iws\",\"ixc\",\"ixl\",\"iya\",\"iyo\",\"iyx\",\"izh\",\"izi\",\"izr\",\"izz\",\"jaa\",\"jab\",\"jac\",\"jad\",\"jae\",\"jaf\",\"jah\",\"jaj\",\"jak\",\"jal\",\"jam\",\"jan\",\"jao\",\"jaq\",\"jar\",\"jas\",\"jat\",\"jau\",\"jax\",\"jay\",\"jaz\",\"jbe\",\"jbi\",\"jbj\",\"jbk\",\"jbn\",\"jbo\",\"jbr\",\"jbt\",\"jbu\",\"jbw\",\"jcs\",\"jct\",\"jda\",\"jdg\",\"jdt\",\"jeb\",\"jee\",\"jeg\",\"jeh\",\"jei\",\"jek\",\"jel\",\"jen\",\"jer\",\"jet\",\"jeu\",\"jgb\",\"jge\",\"jgk\",\"jgo\",\"jhi\",\"jhs\",\"jia\",\"jib\",\"jic\",\"jid\",\"jie\",\"jig\",\"jih\",\"jii\",\"jil\",\"jim\",\"jio\",\"jiq\",\"jit\",\"jiu\",\"jiv\",\"jiy\",\"jje\",\"jjr\",\"jka\",\"jkm\",\"jko\",\"jkp\",\"jkr\",\"jku\",\"jle\",\"jls\",\"jma\",\"jmb\",\"jmc\",\"jmd\",\"jmi\",\"jml\",\"jmn\",\"jmr\",\"jms\",\"jmw\",\"jmx\",\"jna\",\"jnd\",\"jng\",\"jni\",\"jnj\",\"jnl\",\"jns\",\"job\",\"jod\",\"jog\",\"jor\",\"jos\",\"jow\",\"jpa\",\"jpr\",\"jpx\",\"jqr\",\"jra\",\"jrb\",\"jrr\",\"jrt\",\"jru\",\"jsl\",\"jua\",\"jub\",\"juc\",\"jud\",\"juh\",\"jui\",\"juk\",\"jul\",\"jum\",\"jun\",\"juo\",\"jup\",\"jur\",\"jus\",\"jut\",\"juu\",\"juw\",\"juy\",\"jvd\",\"jvn\",\"jwi\",\"jya\",\"jye\",\"jyy\",\"kaa\",\"kab\",\"kac\",\"kad\",\"kae\",\"kaf\",\"kag\",\"kah\",\"kai\",\"kaj\",\"kak\",\"kam\",\"kao\",\"kap\",\"kaq\",\"kar\",\"kav\",\"kaw\",\"kax\",\"kay\",\"kba\",\"kbb\",\"kbc\",\"kbd\",\"kbe\",\"kbf\",\"kbg\",\"kbh\",\"kbi\",\"kbj\",\"kbk\",\"kbl\",\"kbm\",\"kbn\",\"kbo\",\"kbp\",\"kbq\",\"kbr\",\"kbs\",\"kbt\",\"kbu\",\"kbv\",\"kbw\",\"kbx\",\"kby\",\"kbz\",\"kca\",\"kcb\",\"kcc\",\"kcd\",\"kce\",\"kcf\",\"kcg\",\"kch\",\"kci\",\"kcj\",\"kck\",\"kcl\",\"kcm\",\"kcn\",\"kco\",\"kcp\",\"kcq\",\"kcr\",\"kcs\",\"kct\",\"kcu\",\"kcv\",\"kcw\",\"kcx\",\"kcy\",\"kcz\",\"kda\",\"kdc\",\"kdd\",\"kde\",\"kdf\",\"kdg\",\"kdh\",\"kdi\",\"kdj\",\"kdk\",\"kdl\",\"kdm\",\"kdn\",\"kdo\",\"kdp\",\"kdq\",\"kdr\",\"kdt\",\"kdu\",\"kdv\",\"kdw\",\"kdx\",\"kdy\",\"kdz\",\"kea\",\"keb\",\"kec\",\"ked\",\"kee\",\"kef\",\"keg\",\"keh\",\"kei\",\"kej\",\"kek\",\"kel\",\"kem\",\"ken\",\"keo\",\"kep\",\"keq\",\"ker\",\"kes\",\"ket\",\"keu\",\"kev\",\"kew\",\"kex\",\"key\",\"kez\",\"kfa\",\"kfb\",\"kfc\",\"kfd\",\"kfe\",\"kff\",\"kfg\",\"kfh\",\"kfi\",\"kfj\",\"kfk\",\"kfl\",\"kfm\",\"kfn\",\"kfo\",\"kfp\",\"kfq\",\"kfr\",\"kfs\",\"kft\",\"kfu\",\"kfv\",\"kfw\",\"kfx\",\"kfy\",\"kfz\",\"kga\",\"kgb\",\"kgc\",\"kgd\",\"kge\",\"kgf\",\"kgg\",\"kgh\",\"kgi\",\"kgj\",\"kgk\",\"kgl\",\"kgm\",\"kgn\",\"kgo\",\"kgp\",\"kgq\",\"kgr\",\"kgs\",\"kgt\",\"kgu\",\"kgv\",\"kgw\",\"kgx\",\"kgy\",\"kha\",\"khb\",\"khc\",\"khd\",\"khe\",\"khf\",\"khg\",\"khh\",\"khi\",\"khj\",\"khk\",\"khl\",\"khn\",\"kho\",\"khp\",\"khq\",\"khr\",\"khs\",\"kht\",\"khu\",\"khv\",\"khw\",\"khx\",\"khy\",\"khz\",\"kia\",\"kib\",\"kic\",\"kid\",\"kie\",\"kif\",\"kig\",\"kih\",\"kii\",\"kij\",\"kil\",\"kim\",\"kio\",\"kip\",\"kiq\",\"kis\",\"kit\",\"kiu\",\"kiv\",\"kiw\",\"kix\",\"kiy\",\"kiz\",\"kja\",\"kjb\",\"kjc\",\"kjd\",\"kje\",\"kjf\",\"kjg\",\"kjh\",\"kji\",\"kjj\",\"kjk\",\"kjl\",\"kjm\",\"kjn\",\"kjo\",\"kjp\",\"kjq\",\"kjr\",\"kjs\",\"kjt\",\"kju\",\"kjv\",\"kjx\",\"kjy\",\"kjz\",\"kka\",\"kkb\",\"kkc\",\"kkd\",\"kke\",\"kkf\",\"kkg\",\"kkh\",\"kki\",\"kkj\",\"kkk\",\"kkl\",\"kkm\",\"kkn\",\"kko\",\"kkp\",\"kkq\",\"kkr\",\"kks\",\"kkt\",\"kku\",\"kkv\",\"kkw\",\"kkx\",\"kky\",\"kkz\",\"kla\",\"klb\",\"klc\",\"kld\",\"kle\",\"klf\",\"klg\",\"klh\",\"kli\",\"klj\",\"klk\",\"kll\",\"klm\",\"kln\",\"klo\",\"klp\",\"klq\",\"klr\",\"kls\",\"klt\",\"klu\",\"klv\",\"klw\",\"klx\",\"kly\",\"klz\",\"kma\",\"kmb\",\"kmc\",\"kmd\",\"kme\",\"kmf\",\"kmg\",\"kmh\",\"kmi\",\"kmj\",\"kmk\",\"kml\",\"kmm\",\"kmn\",\"kmo\",\"kmp\",\"kmq\",\"kmr\",\"kms\",\"kmt\",\"kmu\",\"kmv\",\"kmw\",\"kmx\",\"kmy\",\"kmz\",\"kna\",\"knb\",\"knc\",\"knd\",\"kne\",\"knf\",\"kng\",\"kni\",\"knj\",\"knk\",\"knl\",\"knm\",\"knn\",\"kno\",\"knp\",\"knq\",\"knr\",\"kns\",\"knt\",\"knu\",\"knv\",\"knw\",\"knx\",\"kny\",\"knz\",\"koa\",\"koc\",\"kod\",\"koe\",\"kof\",\"kog\",\"koh\",\"koi\",\"koj\",\"kok\",\"kol\",\"koo\",\"kop\",\"koq\",\"kos\",\"kot\",\"kou\",\"kov\",\"kow\",\"kox\",\"koy\",\"koz\",\"kpa\",\"kpb\",\"kpc\",\"kpd\",\"kpe\",\"kpf\",\"kpg\",\"kph\",\"kpi\",\"kpj\",\"kpk\",\"kpl\",\"kpm\",\"kpn\",\"kpo\",\"kpp\",\"kpq\",\"kpr\",\"kps\",\"kpt\",\"kpu\",\"kpv\",\"kpw\",\"kpx\",\"kpy\",\"kpz\",\"kqa\",\"kqb\",\"kqc\",\"kqd\",\"kqe\",\"kqf\",\"kqg\",\"kqh\",\"kqi\",\"kqj\",\"kqk\",\"kql\",\"kqm\",\"kqn\",\"kqo\",\"kqp\",\"kqq\",\"kqr\",\"kqs\",\"kqt\",\"kqu\",\"kqv\",\"kqw\",\"kqx\",\"kqy\",\"kqz\",\"kra\",\"krb\",\"krc\",\"krd\",\"kre\",\"krf\",\"krh\",\"kri\",\"krj\",\"krk\",\"krl\",\"krm\",\"krn\",\"kro\",\"krp\",\"krr\",\"krs\",\"krt\",\"kru\",\"krv\",\"krw\",\"krx\",\"kry\",\"krz\",\"ksa\",\"ksb\",\"ksc\",\"ksd\",\"kse\",\"ksf\",\"ksg\",\"ksh\",\"ksi\",\"ksj\",\"ksk\",\"ksl\",\"ksm\",\"ksn\",\"kso\",\"ksp\",\"ksq\",\"ksr\",\"kss\",\"kst\",\"ksu\",\"ksv\",\"ksw\",\"ksx\",\"ksy\",\"ksz\",\"kta\",\"ktb\",\"ktc\",\"ktd\",\"kte\",\"ktf\",\"ktg\",\"kth\",\"kti\",\"ktj\",\"ktk\",\"ktl\",\"ktm\",\"ktn\",\"kto\",\"ktp\",\"ktq\",\"ktr\",\"kts\",\"ktt\",\"ktu\",\"ktv\",\"ktw\",\"ktx\",\"kty\",\"ktz\",\"kub\",\"kuc\",\"kud\",\"kue\",\"kuf\",\"kug\",\"kuh\",\"kui\",\"kuj\",\"kuk\",\"kul\",\"kum\",\"kun\",\"kuo\",\"kup\",\"kuq\",\"kus\",\"kut\",\"kuu\",\"kuv\",\"kuw\",\"kux\",\"kuy\",\"kuz\",\"kva\",\"kvb\",\"kvc\",\"kvd\",\"kve\",\"kvf\",\"kvg\",\"kvh\",\"kvi\",\"kvj\",\"kvk\",\"kvl\",\"kvm\",\"kvn\",\"kvo\",\"kvp\",\"kvq\",\"kvr\",\"kvs\",\"kvt\",\"kvu\",\"kvv\",\"kvw\",\"kvx\",\"kvy\",\"kvz\",\"kwa\",\"kwb\",\"kwc\",\"kwd\",\"kwe\",\"kwf\",\"kwg\",\"kwh\",\"kwi\",\"kwj\",\"kwk\",\"kwl\",\"kwm\",\"kwn\",\"kwo\",\"kwp\",\"kwq\",\"kwr\",\"kws\",\"kwt\",\"kwu\",\"kwv\",\"kww\",\"kwx\",\"kwy\",\"kwz\",\"kxa\",\"kxb\",\"kxc\",\"kxd\",\"kxe\",\"kxf\",\"kxh\",\"kxi\",\"kxj\",\"kxk\",\"kxl\",\"kxm\",\"kxn\",\"kxo\",\"kxp\",\"kxq\",\"kxr\",\"kxs\",\"kxt\",\"kxu\",\"kxv\",\"kxw\",\"kxx\",\"kxy\",\"kxz\",\"kya\",\"kyb\",\"kyc\",\"kyd\",\"kye\",\"kyf\",\"kyg\",\"kyh\",\"kyi\",\"kyj\",\"kyk\",\"kyl\",\"kym\",\"kyn\",\"kyo\",\"kyp\",\"kyq\",\"kyr\",\"kys\",\"kyt\",\"kyu\",\"kyv\",\"kyw\",\"kyx\",\"kyy\",\"kyz\",\"kza\",\"kzb\",\"kzc\",\"kzd\",\"kze\",\"kzf\",\"kzg\",\"kzh\",\"kzi\",\"kzj\",\"kzk\",\"kzl\",\"kzm\",\"kzn\",\"kzo\",\"kzp\",\"kzq\",\"kzr\",\"kzs\",\"kzt\",\"kzu\",\"kzv\",\"kzw\",\"kzx\",\"kzy\",\"kzz\",\"laa\",\"lab\",\"lac\",\"lad\",\"lae\",\"laf\",\"lag\",\"lah\",\"lai\",\"laj\",\"lak\",\"lal\",\"lam\",\"lan\",\"lap\",\"laq\",\"lar\",\"las\",\"lau\",\"law\",\"lax\",\"lay\",\"laz\",\"lba\",\"lbb\",\"lbc\",\"lbe\",\"lbf\",\"lbg\",\"lbi\",\"lbj\",\"lbk\",\"lbl\",\"lbm\",\"lbn\",\"lbo\",\"lbq\",\"lbr\",\"lbs\",\"lbt\",\"lbu\",\"lbv\",\"lbw\",\"lbx\",\"lby\",\"lbz\",\"lcc\",\"lcd\",\"lce\",\"lcf\",\"lch\",\"lcl\",\"lcm\",\"lcp\",\"lcq\",\"lcs\",\"lda\",\"ldb\",\"ldd\",\"ldg\",\"ldh\",\"ldi\",\"ldj\",\"ldk\",\"ldl\",\"ldm\",\"ldn\",\"ldo\",\"ldp\",\"ldq\",\"lea\",\"leb\",\"lec\",\"led\",\"lee\",\"lef\",\"leg\",\"leh\",\"lei\",\"lej\",\"lek\",\"lel\",\"lem\",\"len\",\"leo\",\"lep\",\"leq\",\"ler\",\"les\",\"let\",\"leu\",\"lev\",\"lew\",\"lex\",\"ley\",\"lez\",\"lfa\",\"lfn\",\"lga\",\"lgb\",\"lgg\",\"lgh\",\"lgi\",\"lgk\",\"lgl\",\"lgm\",\"lgn\",\"lgq\",\"lgr\",\"lgt\",\"lgu\",\"lgz\",\"lha\",\"lhh\",\"lhi\",\"lhl\",\"lhm\",\"lhn\",\"lhp\",\"lhs\",\"lht\",\"lhu\",\"lia\",\"lib\",\"lic\",\"lid\",\"lie\",\"lif\",\"lig\",\"lih\",\"lii\",\"lij\",\"lik\",\"lil\",\"lio\",\"lip\",\"liq\",\"lir\",\"lis\",\"liu\",\"liv\",\"liw\",\"lix\",\"liy\",\"liz\",\"lja\",\"lje\",\"lji\",\"ljl\",\"ljp\",\"ljw\",\"ljx\",\"lka\",\"lkb\",\"lkc\",\"lkd\",\"lke\",\"lkh\",\"lki\",\"lkj\",\"lkl\",\"lkm\",\"lkn\",\"lko\",\"lkr\",\"lks\",\"lkt\",\"lku\",\"lky\",\"lla\",\"llb\",\"llc\",\"lld\",\"lle\",\"llf\",\"llg\",\"llh\",\"lli\",\"llj\",\"llk\",\"lll\",\"llm\",\"lln\",\"llo\",\"llp\",\"llq\",\"lls\",\"llu\",\"llx\",\"lma\",\"lmb\",\"lmc\",\"lmd\",\"lme\",\"lmf\",\"lmg\",\"lmh\",\"lmi\",\"lmj\",\"lmk\",\"lml\",\"lmm\",\"lmn\",\"lmo\",\"lmp\",\"lmq\",\"lmr\",\"lmu\",\"lmv\",\"lmw\",\"lmx\",\"lmy\",\"lmz\",\"lna\",\"lnb\",\"lnd\",\"lng\",\"lnh\",\"lni\",\"lnj\",\"lnl\",\"lnm\",\"lnn\",\"lno\",\"lns\",\"lnu\",\"lnw\",\"lnz\",\"loa\",\"lob\",\"loc\",\"loe\",\"lof\",\"log\",\"loh\",\"loi\",\"loj\",\"lok\",\"lol\",\"lom\",\"lon\",\"loo\",\"lop\",\"loq\",\"lor\",\"los\",\"lot\",\"lou\",\"lov\",\"low\",\"lox\",\"loy\",\"loz\",\"lpa\",\"lpe\",\"lpn\",\"lpo\",\"lpx\",\"lra\",\"lrc\",\"lre\",\"lrg\",\"lri\",\"lrk\",\"lrl\",\"lrm\",\"lrn\",\"lro\",\"lrr\",\"lrt\",\"lrv\",\"lrz\",\"lsa\",\"lsd\",\"lse\",\"lsg\",\"lsh\",\"lsi\",\"lsl\",\"lsm\",\"lso\",\"lsp\",\"lsr\",\"lss\",\"lst\",\"lsy\",\"ltc\",\"ltg\",\"lth\",\"lti\",\"ltn\",\"lto\",\"lts\",\"ltu\",\"lua\",\"luc\",\"lud\",\"lue\",\"luf\",\"lui\",\"luj\",\"luk\",\"lul\",\"lum\",\"lun\",\"luo\",\"lup\",\"luq\",\"lur\",\"lus\",\"lut\",\"luu\",\"luv\",\"luw\",\"luy\",\"luz\",\"lva\",\"lvk\",\"lvs\",\"lvu\",\"lwa\",\"lwe\",\"lwg\",\"lwh\",\"lwl\",\"lwm\",\"lwo\",\"lwt\",\"lwu\",\"lww\",\"lya\",\"lyg\",\"lyn\",\"lzh\",\"lzl\",\"lzn\",\"lzz\",\"maa\",\"mab\",\"mad\",\"mae\",\"maf\",\"mag\",\"mai\",\"maj\",\"mak\",\"mam\",\"man\",\"map\",\"maq\",\"mas\",\"mat\",\"mau\",\"mav\",\"maw\",\"max\",\"maz\",\"mba\",\"mbb\",\"mbc\",\"mbd\",\"mbe\",\"mbf\",\"mbh\",\"mbi\",\"mbj\",\"mbk\",\"mbl\",\"mbm\",\"mbn\",\"mbo\",\"mbp\",\"mbq\",\"mbr\",\"mbs\",\"mbt\",\"mbu\",\"mbv\",\"mbw\",\"mbx\",\"mby\",\"mbz\",\"mca\",\"mcb\",\"mcc\",\"mcd\",\"mce\",\"mcf\",\"mcg\",\"mch\",\"mci\",\"mcj\",\"mck\",\"mcl\",\"mcm\",\"mcn\",\"mco\",\"mcp\",\"mcq\",\"mcr\",\"mcs\",\"mct\",\"mcu\",\"mcv\",\"mcw\",\"mcx\",\"mcy\",\"mcz\",\"mda\",\"mdb\",\"mdc\",\"mdd\",\"mde\",\"mdf\",\"mdg\",\"mdh\",\"mdi\",\"mdj\",\"mdk\",\"mdl\",\"mdm\",\"mdn\",\"mdp\",\"mdq\",\"mdr\",\"mds\",\"mdt\",\"mdu\",\"mdv\",\"mdw\",\"mdx\",\"mdy\",\"mdz\",\"mea\",\"meb\",\"mec\",\"med\",\"mee\",\"mef\",\"meg\",\"meh\",\"mei\",\"mej\",\"mek\",\"mel\",\"mem\",\"men\",\"meo\",\"mep\",\"meq\",\"mer\",\"mes\",\"met\",\"meu\",\"mev\",\"mew\",\"mey\",\"mez\",\"mfa\",\"mfb\",\"mfc\",\"mfd\",\"mfe\",\"mff\",\"mfg\",\"mfh\",\"mfi\",\"mfj\",\"mfk\",\"mfl\",\"mfm\",\"mfn\",\"mfo\",\"mfp\",\"mfq\",\"mfr\",\"mfs\",\"mft\",\"mfu\",\"mfv\",\"mfw\",\"mfx\",\"mfy\",\"mfz\",\"mga\",\"mgb\",\"mgc\",\"mgd\",\"mge\",\"mgf\",\"mgg\",\"mgh\",\"mgi\",\"mgj\",\"mgk\",\"mgl\",\"mgm\",\"mgn\",\"mgo\",\"mgp\",\"mgq\",\"mgr\",\"mgs\",\"mgt\",\"mgu\",\"mgv\",\"mgw\",\"mgx\",\"mgy\",\"mgz\",\"mha\",\"mhb\",\"mhc\",\"mhd\",\"mhe\",\"mhf\",\"mhg\",\"mhh\",\"mhi\",\"mhj\",\"mhk\",\"mhl\",\"mhm\",\"mhn\",\"mho\",\"mhp\",\"mhq\",\"mhr\",\"mhs\",\"mht\",\"mhu\",\"mhw\",\"mhx\",\"mhy\",\"mhz\",\"mia\",\"mib\",\"mic\",\"mid\",\"mie\",\"mif\",\"mig\",\"mih\",\"mii\",\"mij\",\"mik\",\"mil\",\"mim\",\"min\",\"mio\",\"mip\",\"miq\",\"mir\",\"mis\",\"mit\",\"miu\",\"miw\",\"mix\",\"miy\",\"miz\",\"mja\",\"mjb\",\"mjc\",\"mjd\",\"mje\",\"mjg\",\"mjh\",\"mji\",\"mjj\",\"mjk\",\"mjl\",\"mjm\",\"mjn\",\"mjo\",\"mjp\",\"mjq\",\"mjr\",\"mjs\",\"mjt\",\"mju\",\"mjv\",\"mjw\",\"mjx\",\"mjy\",\"mjz\",\"mka\",\"mkb\",\"mkc\",\"mke\",\"mkf\",\"mkg\",\"mkh\",\"mki\",\"mkj\",\"mkk\",\"mkl\",\"mkm\",\"mkn\",\"mko\",\"mkp\",\"mkq\",\"mkr\",\"mks\",\"mkt\",\"mku\",\"mkv\",\"mkw\",\"mkx\",\"mky\",\"mkz\",\"mla\",\"mlb\",\"mlc\",\"mld\",\"mle\",\"mlf\",\"mlh\",\"mli\",\"mlj\",\"mlk\",\"mll\",\"mlm\",\"mln\",\"mlo\",\"mlp\",\"mlq\",\"mlr\",\"mls\",\"mlu\",\"mlv\",\"mlw\",\"mlx\",\"mlz\",\"mma\",\"mmb\",\"mmc\",\"mmd\",\"mme\",\"mmf\",\"mmg\",\"mmh\",\"mmi\",\"mmj\",\"mmk\",\"mml\",\"mmm\",\"mmn\",\"mmo\",\"mmp\",\"mmq\",\"mmr\",\"mmt\",\"mmu\",\"mmv\",\"mmw\",\"mmx\",\"mmy\",\"mmz\",\"mna\",\"mnb\",\"mnc\",\"mnd\",\"mne\",\"mnf\",\"mng\",\"mnh\",\"mni\",\"mnj\",\"mnk\",\"mnl\",\"mnm\",\"mnn\",\"mno\",\"mnp\",\"mnq\",\"mnr\",\"mns\",\"mnt\",\"mnu\",\"mnv\",\"mnw\",\"mnx\",\"mny\",\"mnz\",\"moa\",\"moc\",\"mod\",\"moe\",\"mof\",\"mog\",\"moh\",\"moi\",\"moj\",\"mok\",\"mom\",\"moo\",\"mop\",\"moq\",\"mor\",\"mos\",\"mot\",\"mou\",\"mov\",\"mow\",\"mox\",\"moy\",\"moz\",\"mpa\",\"mpb\",\"mpc\",\"mpd\",\"mpe\",\"mpg\",\"mph\",\"mpi\",\"mpj\",\"mpk\",\"mpl\",\"mpm\",\"mpn\",\"mpo\",\"mpp\",\"mpq\",\"mpr\",\"mps\",\"mpt\",\"mpu\",\"mpv\",\"mpw\",\"mpx\",\"mpy\",\"mpz\",\"mqa\",\"mqb\",\"mqc\",\"mqe\",\"mqf\",\"mqg\",\"mqh\",\"mqi\",\"mqj\",\"mqk\",\"mql\",\"mqm\",\"mqn\",\"mqo\",\"mqp\",\"mqq\",\"mqr\",\"mqs\",\"mqt\",\"mqu\",\"mqv\",\"mqw\",\"mqx\",\"mqy\",\"mqz\",\"mra\",\"mrb\",\"mrc\",\"mrd\",\"mre\",\"mrf\",\"mrg\",\"mrh\",\"mrj\",\"mrk\",\"mrl\",\"mrm\",\"mrn\",\"mro\",\"mrp\",\"mrq\",\"mrr\",\"mrs\",\"mrt\",\"mru\",\"mrv\",\"mrw\",\"mrx\",\"mry\",\"mrz\",\"msb\",\"msc\",\"msd\",\"mse\",\"msf\",\"msg\",\"msh\",\"msi\",\"msj\",\"msk\",\"msl\",\"msm\",\"msn\",\"mso\",\"msp\",\"msq\",\"msr\",\"mss\",\"mst\",\"msu\",\"msv\",\"msw\",\"msx\",\"msy\",\"msz\",\"mta\",\"mtb\",\"mtc\",\"mtd\",\"mte\",\"mtf\",\"mtg\",\"mth\",\"mti\",\"mtj\",\"mtk\",\"mtl\",\"mtm\",\"mtn\",\"mto\",\"mtp\",\"mtq\",\"mtr\",\"mts\",\"mtt\",\"mtu\",\"mtv\",\"mtw\",\"mtx\",\"mty\",\"mua\",\"mub\",\"muc\",\"mud\",\"mue\",\"mug\",\"muh\",\"mui\",\"muj\",\"muk\",\"mul\",\"mum\",\"mun\",\"muo\",\"mup\",\"muq\",\"mur\",\"mus\",\"mut\",\"muu\",\"muv\",\"mux\",\"muy\",\"muz\",\"mva\",\"mvb\",\"mvd\",\"mve\",\"mvf\",\"mvg\",\"mvh\",\"mvi\",\"mvk\",\"mvl\",\"mvm\",\"mvn\",\"mvo\",\"mvp\",\"mvq\",\"mvr\",\"mvs\",\"mvt\",\"mvu\",\"mvv\",\"mvw\",\"mvx\",\"mvy\",\"mvz\",\"mwa\",\"mwb\",\"mwc\",\"mwd\",\"mwe\",\"mwf\",\"mwg\",\"mwh\",\"mwi\",\"mwj\",\"mwk\",\"mwl\",\"mwm\",\"mwn\",\"mwo\",\"mwp\",\"mwq\",\"mwr\",\"mws\",\"mwt\",\"mwu\",\"mwv\",\"mww\",\"mwx\",\"mwy\",\"mwz\",\"mxa\",\"mxb\",\"mxc\",\"mxd\",\"mxe\",\"mxf\",\"mxg\",\"mxh\",\"mxi\",\"mxj\",\"mxk\",\"mxl\",\"mxm\",\"mxn\",\"mxo\",\"mxp\",\"mxq\",\"mxr\",\"mxs\",\"mxt\",\"mxu\",\"mxv\",\"mxw\",\"mxx\",\"mxy\",\"mxz\",\"myb\",\"myc\",\"myd\",\"mye\",\"myf\",\"myg\",\"myh\",\"myi\",\"myj\",\"myk\",\"myl\",\"mym\",\"myn\",\"myo\",\"myp\",\"myq\",\"myr\",\"mys\",\"myt\",\"myu\",\"myv\",\"myw\",\"myx\",\"myy\",\"myz\",\"mza\",\"mzb\",\"mzc\",\"mzd\",\"mze\",\"mzg\",\"mzh\",\"mzi\",\"mzj\",\"mzk\",\"mzl\",\"mzm\",\"mzn\",\"mzo\",\"mzp\",\"mzq\",\"mzr\",\"mzs\",\"mzt\",\"mzu\",\"mzv\",\"mzw\",\"mzx\",\"mzy\",\"mzz\",\"naa\",\"nab\",\"nac\",\"nad\",\"nae\",\"naf\",\"nag\",\"nah\",\"nai\",\"naj\",\"nak\",\"nal\",\"nam\",\"nan\",\"nao\",\"nap\",\"naq\",\"nar\",\"nas\",\"nat\",\"naw\",\"nax\",\"nay\",\"naz\",\"nba\",\"nbb\",\"nbc\",\"nbd\",\"nbe\",\"nbf\",\"nbg\",\"nbh\",\"nbi\",\"nbj\",\"nbk\",\"nbm\",\"nbn\",\"nbo\",\"nbp\",\"nbq\",\"nbr\",\"nbs\",\"nbt\",\"nbu\",\"nbv\",\"nbw\",\"nbx\",\"nby\",\"nca\",\"ncb\",\"ncc\",\"ncd\",\"nce\",\"ncf\",\"ncg\",\"nch\",\"nci\",\"ncj\",\"nck\",\"ncl\",\"ncm\",\"ncn\",\"nco\",\"ncp\",\"ncq\",\"ncr\",\"ncs\",\"nct\",\"ncu\",\"ncx\",\"ncz\",\"nda\",\"ndb\",\"ndc\",\"ndd\",\"ndf\",\"ndg\",\"ndh\",\"ndi\",\"ndj\",\"ndk\",\"ndl\",\"ndm\",\"ndn\",\"ndp\",\"ndq\",\"ndr\",\"nds\",\"ndt\",\"ndu\",\"ndv\",\"ndw\",\"ndx\",\"ndy\",\"ndz\",\"nea\",\"neb\",\"nec\",\"ned\",\"nee\",\"nef\",\"neg\",\"neh\",\"nei\",\"nej\",\"nek\",\"nem\",\"nen\",\"neo\",\"neq\",\"ner\",\"nes\",\"net\",\"neu\",\"nev\",\"new\",\"nex\",\"ney\",\"nez\",\"nfa\",\"nfd\",\"nfl\",\"nfr\",\"nfu\",\"nga\",\"ngb\",\"ngc\",\"ngd\",\"nge\",\"ngf\",\"ngg\",\"ngh\",\"ngi\",\"ngj\",\"ngk\",\"ngl\",\"ngm\",\"ngn\",\"ngo\",\"ngp\",\"ngq\",\"ngr\",\"ngs\",\"ngt\",\"ngu\",\"ngv\",\"ngw\",\"ngx\",\"ngy\",\"ngz\",\"nha\",\"nhb\",\"nhc\",\"nhd\",\"nhe\",\"nhf\",\"nhg\",\"nhh\",\"nhi\",\"nhk\",\"nhm\",\"nhn\",\"nho\",\"nhp\",\"nhq\",\"nhr\",\"nht\",\"nhu\",\"nhv\",\"nhw\",\"nhx\",\"nhy\",\"nhz\",\"nia\",\"nib\",\"nic\",\"nid\",\"nie\",\"nif\",\"nig\",\"nih\",\"nii\",\"nij\",\"nik\",\"nil\",\"nim\",\"nin\",\"nio\",\"niq\",\"nir\",\"nis\",\"nit\",\"niu\",\"niv\",\"niw\",\"nix\",\"niy\",\"niz\",\"nja\",\"njb\",\"njd\",\"njh\",\"nji\",\"njj\",\"njl\",\"njm\",\"njn\",\"njo\",\"njr\",\"njs\",\"njt\",\"nju\",\"njx\",\"njy\",\"njz\",\"nka\",\"nkb\",\"nkc\",\"nkd\",\"nke\",\"nkf\",\"nkg\",\"nkh\",\"nki\",\"nkj\",\"nkk\",\"nkm\",\"nkn\",\"nko\",\"nkp\",\"nkq\",\"nkr\",\"nks\",\"nkt\",\"nku\",\"nkv\",\"nkw\",\"nkx\",\"nkz\",\"nla\",\"nlc\",\"nle\",\"nlg\",\"nli\",\"nlj\",\"nlk\",\"nll\",\"nln\",\"nlo\",\"nlq\",\"nlr\",\"nlu\",\"nlv\",\"nlw\",\"nlx\",\"nly\",\"nlz\",\"nma\",\"nmb\",\"nmc\",\"nmd\",\"nme\",\"nmf\",\"nmg\",\"nmh\",\"nmi\",\"nmj\",\"nmk\",\"nml\",\"nmm\",\"nmn\",\"nmo\",\"nmp\",\"nmq\",\"nmr\",\"nms\",\"nmt\",\"nmu\",\"nmv\",\"nmw\",\"nmx\",\"nmy\",\"nmz\",\"nna\",\"nnb\",\"nnc\",\"nnd\",\"nne\",\"nnf\",\"nng\",\"nnh\",\"nni\",\"nnj\",\"nnk\",\"nnl\",\"nnm\",\"nnn\",\"nnp\",\"nnq\",\"nnr\",\"nns\",\"nnt\",\"nnu\",\"nnv\",\"nnw\",\"nnx\",\"nny\",\"nnz\",\"noa\",\"noc\",\"nod\",\"noe\",\"nof\",\"nog\",\"noh\",\"noi\",\"noj\",\"nok\",\"nol\",\"nom\",\"non\",\"noo\",\"nop\",\"noq\",\"nos\",\"not\",\"nou\",\"nov\",\"now\",\"noy\",\"noz\",\"npa\",\"npb\",\"npg\",\"nph\",\"npi\",\"npl\",\"npn\",\"npo\",\"nps\",\"npu\",\"npx\",\"npy\",\"nqg\",\"nqk\",\"nql\",\"nqm\",\"nqn\",\"nqo\",\"nqq\",\"nqy\",\"nra\",\"nrb\",\"nrc\",\"nre\",\"nrf\",\"nrg\",\"nri\",\"nrk\",\"nrl\",\"nrm\",\"nrn\",\"nrp\",\"nrr\",\"nrt\",\"nru\",\"nrx\",\"nrz\",\"nsa\",\"nsc\",\"nsd\",\"nse\",\"nsf\",\"nsg\",\"nsh\",\"nsi\",\"nsk\",\"nsl\",\"nsm\",\"nsn\",\"nso\",\"nsp\",\"nsq\",\"nsr\",\"nss\",\"nst\",\"nsu\",\"nsv\",\"nsw\",\"nsx\",\"nsy\",\"nsz\",\"ntd\",\"nte\",\"ntg\",\"nti\",\"ntj\",\"ntk\",\"ntm\",\"nto\",\"ntp\",\"ntr\",\"nts\",\"ntu\",\"ntw\",\"ntx\",\"nty\",\"ntz\",\"nua\",\"nub\",\"nuc\",\"nud\",\"nue\",\"nuf\",\"nug\",\"nuh\",\"nui\",\"nuj\",\"nuk\",\"nul\",\"num\",\"nun\",\"nuo\",\"nup\",\"nuq\",\"nur\",\"nus\",\"nut\",\"nuu\",\"nuv\",\"nuw\",\"nux\",\"nuy\",\"nuz\",\"nvh\",\"nvm\",\"nvo\",\"nwa\",\"nwb\",\"nwc\",\"nwe\",\"nwg\",\"nwi\",\"nwm\",\"nwo\",\"nwr\",\"nwx\",\"nwy\",\"nxa\",\"nxd\",\"nxe\",\"nxg\",\"nxi\",\"nxk\",\"nxl\",\"nxm\",\"nxn\",\"nxo\",\"nxq\",\"nxr\",\"nxu\",\"nxx\",\"nyb\",\"nyc\",\"nyd\",\"nye\",\"nyf\",\"nyg\",\"nyh\",\"nyi\",\"nyj\",\"nyk\",\"nyl\",\"nym\",\"nyn\",\"nyo\",\"nyp\",\"nyq\",\"nyr\",\"nys\",\"nyt\",\"nyu\",\"nyv\",\"nyw\",\"nyx\",\"nyy\",\"nza\",\"nzb\",\"nzi\",\"nzk\",\"nzm\",\"nzs\",\"nzu\",\"nzy\",\"nzz\",\"oaa\",\"oac\",\"oar\",\"oav\",\"obi\",\"obk\",\"obl\",\"obm\",\"obo\",\"obr\",\"obt\",\"obu\",\"oca\",\"och\",\"oco\",\"ocu\",\"oda\",\"odk\",\"odt\",\"odu\",\"ofo\",\"ofs\",\"ofu\",\"ogb\",\"ogc\",\"oge\",\"ogg\",\"ogo\",\"ogu\",\"oht\",\"ohu\",\"oia\",\"oin\",\"ojb\",\"ojc\",\"ojg\",\"ojp\",\"ojs\",\"ojv\",\"ojw\",\"oka\",\"okb\",\"okd\",\"oke\",\"okg\",\"okh\",\"oki\",\"okj\",\"okk\",\"okl\",\"okm\",\"okn\",\"oko\",\"okr\",\"oks\",\"oku\",\"okv\",\"okx\",\"ola\",\"old\",\"ole\",\"olk\",\"olm\",\"olo\",\"olr\",\"olt\",\"olu\",\"oma\",\"omb\",\"omc\",\"ome\",\"omg\",\"omi\",\"omk\",\"oml\",\"omn\",\"omo\",\"omp\",\"omq\",\"omr\",\"omt\",\"omu\",\"omv\",\"omw\",\"omx\",\"ona\",\"onb\",\"one\",\"ong\",\"oni\",\"onj\",\"onk\",\"onn\",\"ono\",\"onp\",\"onr\",\"ons\",\"ont\",\"onu\",\"onw\",\"onx\",\"ood\",\"oog\",\"oon\",\"oor\",\"oos\",\"opa\",\"opk\",\"opm\",\"opo\",\"opt\",\"opy\",\"ora\",\"orc\",\"ore\",\"org\",\"orh\",\"orn\",\"oro\",\"orr\",\"ors\",\"ort\",\"oru\",\"orv\",\"orw\",\"orx\",\"ory\",\"orz\",\"osa\",\"osc\",\"osi\",\"oso\",\"osp\",\"ost\",\"osu\",\"osx\",\"ota\",\"otb\",\"otd\",\"ote\",\"oti\",\"otk\",\"otl\",\"otm\",\"otn\",\"oto\",\"otq\",\"otr\",\"ots\",\"ott\",\"otu\",\"otw\",\"otx\",\"oty\",\"otz\",\"oua\",\"oub\",\"oue\",\"oui\",\"oum\",\"oun\",\"ovd\",\"owi\",\"owl\",\"oyb\",\"oyd\",\"oym\",\"oyy\",\"ozm\",\"paa\",\"pab\",\"pac\",\"pad\",\"pae\",\"paf\",\"pag\",\"pah\",\"pai\",\"pak\",\"pal\",\"pam\",\"pao\",\"pap\",\"paq\",\"par\",\"pas\",\"pat\",\"pau\",\"pav\",\"paw\",\"pax\",\"pay\",\"paz\",\"pbb\",\"pbc\",\"pbe\",\"pbf\",\"pbg\",\"pbh\",\"pbi\",\"pbl\",\"pbn\",\"pbo\",\"pbp\",\"pbr\",\"pbs\",\"pbt\",\"pbu\",\"pbv\",\"pby\",\"pbz\",\"pca\",\"pcb\",\"pcc\",\"pcd\",\"pce\",\"pcf\",\"pcg\",\"pch\",\"pci\",\"pcj\",\"pck\",\"pcl\",\"pcm\",\"pcn\",\"pcp\",\"pcr\",\"pcw\",\"pda\",\"pdc\",\"pdi\",\"pdn\",\"pdo\",\"pdt\",\"pdu\",\"pea\",\"peb\",\"ped\",\"pee\",\"pef\",\"peg\",\"peh\",\"pei\",\"pej\",\"pek\",\"pel\",\"pem\",\"peo\",\"pep\",\"peq\",\"pes\",\"pev\",\"pex\",\"pey\",\"pez\",\"pfa\",\"pfe\",\"pfl\",\"pga\",\"pgd\",\"pgg\",\"pgi\",\"pgk\",\"pgl\",\"pgn\",\"pgs\",\"pgu\",\"pgy\",\"pgz\",\"pha\",\"phd\",\"phg\",\"phh\",\"phi\",\"phk\",\"phl\",\"phm\",\"phn\",\"pho\",\"phq\",\"phr\",\"pht\",\"phu\",\"phv\",\"phw\",\"pia\",\"pib\",\"pic\",\"pid\",\"pie\",\"pif\",\"pig\",\"pih\",\"pii\",\"pij\",\"pil\",\"pim\",\"pin\",\"pio\",\"pip\",\"pir\",\"pis\",\"pit\",\"piu\",\"piv\",\"piw\",\"pix\",\"piy\",\"piz\",\"pjt\",\"pka\",\"pkb\",\"pkc\",\"pkg\",\"pkh\",\"pkn\",\"pko\",\"pkp\",\"pkr\",\"pks\",\"pkt\",\"pku\",\"pla\",\"plb\",\"plc\",\"pld\",\"ple\",\"plf\",\"plg\",\"plh\",\"plj\",\"plk\",\"pll\",\"pln\",\"plo\",\"plp\",\"plq\",\"plr\",\"pls\",\"plt\",\"plu\",\"plv\",\"plw\",\"ply\",\"plz\",\"pma\",\"pmb\",\"pmc\",\"pmd\",\"pme\",\"pmf\",\"pmh\",\"pmi\",\"pmj\",\"pmk\",\"pml\",\"pmm\",\"pmn\",\"pmo\",\"pmq\",\"pmr\",\"pms\",\"pmt\",\"pmu\",\"pmw\",\"pmx\",\"pmy\",\"pmz\",\"pna\",\"pnb\",\"pnc\",\"pne\",\"png\",\"pnh\",\"pni\",\"pnj\",\"pnk\",\"pnl\",\"pnm\",\"pnn\",\"pno\",\"pnp\",\"pnq\",\"pnr\",\"pns\",\"pnt\",\"pnu\",\"pnv\",\"pnw\",\"pnx\",\"pny\",\"pnz\",\"poc\",\"pod\",\"poe\",\"pof\",\"pog\",\"poh\",\"poi\",\"pok\",\"pom\",\"pon\",\"poo\",\"pop\",\"poq\",\"pos\",\"pot\",\"pov\",\"pow\",\"pox\",\"poy\",\"poz\",\"ppa\",\"ppe\",\"ppi\",\"ppk\",\"ppl\",\"ppm\",\"ppn\",\"ppo\",\"ppp\",\"ppq\",\"ppr\",\"pps\",\"ppt\",\"ppu\",\"pqa\",\"pqe\",\"pqm\",\"pqw\",\"pra\",\"prb\",\"prc\",\"prd\",\"pre\",\"prf\",\"prg\",\"prh\",\"pri\",\"prk\",\"prl\",\"prm\",\"prn\",\"pro\",\"prp\",\"prq\",\"prr\",\"prs\",\"prt\",\"pru\",\"prw\",\"prx\",\"pry\",\"prz\",\"psa\",\"psc\",\"psd\",\"pse\",\"psg\",\"psh\",\"psi\",\"psl\",\"psm\",\"psn\",\"pso\",\"psp\",\"psq\",\"psr\",\"pss\",\"pst\",\"psu\",\"psw\",\"psy\",\"pta\",\"pth\",\"pti\",\"ptn\",\"pto\",\"ptp\",\"ptq\",\"ptr\",\"ptt\",\"ptu\",\"ptv\",\"ptw\",\"pty\",\"pua\",\"pub\",\"puc\",\"pud\",\"pue\",\"puf\",\"pug\",\"pui\",\"puj\",\"puk\",\"pum\",\"puo\",\"pup\",\"puq\",\"pur\",\"put\",\"puu\",\"puw\",\"pux\",\"puy\",\"puz\",\"pwa\",\"pwb\",\"pwg\",\"pwi\",\"pwm\",\"pwn\",\"pwo\",\"pwr\",\"pww\",\"pxm\",\"pye\",\"pym\",\"pyn\",\"pys\",\"pyu\",\"pyx\",\"pyy\",\"pzn\",\"qaa..qtz\",\"qua\",\"qub\",\"quc\",\"qud\",\"quf\",\"qug\",\"quh\",\"qui\",\"quk\",\"qul\",\"qum\",\"qun\",\"qup\",\"quq\",\"qur\",\"qus\",\"quv\",\"quw\",\"qux\",\"quy\",\"quz\",\"qva\",\"qvc\",\"qve\",\"qvh\",\"qvi\",\"qvj\",\"qvl\",\"qvm\",\"qvn\",\"qvo\",\"qvp\",\"qvs\",\"qvw\",\"qvy\",\"qvz\",\"qwa\",\"qwc\",\"qwe\",\"qwh\",\"qwm\",\"qws\",\"qwt\",\"qxa\",\"qxc\",\"qxh\",\"qxl\",\"qxn\",\"qxo\",\"qxp\",\"qxq\",\"qxr\",\"qxs\",\"qxt\",\"qxu\",\"qxw\",\"qya\",\"qyp\",\"raa\",\"rab\",\"rac\",\"rad\",\"raf\",\"rag\",\"rah\",\"rai\",\"raj\",\"rak\",\"ral\",\"ram\",\"ran\",\"rao\",\"rap\",\"raq\",\"rar\",\"ras\",\"rat\",\"rau\",\"rav\",\"raw\",\"rax\",\"ray\",\"raz\",\"rbb\",\"rbk\",\"rbl\",\"rbp\",\"rcf\",\"rdb\",\"rea\",\"reb\",\"ree\",\"reg\",\"rei\",\"rej\",\"rel\",\"rem\",\"ren\",\"rer\",\"res\",\"ret\",\"rey\",\"rga\",\"rge\",\"rgk\",\"rgn\",\"rgr\",\"rgs\",\"rgu\",\"rhg\",\"rhp\",\"ria\",\"rie\",\"rif\",\"ril\",\"rim\",\"rin\",\"rir\",\"rit\",\"riu\",\"rjg\",\"rji\",\"rjs\",\"rka\",\"rkb\",\"rkh\",\"rki\",\"rkm\",\"rkt\",\"rkw\",\"rma\",\"rmb\",\"rmc\",\"rmd\",\"rme\",\"rmf\",\"rmg\",\"rmh\",\"rmi\",\"rmk\",\"rml\",\"rmm\",\"rmn\",\"rmo\",\"rmp\",\"rmq\",\"rmr\",\"rms\",\"rmt\",\"rmu\",\"rmv\",\"rmw\",\"rmx\",\"rmy\",\"rmz\",\"rna\",\"rnd\",\"rng\",\"rnl\",\"rnn\",\"rnp\",\"rnr\",\"rnw\",\"roa\",\"rob\",\"roc\",\"rod\",\"roe\",\"rof\",\"rog\",\"rol\",\"rom\",\"roo\",\"rop\",\"ror\",\"rou\",\"row\",\"rpn\",\"rpt\",\"rri\",\"rro\",\"rrt\",\"rsb\",\"rsi\",\"rsl\",\"rsm\",\"rtc\",\"rth\",\"rtm\",\"rts\",\"rtw\",\"rub\",\"ruc\",\"rue\",\"ruf\",\"rug\",\"ruh\",\"rui\",\"ruk\",\"ruo\",\"rup\",\"ruq\",\"rut\",\"ruu\",\"ruy\",\"ruz\",\"rwa\",\"rwk\",\"rwm\",\"rwo\",\"rwr\",\"rxd\",\"rxw\",\"ryn\",\"rys\",\"ryu\",\"rzh\",\"saa\",\"sab\",\"sac\",\"sad\",\"sae\",\"saf\",\"sah\",\"sai\",\"saj\",\"sak\",\"sal\",\"sam\",\"sao\",\"sap\",\"saq\",\"sar\",\"sas\",\"sat\",\"sau\",\"sav\",\"saw\",\"sax\",\"say\",\"saz\",\"sba\",\"sbb\",\"sbc\",\"sbd\",\"sbe\",\"sbf\",\"sbg\",\"sbh\",\"sbi\",\"sbj\",\"sbk\",\"sbl\",\"sbm\",\"sbn\",\"sbo\",\"sbp\",\"sbq\",\"sbr\",\"sbs\",\"sbt\",\"sbu\",\"sbv\",\"sbw\",\"sbx\",\"sby\",\"sbz\",\"sca\",\"scb\",\"sce\",\"scf\",\"scg\",\"sch\",\"sci\",\"sck\",\"scl\",\"scn\",\"sco\",\"scp\",\"scq\",\"scs\",\"sct\",\"scu\",\"scv\",\"scw\",\"scx\",\"sda\",\"sdb\",\"sdc\",\"sde\",\"sdf\",\"sdg\",\"sdh\",\"sdj\",\"sdk\",\"sdl\",\"sdm\",\"sdn\",\"sdo\",\"sdp\",\"sdr\",\"sds\",\"sdt\",\"sdu\",\"sdv\",\"sdx\",\"sdz\",\"sea\",\"seb\",\"sec\",\"sed\",\"see\",\"sef\",\"seg\",\"seh\",\"sei\",\"sej\",\"sek\",\"sel\",\"sem\",\"sen\",\"seo\",\"sep\",\"seq\",\"ser\",\"ses\",\"set\",\"seu\",\"sev\",\"sew\",\"sey\",\"sez\",\"sfb\",\"sfe\",\"sfm\",\"sfs\",\"sfw\",\"sga\",\"sgb\",\"sgc\",\"sgd\",\"sge\",\"sgg\",\"sgh\",\"sgi\",\"sgj\",\"sgk\",\"sgl\",\"sgm\",\"sgn\",\"sgo\",\"sgp\",\"sgr\",\"sgs\",\"sgt\",\"sgu\",\"sgw\",\"sgx\",\"sgy\",\"sgz\",\"sha\",\"shb\",\"shc\",\"shd\",\"she\",\"shg\",\"shh\",\"shi\",\"shj\",\"shk\",\"shl\",\"shm\",\"shn\",\"sho\",\"shp\",\"shq\",\"shr\",\"shs\",\"sht\",\"shu\",\"shv\",\"shw\",\"shx\",\"shy\",\"shz\",\"sia\",\"sib\",\"sid\",\"sie\",\"sif\",\"sig\",\"sih\",\"sii\",\"sij\",\"sik\",\"sil\",\"sim\",\"sio\",\"sip\",\"siq\",\"sir\",\"sis\",\"sit\",\"siu\",\"siv\",\"siw\",\"six\",\"siy\",\"siz\",\"sja\",\"sjb\",\"sjd\",\"sje\",\"sjg\",\"sjk\",\"sjl\",\"sjm\",\"sjn\",\"sjo\",\"sjp\",\"sjr\",\"sjs\",\"sjt\",\"sju\",\"sjw\",\"ska\",\"skb\",\"skc\",\"skd\",\"ske\",\"skf\",\"skg\",\"skh\",\"ski\",\"skj\",\"skk\",\"skm\",\"skn\",\"sko\",\"skp\",\"skq\",\"skr\",\"sks\",\"skt\",\"sku\",\"skv\",\"skw\",\"skx\",\"sky\",\"skz\",\"sla\",\"slc\",\"sld\",\"sle\",\"slf\",\"slg\",\"slh\",\"sli\",\"slj\",\"sll\",\"slm\",\"sln\",\"slp\",\"slq\",\"slr\",\"sls\",\"slt\",\"slu\",\"slw\",\"slx\",\"sly\",\"slz\",\"sma\",\"smb\",\"smc\",\"smd\",\"smf\",\"smg\",\"smh\",\"smi\",\"smj\",\"smk\",\"sml\",\"smm\",\"smn\",\"smp\",\"smq\",\"smr\",\"sms\",\"smt\",\"smu\",\"smv\",\"smw\",\"smx\",\"smy\",\"smz\",\"snb\",\"snc\",\"sne\",\"snf\",\"sng\",\"snh\",\"sni\",\"snj\",\"snk\",\"snl\",\"snm\",\"snn\",\"sno\",\"snp\",\"snq\",\"snr\",\"sns\",\"snu\",\"snv\",\"snw\",\"snx\",\"sny\",\"snz\",\"soa\",\"sob\",\"soc\",\"sod\",\"soe\",\"sog\",\"soh\",\"soi\",\"soj\",\"sok\",\"sol\",\"son\",\"soo\",\"sop\",\"soq\",\"sor\",\"sos\",\"sou\",\"sov\",\"sow\",\"sox\",\"soy\",\"soz\",\"spb\",\"spc\",\"spd\",\"spe\",\"spg\",\"spi\",\"spk\",\"spl\",\"spm\",\"spn\",\"spo\",\"spp\",\"spq\",\"spr\",\"sps\",\"spt\",\"spu\",\"spv\",\"spx\",\"spy\",\"sqa\",\"sqh\",\"sqj\",\"sqk\",\"sqm\",\"sqn\",\"sqo\",\"sqq\",\"sqr\",\"sqs\",\"sqt\",\"squ\",\"sra\",\"srb\",\"src\",\"sre\",\"srf\",\"srg\",\"srh\",\"sri\",\"srk\",\"srl\",\"srm\",\"srn\",\"sro\",\"srq\",\"srr\",\"srs\",\"srt\",\"sru\",\"srv\",\"srw\",\"srx\",\"sry\",\"srz\",\"ssa\",\"ssb\",\"ssc\",\"ssd\",\"sse\",\"ssf\",\"ssg\",\"ssh\",\"ssi\",\"ssj\",\"ssk\",\"ssl\",\"ssm\",\"ssn\",\"sso\",\"ssp\",\"ssq\",\"ssr\",\"sss\",\"sst\",\"ssu\",\"ssv\",\"ssx\",\"ssy\",\"ssz\",\"sta\",\"stb\",\"std\",\"ste\",\"stf\",\"stg\",\"sth\",\"sti\",\"stj\",\"stk\",\"stl\",\"stm\",\"stn\",\"sto\",\"stp\",\"stq\",\"str\",\"sts\",\"stt\",\"stu\",\"stv\",\"stw\",\"sty\",\"sua\",\"sub\",\"suc\",\"sue\",\"sug\",\"sui\",\"suj\",\"suk\",\"sul\",\"sum\",\"suq\",\"sur\",\"sus\",\"sut\",\"suv\",\"suw\",\"sux\",\"suy\",\"suz\",\"sva\",\"svb\",\"svc\",\"sve\",\"svk\",\"svm\",\"svr\",\"svs\",\"svx\",\"swb\",\"swc\",\"swf\",\"swg\",\"swh\",\"swi\",\"swj\",\"swk\",\"swl\",\"swm\",\"swn\",\"swo\",\"swp\",\"swq\",\"swr\",\"sws\",\"swt\",\"swu\",\"swv\",\"sww\",\"swx\",\"swy\",\"sxb\",\"sxc\",\"sxe\",\"sxg\",\"sxk\",\"sxl\",\"sxm\",\"sxn\",\"sxo\",\"sxr\",\"sxs\",\"sxu\",\"sxw\",\"sya\",\"syb\",\"syc\",\"syd\",\"syi\",\"syk\",\"syl\",\"sym\",\"syn\",\"syo\",\"syr\",\"sys\",\"syw\",\"syx\",\"syy\",\"sza\",\"szb\",\"szc\",\"szd\",\"sze\",\"szg\",\"szl\",\"szn\",\"szp\",\"szs\",\"szv\",\"szw\",\"taa\",\"tab\",\"tac\",\"tad\",\"tae\",\"taf\",\"tag\",\"tai\",\"taj\",\"tak\",\"tal\",\"tan\",\"tao\",\"tap\",\"taq\",\"tar\",\"tas\",\"tau\",\"tav\",\"taw\",\"tax\",\"tay\",\"taz\",\"tba\",\"tbb\",\"tbc\",\"tbd\",\"tbe\",\"tbf\",\"tbg\",\"tbh\",\"tbi\",\"tbj\",\"tbk\",\"tbl\",\"tbm\",\"tbn\",\"tbo\",\"tbp\",\"tbq\",\"tbr\",\"tbs\",\"tbt\",\"tbu\",\"tbv\",\"tbw\",\"tbx\",\"tby\",\"tbz\",\"tca\",\"tcb\",\"tcc\",\"tcd\",\"tce\",\"tcf\",\"tcg\",\"tch\",\"tci\",\"tck\",\"tcl\",\"tcm\",\"tcn\",\"tco\",\"tcp\",\"tcq\",\"tcs\",\"tct\",\"tcu\",\"tcw\",\"tcx\",\"tcy\",\"tcz\",\"tda\",\"tdb\",\"tdc\",\"tdd\",\"tde\",\"tdf\",\"tdg\",\"tdh\",\"tdi\",\"tdj\",\"tdk\",\"tdl\",\"tdm\",\"tdn\",\"tdo\",\"tdq\",\"tdr\",\"tds\",\"tdt\",\"tdu\",\"tdv\",\"tdx\",\"tdy\",\"tea\",\"teb\",\"tec\",\"ted\",\"tee\",\"tef\",\"teg\",\"teh\",\"tei\",\"tek\",\"tem\",\"ten\",\"teo\",\"tep\",\"teq\",\"ter\",\"tes\",\"tet\",\"teu\",\"tev\",\"tew\",\"tex\",\"tey\",\"tfi\",\"tfn\",\"tfo\",\"tfr\",\"tft\",\"tga\",\"tgb\",\"tgc\",\"tgd\",\"tge\",\"tgf\",\"tgg\",\"tgh\",\"tgi\",\"tgj\",\"tgn\",\"tgo\",\"tgp\",\"tgq\",\"tgr\",\"tgs\",\"tgt\",\"tgu\",\"tgv\",\"tgw\",\"tgx\",\"tgy\",\"tgz\",\"thc\",\"thd\",\"the\",\"thf\",\"thh\",\"thi\",\"thk\",\"thl\",\"thm\",\"thn\",\"thp\",\"thq\",\"thr\",\"ths\",\"tht\",\"thu\",\"thv\",\"thw\",\"thx\",\"thy\",\"thz\",\"tia\",\"tic\",\"tid\",\"tie\",\"tif\",\"tig\",\"tih\",\"tii\",\"tij\",\"tik\",\"til\",\"tim\",\"tin\",\"tio\",\"tip\",\"tiq\",\"tis\",\"tit\",\"tiu\",\"tiv\",\"tiw\",\"tix\",\"tiy\",\"tiz\",\"tja\",\"tjg\",\"tji\",\"tjl\",\"tjm\",\"tjn\",\"tjo\",\"tjs\",\"tju\",\"tjw\",\"tka\",\"tkb\",\"tkd\",\"tke\",\"tkf\",\"tkg\",\"tkk\",\"tkl\",\"tkm\",\"tkn\",\"tkp\",\"tkq\",\"tkr\",\"tks\",\"tkt\",\"tku\",\"tkv\",\"tkw\",\"tkx\",\"tkz\",\"tla\",\"tlb\",\"tlc\",\"tld\",\"tlf\",\"tlg\",\"tlh\",\"tli\",\"tlj\",\"tlk\",\"tll\",\"tlm\",\"tln\",\"tlo\",\"tlp\",\"tlq\",\"tlr\",\"tls\",\"tlt\",\"tlu\",\"tlv\",\"tlw\",\"tlx\",\"tly\",\"tma\",\"tmb\",\"tmc\",\"tmd\",\"tme\",\"tmf\",\"tmg\",\"tmh\",\"tmi\",\"tmj\",\"tmk\",\"tml\",\"tmm\",\"tmn\",\"tmo\",\"tmp\",\"tmq\",\"tmr\",\"tms\",\"tmt\",\"tmu\",\"tmv\",\"tmw\",\"tmy\",\"tmz\",\"tna\",\"tnb\",\"tnc\",\"tnd\",\"tne\",\"tnf\",\"tng\",\"tnh\",\"tni\",\"tnk\",\"tnl\",\"tnm\",\"tnn\",\"tno\",\"tnp\",\"tnq\",\"tnr\",\"tns\",\"tnt\",\"tnu\",\"tnv\",\"tnw\",\"tnx\",\"tny\",\"tnz\",\"tob\",\"toc\",\"tod\",\"toe\",\"tof\",\"tog\",\"toh\",\"toi\",\"toj\",\"tol\",\"tom\",\"too\",\"top\",\"toq\",\"tor\",\"tos\",\"tou\",\"tov\",\"tow\",\"tox\",\"toy\",\"toz\",\"tpa\",\"tpc\",\"tpe\",\"tpf\",\"tpg\",\"tpi\",\"tpj\",\"tpk\",\"tpl\",\"tpm\",\"tpn\",\"tpo\",\"tpp\",\"tpq\",\"tpr\",\"tpt\",\"tpu\",\"tpv\",\"tpw\",\"tpx\",\"tpy\",\"tpz\",\"tqb\",\"tql\",\"tqm\",\"tqn\",\"tqo\",\"tqp\",\"tqq\",\"tqr\",\"tqt\",\"tqu\",\"tqw\",\"tra\",\"trb\",\"trc\",\"trd\",\"tre\",\"trf\",\"trg\",\"trh\",\"tri\",\"trj\",\"trk\",\"trl\",\"trm\",\"trn\",\"tro\",\"trp\",\"trq\",\"trr\",\"trs\",\"trt\",\"tru\",\"trv\",\"trw\",\"trx\",\"try\",\"trz\",\"tsa\",\"tsb\",\"tsc\",\"tsd\",\"tse\",\"tsf\",\"tsg\",\"tsh\",\"tsi\",\"tsj\",\"tsk\",\"tsl\",\"tsm\",\"tsp\",\"tsq\",\"tsr\",\"tss\",\"tst\",\"tsu\",\"tsv\",\"tsw\",\"tsx\",\"tsy\",\"tsz\",\"tta\",\"ttb\",\"ttc\",\"ttd\",\"tte\",\"ttf\",\"ttg\",\"tth\",\"tti\",\"ttj\",\"ttk\",\"ttl\",\"ttm\",\"ttn\",\"tto\",\"ttp\",\"ttq\",\"ttr\",\"tts\",\"ttt\",\"ttu\",\"ttv\",\"ttw\",\"tty\",\"ttz\",\"tua\",\"tub\",\"tuc\",\"tud\",\"tue\",\"tuf\",\"tug\",\"tuh\",\"tui\",\"tuj\",\"tul\",\"tum\",\"tun\",\"tuo\",\"tup\",\"tuq\",\"tus\",\"tut\",\"tuu\",\"tuv\",\"tuw\",\"tux\",\"tuy\",\"tuz\",\"tva\",\"tvd\",\"tve\",\"tvk\",\"tvl\",\"tvm\",\"tvn\",\"tvo\",\"tvs\",\"tvt\",\"tvu\",\"tvw\",\"tvy\",\"twa\",\"twb\",\"twc\",\"twd\",\"twe\",\"twf\",\"twg\",\"twh\",\"twl\",\"twm\",\"twn\",\"two\",\"twp\",\"twq\",\"twr\",\"twt\",\"twu\",\"tww\",\"twx\",\"twy\",\"txa\",\"txb\",\"txc\",\"txe\",\"txg\",\"txh\",\"txi\",\"txj\",\"txm\",\"txn\",\"txo\",\"txq\",\"txr\",\"txs\",\"txt\",\"txu\",\"txx\",\"txy\",\"tya\",\"tye\",\"tyh\",\"tyi\",\"tyj\",\"tyl\",\"tyn\",\"typ\",\"tyr\",\"tys\",\"tyt\",\"tyu\",\"tyv\",\"tyx\",\"tyz\",\"tza\",\"tzh\",\"tzj\",\"tzl\",\"tzm\",\"tzn\",\"tzo\",\"tzx\",\"uam\",\"uan\",\"uar\",\"uba\",\"ubi\",\"ubl\",\"ubr\",\"ubu\",\"uby\",\"uda\",\"ude\",\"udg\",\"udi\",\"udj\",\"udl\",\"udm\",\"udu\",\"ues\",\"ufi\",\"uga\",\"ugb\",\"uge\",\"ugn\",\"ugo\",\"ugy\",\"uha\",\"uhn\",\"uis\",\"uiv\",\"uji\",\"uka\",\"ukg\",\"ukh\",\"ukk\",\"ukl\",\"ukp\",\"ukq\",\"uks\",\"uku\",\"ukw\",\"uky\",\"ula\",\"ulb\",\"ulc\",\"ule\",\"ulf\",\"uli\",\"ulk\",\"ull\",\"ulm\",\"uln\",\"ulu\",\"ulw\",\"uma\",\"umb\",\"umc\",\"umd\",\"umg\",\"umi\",\"umm\",\"umn\",\"umo\",\"ump\",\"umr\",\"ums\",\"umu\",\"una\",\"und\",\"une\",\"ung\",\"unk\",\"unm\",\"unn\",\"unp\",\"unr\",\"unu\",\"unx\",\"unz\",\"uok\",\"upi\",\"upv\",\"ura\",\"urb\",\"urc\",\"ure\",\"urf\",\"urg\",\"urh\",\"uri\",\"urj\",\"urk\",\"url\",\"urm\",\"urn\",\"uro\",\"urp\",\"urr\",\"urt\",\"uru\",\"urv\",\"urw\",\"urx\",\"ury\",\"urz\",\"usa\",\"ush\",\"usi\",\"usk\",\"usp\",\"usu\",\"uta\",\"ute\",\"utp\",\"utr\",\"utu\",\"uum\",\"uun\",\"uur\",\"uuu\",\"uve\",\"uvh\",\"uvl\",\"uwa\",\"uya\",\"uzn\",\"uzs\",\"vaa\",\"vae\",\"vaf\",\"vag\",\"vah\",\"vai\",\"vaj\",\"val\",\"vam\",\"van\",\"vao\",\"vap\",\"var\",\"vas\",\"vau\",\"vav\",\"vay\",\"vbb\",\"vbk\",\"vec\",\"ved\",\"vel\",\"vem\",\"veo\",\"vep\",\"ver\",\"vgr\",\"vgt\",\"vic\",\"vid\",\"vif\",\"vig\",\"vil\",\"vin\",\"vis\",\"vit\",\"viv\",\"vka\",\"vki\",\"vkj\",\"vkk\",\"vkl\",\"vkm\",\"vko\",\"vkp\",\"vkt\",\"vku\",\"vlp\",\"vls\",\"vma\",\"vmb\",\"vmc\",\"vmd\",\"vme\",\"vmf\",\"vmg\",\"vmh\",\"vmi\",\"vmj\",\"vmk\",\"vml\",\"vmm\",\"vmp\",\"vmq\",\"vmr\",\"vms\",\"vmu\",\"vmv\",\"vmw\",\"vmx\",\"vmy\",\"vmz\",\"vnk\",\"vnm\",\"vnp\",\"vor\",\"vot\",\"vra\",\"vro\",\"vrs\",\"vrt\",\"vsi\",\"vsl\",\"vsv\",\"vto\",\"vum\",\"vun\",\"vut\",\"vwa\",\"waa\",\"wab\",\"wac\",\"wad\",\"wae\",\"waf\",\"wag\",\"wah\",\"wai\",\"waj\",\"wak\",\"wal\",\"wam\",\"wan\",\"wao\",\"wap\",\"waq\",\"war\",\"was\",\"wat\",\"wau\",\"wav\",\"waw\",\"wax\",\"way\",\"waz\",\"wba\",\"wbb\",\"wbe\",\"wbf\",\"wbh\",\"wbi\",\"wbj\",\"wbk\",\"wbl\",\"wbm\",\"wbp\",\"wbq\",\"wbr\",\"wbs\",\"wbt\",\"wbv\",\"wbw\",\"wca\",\"wci\",\"wdd\",\"wdg\",\"wdj\",\"wdk\",\"wdu\",\"wdy\",\"wea\",\"wec\",\"wed\",\"weg\",\"weh\",\"wei\",\"wem\",\"wen\",\"weo\",\"wep\",\"wer\",\"wes\",\"wet\",\"weu\",\"wew\",\"wfg\",\"wga\",\"wgb\",\"wgg\",\"wgi\",\"wgo\",\"wgu\",\"wgw\",\"wgy\",\"wha\",\"whg\",\"whk\",\"whu\",\"wib\",\"wic\",\"wie\",\"wif\",\"wig\",\"wih\",\"wii\",\"wij\",\"wik\",\"wil\",\"wim\",\"win\",\"wir\",\"wit\",\"wiu\",\"wiv\",\"wiw\",\"wiy\",\"wja\",\"wji\",\"wka\",\"wkb\",\"wkd\",\"wkl\",\"wku\",\"wkw\",\"wky\",\"wla\",\"wlc\",\"wle\",\"wlg\",\"wli\",\"wlk\",\"wll\",\"wlm\",\"wlo\",\"wlr\",\"wls\",\"wlu\",\"wlv\",\"wlw\",\"wlx\",\"wly\",\"wma\",\"wmb\",\"wmc\",\"wmd\",\"wme\",\"wmh\",\"wmi\",\"wmm\",\"wmn\",\"wmo\",\"wms\",\"wmt\",\"wmw\",\"wmx\",\"wnb\",\"wnc\",\"wnd\",\"wne\",\"wng\",\"wni\",\"wnk\",\"wnm\",\"wnn\",\"wno\",\"wnp\",\"wnu\",\"wnw\",\"wny\",\"woa\",\"wob\",\"woc\",\"wod\",\"woe\",\"wof\",\"wog\",\"woi\",\"wok\",\"wom\",\"won\",\"woo\",\"wor\",\"wos\",\"wow\",\"woy\",\"wpc\",\"wra\",\"wrb\",\"wrd\",\"wrg\",\"wrh\",\"wri\",\"wrk\",\"wrl\",\"wrm\",\"wrn\",\"wro\",\"wrp\",\"wrr\",\"wrs\",\"wru\",\"wrv\",\"wrw\",\"wrx\",\"wry\",\"wrz\",\"wsa\",\"wsg\",\"wsi\",\"wsk\",\"wsr\",\"wss\",\"wsu\",\"wsv\",\"wtf\",\"wth\",\"wti\",\"wtk\",\"wtm\",\"wtw\",\"wua\",\"wub\",\"wud\",\"wuh\",\"wul\",\"wum\",\"wun\",\"wur\",\"wut\",\"wuu\",\"wuv\",\"wux\",\"wuy\",\"wwa\",\"wwb\",\"wwo\",\"wwr\",\"www\",\"wxa\",\"wxw\",\"wya\",\"wyb\",\"wyi\",\"wym\",\"wyr\",\"wyy\",\"xaa\",\"xab\",\"xac\",\"xad\",\"xae\",\"xag\",\"xai\",\"xaj\",\"xak\",\"xal\",\"xam\",\"xan\",\"xao\",\"xap\",\"xaq\",\"xar\",\"xas\",\"xat\",\"xau\",\"xav\",\"xaw\",\"xay\",\"xba\",\"xbb\",\"xbc\",\"xbd\",\"xbe\",\"xbg\",\"xbi\",\"xbj\",\"xbm\",\"xbn\",\"xbo\",\"xbp\",\"xbr\",\"xbw\",\"xbx\",\"xby\",\"xcb\",\"xcc\",\"xce\",\"xcg\",\"xch\",\"xcl\",\"xcm\",\"xcn\",\"xco\",\"xcr\",\"xct\",\"xcu\",\"xcv\",\"xcw\",\"xcy\",\"xda\",\"xdc\",\"xdk\",\"xdm\",\"xdo\",\"xdy\",\"xeb\",\"xed\",\"xeg\",\"xel\",\"xem\",\"xep\",\"xer\",\"xes\",\"xet\",\"xeu\",\"xfa\",\"xga\",\"xgb\",\"xgd\",\"xgf\",\"xgg\",\"xgi\",\"xgl\",\"xgm\",\"xgn\",\"xgr\",\"xgu\",\"xgw\",\"xha\",\"xhc\",\"xhd\",\"xhe\",\"xhr\",\"xht\",\"xhu\",\"xhv\",\"xia\",\"xib\",\"xii\",\"xil\",\"xin\",\"xip\",\"xir\",\"xis\",\"xiv\",\"xiy\",\"xjb\",\"xjt\",\"xka\",\"xkb\",\"xkc\",\"xkd\",\"xke\",\"xkf\",\"xkg\",\"xkh\",\"xki\",\"xkj\",\"xkk\",\"xkl\",\"xkn\",\"xko\",\"xkp\",\"xkq\",\"xkr\",\"xks\",\"xkt\",\"xku\",\"xkv\",\"xkw\",\"xkx\",\"xky\",\"xkz\",\"xla\",\"xlb\",\"xlc\",\"xld\",\"xle\",\"xlg\",\"xli\",\"xln\",\"xlo\",\"xlp\",\"xls\",\"xlu\",\"xly\",\"xma\",\"xmb\",\"xmc\",\"xmd\",\"xme\",\"xmf\",\"xmg\",\"xmh\",\"xmj\",\"xmk\",\"xml\",\"xmm\",\"xmn\",\"xmo\",\"xmp\",\"xmq\",\"xmr\",\"xms\",\"xmt\",\"xmu\",\"xmv\",\"xmw\",\"xmx\",\"xmy\",\"xmz\",\"xna\",\"xnb\",\"xnd\",\"xng\",\"xnh\",\"xni\",\"xnk\",\"xnn\",\"xno\",\"xnr\",\"xns\",\"xnt\",\"xnu\",\"xny\",\"xnz\",\"xoc\",\"xod\",\"xog\",\"xoi\",\"xok\",\"xom\",\"xon\",\"xoo\",\"xop\",\"xor\",\"xow\",\"xpa\",\"xpc\",\"xpe\",\"xpg\",\"xpi\",\"xpj\",\"xpk\",\"xpm\",\"xpn\",\"xpo\",\"xpp\",\"xpq\",\"xpr\",\"xps\",\"xpt\",\"xpu\",\"xpy\",\"xqa\",\"xqt\",\"xra\",\"xrb\",\"xrd\",\"xre\",\"xrg\",\"xri\",\"xrm\",\"xrn\",\"xrq\",\"xrr\",\"xrt\",\"xru\",\"xrw\",\"xsa\",\"xsb\",\"xsc\",\"xsd\",\"xse\",\"xsh\",\"xsi\",\"xsj\",\"xsl\",\"xsm\",\"xsn\",\"xso\",\"xsp\",\"xsq\",\"xsr\",\"xss\",\"xsu\",\"xsv\",\"xsy\",\"xta\",\"xtb\",\"xtc\",\"xtd\",\"xte\",\"xtg\",\"xth\",\"xti\",\"xtj\",\"xtl\",\"xtm\",\"xtn\",\"xto\",\"xtp\",\"xtq\",\"xtr\",\"xts\",\"xtt\",\"xtu\",\"xtv\",\"xtw\",\"xty\",\"xtz\",\"xua\",\"xub\",\"xud\",\"xug\",\"xuj\",\"xul\",\"xum\",\"xun\",\"xuo\",\"xup\",\"xur\",\"xut\",\"xuu\",\"xve\",\"xvi\",\"xvn\",\"xvo\",\"xvs\",\"xwa\",\"xwc\",\"xwd\",\"xwe\",\"xwg\",\"xwj\",\"xwk\",\"xwl\",\"xwo\",\"xwr\",\"xwt\",\"xww\",\"xxb\",\"xxk\",\"xxm\",\"xxr\",\"xxt\",\"xya\",\"xyb\",\"xyj\",\"xyk\",\"xyl\",\"xyt\",\"xyy\",\"xzh\",\"xzm\",\"xzp\",\"yaa\",\"yab\",\"yac\",\"yad\",\"yae\",\"yaf\",\"yag\",\"yah\",\"yai\",\"yaj\",\"yak\",\"yal\",\"yam\",\"yan\",\"yao\",\"yap\",\"yaq\",\"yar\",\"yas\",\"yat\",\"yau\",\"yav\",\"yaw\",\"yax\",\"yay\",\"yaz\",\"yba\",\"ybb\",\"ybd\",\"ybe\",\"ybh\",\"ybi\",\"ybj\",\"ybk\",\"ybl\",\"ybm\",\"ybn\",\"ybo\",\"ybx\",\"yby\",\"ych\",\"ycl\",\"ycn\",\"ycp\",\"yda\",\"ydd\",\"yde\",\"ydg\",\"ydk\",\"yds\",\"yea\",\"yec\",\"yee\",\"yei\",\"yej\",\"yel\",\"yen\",\"yer\",\"yes\",\"yet\",\"yeu\",\"yev\",\"yey\",\"yga\",\"ygi\",\"ygl\",\"ygm\",\"ygp\",\"ygr\",\"ygs\",\"ygu\",\"ygw\",\"yha\",\"yhd\",\"yhl\",\"yhs\",\"yia\",\"yif\",\"yig\",\"yih\",\"yii\",\"yij\",\"yik\",\"yil\",\"yim\",\"yin\",\"yip\",\"yiq\",\"yir\",\"yis\",\"yit\",\"yiu\",\"yiv\",\"yix\",\"yiy\",\"yiz\",\"yka\",\"ykg\",\"yki\",\"ykk\",\"ykl\",\"ykm\",\"ykn\",\"yko\",\"ykr\",\"ykt\",\"yku\",\"yky\",\"yla\",\"ylb\",\"yle\",\"ylg\",\"yli\",\"yll\",\"ylm\",\"yln\",\"ylo\",\"ylr\",\"ylu\",\"yly\",\"yma\",\"ymb\",\"ymc\",\"ymd\",\"yme\",\"ymg\",\"ymh\",\"ymi\",\"ymk\",\"yml\",\"ymm\",\"ymn\",\"ymo\",\"ymp\",\"ymq\",\"ymr\",\"yms\",\"ymt\",\"ymx\",\"ymz\",\"yna\",\"ynd\",\"yne\",\"yng\",\"ynh\",\"ynk\",\"ynl\",\"ynn\",\"yno\",\"ynq\",\"yns\",\"ynu\",\"yob\",\"yog\",\"yoi\",\"yok\",\"yol\",\"yom\",\"yon\",\"yos\",\"yot\",\"yox\",\"yoy\",\"ypa\",\"ypb\",\"ypg\",\"yph\",\"ypk\",\"ypm\",\"ypn\",\"ypo\",\"ypp\",\"ypz\",\"yra\",\"yrb\",\"yre\",\"yri\",\"yrk\",\"yrl\",\"yrm\",\"yrn\",\"yro\",\"yrs\",\"yrw\",\"yry\",\"ysc\",\"ysd\",\"ysg\",\"ysl\",\"ysn\",\"yso\",\"ysp\",\"ysr\",\"yss\",\"ysy\",\"yta\",\"ytl\",\"ytp\",\"ytw\",\"yty\",\"yua\",\"yub\",\"yuc\",\"yud\",\"yue\",\"yuf\",\"yug\",\"yui\",\"yuj\",\"yuk\",\"yul\",\"yum\",\"yun\",\"yup\",\"yuq\",\"yur\",\"yut\",\"yuu\",\"yuw\",\"yux\",\"yuy\",\"yuz\",\"yva\",\"yvt\",\"ywa\",\"ywg\",\"ywl\",\"ywn\",\"ywq\",\"ywr\",\"ywt\",\"ywu\",\"yww\",\"yxa\",\"yxg\",\"yxl\",\"yxm\",\"yxu\",\"yxy\",\"yyr\",\"yyu\",\"yyz\",\"yzg\",\"yzk\",\"zaa\",\"zab\",\"zac\",\"zad\",\"zae\",\"zaf\",\"zag\",\"zah\",\"zai\",\"zaj\",\"zak\",\"zal\",\"zam\",\"zao\",\"zap\",\"zaq\",\"zar\",\"zas\",\"zat\",\"zau\",\"zav\",\"zaw\",\"zax\",\"zay\",\"zaz\",\"zbc\",\"zbe\",\"zbl\",\"zbt\",\"zbw\",\"zca\",\"zch\",\"zdj\",\"zea\",\"zeg\",\"zeh\",\"zen\",\"zga\",\"zgb\",\"zgh\",\"zgm\",\"zgn\",\"zgr\",\"zhb\",\"zhd\",\"zhi\",\"zhn\",\"zhw\",\"zhx\",\"zia\",\"zib\",\"zik\",\"zil\",\"zim\",\"zin\",\"zir\",\"ziw\",\"ziz\",\"zka\",\"zkb\",\"zkd\",\"zkg\",\"zkh\",\"zkk\",\"zkn\",\"zko\",\"zkp\",\"zkr\",\"zkt\",\"zku\",\"zkv\",\"zkz\",\"zle\",\"zlj\",\"zlm\",\"zln\",\"zlq\",\"zls\",\"zlw\",\"zma\",\"zmb\",\"zmc\",\"zmd\",\"zme\",\"zmf\",\"zmg\",\"zmh\",\"zmi\",\"zmj\",\"zmk\",\"zml\",\"zmm\",\"zmn\",\"zmo\",\"zmp\",\"zmq\",\"zmr\",\"zms\",\"zmt\",\"zmu\",\"zmv\",\"zmw\",\"zmx\",\"zmy\",\"zmz\",\"zna\",\"znd\",\"zne\",\"zng\",\"znk\",\"zns\",\"zoc\",\"zoh\",\"zom\",\"zoo\",\"zoq\",\"zor\",\"zos\",\"zpa\",\"zpb\",\"zpc\",\"zpd\",\"zpe\",\"zpf\",\"zpg\",\"zph\",\"zpi\",\"zpj\",\"zpk\",\"zpl\",\"zpm\",\"zpn\",\"zpo\",\"zpp\",\"zpq\",\"zpr\",\"zps\",\"zpt\",\"zpu\",\"zpv\",\"zpw\",\"zpx\",\"zpy\",\"zpz\",\"zqe\",\"zra\",\"zrg\",\"zrn\",\"zro\",\"zrp\",\"zrs\",\"zsa\",\"zsk\",\"zsl\",\"zsm\",\"zsr\",\"zsu\",\"zte\",\"ztg\",\"ztl\",\"ztm\",\"ztn\",\"ztp\",\"ztq\",\"zts\",\"ztt\",\"ztu\",\"ztx\",\"zty\",\"zua\",\"zuh\",\"zum\",\"zun\",\"zuy\",\"zwa\",\"zxx\",\"zyb\",\"zyg\",\"zyj\",\"zyn\",\"zyp\",\"zza\",\"zzj\"]\n;return axe.utils.validLangs=function(){\"use strict\";return I},commons}()})}(\"object\"==typeof window?window:this);";
+const axeLibSource="/*! aXe v3.0.0-beta.2\n * Copyright (c) 2018 Deque Systems, Inc.\n *\n * Your use of this Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This entire copyright notice must appear in every copy of this file you\n * distribute or in any file that contains substantial portions of this source\n * code.\n */\n!function a(window){function b(a){this.name=\"SupportError\",this.cause=a.cause,this.message=\"`\"+a.cause+\"` - feature unsupported in your environment.\",a.ruleId&&(this.ruleId=a.ruleId,this.message+=\" Skipping \"+this.ruleId+\" rule.\"),this.stack=(new Error).stack}function c(a){\"use strict\";var b;return a?(b=axe.utils.clone(a),b.commons=a.commons):b={},b.reporter=b.reporter||null,b.rules=b.rules||[],b.checks=b.checks||[],b.data=Object.assign({checks:{},rules:{}},b.data),b}function d(a,b,c){\"use strict\";var d,e;for(d=0,e=a.length;d<e;d++)b[c](a[d])}function e(a){this.brand=\"axe\",this.application=\"axeAPI\",this.tagExclude=[\"experimental\"],this.defaultConfig=a,this._init()}function f(a,b,c){var d=a.brand,e=a.application;return axe.constants.helpUrlBase+d+\"/\"+(c||axe.version.substring(0,axe.version.lastIndexOf(\".\")))+\"/\"+b+\"?application=\"+e}function g(a){\"use strict\";this.id=a.id,this.data=null,this.relatedNodes=[],this.result=null}function h(a){\"use strict\";return\"string\"==typeof a?new Function(\"return \"+a+\";\")():a}function i(a){a&&(this.id=a.id,this.configure(a))}function j(a,b){\"use strict\";if(!axe.utils.isHidden(b)){axe.utils.findBy(a,\"node\",b)||a.push({node:b,include:[],exclude:[]})}}function k(a,b,c){\"use strict\";a.frames=a.frames||[];var d,e,f=document.querySelectorAll(c.shift());a:for(var g=0,h=f.length;g<h;g++){e=f[g];for(var i=0,j=a.frames.length;i<j;i++)if(a.frames[i].node===e){a.frames[i][b].push(c);break a}d={node:e,include:[],exclude:[]},c&&d[b].push(c),a.frames.push(d)}}function l(a){\"use strict\";if(a&&\"object\"===(void 0===a?\"undefined\":za(a))||a instanceof NodeList){if(a instanceof Node)return{include:[a],exclude:[]};if(a.hasOwnProperty(\"include\")||a.hasOwnProperty(\"exclude\"))return{include:a.include&&+a.include.length?a.include:[document],exclude:a.exclude||[]};if(a.length===+a.length)return{include:a,exclude:[]}}return\"string\"==typeof a?{include:[a],exclude:[]}:{include:[document],exclude:[]}}function m(a,b){\"use strict\";for(var c,d,e=[],f=0,g=a[b].length;f<g;f++){if(\"string\"==typeof(c=a[b][f])){d=Array.from(document.querySelectorAll(c)),e=e.concat(d.map(function(a){return axe.utils.getFlattenedTree(a)[0]}));break}!c||!c.length||c instanceof Node?c instanceof Node&&e.push(axe.utils.getFlattenedTree(c)[0]):c.length>1?k(a,b,c):(d=Array.from(document.querySelectorAll(c[0])),e=e.concat(d.map(function(a){return axe.utils.getFlattenedTree(a)[0]})))}return e.filter(function(a){return a})}function n(a){\"use strict\";if(0===a.include.length){if(0===a.frames.length){var b=axe.utils.respondable.isInFrame()?\"frame\":\"page\";return new Error(\"No elements found for include in \"+b+\" Context\")}a.frames.forEach(function(a,b){if(0===a.include.length)return new Error(\"No elements found for include in Context of frame \"+b)})}}function o(a){\"use strict\";var b=this;this.frames=[],this.initiator=!a||\"boolean\"!=typeof a.initiator||a.initiator,this.page=!1,a=l(a),this.exclude=a.exclude,this.include=a.include,this.include=m(this,\"include\"),this.exclude=m(this,\"exclude\"),axe.utils.select(\"frame, iframe\",this).forEach(function(a){wa(a,b)&&j(b.frames,a.actualNode)}),1===this.include.length&&this.include[0].actualNode===document.documentElement&&(this.page=!0);var c=n(this);if(c instanceof Error)throw c;Array.isArray(this.include)||(this.include=Array.from(this.include)),this.include.sort(axe.utils.nodeSorter)}function p(a){\"use strict\";this.id=a.id,this.result=axe.constants.NA,this.pageLevel=a.pageLevel,this.impact=null,this.nodes=[]}function q(a,b){\"use strict\";this._audit=b,this.id=a.id,this.selector=a.selector||\"*\",this.excludeHidden=\"boolean\"!=typeof a.excludeHidden||a.excludeHidden,this.enabled=\"boolean\"!=typeof a.enabled||a.enabled,this.pageLevel=\"boolean\"==typeof a.pageLevel&&a.pageLevel,this.any=a.any||[],this.all=a.all||[],this.none=a.none||[],this.tags=a.tags||[],a.matches&&(this.matches=h(a.matches))}function r(a){\"use strict\";return axe.utils.getAllChecks(a).map(function(b){var c=a._audit.checks[b.id||b];return c&&\"function\"==typeof c.after?c:null}).filter(Boolean)}function s(a,b){\"use strict\";var c=[];return a.forEach(function(a){axe.utils.getAllChecks(a).forEach(function(a){a.id===b&&c.push(a)})}),c}function t(a){\"use strict\";return a.filter(function(a){return!0!==a.filtered})}function u(a){\"use strict\";var b=[\"any\",\"all\",\"none\"],c=a.nodes.filter(function(a){var c=0;return b.forEach(function(b){a[b]=t(a[b]),c+=a[b].length}),c>0});return a.pageLevel&&c.length&&(c=[c.reduce(function(a,c){if(a)return b.forEach(function(b){a[b].push.apply(a[b],c[b])}),a})]),c}function v(a,b){\"use strict\";if(a=a||function(){},b=b||axe.log,!axe._audit)throw new Error(\"No audit configured\");var c=axe.utils.queue(),d=[];Object.keys(axe.plugins).forEach(function(a){c.defer(function(b){var c=function(a){d.push(a),b()};try{axe.plugins[a].cleanup(b,c)}catch(a){c(a)}})});var e=axe.utils.getFlattenedTree(document.body);axe.utils.querySelectorAll(e,\"iframe, frame\").forEach(function(a){c.defer(function(b,c){return axe.utils.sendCommandToFrame(a.actualNode,{command:\"cleanup-plugin\"},b,c)})}),c.then(function(c){0===d.length?a(c):b(d)}).catch(b)}function w(a){\"use strict\";var b;if(!(b=axe._audit))throw new Error(\"No audit configured\");a.reporter&&(\"function\"==typeof a.reporter||Ca[a.reporter])&&(b.reporter=a.reporter),a.checks&&a.checks.forEach(function(a){b.addCheck(a)});var c=[];a.rules&&a.rules.forEach(function(a){c.push(a.id),b.addRule(a)}),a.disableOtherRules&&b.rules.forEach(function(a){!1===c.includes(a.id)&&(a.enabled=!1)}),void 0!==a.branding?b.setBranding(a.branding):b._constructHelpUrls(),a.tagExclude&&(b.tagExclude=a.tagExclude)}function x(a,b,c){\"use strict\";var d=c,e=function(a){a instanceof Error==!1&&(a=new Error(a)),c(a)},f=a&&a.context||{};f.hasOwnProperty(\"include\")&&!f.include.length&&(f.include=[document]);var g=a&&a.options||{};switch(a.command){case\"rules\":return A(f,g,d,e);case\"cleanup-plugin\":return v(d,e);default:if(axe._audit&&axe._audit.commands&&axe._audit.commands[a.command])return axe._audit.commands[a.command](a,c)}}function y(a){\"use strict\";this._run=a.run,this._collect=a.collect,this._registry={},a.commands.forEach(function(a){axe._audit.registerCommand(a)})}function z(){\"use strict\";var a=axe._audit;if(!a)throw new Error(\"No audit configured\");a.resetRulesAndChecks()}function A(a,b,c,d){\"use strict\";try{a=new o(a)}catch(a){return d(a)}var e=axe.utils.queue(),f=axe._audit;b.performanceTimer&&axe.utils.performanceTimer.auditStart(),a.frames.length&&!1!==b.iframes&&e.defer(function(c,d){axe.utils.collectResultsFromFrames(a,b,\"rules\",null,c,d)});var g=void 0;e.defer(function(c,d){b.restoreScroll&&(g=axe.utils.getScrollState()),f.run(a,b,c,d)}),e.then(function(e){try{g&&axe.utils.setScrollState(g),b.performanceTimer&&axe.utils.performanceTimer.auditEnd();var h=axe.utils.mergeResults(e.map(function(a){return{results:a}}));a.initiator&&(h=f.after(h,b),h.forEach(axe.utils.publishMetaData),h=h.map(axe.utils.finalizeRuleResult));try{c(h)}catch(a){axe.log(a)}}catch(a){d(a)}}).catch(d)}function B(a){\"use strict\";switch(!0){case\"string\"==typeof a:case Array.isArray(a):case Node&&a instanceof Node:case NodeList&&a instanceof NodeList:return!0;case\"object\"!==(void 0===a?\"undefined\":za(a)):return!1;case void 0!==a.include:case void 0!==a.exclude:case\"number\"==typeof a.length:return!0;default:return!1}}function C(a,b,c){\"use strict\";var d=new TypeError(\"axe.run arguments are invalid\");if(!B(a)){if(void 0!==c)throw d;c=b,b=a,a=document}if(\"object\"!==(void 0===b?\"undefined\":za(b))){if(void 0!==c)throw d;c=b,b={}}if(\"function\"!=typeof c&&void 0!==c)throw d;return{context:a,options:b,callback:c||Da}}function D(a,b){\"use strict\";[\"any\",\"all\",\"none\"].forEach(function(c){Array.isArray(a[c])&&a[c].filter(function(a){return Array.isArray(a.relatedNodes)}).forEach(function(a){a.relatedNodes=a.relatedNodes.map(function(a){var c={html:a.source};return b.elementRef&&!a.fromFrame&&(c.element=a.element),(!1!==b.selectors||a.fromFrame)&&(c.target=a.selector),b.xpath&&(c.xpath=a.xpath),c})})})}function E(a,b){return Ja.reduce(function(c,d){return c[d]=(a[d]||[]).map(function(a){return b(a,d)}),c},{})}function F(a,b,c){var d=Object.assign({},b);d.nodes=(d[c]||[]).concat(),axe.constants.resultGroups.forEach(function(a){delete d[a]}),a[c].push(d)}function G(a,b,c){\"use strict\";var d=window.getComputedStyle(a,null),e=!1;return!!d&&(b.forEach(function(a){d.getPropertyValue(a.property)===a.value&&(e=!0)}),!!e||!(a.nodeName.toUpperCase()===c.toUpperCase()||!a.parentNode)&&G(a.parentNode,b,c))}function H(a,b){\"use strict\";var c;return axe._tree&&(c=axe.utils.getSelector(b)),new Error(a+\": \"+(c||b))}function I(a,b,c,d,e,f){\"use strict\";var g=axe.utils.queue();a.frames.forEach(function(e){var f={options:b,command:c,parameter:d,context:{initiator:!1,page:a.page,include:e.include||[],exclude:e.exclude||[]}};g.defer(function(a,b){var c=e.node;axe.utils.sendCommandToFrame(c,f,function(b){if(b)return a({results:b,frameElement:c,frame:axe.utils.getSelector(c)});a(null)},b)})}),g.then(function(a){e(axe.utils.mergeResults(a,b))}).catch(f)}function J(a,b){if(b=b||300,a.length>b){var c=a.indexOf(\">\");a=a.substring(0,c+1)}return a}function K(a){var b=a.outerHTML;return b||\"function\"!=typeof XMLSerializer||(b=(new XMLSerializer).serializeToString(a)),J(b||\"\")}function L(a,b,c){this._fromFrame=!!c,this.spec=c||{},b&&b.absolutePaths&&(this._options={toRoot:!0}),this.source=void 0!==this.spec.source?this.spec.source:K(a),this._element=a}function M(a,b){return{shadowId:b,children:[],actualNode:a}}function N(a){var b=[];for(a=a.firstChild;a;)b.push(a),a=a.nextSibling;return b}function O(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\";return 0!==a.length&&(a.match(/[0-9]/g)||\"\").length>=a.length/2}function P(a,b){return[a.substring(0,b),a.substring(b)]}function Q(a){var b=a,c=\"\",d=\"\",e=\"\",f=\"\",g=\"\",h=\"\";if(a.includes(\"#\")){var i=P(a,a.indexOf(\"#\")),j=Ka(i,2);a=j[0],h=j[1]}if(a.includes(\"?\")){var k=P(a,a.indexOf(\"?\")),l=Ka(k,2);a=l[0],g=l[1]}if(a.includes(\"://\")){var m=a.split(\"://\"),n=Ka(m,2);c=n[0],a=n[1];var o=P(a,a.indexOf(\"/\")),p=Ka(o,2);d=p[0],a=p[1]}else if(\"//\"===a.substr(0,2)){a=a.substr(2);var q=P(a,a.indexOf(\"/\")),r=Ka(q,2);d=r[0],a=r[1]}if(\"www.\"===d.substr(0,4)&&(d=d.substr(4)),d&&d.includes(\":\")){var s=P(d,d.indexOf(\":\")),t=Ka(s,2);d=t[0],e=t[1]}return f=a,{original:b,protocol:c,domain:d,port:e,path:f,query:g,hash:h}}function R(a,b){var c=b.name,d=void 0;if(-1!==c.indexOf(\"href\")||-1!==c.indexOf(\"src\")){var e=encodeURI(axe.utils.getFriendlyUriEnd(a.getAttribute(c)));if(!e)return;d=La(b.name)+'$=\"'+e+'\"'}else d=La(c)+'=\"'+La(b.value)+'\"';return d}function S(a,b){return a.count<b.count?-1:a.count===b.count?0:1}function T(a){return!Na.includes(a.name)&&-1===a.name.indexOf(\":\")&&(!a.value||a.value.length<Oa)}function U(a,b){var c=[],d=b.classes,e=b.tags;return a.classList&&Array.from(a.classList).forEach(function(b){var f=La(b);d[f]<e[a.nodeName]&&c.push({name:f,count:d[f],species:\"class\"})}),c.sort(S)}function V(a,b){var c=a.parentNode&&Array.from(a.parentNode.children||\"\")||[];if(c.find(function(c){return c!==a&&axe.utils.matchesSelector(c,b)}))return\":nth-child(\"+(1+c.indexOf(a))+\")\";return\"\"}function W(a){if(a.getAttribute(\"id\")){var b=a.getRootNode&&a.getRootNode()||document,c=\"#\"+La(a.getAttribute(\"id\")||\"\");return c.match(/player_uid_/)||1!==b.querySelectorAll(c).length?void 0:c}}function X(a){return void 0===Ma&&(Ma=axe.utils.isXHTML(document)),La(Ma?a.localName:a.nodeName.toLowerCase())}function Y(a,b){var c=[],d=b.attributes,e=b.tags;return a.attributes&&Array.from(a.attributes).filter(T).forEach(function(b){var f=R(a,b);f&&d[f]<e[a.nodeName]&&c.push({name:f,count:d[f],species:\"attribute\"})}),c.sort(S)}function Z(a,b){var c=\"\",d=void 0,e=U(a,b),f=Y(a,b);return e.length&&1===e[0].count?d=[e[0]]:f.length&&1===f[0].count?(d=[f[0]],c=X(a)):(d=e.concat(f),d.sort(S),d=d.slice(0,3),d.some(function(a){return\"class\"===a.species})?d.sort(function(a,b){return a.species!==b.species&&\"class\"===a.species?-1:a.species===b.species?0:1}):c=X(a)),c+=d.reduce(function(a,b){switch(b.species){case\"class\":return a+\".\"+b.name;case\"attribute\":return a+\"[\"+b.name+\"]\"}return a},\"\")}function $(a,b,c){axe._selectorData||(axe._selectorData=axe.utils.getSelectorData(axe._tree));var d=b.toRoot,e=void 0!==d&&d,f=void 0,g=void 0;do{var h=W(a);h||(h=Z(a,axe._selectorData),h+=V(a,h)),f=f?h+\" > \"+f:h,g=g?g.filter(function(a){return axe.utils.matchesSelector(a,f)}):Array.from(c.querySelectorAll(f)),a=a.parentElement}while((g.length>1||e)&&a&&11!==a.nodeType);return 1===g.length?f:-1!==f.indexOf(\" > \")?\":root\"+f.substring(f.indexOf(\" > \")):\":root\"}function _(a,b){var c,d;if(!a)return[];if(!b&&9===a.nodeType)return b=[{str:\"html\"}];if(b=b||[],a.parentNode&&a.parentNode!==a&&(b=_(a.parentNode,b)),a.previousSibling){d=1,c=a.previousSibling;do{1===c.nodeType&&c.nodeName===a.nodeName&&d++,c=c.previousSibling}while(c);1===d&&(d=null)}else if(a.nextSibling){c=a.nextSibling;do{1===c.nodeType&&c.nodeName===a.nodeName?(d=1,c=null):(d=null,c=c.previousSibling)}while(c)}if(1===a.nodeType){var e={};e.str=a.nodeName.toLowerCase();var f=a.getAttribute&&axe.utils.escapeSelector(a.getAttribute(\"id\"));f&&1===a.ownerDocument.querySelectorAll(\"#\"+f).length&&(e.id=a.getAttribute(\"id\")),d>1&&(e.count=d),b.push(e)}return b}function aa(a){return a.reduce(function(a,b){return b.id?\"/\"+b.str+\"[@id='\"+b.id+\"']\":a+\"/\"+b.str+(b.count>0?\"[\"+b.count+\"]\":\"\")},\"\")}function ba(a){\"use strict\";if(Pa&&Pa.parentNode)return void 0===Pa.styleSheet?Pa.appendChild(document.createTextNode(a)):Pa.styleSheet.cssText+=a,Pa;if(a){var b=document.head||document.getElementsByTagName(\"head\")[0];return Pa=document.createElement(\"style\"),Pa.type=\"text/css\",void 0===Pa.styleSheet?Pa.appendChild(document.createTextNode(a)):Pa.styleSheet.cssText=a,b.appendChild(Pa),Pa}}function ca(a,b,c,d){\"use strict\";var e=axe.utils.getXpath(c),f={element:c,selector:d,xpath:e};a.forEach(function(a){a.node=axe.utils.DqElement.fromFrame(a.node,b,f);var c=axe.utils.getAllChecks(a);c.length&&c.forEach(function(a){a.relatedNodes=a.relatedNodes.map(function(a){return axe.utils.DqElement.fromFrame(a,b,f)})})})}function da(a,b){\"use strict\";for(var c,d,e=b[0].node,f=0,g=a.length;f<g;f++)if(d=a[f].node,(c=axe.utils.nodeSorter({actualNode:d.element},{actualNode:e.element}))>0||0===c&&e.selector.length<d.selector.length)return void a.splice.apply(a,[f,0].concat(b));a.push.apply(a,b)}function ea(a){\"use strict\";return a&&a.results?Array.isArray(a.results)?a.results.length?a.results:null:[a.results]:null}function fa(a,b){function c(a){return a.incomplete&&a.incomplete.default?a.incomplete.default:Aa.incompleteFallbackMessage()}if(!a||!a.missingData)return c(b);try{var d=b.incomplete[a.missingData[0].reason];if(!d)throw new Error;return d}catch(d){return\"string\"==typeof a.missingData?b.incomplete[a.missingData]:c(b)}}function ga(a,b){\"use strict\";return function(c){var d=a[c.id]||{},e=d.messages||{},f=Object.assign({},d);delete f.messages,void 0===c.result?\"object\"===za(e.incomplete)?f.message=function(){return fa(c.data,e)}:f.message=e.incomplete:f.message=c.result===b?e.pass:e.fail,axe.utils.extendMetaData(c,f)}}function ha(a,b){return 1===a.nodeType&&(\"*\"===b.tag||a.nodeName.toLowerCase()===b.tag)}function ia(a,b){return!b.classes||b.classes.reduce(function(b,c){return b&&a.className&&a.className.match(c.regexp)},!0)}function ja(a,b){return!b.attributes||b.attributes.reduce(function(b,c){var d=a.getAttribute(c.key);return b&&null!==d&&(!c.value||c.test(d))},!0)}function ka(a,b){return!b.id||a.id===b.id}function la(a,b){return!(b.pseudos&&!b.pseudos.reduce(function(b,c){if(\"not\"===c.name)return b&&!Sa([a],c.expressions,!1).length;throw new Error(\"the pseudo selector \"+c.name+\" has not yet been implemented\")},!0))}function ma(a){/*! Credit Mootools Copyright Mootools, MIT License */\nif(a)return a.map(function(a){var b,c,d=a.name.replace(Ua,\"\"),e=(a.value||\"\").replace(Ua,\"\");switch(a.operator){case\"^=\":c=new RegExp(\"^\"+Ta(e));break;case\"$=\":c=new RegExp(Ta(e)+\"$\");break;case\"~=\":c=new RegExp(\"(^|\\\\s)\"+Ta(e)+\"(\\\\s|$)\");break;case\"|=\":c=new RegExp(\"^\"+Ta(e)+\"(-|$)\");break;case\"=\":b=function(a){return e===a};break;case\"*=\":b=function(a){return a&&a.includes(e)};break;case\"!=\":b=function(a){return e!==a};break;default:b=function(a){return!!a}}return\"\"===e&&/^[*$^]=$/.test(a.operator)&&(b=function(){return!1}),b||(b=function(a){return a&&c.test(a)}),{key:d,value:e,test:b}})}function na(a){if(a)return a.map(function(a){return a=a.replace(Ua,\"\"),{value:a,regexp:new RegExp(\"(^|\\\\s)\"+Ta(a)+\"(\\\\s|$)\")}})}function oa(a){if(a)return a.map(function(a){var b;return\"not\"===a.name&&(b=axe.utils.cssParser.parse(a.value),b=b.selectors?b.selectors:[b],b=Ra(b)),{name:a.name,expressions:b,value:a.value}})}function pa(a,b,c,d){var e={nodes:a.slice(),anyLevel:b,thisLevel:c,parentShadowId:d};return e.nodes.reverse(),e}function qa(a,b){return ha(a.actualNode,b[0])&&ia(a.actualNode,b[0])&&ja(a.actualNode,b[0])&&ka(a.actualNode,b[0])&&la(a,b[0])}function ra(a,b){\"use strict\";var c,d,e=axe._audit&&axe._audit.tagExclude?axe._audit.tagExclude:[];return b.hasOwnProperty(\"include\")||b.hasOwnProperty(\"exclude\")?(c=b.include||[],c=Array.isArray(c)?c:[c],d=b.exclude||[],d=Array.isArray(d)?d:[d],d=d.concat(e.filter(function(a){return-1===c.indexOf(a)}))):(c=Array.isArray(b)?b:[b],d=e.filter(function(a){return-1===c.indexOf(a)})),!!(c.some(function(b){return-1!==a.tags.indexOf(b)})||0===c.length&&!1!==a.enabled)&&d.every(function(b){return-1===a.tags.indexOf(b)})}function sa(a){var b=window.getComputedStyle(a),c=\"visible\"===b.getPropertyValue(\"overflow-y\"),d=\"visible\"===b.getPropertyValue(\"overflow-x\");if(!c&&a.scrollHeight>a.clientHeight||!d&&a.scrollWidth>a.clientWidth)return{elm:a,top:a.scrollTop,left:a.scrollLeft}}function ta(a,b,c){if(a===window)return a.scroll(b,c);a.scrollTop=b,a.scrollLeft=c}function ua(a){return Array.from(a.children).reduce(function(a,b){var c=sa(b);return c&&a.push(c),a.concat(ua(b))},[])}function va(a){\"use strict\";return a.sort(function(a,b){return axe.utils.contains(a,b)?1:-1})[0]}function wa(a,b){\"use strict\";var c=b.include&&va(b.include.filter(function(b){return axe.utils.contains(b,a)})),d=b.exclude&&va(b.exclude.filter(function(b){return axe.utils.contains(b,a)}));return!!(!d&&c||d&&axe.utils.contains(d,c))}function xa(a,b){\"use strict\";var c;if(0===a.length)return b;a.length<b.length&&(c=a,a=b,b=c);for(var d=0,e=b.length;d<e;d++)a.includes(b[d])||a.push(b[d]);return a}function ya(a){return a.reduce(function(a,b){return a.length&&a[a.length-1].actualNode.contains(b.actualNode)||a.push(b),a},[])}var document=window.document,za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},axe=axe||{};axe.version=\"3.0.0-beta.2\",\"function\"==typeof define&&define.amd&&define([],function(){\"use strict\";return axe}),\"object\"===(\"undefined\"==typeof module?\"undefined\":za(module))&&module.exports&&\"function\"==typeof a.toString&&(axe.source=\"(\"+a.toString()+')(typeof window === \"object\" ? window : this);',module.exports=axe),\"function\"==typeof window.getComputedStyle&&(window.axe=axe);var commons;b.prototype=Object.create(Error.prototype),b.prototype.constructor=b;var utils=axe.utils={},Aa={},za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};e.prototype._init=function(){var a=c(this.defaultConfig);axe.commons=commons=a.commons,this.reporter=a.reporter,this.commands={},this.rules=[],this.checks={},d(a.rules,this,\"addRule\"),d(a.checks,this,\"addCheck\"),this.data={},this.data.checks=a.data&&a.data.checks||{},this.data.rules=a.data&&a.data.rules||{},this.data.failureSummaries=a.data&&a.data.failureSummaries||{},this.data.incompleteFallbackMessage=a.data&&a.data.incompleteFallbackMessage||\"\",this._constructHelpUrls()},e.prototype.registerCommand=function(a){\"use strict\";this.commands[a.id]=a.callback},e.prototype.addRule=function(a){\"use strict\";a.metadata&&(this.data.rules[a.id]=a.metadata);var b=this.getRule(a.id);b?b.configure(a):this.rules.push(new q(a,this))},e.prototype.addCheck=function(a){\"use strict\";var b=a.metadata;\"object\"===(void 0===b?\"undefined\":za(b))&&(this.data.checks[a.id]=b,\"object\"===za(b.messages)&&Object.keys(b.messages).filter(function(a){return b.messages.hasOwnProperty(a)&&\"string\"==typeof b.messages[a]}).forEach(function(a){0===b.messages[a].indexOf(\"function\")&&(b.messages[a]=new Function(\"return \"+b.messages[a]+\";\")())})),this.checks[a.id]?this.checks[a.id].configure(a):this.checks[a.id]=new i(a)},e.prototype.run=function(a,b,c,d){\"use strict\";this.validateOptions(b),axe._tree=axe.utils.getFlattenedTree(document.documentElement),axe._selectCache=[];var e=axe.utils.queue();this.rules.forEach(function(c){if(axe.utils.ruleShouldRun(c,a,b)){if(b.performanceTimer){var d=\"mark_rule_end_\"+c.id,f=\"mark_rule_start_\"+c.id;axe.utils.performanceTimer.mark(f)}e.defer(function(e,g){c.run(a,b,function(a){b.performanceTimer&&(axe.utils.performanceTimer.mark(d),axe.utils.performanceTimer.measure(\"rule_\"+c.id,f,d)),e(a)},function(a){if(b.debug)g(a);else{var d=Object.assign(new p(c),{result:axe.constants.CANTTELL,description:\"An error occured while running this rule\",message:a.message,stack:a.stack,error:a});e(d)}})})}}),e.then(function(a){axe._selectCache=void 0,c(a.filter(function(a){return!!a}))}).catch(d)},e.prototype.after=function(a,b){\"use strict\";var c=this.rules;return a.map(function(a){return axe.utils.findBy(c,\"id\",a.id).after(a,b)})},e.prototype.getRule=function(a){return this.rules.find(function(b){return b.id===a})},e.prototype.validateOptions=function(a){\"use strict\";var b=this;if(\"object\"===za(a.runOnly)){var c=a.runOnly;if(\"rule\"===c.type&&Array.isArray(c.value))c.value.forEach(function(a){if(!b.getRule(a))throw new Error(\"unknown rule `\"+a+\"` in options.runOnly\")});else if(Array.isArray(c.value)&&c.value.length>0){var d=[].concat(c.value);if(b.rules.forEach(function(a){var b,c,e;if(d)for(c=0,e=a.tags.length;c<e;c++)-1!==(b=d.indexOf(a.tags[c]))&&d.splice(b,1)}),0!==d.length)throw new Error(\"could not find tags `\"+d.join(\"`, `\")+\"`\")}}return\"object\"===za(a.rules)&&Object.keys(a.rules).forEach(function(a){if(!b.getRule(a))throw new Error(\"unknown rule `\"+a+\"` in options.rules\")}),a},e.prototype.setBranding=function(a){\"use strict\";var b={brand:this.brand,application:this.application};a&&a.hasOwnProperty(\"brand\")&&a.brand&&\"string\"==typeof a.brand&&(this.brand=a.brand),a&&a.hasOwnProperty(\"application\")&&a.application&&\"string\"==typeof a.application&&(this.application=a.application),this._constructHelpUrls(b)},e.prototype._constructHelpUrls=function(){var a=this,b=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,c=(axe.version.match(/^[1-9][0-9]*\\.[0-9]+/)||[\"x.y\"])[0];this.rules.forEach(function(d){a.data.rules[d.id]||(a.data.rules[d.id]={});var e=a.data.rules[d.id];(\"string\"!=typeof e.helpUrl||b&&e.helpUrl===f(b,d.id,c))&&(e.helpUrl=f(a,d.id,c))})},e.prototype.resetRulesAndChecks=function(){\"use strict\";this._init()},i.prototype.enabled=!0,i.prototype.run=function(a,b,c,d){\"use strict\";b=b||{};var e=b.hasOwnProperty(\"enabled\")?b.enabled:this.enabled,f=b.options||this.options;if(e){var h,i=new g(this),j=axe.utils.checkHelper(i,b,c,d);try{h=this.evaluate.call(j,a.actualNode,f,a)}catch(a){return void d(a)}j.isAsync||(i.result=h,setTimeout(function(){c(i)},0))}else c(null)},i.prototype.configure=function(a){var b=this;[\"options\",\"enabled\"].filter(function(b){return a.hasOwnProperty(b)}).forEach(function(c){return b[c]=a[c]}),[\"evaluate\",\"after\"].filter(function(b){return a.hasOwnProperty(b)}).forEach(function(c){return b[c]=h(a[c])})};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};q.prototype.matches=function(){\"use strict\";return!0},q.prototype.gather=function(a){\"use strict\";var b=axe.utils.select(this.selector,a);return this.excludeHidden?b.filter(function(a){return!axe.utils.isHidden(a.actualNode)}):b},q.prototype.runChecks=function(a,b,c,d,e){\"use strict\";var f=this,g=axe.utils.queue();this[a].forEach(function(a){var d=f._audit.checks[a.id||a],e=axe.utils.getCheckOption(d,f.id,c);g.defer(function(a,c){d.run(b,e,a,c)})}),g.then(function(b){b=b.filter(function(a){return a}),d({type:a,results:b})}).catch(e)},q.prototype.run=function(a,c,d,e){var f=this,g=axe.utils.queue(),h=new p(this),i=\"mark_runchecks_start_\"+this.id,j=\"mark_runchecks_end_\"+this.id,k=void 0;try{k=this.gather(a).filter(function(a){return f.matches(a.actualNode,a)})}catch(a){return void e(new b({cause:a,ruleId:this.id}))}c.performanceTimer&&(axe.log(\"gather (\",k.length,\"):\",axe.utils.performanceTimer.timeElapsed()+\"ms\"),axe.utils.performanceTimer.mark(i)),k.forEach(function(a){g.defer(function(b,d){var e=axe.utils.queue();e.defer(function(b,d){f.runChecks(\"any\",a,c,b,d)}),e.defer(function(b,d){f.runChecks(\"all\",a,c,b,d)}),e.defer(function(b,d){f.runChecks(\"none\",a,c,b,d)}),e.then(function(d){if(d.length){var e=!1,f={};d.forEach(function(a){var b=a.results.filter(function(a){return a});f[a.type]=b,b.length&&(e=!0)}),e&&(f.node=new axe.utils.DqElement(a.actualNode,c),h.nodes.push(f))}b()}).catch(function(a){return d(a)})})}),c.performanceTimer&&(axe.utils.performanceTimer.mark(j),axe.utils.performanceTimer.measure(\"runchecks_\"+this.id,i,j)),g.then(function(){return d(h)}).catch(function(a){return e(a)})},q.prototype.after=function(a,b){\"use strict\";var c=r(this),d=this.id;return c.forEach(function(c){var e=s(a.nodes,c.id),f=axe.utils.getCheckOption(c,d,b),g=c.after(e,f);e.forEach(function(a){-1===g.indexOf(a)&&(a.filtered=!0)})}),a.nodes=u(a),a},q.prototype.configure=function(a){\"use strict\";a.hasOwnProperty(\"selector\")&&(this.selector=a.selector),a.hasOwnProperty(\"excludeHidden\")&&(this.excludeHidden=\"boolean\"!=typeof a.excludeHidden||a.excludeHidden),a.hasOwnProperty(\"enabled\")&&(this.enabled=\"boolean\"!=typeof a.enabled||a.enabled),a.hasOwnProperty(\"pageLevel\")&&(this.pageLevel=\"boolean\"==typeof a.pageLevel&&a.pageLevel),a.hasOwnProperty(\"any\")&&(this.any=a.any),a.hasOwnProperty(\"all\")&&(this.all=a.all),a.hasOwnProperty(\"none\")&&(this.none=a.none),a.hasOwnProperty(\"tags\")&&(this.tags=a.tags),a.hasOwnProperty(\"matches\")&&(\"string\"==typeof a.matches?this.matches=new Function(\"return \"+a.matches+\";\")():this.matches=a.matches)},function(axe){var a=[{name:\"NA\",value:\"inapplicable\",priority:0,group:\"inapplicable\"},{name:\"PASS\",value:\"passed\",priority:1,group:\"passes\"},{name:\"CANTTELL\",value:\"cantTell\",priority:2,group:\"incomplete\"},{name:\"FAIL\",value:\"failed\",priority:3,group:\"violations\"}],b={helpUrlBase:\"https://dequeuniversity.com/rules/\",results:[],resultGroups:[],resultGroupMap:{},impact:Object.freeze([\"minor\",\"moderate\",\"serious\",\"critical\"])};a.forEach(function(a){var c=a.name,d=a.value,e=a.priority,f=a.group;b[c]=d,b[c+\"_PRIO\"]=e,b[c+\"_GROUP\"]=f,b.results[e]=d,b.resultGroups[e]=f,b.resultGroupMap[d]=f}),Object.freeze(b.results),Object.freeze(b.resultGroups),Object.freeze(b.resultGroupMap),Object.freeze(b),Object.defineProperty(axe,\"constants\",{value:b,enumerable:!0,configurable:!1,writable:!1})}(axe);var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.log=function(){\"use strict\";\"object\"===(\"undefined\"==typeof console?\"undefined\":za(console))&&console.log&&Function.prototype.apply.call(console.log,console,arguments)},axe.cleanup=v,axe.configure=w,axe.getRules=function(a){\"use strict\";a=a||[];var b=a.length?axe._audit.rules.filter(function(b){return!!a.filter(function(a){return-1!==b.tags.indexOf(a)}).length}):axe._audit.rules,c=axe._audit.data.rules||{};return b.map(function(a){var b=c[a.id]||{};return{ruleId:a.id,description:b.description,help:b.help,helpUrl:b.helpUrl,tags:a.tags}})},axe._load=function(a){\"use strict\";axe.utils.respondable.subscribe(\"axe.ping\",function(a,b,c){c({axe:!0})}),axe.utils.respondable.subscribe(\"axe.start\",x),axe._audit=new e(a)};var axe=axe||{};axe.plugins={},y.prototype.run=function(){\"use strict\";return this._run.apply(this,arguments)},y.prototype.collect=function(){\"use strict\";return this._collect.apply(this,arguments)},y.prototype.cleanup=function(a){\"use strict\";var b=axe.utils.queue(),c=this;Object.keys(this._registry).forEach(function(a){b.defer(function(b){c._registry[a].cleanup(b)})}),b.then(function(){a()})},y.prototype.add=function(a){\"use strict\";this._registry[a.id]=a},axe.registerPlugin=function(a){\"use strict\";axe.plugins[a.id]=new y(a)};var Ba,Ca={};axe.getReporter=function(a){\"use strict\";return\"string\"==typeof a&&Ca[a]?Ca[a]:\"function\"==typeof a?a:Ba},axe.addReporter=function(a,b,c){\"use strict\";Ca[a]=b,c&&(Ba=b)},axe.reset=z,axe._runRules=A;var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},Da=function(){};axe.run=function(a,b,c){\"use strict\";if(!axe._audit)throw new Error(\"No audit configured\");var d=C(a,b,c);a=d.context,b=d.options,c=d.callback,b.reporter=b.reporter||axe._audit.reporter||\"v1\",b.performanceTimer&&axe.utils.performanceTimer.start();var e=void 0,f=Da,g=Da;return window.Promise&&c===Da&&(e=new Promise(function(a,b){f=b,g=a})),axe._runRules(a,b,function(a){var d=function(a){try{c(null,a)}catch(a){axe.log(a)}g(a)};b.performanceTimer&&axe.utils.performanceTimer.end();try{var e=axe.getReporter(b.reporter),h=e(a,b,d);axe._selectorData=void 0,axe._tree=void 0,void 0!==h&&d(h)}catch(a){c(a),f(a)}},function(a){c(a),f(a)}),e},Aa.failureSummary=function(a){\"use strict\";var b={};return b.none=a.none.concat(a.all),b.any=a.any,Object.keys(b).map(function(a){if(b[a].length){var c=axe._audit.data.failureSummaries[a];return c&&\"function\"==typeof c.failureMessage?c.failureMessage(b[a].map(function(a){return a.message||\"\"})):void 0}}).filter(function(a){return void 0!==a}).join(\"\\n\\n\")},Aa.incompleteFallbackMessage=function(){\"use strict\";return axe._audit.data.incompleteFallbackMessage()};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a},Ea=axe.constants.resultGroups;Aa.processAggregate=function(a,b){var c=axe.utils.aggregateResult(a);return c.timestamp=(new Date).toISOString(),c.url=window.location.href,Ea.forEach(function(a){b.resultTypes&&!b.resultTypes.includes(a)&&(c[a]||[]).forEach(function(a){Array.isArray(a.nodes)&&a.nodes.length>0&&(a.nodes=[a.nodes[0]])}),c[a]=(c[a]||[]).map(function(a){return a=Object.assign({},a),Array.isArray(a.nodes)&&a.nodes.length>0&&(a.nodes=a.nodes.map(function(a){return\"object\"===za(a.node)&&(a.html=a.node.source,b.elementRef&&!a.node.fromFrame&&(a.element=a.node.element),(!1!==b.selectors||a.node.fromFrame)&&(a.target=a.node.selector),b.xpath&&(a.xpath=a.node.xpath)),delete a.result,delete a.node,D(a,b),a})),Ea.forEach(function(b){return delete a[b]}),delete a.pageLevel,delete a.result,a})}),c},axe.addReporter(\"na\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=Aa.processAggregate(a,b);c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"no-passes\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={}),b.resultTypes=[\"violations\"];var d=Aa.processAggregate(a,b);c({violations:d.violations,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"raw\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={}),c(a)}),axe.addReporter(\"v1\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=Aa.processAggregate(a,b);d.violations.forEach(function(a){return a.nodes.forEach(function(a){a.failureSummary=Aa.failureSummary(a)})}),c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})}),axe.addReporter(\"v2\",function(a,b,c){\"use strict\";\"function\"==typeof b&&(c=b,b={});var d=Aa.processAggregate(a,b);c({violations:d.violations,passes:d.passes,incomplete:d.incomplete,inapplicable:d.inapplicable,timestamp:d.timestamp,url:d.url})},!0),axe.utils.aggregate=function(a,b,c){b=b.slice(),c&&b.push(c);var d=b.map(function(b){return a.indexOf(b)}).sort();return a[d.pop()]};var Fa=axe.constants,Ga=Fa.CANTTELL_PRIO,Ha=Fa.FAIL_PRIO,Ia=[];Ia[axe.constants.PASS_PRIO]=!0,Ia[axe.constants.CANTTELL_PRIO]=null,Ia[axe.constants.FAIL_PRIO]=!1;var Ja=[\"any\",\"all\",\"none\"];axe.utils.aggregateChecks=function(a){var b=Object.assign({},a);E(b,function(a,b){var c=Ia.indexOf(a.result);a.priority=-1!==c?c:axe.constants.CANTTELL_PRIO,\"none\"===b&&(a.priority=4-a.priority)});var c={all:b.all.reduce(function(a,b){return Math.max(a,b.priority)},0),none:b.none.reduce(function(a,b){return Math.max(a,b.priority)},0),any:b.any.reduce(function(a,b){return Math.min(a,b.priority)},4)%4};b.priority=Math.max(c.all,c.none,c.any);var d=[];return Ja.forEach(function(a){b[a]=b[a].filter(function(d){return d.priority===b.priority&&d.priority===c[a]}),b[a].forEach(function(a){return d.push(a.impact)})}),[Ga,Ha].includes(b.priority)?b.impact=axe.utils.aggregate(axe.constants.impact,d):b.impact=null,E(b,function(a){delete a.result,delete a.priority}),b.result=axe.constants.results[b.priority],delete b.priority,b},function(){axe.utils.aggregateNodeResults=function(a){var b={};if((a=a.map(function(a){if(a.any&&a.all&&a.none)return axe.utils.aggregateChecks(a);if(Array.isArray(a.node))return axe.utils.finalizeRuleResult(a);throw new TypeError(\"Invalid Result type\")}))&&a.length){var c=a.map(function(a){return a.result});b.result=axe.utils.aggregate(axe.constants.results,c,b.result)}else b.result=\"inapplicable\";axe.constants.resultGroups.forEach(function(a){return b[a]=[]}),a.forEach(function(a){var c=axe.constants.resultGroupMap[a.result];b[c].push(a)});var d=axe.constants.FAIL_GROUP;if(0===b[d].length&&(d=axe.constants.CANTTELL_GROUP),b[d].length>0){var e=b[d].map(function(a){return a.impact});b.impact=axe.utils.aggregate(axe.constants.impact,e)||null}else b.impact=null;return b}}(),axe.utils.aggregateResult=function(a){var b={};return axe.constants.resultGroups.forEach(function(a){return b[a]=[]}),a.forEach(function(a){a.error?F(b,a,axe.constants.CANTTELL_GROUP):a.result===axe.constants.NA?F(b,a,axe.constants.NA_GROUP):axe.constants.resultGroups.forEach(function(c){Array.isArray(a[c])&&a[c].length>0&&F(b,a,c)})}),b},axe.utils.areStylesSet=G,axe.utils.checkHelper=function(a,b,c,d){\"use strict\";return{isAsync:!1,async:function(){return this.isAsync=!0,function(b){b instanceof Error==!1?(a.result=b,c(a)):d(b)}},data:function(b){a.data=b},relatedNodes:function(c){c=c instanceof Node?[c]:axe.utils.toArray(c),a.relatedNodes=c.map(function(a){return new axe.utils.DqElement(a,b)})}}};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.clone=function(a){\"use strict\";var b,c,d=a;if(null!==a&&\"object\"===(void 0===a?\"undefined\":za(a)))if(Array.isArray(a))for(d=[],b=0,c=a.length;b<c;b++)d[b]=axe.utils.clone(a[b]);else{d={};for(b in a)d[b]=axe.utils.clone(a[b])}return d},axe.utils.sendCommandToFrame=function(a,b,c,d){\"use strict\";var e=a.contentWindow;if(!e)return axe.log(\"Frame does not have a content window\",a),void c(null);var f=setTimeout(function(){f=setTimeout(function(){var e=H(\"No response from frame\",a);b.debug?d(e):(axe.log(e),c(null))},0)},500);axe.utils.respondable(e,\"axe.ping\",null,void 0,function(){clearTimeout(f);var g=b.options&&b.options.frameWaitTime||6e4;f=setTimeout(function(){d(H(\"Axe in frame timed out\",a))},g),axe.utils.respondable(e,\"axe.start\",b,void 0,function(a){clearTimeout(f),a instanceof Error==!1?c(a):d(a)})})},axe.utils.collectResultsFromFrames=I,axe.utils.contains=function(a,b){\"use strict\";function c(a,b){return a.shadowId===b.shadowId||!!a.children.find(function(a){return c(a,b)})}return a.shadowId||b.shadowId?c(a,b):\"function\"==typeof a.actualNode.contains?a.actualNode.contains(b.actualNode):!!(16&a.actualNode.compareDocumentPosition(b.actualNode))},function(axe){/*!\n  * The copyright below covers the code within this function block only\n  *\n  * Copyright (c) 2013 Dulin Marat\n  * \n  * Permission is hereby granted, free of charge, to any person obtaining a copy\n  * of this software and associated documentation files (the \"Software\"), to deal\n  * in the Software without restriction, including without limitation the rights\n  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  * copies of the Software, and to permit persons to whom the Software is\n  * furnished to do so, subject to the following conditions:\n  * \n  * The above copyright notice and this permission notice shall be included in\n  * all copies or substantial portions of the Software.\n  * \n  * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  * THE SOFTWARE.\n  */\nfunction a(){this.pseudos={},this.attrEqualityMods={},this.ruleNestingOperators={},this.substitutesEnabled=!1}function b(a){return a>=\"a\"&&a<=\"z\"||a>=\"A\"&&a<=\"Z\"||\"-\"===a||\"_\"===a}function c(a){return a>=\"a\"&&a<=\"z\"||a>=\"A\"&&a<=\"Z\"||a>=\"0\"&&a<=\"9\"||\"-\"===a||\"_\"===a}function d(a){return a>=\"a\"&&a<=\"f\"||a>=\"A\"&&a<=\"F\"||a>=\"0\"&&a<=\"9\"}function e(a,e,g,j,k,l){var m,n,o,p,q;return p=a.length,m=null,o=function(b,c){var f,g,h;for(h=\"\",e++,m=a.charAt(e);e<p;){if(m===b)return e++,h;if(\"\\\\\"===m)if(e++,(m=a.charAt(e))===b)h+=b;else if(f=c[m])h+=f;else{if(d(m)){for(g=m,e++,m=a.charAt(e);d(m);)g+=m,e++,m=a.charAt(e);\" \"===m&&(e++,m=a.charAt(e)),h+=String.fromCharCode(parseInt(g,16));continue}h+=m}else h+=m;e++,m=a.charAt(e)}return h},n=function(){var b=\"\";for(m=a.charAt(e);e<p;){if(c(m))b+=m;else{if(\"\\\\\"!==m)return b;if(++e>=p)throw Error(\"Expected symbol but end of file reached.\");if(m=a.charAt(e),f[m])b+=m;else{if(d(m)){var g=m;for(e++,m=a.charAt(e);d(m);)g+=m,e++,m=a.charAt(e);\" \"===m&&(e++,m=a.charAt(e)),b+=String.fromCharCode(parseInt(g,16));continue}b+=m}}e++,m=a.charAt(e)}return b},q=function(){m=a.charAt(e);for(var b=!1;\" \"===m||\"\\t\"===m||\"\\n\"===m||\"\\r\"===m||\"\\f\"===m;)b=!0,e++,m=a.charAt(e);return b},this.parse=function(){var b=this.parseSelector();if(e<p)throw Error('Rule expected but \"'+a.charAt(e)+'\" found.');return b},this.parseSelector=function(){var b,c=b=this.parseSingleSelector();for(m=a.charAt(e);\",\"===m;){if(e++,q(),\"selectors\"!==b.type&&(b={type:\"selectors\",selectors:[c]}),!(c=this.parseSingleSelector()))throw Error('Rule expected after \",\".');b.selectors.push(c)}return b},this.parseSingleSelector=function(){q();var b={type:\"ruleSet\"},c=this.parseRule();if(!c)return null;for(var d=b;c&&(c.type=\"rule\",d.rule=c,d=c,q(),m=a.charAt(e),!(e>=p||\",\"===m||\")\"===m));)if(k[m]){var f=m;if(e++,q(),!(c=this.parseRule()))throw Error('Rule expected after \"'+f+'\".');c.nestingOperator=f}else(c=this.parseRule())&&(c.nestingOperator=null);return b},this.parseRule=function(){for(var c=null;e<p;)if(\"*\"===(m=a.charAt(e)))e++,(c=c||{}).tagName=\"*\";else if(b(m)||\"\\\\\"===m)(c=c||{}).tagName=n();else if(\".\"===m)e++,c=c||{},(c.classNames=c.classNames||[]).push(n());else if(\"#\"===m)e++,(c=c||{}).id=n();else if(\"[\"===m){e++,q();var d={name:n()};if(q(),\"]\"===m)e++;else{var f=\"\";if(j[m]&&(f=m,e++,m=a.charAt(e)),e>=p)throw Error('Expected \"=\" but end of file reached.');if(\"=\"!==m)throw Error('Expected \"=\" but \"'+m+'\" found.');d.operator=f+\"=\",e++,q();var k=\"\";if(d.valueType=\"string\",'\"'===m)k=o('\"',i);else if(\"'\"===m)k=o(\"'\",h);else if(l&&\"$\"===m)e++,k=n(),d.valueType=\"substitute\";else{for(;e<p&&\"]\"!==m;)k+=m,e++,m=a.charAt(e);k=k.trim()}if(q(),e>=p)throw Error('Expected \"]\" but end of file reached.');if(\"]\"!==m)throw Error('Expected \"]\" but \"'+m+'\" found.');e++,d.value=k}c=c||{},(c.attrs=c.attrs||[]).push(d)}else{if(\":\"!==m)break;e++;var r=n(),s={name:r};if(\"(\"===m){e++;var t=\"\";if(q(),\"selector\"===g[r])s.valueType=\"selector\",t=this.parseSelector();else{if(s.valueType=g[r]||\"string\",'\"'===m)t=o('\"',i);else if(\"'\"===m)t=o(\"'\",h);else if(l&&\"$\"===m)e++,t=n(),s.valueType=\"substitute\";else{for(;e<p&&\")\"!==m;)t+=m,e++,m=a.charAt(e);t=t.trim()}q()}if(e>=p)throw Error('Expected \")\" but end of file reached.');if(\")\"!==m)throw Error('Expected \")\" but \"'+m+'\" found.');e++,s.value=t}c=c||{},(c.pseudos=c.pseudos||[]).push(s)}return c},this}a.prototype.registerSelectorPseudos=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],this.pseudos[a]=\"selector\";return this},a.prototype.unregisterSelectorPseudos=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],delete this.pseudos[a];return this},a.prototype.registerNumericPseudos=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],this.pseudos[a]=\"numeric\";return this},a.prototype.unregisterNumericPseudos=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],delete this.pseudos[a];return this},a.prototype.registerNestingOperators=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],this.ruleNestingOperators[a]=!0;return this},a.prototype.unregisterNestingOperators=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],delete this.ruleNestingOperators[a];return this},a.prototype.registerAttrEqualityMods=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],this.attrEqualityMods[a]=!0;return this},a.prototype.unregisterAttrEqualityMods=function(a){for(var b=0,c=arguments.length;b<c;b++)a=arguments[b],delete this.attrEqualityMods[a];return this},a.prototype.enableSubstitutes=function(){return this.substitutesEnabled=!0,this},a.prototype.disableSubstitutes=function(){return this.substitutesEnabled=!1,this};var f={\"!\":!0,'\"':!0,\"#\":!0,$:!0,\"%\":!0,\"&\":!0,\"'\":!0,\"(\":!0,\")\":!0,\"*\":!0,\"+\":!0,\",\":!0,\".\":!0,\"/\":!0,\";\":!0,\"<\":!0,\"=\":!0,\">\":!0,\"?\":!0,\"@\":!0,\"[\":!0,\"\\\\\":!0,\"]\":!0,\"^\":!0,\"`\":!0,\"{\":!0,\"|\":!0,\"}\":!0,\"~\":!0},g={\"\\n\":\"\\\\n\",\"\\r\":\"\\\\r\",\"\\t\":\"\\\\t\",\"\\f\":\"\\\\f\",\"\\v\":\"\\\\v\"},h={n:\"\\n\",r:\"\\r\",t:\"\\t\",f:\"\\f\",\"\\\\\":\"\\\\\",\"'\":\"'\"},i={n:\"\\n\",r:\"\\r\",t:\"\\t\",f:\"\\f\",\"\\\\\":\"\\\\\",'\"':'\"'};a.prototype.parse=function(a){return new e(a,0,this.pseudos,this.attrEqualityMods,this.ruleNestingOperators,this.substitutesEnabled).parse()},a.prototype.escapeIdentifier=function(a){for(var b=\"\",c=0,d=a.length;c<d;){var e=a.charAt(c);if(f[e])b+=\"\\\\\"+e;else if(\"_\"===e||\"-\"===e||e>=\"A\"&&e<=\"Z\"||e>=\"a\"&&e<=\"z\"||0!==c&&e>=\"0\"&&e<=\"9\")b+=e;else{var g=e.charCodeAt(0);if(55296==(63488&g)){var h=a.charCodeAt(c++);if(55296!=(64512&g)||56320!=(64512&h))throw Error(\"UCS-2(decode): illegal sequence\");g=((1023&g)<<10)+(1023&h)+65536}b+=\"\\\\\"+g.toString(16)+\" \"}c++}return b},a.prototype.escapeStr=function(a){for(var b,c,d=\"\",e=0,f=a.length;e<f;)b=a.charAt(e),'\"'===b?b='\\\\\"':\"\\\\\"===b?b=\"\\\\\\\\\":(c=g[b])&&(b=c),d+=b,e++;return'\"'+d+'\"'},a.prototype.render=function(a){return this._renderEntity(a).trim()},a.prototype._renderEntity=function(a){var b,c,d;switch(d=\"\",a.type){case\"ruleSet\":for(b=a.rule,c=[];b;)b.nestingOperator&&c.push(b.nestingOperator),c.push(this._renderEntity(b)),b=b.rule;d=c.join(\" \");break;case\"selectors\":d=a.selectors.map(this._renderEntity,this).join(\", \");break;case\"rule\":a.tagName&&(d=\"*\"===a.tagName?\"*\":this.escapeIdentifier(a.tagName)),a.id&&(d+=\"#\"+this.escapeIdentifier(a.id)),a.classNames&&(d+=a.classNames.map(function(a){return\".\"+this.escapeIdentifier(a)},this).join(\"\")),a.attrs&&(d+=a.attrs.map(function(a){return a.operator?\"substitute\"===a.valueType?\"[\"+this.escapeIdentifier(a.name)+a.operator+\"$\"+a.value+\"]\":\"[\"+this.escapeIdentifier(a.name)+a.operator+this.escapeStr(a.value)+\"]\":\"[\"+this.escapeIdentifier(a.name)+\"]\"},this).join(\"\")),a.pseudos&&(d+=a.pseudos.map(function(a){return a.valueType?\"selector\"===a.valueType?\":\"+this.escapeIdentifier(a.name)+\"(\"+this._renderEntity(a.value)+\")\":\"substitute\"===a.valueType?\":\"+this.escapeIdentifier(a.name)+\"($\"+a.value+\")\":\"numeric\"===a.valueType?\":\"+this.escapeIdentifier(a.name)+\"(\"+a.value+\")\":\":\"+this.escapeIdentifier(a.name)+\"(\"+this.escapeIdentifier(a.value)+\")\":\":\"+this.escapeIdentifier(a.name)},this).join(\"\"));break;default:throw Error('Unknown entity type: \"'+a.type(NaN))}return d};var j=new a;j.registerNestingOperators(\">\"),axe.utils.cssParser=j}(axe),L.prototype={get selector(){return this.spec.selector||[axe.utils.getSelector(this.element,this._options)]},get xpath(){return this.spec.xpath||[axe.utils.getXpath(this.element)]},get element(){return this._element},get fromFrame(){return this._fromFrame},toJSON:function(){\"use strict\";return{selector:this.selector,source:this.source,xpath:this.xpath}}},L.fromFrame=function(a,b,c){return a.selector.unshift(c.selector),a.xpath.unshift(c.xpath),new axe.utils.DqElement(c.element,b,a)},axe.utils.DqElement=L,axe.utils.matchesSelector=function(){\"use strict\";function a(a){var b,c,d=a.Element.prototype,e=[\"matches\",\"matchesSelector\",\"mozMatchesSelector\",\"webkitMatchesSelector\",\"msMatchesSelector\"],f=e.length;for(b=0;b<f;b++)if(c=e[b],d[c])return c}var b;return function(c,d){return b&&c[b]||(b=a(c.ownerDocument.defaultView)),c[b](d)}}(),axe.utils.escapeSelector=function(a){\"use strict\";for(var b,c=String(a),d=c.length,e=-1,f=\"\",g=c.charCodeAt(0);++e<d;){if(0==(b=c.charCodeAt(e)))throw new Error(\"INVALID_CHARACTER_ERR\");b>=1&&b<=31||b>=127&&b<=159||0==e&&b>=48&&b<=57||1==e&&b>=48&&b<=57&&45==g?f+=\"\\\\\"+b.toString(16)+\" \":f+=(1!=e||45!=b||45!=g)&&(b>=128||45==b||95==b||b>=48&&b<=57||b>=65&&b<=90||b>=97&&b<=122)?c.charAt(e):\"\\\\\"+c.charAt(e)}return f},axe.utils.extendMetaData=function(a,b){Object.assign(a,b),Object.keys(b).filter(function(a){return\"function\"==typeof b[a]}).forEach(function(c){a[c]=null;try{a[c]=b[c](a)}catch(a){}})},axe.utils.finalizeRuleResult=function(a){return Object.assign(a,axe.utils.aggregateNodeResults(a.nodes)),delete a.nodes,a};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.findBy=function(a,b,c){if(Array.isArray(a))return a.find(function(a){return\"object\"===(void 0===a?\"undefined\":za(a))&&a[b]===c})};var axe=axe||{utils:{}};axe.utils.getFlattenedTree=function(a,b){function c(a,c){var d=axe.utils.getFlattenedTree(c,b);return d&&(a=a.concat(d)),a}var d,e,f;if(a.documentElement&&(a=a.documentElement),f=a.nodeName.toLowerCase(),axe.utils.isShadowRoot(a))return d=M(a,b),b=\"a\"+Math.random().toString().substring(2),e=Array.from(a.shadowRoot.childNodes),d.children=e.reduce(c,[]),[d];if(\"content\"===f)return e=Array.from(a.getDistributedNodes()),e.reduce(c,[]);if(\"slot\"===f){e=Array.from(a.assignedNodes()),e.length||(e=N(a));window.getComputedStyle(a);return e.reduce(c,[])}return 1===a.nodeType?(d=M(a,b),e=Array.from(a.childNodes),d.children=e.reduce(c,[]),[d]):3===a.nodeType?[M(a)]:void 0},axe.utils.getNodeFromTree=function(a,b){var c;return a.actualNode===b?a:(a.children.forEach(function(a){var d;a.actualNode===b?c=a:(d=axe.utils.getNodeFromTree(a,b))&&(c=d)}),c)},axe.utils.getAllChecks=function(a){\"use strict\";return[].concat(a.any||[]).concat(a.all||[]).concat(a.none||[])},axe.utils.getCheckOption=function(a,b,c){var d=((c.rules&&c.rules[b]||{}).checks||{})[a.id],e=(c.checks||{})[a.id],f=a.enabled,g=a.options;return e&&(e.hasOwnProperty(\"enabled\")&&(f=e.enabled),e.hasOwnProperty(\"options\")&&(g=e.options)),d&&(d.hasOwnProperty(\"enabled\")&&(f=d.enabled),d.hasOwnProperty(\"options\")&&(g=d.options)),{enabled:f,options:g,absolutePaths:c.absolutePaths}};var Ka=function(){function a(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g,h=a[Symbol.iterator]();!(d=(g=h.next()).done)&&(c.push(g.value),!b||c.length!==b);d=!0);}catch(a){e=!0,f=a}finally{try{!d&&h.return&&h.return()}finally{if(e)throw f}}return c}return function(b,c){if(Array.isArray(b))return b;if(Symbol.iterator in Object(b))return a(b,c);throw new TypeError(\"Invalid attempt to destructure non-iterable instance\")}}();axe.utils.getFriendlyUriEnd=function(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\",b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!(a.length<=1||\"data:\"===a.substr(0,5)||\"javascript:\"===a.substr(0,11)||a.includes(\"?\"))){var c=b.currentDomain,d=b.maxLength,e=void 0===d?25:d,f=Q(a),g=f.path,h=f.domain,i=f.hash,j=g.substr(g.substr(0,g.length-2).lastIndexOf(\"/\")+1);if(i)return j&&(j+i).length<=e?j+i:j.length<2&&i.length>2&&i.length<=e?i:void 0;if(h&&h.length<e&&g.length<=1)return h+g;if(g===\"/\"+j&&h&&c&&h!==c&&(h+g).length<=e)return h+g;var k=j.lastIndexOf(\".\");return(-1===k||k>1)&&(-1!==k||j.length>2)&&j.length<=e&&!j.match(/index(\\.[a-zA-Z]{2-4})?/)&&!O(j)?j:void 0}};var La=axe.utils.escapeSelector,Ma=void 0,Na=[\"class\",\"style\",\"id\",\"selected\",\"checked\",\"disabled\",\"tabindex\",\"aria-checked\",\"aria-selected\",\"aria-invalid\",\"aria-activedescendant\",\"aria-busy\",\"aria-disabled\",\"aria-expanded\",\"aria-grabbed\",\"aria-pressed\",\"aria-valuenow\"],Oa=31;axe.utils.getSelectorData=function(a){var b={classes:{},tags:{},attributes:{}};a=Array.isArray(a)?a:[a];for(var c=a.slice(),d=[];c.length;)!function(){var a=c.pop(),e=a.actualNode;if(e.querySelectorAll){var f=e.nodeName;b.tags[f]?b.tags[f]++:b.tags[f]=1,e.classList&&Array.from(e.classList).forEach(function(a){var c=La(a);b.classes[c]?b.classes[c]++:b.classes[c]=1}),e.attributes&&Array.from(e.attributes).filter(T).forEach(function(a){var c=R(e,a);c&&(b.attributes[c]?b.attributes[c]++:b.attributes[c]=1)})}for(a.children.length&&(d.push(c),c=a.children.slice());!c.length&&d.length;)c=d.pop()}();return b},axe.utils.getSelector=function(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!a)return\"\";var c=a.getRootNode&&a.getRootNode()||document;if(11===c.nodeType){for(var d=[];11===c.nodeType;)d.push({elm:a,doc:c}),a=c.host,c=a.getRootNode();return d.push({elm:a,doc:c}),d.reverse().map(function(a){return $(a.elm,b,a.doc)})}return $(a,b,c)},axe.utils.getXpath=function(a){return aa(_(a))};var Pa;axe.utils.injectStyle=ba,axe.utils.isHidden=function(a,b){\"use strict\";var c;if(9===a.nodeType)return!1;11===a.nodeType&&(a=a.host);var d=window.getComputedStyle(a,null);return!d||!a.parentNode||\"none\"===d.getPropertyValue(\"display\")||!b&&\"hidden\"===d.getPropertyValue(\"visibility\")||\"true\"===a.getAttribute(\"aria-hidden\")||(c=a.assignedSlot?a.assignedSlot:a.parentNode,axe.utils.isHidden(c,!0))};var Qa=[\"article\",\"aside\",\"blockquote\",\"body\",\"div\",\"footer\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"header\",\"main\",\"nav\",\"p\",\"section\",\"span\"];axe.utils.isShadowRoot=function(a){var b=a.nodeName.toLowerCase();return!(!a.shadowRoot||!/^[a-z][a-z0-9_.-]*-[a-z0-9_.-]*$/.test(b)&&!Qa.includes(b))},axe.utils.isXHTML=function(a){\"use strict\";return!!a.createElement&&\"A\"===a.createElement(\"A\").localName},axe.utils.mergeResults=function(a,b){\"use strict\";var c=[];return a.forEach(function(a){var d=ea(a);d&&d.length&&d.forEach(function(d){d.nodes&&a.frame&&ca(d.nodes,b,a.frameElement,a.frame);var e=axe.utils.findBy(c,\"id\",d.id);e?d.nodes.length&&da(e.nodes,d.nodes):c.push(d)})}),c},axe.utils.nodeSorter=function(a,b){\"use strict\";return a.actualNode===b.actualNode?0:4&a.actualNode.compareDocumentPosition(b.actualNode)?-1:1},utils.performanceTimer=function(){\"use strict\";function a(){if(window.performance&&window.performance)return window.performance.now()}var b=null,c=a();return{start:function(){this.mark(\"mark_axe_start\")},end:function(){this.mark(\"mark_axe_end\"),this.measure(\"axe\",\"mark_axe_start\",\"mark_axe_end\"),this.logMeasures(\"axe\")},auditStart:function(){this.mark(\"mark_audit_start\")},auditEnd:function(){this.mark(\"mark_audit_end\"),this.measure(\"audit_start_to_end\",\"mark_audit_start\",\"mark_audit_end\"),this.logMeasures()},mark:function(a){window.performance&&void 0!==window.performance.mark&&window.performance.mark(a)},measure:function(a,b,c){window.performance&&void 0!==window.performance.measure&&window.performance.measure(a,b,c)},logMeasures:function(a){function b(a){axe.log(\"Measure \"+a.name+\" took \"+a.duration+\"ms\")}if(window.performance&&void 0!==window.performance.getEntriesByType)for(var c=window.performance.getEntriesByType(\"measure\"),d=0;d<c.length;++d){var e=c[d];if(e.name===a)return void b(e);b(e)}},timeElapsed:function(){return a()-c},reset:function(){b||(b=a()),c=a()}}}(),\"function\"!=typeof Object.assign&&function(){Object.assign=function(a){\"use strict\";if(void 0===a||null===a)throw new TypeError(\"Cannot convert undefined or null to object\");for(var b=Object(a),c=1;c<arguments.length;c++){var d=arguments[c];if(void 0!==d&&null!==d)for(var e in d)d.hasOwnProperty(e)&&(b[e]=d[e])}return b}}(),Array.prototype.find||Object.defineProperty(Array.prototype,\"find\",{value:function(a){if(null===this)throw new TypeError(\"Array.prototype.find called on null or undefined\");if(\"function\"!=typeof a)throw new TypeError(\"predicate must be a function\");for(var b,c=Object(this),d=c.length>>>0,e=arguments[1],f=0;f<d;f++)if(b=c[f],a.call(e,b,f,c))return b}}),axe.utils.pollyfillElementsFromPoint=function(){if(document.elementsFromPoint)return document.elementsFromPoint;if(document.msElementsFromPoint)return document.msElementsFromPoint;var a=function(){var a=document.createElement(\"x\");return a.style.cssText=\"pointer-events:auto\",\"auto\"===a.style.pointerEvents}(),b=a?\"pointer-events\":\"visibility\",c=a?\"none\":\"hidden\",d=document.createElement(\"style\");return d.innerHTML=a?\"* { pointer-events: all }\":\"* { visibility: visible }\",function(a,e){var f,g,h,i=[],j=[];for(document.head.appendChild(d);(f=document.elementFromPoint(a,e))&&-1===i.indexOf(f);)i.push(f),j.push({value:f.style.getPropertyValue(b),priority:f.style.getPropertyPriority(b)}),f.style.setProperty(b,c,\"important\");for(i.indexOf(document.documentElement)<i.length-1&&(i.splice(i.indexOf(document.documentElement),1),i.push(document.documentElement)),g=j.length;h=j[--g];)i[g].style.setProperty(b,h.value?h.value:\"\",h.priority);return document.head.removeChild(d),i}},\"function\"==typeof window.addEventListener&&(document.elementsFromPoint=axe.utils.pollyfillElementsFromPoint()),Array.prototype.includes||Object.defineProperty(Array.prototype,\"includes\",{value:function(a){\"use strict\";var b=Object(this),c=parseInt(b.length,10)||0;if(0===c)return!1;var d,e=parseInt(arguments[1],10)||0;e>=0?d=e:(d=c+e)<0&&(d=0);for(var f;d<c;){if(f=b[d],a===f||a!==a&&f!==f)return!0;d++}return!1}}),Array.prototype.some||Object.defineProperty(Array.prototype,\"some\",{value:function(a){\"use strict\";if(null==this)throw new TypeError(\"Array.prototype.some called on null or undefined\");if(\"function\"!=typeof a)throw new TypeError;for(var b=Object(this),c=b.length>>>0,d=arguments.length>=2?arguments[1]:void 0,e=0;e<c;e++)if(e in b&&a.call(d,b[e],e,b))return!0;return!1}}),Array.from||Object.defineProperty(Array,\"from\",{value:function(){var a=Object.prototype.toString,b=function(b){return\"function\"==typeof b||\"[object Function]\"===a.call(b)},c=function(a){var b=Number(a);return isNaN(b)?0:0!==b&&isFinite(b)?(b>0?1:-1)*Math.floor(Math.abs(b)):b},d=Math.pow(2,53)-1,e=function(a){var b=c(a);return Math.min(Math.max(b,0),d)};return function(a){var c=this,d=Object(a);if(null==a)throw new TypeError(\"Array.from requires an array-like object - not null or undefined\");var f,g=arguments.length>1?arguments[1]:void 0;if(void 0!==g){if(!b(g))throw new TypeError(\"Array.from: when provided, the second argument must be a function\");arguments.length>2&&(f=arguments[2])}for(var h,i=e(d.length),j=b(c)?Object(new c(i)):new Array(i),k=0;k<i;)h=d[k],j[k]=g?void 0===f?g(h,k):g.call(f,h,k):h,k+=1;return j.length=i,j}}()}),String.prototype.includes||(String.prototype.includes=function(a,b){return\"number\"!=typeof b&&(b=0),!(b+a.length>this.length)&&-1!==this.indexOf(a,b)});var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};axe.utils.publishMetaData=function(a){\"use strict\";var b=axe._audit.data.checks||{},c=axe._audit.data.rules||{},d=axe.utils.findBy(axe._audit.rules,\"id\",a.id)||{};a.tags=axe.utils.clone(d.tags||[]);var e=ga(b,!0),f=ga(b,!1);a.nodes.forEach(function(a){a.any.forEach(e),a.all.forEach(e),a.none.forEach(f)}),axe.utils.extendMetaData(a,axe.utils.clone(c[a.id]||{}))};var Ra=function(){},Sa=function(){},Ta=function(){/*! Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License */\nvar a=/(?=[\\-\\[\\]{}()*+?.\\\\\\^$|,#\\s])/g;return function(b){return b.replace(a,\"\\\\\")}}(),Ua=/\\\\/g;Ra=function(a){return a.map(function(a){for(var b=[],c=a.rule;c;)b.push({tag:c.tagName?c.tagName.toLowerCase():\"*\",combinator:c.nestingOperator?c.nestingOperator:\" \",id:c.id,attributes:ma(c.attrs),classes:na(c.classNames),pseudos:oa(c.pseudos)}),c=c.rule;return b})},Sa=function(a,b,c,d){for(var e=[],f=Array.isArray(a)?a:[a],g=pa(f,b,[],a[0].shadowId),h=[];g.nodes.length;){for(var i=g.nodes.pop(),j=[],k=[],l=g.anyLevel.slice().concat(g.thisLevel),m=!1,n=0;n<l.length;n++){var o=l[n];if(qa(i,o)&&(!o[0].id||i.shadowId===g.parentShadowId))if(1===o.length)m||d&&!d(i)||(h.push(i),m=!0);else{var p=o.slice(1);if(!1===[\" \",\">\"].includes(p[0].combinator))throw new Error(\"axe.utils.querySelectorAll does not support the combinator: \"+o[1].combinator);\">\"===p[0].combinator?j.push(p):k.push(p)}!g.anyLevel.includes(o)||o[0].id&&i.shadowId!==g.parentShadowId||k.push(o)}for(i.children&&i.children.length&&c&&(e.push(g),g=pa(i.children,k,j,i.shadowId));!g.nodes.length&&e.length;)g=e.pop()}return h},axe.utils.querySelectorAll=function(a,b){return axe.utils.querySelectorAllFilter(a,b)},axe.utils.querySelectorAllFilter=function(a,b,c){a=Array.isArray(a)?a:[a];var d=axe.utils.cssParser.parse(b);return d=d.selectors?d.selectors:[d],d=Ra(d),Sa(a,d,!0,c)};var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};!function(){\"use strict\";function a(){}function b(a){if(\"function\"!=typeof a)throw new TypeError(\"Queue methods require functions as arguments\")}function c(){function c(b){return function(c){g[b]=c,(i-=1)||j===a||(k=!0,j(g))}}function d(b){return j=a,m(b),g}function e(){for(var a=g.length;h<a;h++){var b=g[h];try{b.call(null,c(h),d)}catch(a){d(a)}}}var f,g=[],h=0,i=0,j=a,k=!1,l=function(a){f=a,setTimeout(function(){void 0!==f&&null!==f&&axe.log(\"Uncaught error (of queue)\",f)},1)},m=l,n={defer:function(a){if(\"object\"===(void 0===a?\"undefined\":za(a))&&a.then&&a.catch){var c=a;a=function(a,b){c.then(a).catch(b)}}if(b(a),void 0===f){if(k)throw new Error(\"Queue already completed\");return g.push(a),++i,e(),n}},then:function(c){if(b(c),j!==a)throw new Error(\"queue `then` already set\");return f||(j=c,i||(k=!0,j(g))),n},catch:function(a){if(b(a),m!==l)throw new Error(\"queue `catch` already set\");return f?(a(f),f=null):m=a,n},abort:d};return n}axe.utils.queue=c}();var za=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&\"function\"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?\"symbol\":typeof a};!function(a){\"use strict\";function b(){var a=\"axe\",b=\"\";return void 0!==axe&&axe._audit&&!axe._audit.application&&(a=axe._audit.application),void 0!==axe&&(b=axe.version),a+\".\"+b}function c(a){if(\"object\"===(void 0===a?\"undefined\":za(a))&&\"string\"==typeof a.uuid&&!0===a._respondable){var c=b();return a._source===c||\"axe.x.y.z\"===a._source||\"axe.x.y.z\"===c}return!1}function d(a,c,d,e,f,g){var h;d instanceof Error&&(h={name:d.name,message:d.message,stack:d.stack},d=void 0);var i={uuid:e,topic:c,message:d,error:h,_respondable:!0,_source:b(),_keepalive:f};\"function\"==typeof g&&(j[e]=g),a.postMessage(JSON.stringify(i),\"*\")}function e(a,b,c,e,f){d(a,b,c,Va.v1(),e,f)}function f(a,b,c){return function(e,f,g){d(a,b,e,c,f,g)}}function g(a,b,c){var d=b.topic,e=k[d];if(e){var g=f(a,null,b.uuid);e(b.message,c,g)}}function h(a){var b=a.message||\"Unknown error occurred\",c=l.includes(a.name)?a.name:\"Error\",d=window[c]||Error;return a.stack&&(b+=\"\\n\"+a.stack.replace(a.message,\"\")),new d(b)}function i(a){var b;if(\"string\"==typeof a){try{b=JSON.parse(a)}catch(a){}if(c(b))return\"object\"===za(b.error)?b.error=h(b.error):b.error=void 0,b}}var j={},k={},l=Object.freeze([\"EvalError\",\"RangeError\",\"ReferenceError\",\"SyntaxError\",\"TypeError\",\"URIError\"]);e.subscribe=function(a,b){k[a]=b},e.isInFrame=function(a){return a=a||window,!!a.frameElement},\"function\"==typeof window.addEventListener&&window.addEventListener(\"message\",function(a){var b=i(a.data);if(b){var c=b.uuid,e=b._keepalive,h=j[c];if(h){h(b.error||b.message,e,f(a.source,b.topic,c)),e||delete j[c]}if(!b.error)try{g(a.source,b,e)}catch(e){d(a.source,b.topic,e,c,!1)}}},!1),a.respondable=e}(utils),axe.utils.ruleShouldRun=function(a,b,c){\"use strict\";var d=c.runOnly||{},e=(c.rules||{})[a.id];return!(a.pageLevel&&!b.page)&&(\"rule\"===d.type?-1!==d.values.indexOf(a.id):e&&\"boolean\"==typeof e.enabled?e.enabled:\"tag\"===d.type&&d.values?ra(a,d.values):ra(a,[]))},axe.utils.getScrollState=function(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window,b=a.document.documentElement;return[void 0!==a.pageXOffset?{elm:a,top:a.pageYOffset,left:a.pageXOffset}:{elm:b,top:b.scrollTop,left:b.scrollLeft}].concat(ua(document.body))},axe.utils.setScrollState=function(a){a.forEach(function(a){return ta(a.elm,a.top,a.left)})},axe.utils.select=function(a,b){\"use strict\";var c,d=[];if(axe._selectCache)for(var e=0,f=axe._selectCache.length;e<f;e++){var g=axe._selectCache[e];if(g.selector===a)return g.result}for(var h=function(a){return function(b){return wa(b,a)}}(b),i=ya(b.include),j=0;j<i.length;j++)c=i[j],c.actualNode.nodeType===c.actualNode.ELEMENT_NODE&&axe.utils.matchesSelector(c.actualNode,a)&&h(c)&&(d=xa(d,[c])),d=xa(d,axe.utils.querySelectorAllFilter(c,a,h));return axe._selectCache&&axe._selectCache.push({selector:a,result:d}),d},axe.utils.toArray=function(a){\"use strict\";return Array.prototype.slice.call(a)},axe.utils.uniqueArray=function(a,b){return a.concat(b).filter(function(a,b,c){return c.indexOf(a)===b})};var Va;!function(a){function b(a,b,c){var d=b&&c||0,e=0;for(b=b||[],a.toLowerCase().replace(/[0-9a-f]{2}/g,function(a){e<16&&(b[d+e++]=l[a])});e<16;)b[d+e++]=0;return b}function c(a,b){var c=b||0,d=k;return d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+\"-\"+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]+d[a[c++]]}function d(a,b,d){var e=b&&d||0,f=b||[];a=a||{};var g=null!=a.clockseq?a.clockseq:p,h=null!=a.msecs?a.msecs:(new Date).getTime(),i=null!=a.nsecs?a.nsecs:r+1,j=h-q+(i-r)/1e4;if(j<0&&null==a.clockseq&&(g=g+1&16383),(j<0||h>q)&&null==a.nsecs&&(i=0),i>=1e4)throw new Error(\"uuid.v1(): Can't create more than 10M uuids/sec\");q=h,r=i,p=g,h+=122192928e5;var k=(1e4*(268435455&h)+i)%4294967296;f[e++]=k>>>24&255,f[e++]=k>>>16&255,f[e++]=k>>>8&255,f[e++]=255&k;var l=h/4294967296*1e4&268435455;f[e++]=l>>>8&255,f[e++]=255&l,f[e++]=l>>>24&15|16,f[e++]=l>>>16&255,f[e++]=g>>>8|128,f[e++]=255&g;for(var m=a.node||o,n=0;n<6;n++)f[e+n]=m[n];return b||c(f)}function e(a,b,d){var e=b&&d||0;\"string\"==typeof a&&(b=\"binary\"==a?new j(16):null,a=null),a=a||{};var g=a.random||(a.rng||f)();if(g[6]=15&g[6]|64,g[8]=63&g[8]|128,b)for(var h=0;h<16;h++)b[e+h]=g[h];return b||c(g)}var f,g=a.crypto||a.msCrypto;if(!f&&g&&g.getRandomValues){var h=new Uint8Array(16);f=function(){return g.getRandomValues(h),h}}if(!f){var i=new Array(16);f=function(){for(var a,b=0;b<16;b++)0==(3&b)&&(a=4294967296*Math.random()),i[b]=a>>>((3&b)<<3)&255;return i}}for(var j=\"function\"==typeof a.Buffer?a.Buffer:Array,k=[],l={},m=0;m<256;m++)k[m]=(m+256).toString(16).substr(1),l[k[m]]=m;var n=f(),o=[1|n[0],n[1],n[2],n[3],n[4],n[5]],p=16383&(n[6]<<8|n[7]),q=0,r=0;Va=e,Va.v1=d,Va.v4=e,Va.parse=b,Va.unparse=c,Va.BufferClass=j}(window),axe._load({data:{rules:{accesskeys:{description:\"Ensures every accesskey attribute value is unique\",help:\"accesskey attribute value must be unique\"},\"area-alt\":{description:\"Ensures <area> elements of image maps have alternate text\",help:\"Active <area> elements must have alternate text\"},\"aria-allowed-attr\":{description:\"Ensures ARIA attributes are allowed for an element's role\",help:\"Elements must only use allowed ARIA attributes\"},\"aria-hidden-body\":{description:\"Ensures aria-hidden='true' is not present on the document body.\",help:\"aria-hidden='true' must not be present on the document body\"},\"aria-required-attr\":{description:\"Ensures elements with ARIA roles have all required ARIA attributes\",help:\"Required ARIA attributes must be provided\"},\"aria-required-children\":{description:\"Ensures elements with an ARIA role that require child roles contain them\",help:\"Certain ARIA roles must contain particular children\"},\"aria-required-parent\":{description:\"Ensures elements with an ARIA role that require parent roles are contained by them\",help:\"Certain ARIA roles must be contained by particular parents\"},\"aria-roles\":{description:\"Ensures all elements with a role attribute use a valid value\",help:\"ARIA roles used must conform to valid values\"},\"aria-valid-attr-value\":{description:\"Ensures all ARIA attributes have valid values\",help:\"ARIA attributes must conform to valid values\"},\"aria-valid-attr\":{description:\"Ensures attributes that begin with aria- are valid ARIA attributes\",help:\"ARIA attributes must conform to valid names\"},\"audio-caption\":{description:\"Ensures <audio> elements have captions\",help:\"<audio> elements must have a captions track\"},blink:{description:\"Ensures <blink> elements are not used\",help:\"<blink> elements are deprecated and must not be used\"},\"button-name\":{description:\"Ensures buttons have discernible text\",help:\"Buttons must have discernible text\"},bypass:{description:\"Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content\",help:\"Page must have means to bypass repeated blocks\"},checkboxgroup:{description:'Ensures related <input type=\"checkbox\"> elements have a group and that that group designation is consistent',help:\"Checkbox inputs with the same name attribute value must be part of a group\"},\"color-contrast\":{description:\"Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds\",help:\"Elements must have sufficient color contrast\"},\"definition-list\":{description:\"Ensures <dl> elements are structured correctly\",help:\"<dl> elements must only directly contain properly-ordered <dt> and <dd> groups, <script> or <template> elements\"},dlitem:{description:\"Ensures <dt> and <dd> elements are contained by a <dl>\",help:\"<dt> and <dd> elements must be contained by a <dl>\"},\"document-title\":{description:\"Ensures each HTML document contains a non-empty <title> element\",help:\"Documents must have <title> element to aid in navigation\"},\"duplicate-id\":{description:\"Ensures every id attribute value is unique\",help:\"id attribute value must be unique\"},\"empty-heading\":{description:\"Ensures headings have discernible text\",help:\"Headings must not be empty\"},\"focus-order-semantics\":{description:\"Ensures elements in the focus order have an appropriate role\",help:\"Elements in the focus order need a role appropriate for interactive content\"},\"frame-title-unique\":{description:\"Ensures <iframe> and <frame> elements contain a unique title attribute\",help:\"Frames must have a unique title attribute\"},\"frame-title\":{description:\"Ensures <iframe> and <frame> elements contain a non-empty title attribute\",help:\"Frames must have title attribute\"},\"heading-order\":{description:\"Ensures the order of headings is semantically correct\",help:\"Heading levels should only increase by one\"},\"hidden-content\":{description:\"Informs users about hidden content.\",help:\"Hidden content on the page cannot be analyzed\"},\"html-has-lang\":{description:\"Ensures every HTML document has a lang attribute\",help:\"<html> element must have a lang attribute\"},\"html-lang-valid\":{description:\"Ensures the lang attribute of the <html> element has a valid value\",help:\"<html> element must have a valid value for the lang attribute\"},\"image-alt\":{description:\"Ensures <img> elements have alternate text or a role of none or presentation\",help:\"Images must have alternate text\"},\"image-redundant-alt\":{description:\"Ensure button and link text is not repeated as image alternative\",help:\"Text of buttons and links should not be repeated in the image alternative\"},\"input-image-alt\":{description:'Ensures <input type=\"image\"> elements have alternate text',help:\"Image buttons must have alternate text\"},\"label-title-only\":{description:\"Ensures that every form element is not solely labeled using the title or aria-describedby attributes\",help:\"Form elements should have a visible label\"},label:{description:\"Ensures every form element has a label\",help:\"Form elements must have labels\"},\"landmark-main-is-top-level\":{description:\"The main landmark should not be contained in another landmark\",help:\"Main landmark is not at top level\"},\"landmark-one-main\":{description:\"Ensures a navigation point to the primary content of the page. If the page contains iframes, each iframe should contain either no main landmarks or just one.\",help:\"Page must contain one main landmark.\"},\"layout-table\":{description:\"Ensures presentational <table> elements do not use <th>, <caption> elements or the summary attribute\",help:\"Layout tables must not use data table elements\"},\"link-in-text-block\":{description:\"Links can be distinguished without relying on color\",help:\"Links must be distinguished from surrounding text in a way that does not rely on color\"},\"link-name\":{description:\"Ensures links have discernible text\",help:\"Links must have discernible text\"},list:{description:\"Ensures that lists are structured correctly\",help:\"<ul> and <ol> must only directly contain <li>, <script> or <template> elements\"},listitem:{description:\"Ensures <li> elements are used semantically\",help:\"<li> elements must be contained in a <ul> or <ol>\"},marquee:{description:\"Ensures <marquee> elements are not used\",help:\"<marquee> elements are deprecated and must not be used\"},\"meta-refresh\":{description:'Ensures <meta http-equiv=\"refresh\"> is not used',help:\"Timed refresh must not exist\"},\"meta-viewport-large\":{description:'Ensures <meta name=\"viewport\"> can scale a significant amount',help:\"Users should be able to zoom and scale the text up to 500%\"},\"meta-viewport\":{description:'Ensures <meta name=\"viewport\"> does not disable text scaling and zooming',help:\"Zooming and scaling must not be disabled\"},\"object-alt\":{description:\"Ensures <object> elements have alternate text\",help:\"<object> elements must have alternate text\"},\"p-as-heading\":{description:\"Ensure p elements are not used to style headings\",help:\"Bold, italic text and font-size are not used to style p elements as a heading\"},radiogroup:{description:'Ensures related <input type=\"radio\"> elements have a group and that the group designation is consistent',help:\"Radio inputs with the same name attribute value must be part of a group\"},region:{description:\"Ensures all content is contained within a landmark region\",help:\"Content should be contained in a landmark region\"},\"scope-attr-valid\":{description:\"Ensures the scope attribute is used correctly on tables\",help:\"scope attribute should be used correctly\"},\"server-side-image-map\":{description:\"Ensures that server-side image maps are not used\",help:\"Server-side image maps must not be used\"},\"skip-link\":{description:\"Ensure all skip links have a focusable target\",help:\"The skip-link target should exist and be focusable\"},tabindex:{description:\"Ensures tabindex attribute values are not greater than 0\",help:\"Elements should not have tabindex greater than zero\"},\"table-duplicate-name\":{description:\"Ensure that tables do not have the same summary and caption\",help:\"The <caption> element should not contain the same text as the summary attribute\"},\"table-fake-caption\":{description:\"Ensure that tables with a caption use the <caption> element.\",help:\"Data or header cells should not be used to give caption to a data table.\"},\"td-has-header\":{description:\"Ensure that each non-empty data cell in a large table has one or more table headers\",help:\"All non-empty td element in table larger than 3 by 3 must have an associated table header\"},\"td-headers-attr\":{description:\"Ensure that each cell in a table using the headers refers to another cell in that table\",help:\"All cells in a table element that use the headers attribute must only refer to other cells of that same table\"},\"th-has-data-cells\":{description:\"Ensure that each table header in a data table refers to data cells\",help:\"All th elements and elements with role=columnheader/rowheader must have data cells they describe\"},\"valid-lang\":{description:\"Ensures lang attributes have valid values\",help:\"lang attribute must have a valid value\"},\"video-caption\":{description:\"Ensures <video> elements have captions\",help:\"<video> elements must have captions\"},\"video-description\":{description:\"Ensures <video> elements have audio descriptions\",help:\"<video> elements must have an audio description track\"}},checks:{accesskeys:{impact:\"serious\",messages:{pass:function(a){return\"Accesskey attribute value is unique\"},fail:function(a){return\"Document has multiple elements with the same accesskey\"}}},\"non-empty-alt\":{impact:\"critical\",messages:{pass:function(a){return\"Element has a non-empty alt attribute\"},fail:function(a){return\"Element has no alt attribute or the alt attribute is empty\"}}},\"non-empty-title\":{impact:\"serious\",messages:{pass:function(a){return\"Element has a title attribute\"},fail:function(a){return\"Element has no title attribute or the title attribute is empty\"}}},\"aria-label\":{impact:\"serious\",messages:{pass:function(a){return\"aria-label attribute exists and is not empty\"},fail:function(a){return\"aria-label attribute does not exist or is empty\"}}},\"aria-labelledby\":{impact:\"serious\",messages:{pass:function(a){return\"aria-labelledby attribute exists and references elements that are visible to screen readers\"},fail:function(a){return\"aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty or not visible\"}}},\"aria-allowed-attr\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attributes are used correctly for the defined role\"},fail:function(a){var b=\"ARIA attribute\"+(a.data&&a.data.length>1?\"s are\":\" is\")+\" not allowed:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-hidden-body\":{impact:\"critical\",messages:{pass:function(a){return\"No aria-hidden attribute is present on document body\"},fail:function(a){return\"aria-hidden=true should not be present on the document body\"}}},\"aria-required-attr\":{impact:\"critical\",messages:{pass:function(a){return\"All required ARIA attributes are present\"},fail:function(a){var b=\"Required ARIA attribute\"+(a.data&&a.data.length>1?\"s\":\"\")+\" not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-required-children\":{impact:\"critical\",messages:{pass:function(a){return\"Required ARIA children are present\"},fail:function(a){var b=\"Required ARIA \"+(a.data&&a.data.length>1?\"children\":\"child\")+\" role not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-required-parent\":{impact:\"critical\",messages:{pass:function(a){return\"Required ARIA parent role present\"},fail:function(a){var b=\"Required ARIA parent\"+(a.data&&a.data.length>1?\"s\":\"\")+\" role not present:\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},invalidrole:{impact:\"critical\",messages:{pass:function(a){return\"ARIA role is valid\"},fail:function(a){return\"Role must be one of the valid ARIA roles\"}}},abstractrole:{impact:\"serious\",messages:{pass:function(a){return\"Abstract roles are not used\"},fail:function(a){return\"Abstract roles cannot be directly used\"}}},\"aria-valid-attr-value\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attribute values are valid\"},fail:function(a){var b=\"Invalid ARIA attribute value\"+(a.data&&a.data.length>1?\"s\":\"\")+\":\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},\"aria-errormessage\":{impact:\"critical\",messages:{pass:function(a){return\"Uses a supported aria-errormessage technique\"},fail:function(a){var b=\"aria-errormessage value\"+(a.data&&a.data.length>1?\"s\":\"\")+\" \",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" `\"+d;return b+=\"` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)\"}}},\"aria-valid-attr\":{impact:\"critical\",messages:{pass:function(a){return\"ARIA attribute name\"+(a.data&&a.data.length>1?\"s\":\"\")+\" are valid\"},fail:function(a){var b=\"Invalid ARIA attribute name\"+(a.data&&a.data.length>1?\"s\":\"\")+\":\",c=a.data;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\" \"+d;return b}}},caption:{impact:\"critical\",messages:{pass:function(a){return\"The multimedia element has a captions track\"},fail:function(a){return\"The multimedia element does not have a captions track\"},incomplete:function(a){return\"A captions track for this element could not be found\"}}},\"is-on-screen\":{impact:\"serious\",messages:{pass:function(a){return\"Element is not visible\"},fail:function(a){return\"Element is visible\"}}},\"non-empty-if-present\":{impact:\"critical\",messages:{pass:function(a){var b=\"Element \";return a.data?b+=\"has a non-empty value attribute\":b+=\"does not have a value attribute\",b},fail:function(a){return\"Element has a value attribute and the value attribute is empty\"}}},\"non-empty-value\":{impact:\"critical\",messages:{pass:function(a){return\"Element has a non-empty value attribute\"},fail:function(a){return\"Element has no value attribute or the value attribute is empty\"}}},\"button-has-visible-text\":{impact:\"critical\",messages:{pass:function(a){return\"Element has inner text that is visible to screen readers\"},fail:function(a){return\"Element does not have inner text that is visible to screen readers\"}}},\"role-presentation\":{impact:\"minor\",messages:{pass:function(a){return'Element\\'s default semantics were overriden with role=\"presentation\"'},fail:function(a){return'Element\\'s default semantics were not overridden with role=\"presentation\"'}}},\"role-none\":{impact:\"minor\",messages:{pass:function(a){return'Element\\'s default semantics were overriden with role=\"none\"'},fail:function(a){return'Element\\'s default semantics were not overridden with role=\"none\"'}}},\"focusable-no-name\":{impact:\"serious\",messages:{pass:function(a){return\"Element is not in tab order or has accessible text\"},fail:function(a){return\"Element is in tab order and does not have accessible text\"}}},\"internal-link-present\":{impact:\"serious\",messages:{pass:function(a){return\"Valid skip link found\"},fail:function(a){return\"No valid skip link found\"}}},\"header-present\":{impact:\"serious\",messages:{pass:function(a){return\"Page has a header\"},fail:function(a){return\"Page does not have a header\"}}},landmark:{impact:\"serious\",messages:{pass:function(a){return\"Page has a landmark region\"},fail:function(a){return\"Page does not have a landmark region\"}}},\"group-labelledby\":{impact:\"critical\",messages:{pass:function(a){return'All elements with the name \"'+a.data.name+'\" reference the same element with aria-labelledby'},fail:function(a){return'All elements with the name \"'+a.data.name+'\" do not reference the same element with aria-labelledby'}}},fieldset:{impact:\"critical\",messages:{pass:function(a){return\"Element is contained in a fieldset\"},fail:function(a){var b=\"\",c=a.data&&a.data.failureCode;return b+=\"no-legend\"===c?\"Fieldset does not have a legend as its first child\":\"empty-legend\"===c?\"Legend does not have text that is visible to screen readers\":\"mixed-inputs\"===c?\"Fieldset contains unrelated inputs\":\"no-group-label\"===c?\"ARIA group does not have aria-label or aria-labelledby\":\"group-mixed-inputs\"===c?\"ARIA group contains unrelated inputs\":\"Element does not have a containing fieldset or ARIA group\"}}},\"color-contrast\":{impact:\"serious\",messages:{pass:function(a){return\"Element has sufficient color contrast of \"+a.data.contrastRatio},fail:function(a){return\"Element has insufficient color contrast of \"+a.data.contrastRatio+\" (foreground color: \"+a.data.fgColor+\", background color: \"+a.data.bgColor+\", font size: \"+a.data.fontSize+\", font weight: \"+a.data.fontWeight+\"). Expected contrast ratio of \"+a.data.expectedContrastRatio},incomplete:{bgImage:\"Element's background color could not be determined due to a background image\",bgGradient:\"Element's background color could not be determined due to a background gradient\",imgNode:\"Element's background color could not be determined because element contains an image node\",bgOverlap:\"Element's background color could not be determined because it is overlapped by another element\",fgAlpha:\"Element's foreground color could not be determined because of alpha transparency\",elmPartiallyObscured:\"Element's background color could not be determined because it's partially obscured by another element\",elmPartiallyObscuring:\"Element's background color could not be determined because it partially overlaps other elements\",outsideViewport:\"Element's background color could not be determined because it's outside the viewport\",equalRatio:\"Element has a 1:1 contrast ratio with the background\",default:\"Unable to determine contrast ratio\"}}},\"structured-dlitems\":{impact:\"serious\",messages:{pass:function(a){return\"When not empty, element has both <dt> and <dd> elements\"},fail:function(a){return\"When not empty, element does not have at least one <dt> element followed by at least one <dd> element\"}}},\"only-dlitems\":{impact:\"serious\",messages:{pass:function(a){return\"List element only has direct children that are allowed inside <dt> or <dd> elements\"},fail:function(a){return\"List element has direct children that are not allowed inside <dt> or <dd> elements\"}}},dlitem:{impact:\"serious\",messages:{pass:function(a){return\"Description list item has a <dl> parent element\"},fail:function(a){return\"Description list item does not have a <dl> parent element\"}}},\"doc-has-title\":{impact:\"serious\",messages:{pass:function(a){return\"Document has a non-empty <title> element\"},fail:function(a){return\"Document does not have a non-empty <title> element\"}}},\"duplicate-id\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has no elements that share the same id attribute\"},fail:function(a){return\"Document has multiple elements with the same id attribute: \"+a.data}}},\"has-visible-text\":{impact:\"minor\",messages:{pass:function(a){return\"Element has text that is visible to screen readers\"},fail:function(a){return\"Element does not have text that is visible to screen readers\"}}},\"has-widget-role\":{impact:\"minor\",messages:{pass:function(a){return\"Element has a widget role.\"},fail:function(a){return\"Element does not have a widget role.\"}}},\"valid-scrollable-semantics\":{impact:\"minor\",messages:{pass:function(a){return\"Element has valid semantics for an element in the focus order.\"},fail:function(a){return\"Element has invalid semantics for an element in the focus order.\"}}},\"unique-frame-title\":{impact:\"serious\",messages:{pass:function(a){return\"Element's title attribute is unique\"},fail:function(a){return\"Element's title attribute is not unique\"}}},\"heading-order\":{impact:\"moderate\",messages:{pass:function(a){return\"Heading order valid\"},fail:function(a){return\"Heading order invalid\"}}},\"hidden-content\":{impact:\"minor\",messages:{pass:function(a){return\"All content on the page has been analyzed.\"},fail:function(a){return\"There were problems analyzing the content on this page.\"},incomplete:function(a){return\"There is hidden content on the page that was not analyzed. You will need to trigger the display of this content in order to analyze it.\"}}},\"has-lang\":{impact:\"serious\",messages:{pass:function(a){return\"The <html> element has a lang attribute\"},fail:function(a){return\"The <html> element does not have a lang attribute\"}}},\"valid-lang\":{impact:\"serious\",messages:{pass:function(a){return\"Value of lang attribute is included in the list of valid languages\"},fail:function(a){return\"Value of lang attribute not included in the list of valid languages\"}}},\"has-alt\":{impact:\"critical\",messages:{pass:function(a){return\"Element has an alt attribute\"},fail:function(a){return\"Element does not have an alt attribute\"}}},\"duplicate-img-label\":{impact:\"minor\",messages:{pass:function(a){return\"Element does not duplicate existing text in <img> alt text\"},fail:function(a){return\"Element contains <img> element with alt text that duplicates existing text\"}}},\"title-only\":{impact:\"serious\",messages:{pass:function(a){return\"Form element does not solely use title attribute for its label\"},fail:function(a){return\"Only title used to generate label for form element\"}}},\"implicit-label\":{impact:\"critical\",messages:{pass:function(a){return\"Form element has an implicit (wrapped) <label>\"},fail:function(a){return\"Form element does not have an implicit (wrapped) <label>\"}}},\"explicit-label\":{impact:\"critical\",messages:{pass:function(a){return\"Form element has an explicit <label>\"},fail:function(a){return\"Form element does not have an explicit <label>\"}}},\"help-same-as-label\":{impact:\"minor\",messages:{pass:function(a){return\"Help text (title or aria-describedby) does not duplicate label text\"},fail:function(a){return\"Help text (title or aria-describedby) text is the same as the label text\"}}},\"multiple-label\":{impact:\"serious\",messages:{pass:function(a){return\"Form element does not have multiple <label> elements\"},fail:function(a){return\"Form element has multiple <label> elements\"}}},\"main-is-top-level\":{impact:\"moderate\",messages:{pass:function(a){return\"The main landmark is at the top level.\"},fail:function(a){return\"The main landmark is contained in another landmark.\"}}},\"has-at-least-one-main\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has at least one main landmark\"},fail:function(a){return\"Document has no main landmarks\"}}},\"has-no-more-than-one-main\":{impact:\"moderate\",messages:{pass:function(a){return\"Document has no more than one main landmark\"},fail:function(a){return\"Document has more than one main landmark\"}}},\"has-th\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use <th> elements\"},fail:function(a){return\"Layout table uses <th> elements\"}}},\"has-caption\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use <caption> element\"},fail:function(a){return\"Layout table uses <caption> element\"}}},\"has-summary\":{impact:\"serious\",messages:{pass:function(a){return\"Layout table does not use summary attribute\"},fail:function(a){return\"Layout table uses summary attribute\"}}},\"link-in-text-block\":{impact:\"serious\",messages:{pass:function(a){return\"Links can be distinguished from surrounding text in some way other than by color\"},fail:function(a){return\"Links need to be distinguished from surrounding text in some way other than by color\"},incomplete:{bgContrast:\"Element's contrast ratio could not be determined. Check for a distinct hover/focus style\",bgImage:\"Element's contrast ratio could not be determined due to a background image\",bgGradient:\"Element's contrast ratio could not be determined due to a background gradient\",imgNode:\"Element's contrast ratio could not be determined because element contains an image node\",bgOverlap:\"Element's contrast ratio could not be determined because of element overlap\",default:\"Unable to determine contrast ratio\"}}},\"only-listitems\":{impact:\"serious\",messages:{pass:function(a){return\"List element only has direct children that are allowed inside <li> elements\"},fail:function(a){return\"List element has direct children that are not allowed inside <li> elements\"}}},listitem:{impact:\"serious\",messages:{pass:function(a){return'List item has a <ul>, <ol> or role=\"list\" parent element'},fail:function(a){return'List item does not have a <ul>, <ol> or role=\"list\" parent element'}}},\"meta-refresh\":{impact:\"critical\",messages:{pass:function(a){return\"<meta> tag does not immediately refresh the page\"},fail:function(a){return\"<meta> tag forces timed refresh of page\"}}},\"meta-viewport-large\":{impact:\"minor\",messages:{pass:function(a){\nreturn\"<meta> tag does not prevent significant zooming on mobile devices\"},fail:function(a){return\"<meta> tag limits zooming on mobile devices\"}}},\"meta-viewport\":{impact:\"critical\",messages:{pass:function(a){return\"<meta> tag does not disable zooming on mobile devices\"},fail:function(a){return\"<meta> tag disables zooming on mobile devices\"}}},\"p-as-heading\":{impact:\"serious\",messages:{pass:function(a){return\"<p> elements are not styled as headings\"},fail:function(a){return\"Heading elements should be used instead of styled p elements\"}}},region:{impact:\"moderate\",messages:{pass:function(a){return\"Content contained by ARIA landmark\"},fail:function(a){return\"Content not contained by an ARIA landmark\"}}},\"html5-scope\":{impact:\"moderate\",messages:{pass:function(a){return\"Scope attribute is only used on table header elements (<th>)\"},fail:function(a){return\"In HTML 5, scope attributes may only be used on table header elements (<th>)\"}}},\"scope-value\":{impact:\"critical\",messages:{pass:function(a){return\"Scope attribute is used correctly\"},fail:function(a){return\"The value of the scope attribute may only be 'row' or 'col'\"}}},exists:{impact:\"minor\",messages:{pass:function(a){return\"Element does not exist\"},fail:function(a){return\"Element exists\"}}},\"skip-link\":{impact:\"moderate\",messages:{pass:function(a){return\"Skip link target exists\"},incomplete:function(a){return\"Skip link target should become visible on activation\"},fail:function(a){return\"No skip link target\"}}},tabindex:{impact:\"serious\",messages:{pass:function(a){return\"Element does not have a tabindex greater than 0\"},fail:function(a){return\"Element has a tabindex greater than 0\"}}},\"same-caption-summary\":{impact:\"minor\",messages:{pass:function(a){return\"Content of summary attribute and <caption> are not duplicated\"},fail:function(a){return\"Content of summary attribute and <caption> element are identical\"}}},\"caption-faked\":{impact:\"serious\",messages:{pass:function(a){return\"The first row of a table is not used as a caption\"},fail:function(a){return\"The first row of the table should be a caption instead of a table cell\"}}},\"td-has-header\":{impact:\"critical\",messages:{pass:function(a){return\"All non-empty data cells have table headers\"},fail:function(a){return\"Some non-empty data cells do not have table headers\"}}},\"td-headers-attr\":{impact:\"serious\",messages:{pass:function(a){return\"The headers attribute is exclusively used to refer to other cells in the table\"},fail:function(a){return\"The headers attribute is not exclusively used to refer to other cells in the table\"}}},\"th-has-data-cells\":{impact:\"serious\",messages:{pass:function(a){return\"All table header cells refer to data cells\"},fail:function(a){return\"Not all table header cells refer to data cells\"},incomplete:function(a){return\"Table data cells are missing or empty\"}}},description:{impact:\"critical\",messages:{pass:function(a){return\"The multimedia element has an audio description track\"},fail:function(a){return\"The multimedia element does not have an audio description track\"},incomplete:function(a){return\"An audio description track for this element could not be found\"}}}},failureSummaries:{any:{failureMessage:function(a){var b=\"Fix any of the following:\",c=a;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\"\\n  \"+d.split(\"\\n\").join(\"\\n  \");return b}},none:{failureMessage:function(a){var b=\"Fix all of the following:\",c=a;if(c)for(var d,e=-1,f=c.length-1;e<f;)d=c[e+=1],b+=\"\\n  \"+d.split(\"\\n\").join(\"\\n  \");return b}}},incompleteFallbackMessage:function(a){return\"aXe couldn't tell the reason. Time to break out the element inspector!\"}},rules:[{id:\"accesskeys\",selector:\"[accesskey]\",excludeHidden:!1,tags:[\"wcag2a\",\"wcag211\",\"cat.keyboard\"],all:[],any:[],none:[\"accesskeys\"]},{id:\"area-alt\",selector:\"map area[href]\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-alt\",\"non-empty-title\",\"aria-label\",\"aria-labelledby\"],none:[]},{id:\"aria-allowed-attr\",matches:function(a,b){var c=a.getAttribute(\"role\");c||(c=axe.commons.aria.implicitRole(a));var d=axe.commons.aria.allowedAttr(c);if(c&&d){var e=/^aria-/;if(a.hasAttributes())for(var f=a.attributes,g=0,h=f.length;g<h;g++)if(e.test(f[g].name))return!0}return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag411\",\"wcag412\"],all:[],any:[\"aria-allowed-attr\"],none:[]},{id:\"aria-hidden-body\",selector:\"body\",excludeHidden:!1,tags:[\"cat.aria\",\"wcag2a\",\"wcag412\"],all:[],any:[\"aria-hidden-body\"],none:[]},{id:\"aria-required-attr\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag411\",\"wcag412\"],all:[],any:[\"aria-required-attr\"],none:[]},{id:\"aria-required-children\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[],any:[\"aria-required-children\"],none:[]},{id:\"aria-required-parent\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\"],all:[],any:[\"aria-required-parent\"],none:[]},{id:\"aria-roles\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"wcag411\",\"wcag412\"],all:[],any:[],none:[\"invalidrole\",\"abstractrole\"]},{id:\"aria-valid-attr-value\",matches:function(a,b){var c=/^aria-/;if(a.hasAttributes())for(var d=a.attributes,e=0,f=d.length;e<f;e++)if(c.test(d[e].name))return!0;return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"wcag411\",\"wcag412\"],all:[{options:[],id:\"aria-valid-attr-value\"},\"aria-errormessage\"],any:[],none:[]},{id:\"aria-valid-attr\",matches:function(a,b){var c=/^aria-/;if(a.hasAttributes())for(var d=a.attributes,e=0,f=d.length;e<f;e++)if(c.test(d[e].name))return!0;return!1},tags:[\"cat.aria\",\"wcag2a\",\"wcag411\"],all:[],any:[{options:[],id:\"aria-valid-attr\"}],none:[]},{id:\"audio-caption\",selector:\"audio\",excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag121\",\"section508\",\"section508.22.a\"],all:[],any:[],none:[\"caption\"]},{id:\"blink\",selector:\"blink\",excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag222\",\"section508\",\"section508.22.j\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"button-name\",selector:'button, [role=\"button\"], input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"]',tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-if-present\",\"non-empty-value\",\"button-has-visible-text\",\"aria-label\",\"aria-labelledby\",\"role-presentation\",\"role-none\"],none:[\"focusable-no-name\"]},{id:\"bypass\",selector:\"html\",pageLevel:!0,matches:function(a,b){return!!a.querySelector(\"a[href]\")},tags:[\"cat.keyboard\",\"wcag2a\",\"wcag241\",\"section508\",\"section508.22.o\"],all:[],any:[\"internal-link-present\",\"header-present\",\"landmark\"],none:[]},{id:\"checkboxgroup\",selector:\"input[type=checkbox][name]\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[\"group-labelledby\",\"fieldset\"],none:[]},{id:\"color-contrast\",matches:function(a,b){var c=a.nodeName.toUpperCase(),d=a.type;if(\"true\"===a.getAttribute(\"aria-disabled\")||axe.commons.dom.findUpVirtual(b,'[aria-disabled=\"true\"]'))return!1;if(\"INPUT\"===c)return-1===[\"hidden\",\"range\",\"color\",\"checkbox\",\"radio\",\"image\"].indexOf(d)&&!a.disabled;if(\"SELECT\"===c)return!!a.options.length&&!a.disabled;if(\"TEXTAREA\"===c)return!a.disabled;if(\"OPTION\"===c)return!1;if(\"BUTTON\"===c&&a.disabled||axe.commons.dom.findUpVirtual(b,\"button[disabled]\"))return!1;if(\"FIELDSET\"===c&&a.disabled||axe.commons.dom.findUpVirtual(b,\"fieldset[disabled]\"))return!1;var e=axe.commons.dom.findUpVirtual(b,\"label\");if(\"LABEL\"===c||e){var f=a,g=b;e&&(f=e,g=axe.utils.getNodeFromTree(axe._tree[0],e));var h=axe.commons.dom.getRootNode(f),i=f.htmlFor&&h.getElementById(f.htmlFor);if(i&&i.disabled)return!1;var i=axe.utils.querySelectorAll(g,'input:not([type=\"hidden\"]):not([type=\"image\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]), select, textarea');if(i.length&&i[0].actualNode.disabled)return!1}if(a.getAttribute(\"id\")){var j=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),k=axe.commons.dom.getRootNode(a),i=k.querySelector(\"[aria-labelledby~=\"+j+\"]\");if(i&&i.disabled)return!1}if(\"\"===axe.commons.text.visibleVirtual(b,!1,!0))return!1;var l,m,n=document.createRange(),o=b.children,p=o.length;for(m=0;m<p;m++)l=o[m],3===l.actualNode.nodeType&&\"\"!==axe.commons.text.sanitize(l.actualNode.nodeValue)&&n.selectNodeContents(l.actualNode);var q=n.getClientRects();for(p=q.length,m=0;m<p;m++)if(axe.commons.dom.visuallyOverlaps(q[m],a))return!0;return!1},excludeHidden:!1,options:{noScroll:!1},tags:[\"cat.color\",\"wcag2aa\",\"wcag143\"],all:[],any:[\"color-contrast\"],none:[]},{id:\"definition-list\",selector:\"dl\",matches:function(a,b){return!a.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"structured-dlitems\",\"only-dlitems\"]},{id:\"dlitem\",selector:\"dd, dt\",matches:function(a,b){return!a.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[\"dlitem\"],none:[]},{id:\"document-title\",selector:\"html\",matches:function(a,b){return a.ownerDocument.defaultView.self===a.ownerDocument.defaultView.top},tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag242\"],all:[],any:[\"doc-has-title\"],none:[]},{id:\"duplicate-id\",selector:\"[id]\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag411\"],all:[],any:[\"duplicate-id\"],none:[]},{id:\"empty-heading\",selector:'h1, h2, h3, h4, h5, h6, [role=\"heading\"]',matches:function(a,b){var c=void 0;return a.hasAttribute(\"role\")&&(c=a.getAttribute(\"role\").split(/\\s+/i).filter(axe.commons.aria.isValidRole)),c&&c.length>0?c.includes(\"heading\"):\"heading\"===axe.commons.aria.implicitRole(a)},tags:[\"cat.name-role-value\",\"best-practice\"],all:[],any:[\"has-visible-text\"],none:[]},{id:\"focus-order-semantics\",selector:\"div, h1, h2, h3, h4, h5, h6, [role=heading], p, span\",matches:function(a,b){return axe.commons.dom.insertedIntoFocusOrder(a)},tags:[\"cat.keyboard\",\"best-practice\",\"experimental\"],all:[],any:[{options:[],id:\"has-widget-role\"},{options:[],id:\"valid-scrollable-semantics\"}],none:[]},{id:\"frame-title-unique\",selector:\"frame[title], iframe[title]\",matches:function(a,b){var c=a.getAttribute(\"title\");return!!(c?axe.commons.text.sanitize(c).trim():\"\")},tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[\"unique-frame-title\"]},{id:\"frame-title\",selector:\"frame, iframe\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag241\",\"section508\",\"section508.22.i\"],all:[],any:[\"aria-label\",\"aria-labelledby\",\"non-empty-title\",\"role-presentation\",\"role-none\"],none:[]},{id:\"heading-order\",selector:\"h1, h2, h3, h4, h5, h6, [role=heading]\",matches:function(a,b){var c=void 0;return a.hasAttribute(\"role\")&&(c=a.getAttribute(\"role\").split(/\\s+/i).filter(axe.commons.aria.isValidRole)),c&&c.length>0?c.includes(\"heading\"):\"heading\"===axe.commons.aria.implicitRole(a)},tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"heading-order\"],none:[]},{id:\"hidden-content\",selector:\"*\",excludeHidden:!1,tags:[\"experimental\",\"review-item\"],all:[],any:[\"hidden-content\"],none:[]},{id:\"html-has-lang\",selector:\"html\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[],any:[\"has-lang\"],none:[]},{id:\"html-lang-valid\",selector:\"html[lang]\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\"],all:[],any:[],none:[\"valid-lang\"]},{id:\"image-alt\",selector:\"img, [role='img']:not(svg)\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-alt\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\",\"role-presentation\",\"role-none\"],none:[]},{id:\"image-redundant-alt\",selector:'button, [role=\"button\"], a[href], p, li, td, th',tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[\"duplicate-img-label\"]},{id:\"input-image-alt\",selector:'input[type=\"image\"]',tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"non-empty-alt\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\"],none:[]},{id:\"label-title-only\",selector:\"input, select, textarea\",matches:function(a,b){return\"input\"!==a.nodeName.toLowerCase()||!1===a.hasAttribute(\"type\")||!1===[\"hidden\",\"image\",\"button\",\"submit\",\"reset\"].includes(a.getAttribute(\"type\").toLowerCase())},tags:[\"cat.forms\",\"best-practice\"],all:[],any:[],none:[\"title-only\"]},{id:\"label\",selector:\"input, select, textarea\",matches:function(a,b){return\"input\"!==a.nodeName.toLowerCase()||!1===a.hasAttribute(\"type\")||!1===[\"hidden\",\"image\",\"button\",\"submit\",\"reset\"].includes(a.getAttribute(\"type\").toLowerCase())},tags:[\"cat.forms\",\"wcag2a\",\"wcag332\",\"wcag131\",\"section508\",\"section508.22.n\"],all:[],any:[\"aria-label\",\"aria-labelledby\",\"implicit-label\",\"explicit-label\",\"non-empty-title\"],none:[\"help-same-as-label\",\"multiple-label\"]},{id:\"landmark-main-is-top-level\",selector:\"main, [role=main]\",tags:[\"best-practice\"],all:[],any:[\"main-is-top-level\"],none:[]},{id:\"landmark-one-main\",selector:\"html\",tags:[\"best-practice\"],all:[\"has-at-least-one-main\",\"has-no-more-than-one-main\"],any:[],none:[]},{id:\"layout-table\",selector:\"table\",matches:function(a,b){return!axe.commons.table.isDataTable(a)},tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"has-th\",\"has-caption\",\"has-summary\"]},{id:\"link-in-text-block\",selector:\"a[href], [role=link]\",matches:function(a,b){var c=axe.commons.text.sanitize(a.textContent),d=a.getAttribute(\"role\");return(!d||\"link\"===d)&&(!!c&&(!!axe.commons.dom.isVisible(a,!1)&&axe.commons.dom.isInTextBlock(a)))},excludeHidden:!1,tags:[\"cat.color\",\"experimental\",\"wcag2a\",\"wcag141\"],all:[\"link-in-text-block\"],any:[],none:[]},{id:\"link-name\",selector:\"a[href], [role=link][href]\",matches:function(a,b){return\"button\"!==a.getAttribute(\"role\")},tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag111\",\"wcag412\",\"wcag244\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",\"role-presentation\",\"role-none\"],none:[\"focusable-no-name\"]},{id:\"list\",selector:\"ul, ol\",matches:function(a,b){return!a.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[],none:[\"only-listitems\"]},{id:\"listitem\",selector:\"li\",matches:function(a,b){return!a.getAttribute(\"role\")},tags:[\"cat.structure\",\"wcag2a\",\"wcag131\"],all:[],any:[\"listitem\"],none:[]},{id:\"marquee\",selector:\"marquee\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag222\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"meta-refresh\",selector:'meta[http-equiv=\"refresh\"]',excludeHidden:!1,tags:[\"cat.time\",\"wcag2a\",\"wcag2aaa\",\"wcag221\",\"wcag224\",\"wcag325\"],all:[],any:[\"meta-refresh\"],none:[]},{id:\"meta-viewport-large\",selector:'meta[name=\"viewport\"]',excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"best-practice\"],all:[],any:[{options:{scaleMinimum:5,lowerBound:2},id:\"meta-viewport-large\"}],none:[]},{id:\"meta-viewport\",selector:'meta[name=\"viewport\"]',excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"wcag2aa\",\"wcag144\"],all:[],any:[{options:{scaleMinimum:2},id:\"meta-viewport\"}],none:[]},{id:\"object-alt\",selector:\"object\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",\"non-empty-title\"],none:[]},{id:\"p-as-heading\",selector:\"p\",matches:function(a,b){var c=Array.from(a.parentNode.childNodes),d=a.textContent.trim(),e=/[.!?:;](?![.!?:;])/g;return!(0===d.length||(d.match(e)||[]).length>=2)&&0!==c.slice(c.indexOf(a)+1).filter(function(a){return\"P\"===a.nodeName.toUpperCase()&&\"\"!==a.textContent.trim()}).length},tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\",\"experimental\"],all:[{options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}]},id:\"p-as-heading\"}],any:[],none:[]},{id:\"radiogroup\",selector:\"input[type=radio][name]\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[\"group-labelledby\",\"fieldset\"],none:[]},{id:\"region\",selector:\"html\",pageLevel:!0,tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"region\"],none:[]},{id:\"scope-attr-valid\",selector:\"td[scope], th[scope]\",tags:[\"cat.tables\",\"best-practice\"],all:[\"html5-scope\",\"scope-value\"],any:[],none:[]},{id:\"server-side-image-map\",selector:\"img[ismap]\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag211\",\"section508\",\"section508.22.f\"],all:[],any:[],none:[\"exists\"]},{id:\"skip-link\",selector:\"a[href]\",matches:function(a,b){var c=a.getAttribute(\"href\");return\"#\"===c[0]&&c.length>1},tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"skip-link\"],none:[]},{id:\"tabindex\",selector:\"[tabindex]\",tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"tabindex\"],none:[]},{id:\"table-duplicate-name\",selector:\"table\",tags:[\"cat.tables\",\"best-practice\"],all:[],any:[],none:[\"same-caption-summary\"]},{id:\"table-fake-caption\",selector:\"table\",matches:function(a,b){return axe.commons.table.isDataTable(a)},tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"caption-faked\"],any:[],none:[]},{id:\"td-has-header\",selector:\"table\",matches:function(a,b){if(axe.commons.table.isDataTable(a)){var c=axe.commons.table.toArray(a);return c.length>=3&&c[0].length>=3&&c[1].length>=3&&c[2].length>=3}return!1},tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"td-has-header\"],any:[],none:[]},{id:\"td-headers-attr\",selector:\"table\",tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"td-headers-attr\"],any:[],none:[]},{id:\"th-has-data-cells\",selector:\"table\",matches:function(a,b){return axe.commons.table.isDataTable(a)},tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\"],all:[\"th-has-data-cells\"],any:[],none:[]},{id:\"valid-lang\",selector:\"[lang], [xml\\\\:lang]\",matches:function(a,b){return\"html\"!==a.nodeName.toLowerCase()},tags:[\"cat.language\",\"wcag2aa\",\"wcag312\"],all:[],any:[],none:[\"valid-lang\"]},{id:\"video-caption\",selector:\"video\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag122\",\"wcag123\",\"section508\",\"section508.22.a\"],all:[],any:[],none:[\"caption\"]},{id:\"video-description\",selector:\"video\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2aa\",\"wcag125\",\"section508\",\"section508.22.b\"],all:[],any:[],none:[\"description\"]}],checks:[{id:\"abstractrole\",evaluate:function(a,b,c){return\"abstract\"===axe.commons.aria.getRoleType(a.getAttribute(\"role\"))}},{id:\"aria-allowed-attr\",evaluate:function(a,b,c){b=b||{};var d,e,f,g=[],h=a.getAttribute(\"role\"),i=a.attributes;if(h||(h=axe.commons.aria.implicitRole(a)),f=axe.commons.aria.allowedAttr(h),Array.isArray(b[h])&&(f=axe.utils.uniqueArray(b[h].concat(f))),h&&f)for(var j=0,k=i.length;j<k;j++)d=i[j],e=d.name,axe.commons.aria.validateAttr(e)&&!f.includes(e)&&g.push(e+'=\"'+d.nodeValue+'\"');return!g.length||(this.data(g),!1)}},{id:\"aria-hidden-body\",evaluate:function(a,b,c){return\"true\"!==a.getAttribute(\"aria-hidden\")}},{id:\"aria-errormessage\",evaluate:function(a,b,c){b=Array.isArray(b)?b:[];var d=a.getAttribute(\"aria-errormessage\"),e=a.hasAttribute(\"aria-errormessage\"),f=axe.commons.dom.getRootNode(a);return!(-1===b.indexOf(d)&&e&&!function(){var b=d&&f.getElementById(d);if(b)return\"alert\"===b.getAttribute(\"role\")||\"assertive\"===b.getAttribute(\"aria-live\")||axe.utils.tokenList(a.getAttribute(\"aria-describedby\")||\"\").indexOf(d)>-1}())||(this.data(d),!1)}},{id:\"has-widget-role\",evaluate:function(a,b,c){var d=a.getAttribute(\"role\");if(null===d)return!1;var e=axe.commons.aria.getRoleType(d);return\"widget\"===e||\"composite\"===e},options:[]},{id:\"invalidrole\",evaluate:function(a,b,c){return!axe.commons.aria.isValidRole(a.getAttribute(\"role\"))}},{id:\"aria-required-attr\",evaluate:function(a,b,c){b=b||{};var d=[];if(a.hasAttributes()){var e,f=a.getAttribute(\"role\"),g=axe.commons.aria.requiredAttr(f);if(Array.isArray(b[f])&&(g=axe.utils.uniqueArray(b[f],g)),f&&g)for(var h=0,i=g.length;h<i;h++)e=g[h],a.getAttribute(e)||d.push(e)}return!d.length||(this.data(d),!1)}},{id:\"aria-required-children\",evaluate:function(a,b,c){function d(a,b,c,d){if(null===a)return!1;var e=g(c),f=['[role=\"'+c+'\"]'];return e&&(f=f.concat(e)),f=f.join(\",\"),d?h(a,f)||!!axe.utils.querySelectorAll(b,f)[0]:!!axe.utils.querySelectorAll(b,f)[0]}function e(a,b){var c,e;for(c=0,e=a.length;c<e;c++)if(null!==a[c]){var f=axe.utils.getNodeFromTree(axe._tree[0],a[c]);if(d(a[c],f,b,!0))return!0}return!1}var f=axe.commons.aria.requiredOwned,g=axe.commons.aria.implicitNodes,h=axe.commons.utils.matchesSelector,i=axe.commons.dom.idrefs,j=a.getAttribute(\"role\"),k=f(j);if(!k)return!0;var l=!1,m=k.one;if(!m){var l=!0;m=k.all}var n=function(a,b,f,g){var h,j=b.length,k=[],l=i(a,\"aria-owns\");for(h=0;h<j;h++){var m=b[h];if(d(a,c,m)||e(l,m)){if(!f)return null}else f&&k.push(m)}if(\"combobox\"===g){var n=k.indexOf(\"textbox\"),o=[\"text\",\"search\",\"email\",\"url\",\"tel\"];n>=0&&\"INPUT\"===a.tagName&&o.includes(a.type)&&k.splice(n,1);var p=k.indexOf(\"listbox\"),q=a.getAttribute(\"aria-expanded\");p>=0&&(!q||\"false\"===q)&&k.splice(p,1)}return k.length?k:!f&&b.length?b:null}(a,m,l,j);return!n||(this.data(n),!1)}},{id:\"aria-required-parent\",evaluate:function(a,b,c){function d(a){return(axe.commons.aria.implicitNodes(a)||[]).concat('[role=\"'+a+'\"]').join(\",\")}function e(a,b,c){var e,f,g=a.actualNode.getAttribute(\"role\"),h=[];if(b||(b=axe.commons.aria.requiredContext(g)),!b)return null;for(e=0,f=b.length;e<f;e++){if(c&&axe.utils.matchesSelector(a.actualNode,d(b[e])))return null;if(axe.commons.dom.findUpVirtual(a,d(b[e])))return null;h.push(b[e])}return h}var f=e(c);if(!f)return!0;var g=function(a){for(var b=[],c=null;a;){if(a.getAttribute(\"id\")){var d=axe.commons.utils.escapeSelector(a.getAttribute(\"id\"));c=axe.commons.dom.getRootNode(a).querySelector(\"[aria-owns~=\"+d+\"]\"),c&&b.push(c)}a=a.parentElement}return b.length?b:null}(a);if(g)for(var h=0,i=g.length;h<i;h++)if(!(f=e(axe.utils.getNodeFromTree(axe._tree[0],g[h]),f,!0)))return!0;return this.data(f),!1}},{id:\"aria-valid-attr-value\",evaluate:function(a,b,c){b=Array.isArray(b)?b:[];for(var d,e,f=[],g=/^aria-/,h=a.attributes,i=[\"aria-errormessage\"],j=0,k=h.length;j<k;j++)d=h[j],e=d.name,i.includes(e)||-1===b.indexOf(e)&&g.test(e)&&!axe.commons.aria.validateAttrValue(a,e)&&f.push(e+'=\"'+d.nodeValue+'\"');return!f.length||(this.data(f),!1)},options:[]},{id:\"aria-valid-attr\",evaluate:function(a,b,c){b=Array.isArray(b)?b:[];for(var d,e=[],f=/^aria-/,g=a.attributes,h=0,i=g.length;h<i;h++)d=g[h].name,-1===b.indexOf(d)&&f.test(d)&&!axe.commons.aria.validateAttr(d)&&e.push(d);return!e.length||(this.data(e),!1)},options:[]},{id:\"valid-scrollable-semantics\",evaluate:function(a,b,c){function d(a){var b=a.tagName.toUpperCase();return f[b]||!1}function e(a){var b=a.getAttribute(\"role\");return!!b&&(g[b.toLowerCase()]||!1)}var f={ARTICLE:!0,ASIDE:!0,NAV:!0,SECTION:!0},g={banner:!1,complementary:!0,contentinfo:!0,form:!0,main:!0,navigation:!0,region:!0,search:!1};return function(a){return e(a)||d(a)}(a)},options:[]},{id:\"color-contrast\",evaluate:function(a,b,c){if(!axe.commons.dom.isVisible(a,!1))return!0;var d,e=!!(b||{}).noScroll,f=[],g=axe.commons.color.getBackgroundColor(a,f,e),h=axe.commons.color.getForegroundColor(a,e),i=window.getComputedStyle(a),j=parseFloat(i.getPropertyValue(\"font-size\")),k=i.getPropertyValue(\"font-weight\"),l=-1!==[\"bold\",\"bolder\",\"600\",\"700\",\"800\",\"900\"].indexOf(k),m=axe.commons.color.hasValidContrastRatio(g,h,j,l),n=Math.floor(100*m.contrastRatio)/100;null===g&&(d=axe.commons.color.incompleteData.get(\"bgColor\"));var o=!1;1===n&&(o=!0,d=axe.commons.color.incompleteData.set(\"bgColor\",\"equalRatio\"));var p={fgColor:h?h.toHexString():void 0,bgColor:g?g.toHexString():void 0,contrastRatio:m?n:void 0,fontSize:(72*j/96).toFixed(1)+\"pt\",fontWeight:l?\"bold\":\"normal\",missingData:d,expectedContrastRatio:m.expectedContrastRatio+\":1\"};return this.data(p),null===h||null===g||o?(d=null,axe.commons.color.incompleteData.clear(),void this.relatedNodes(f)):(m.isValid||this.relatedNodes(f),m.isValid)}},{id:\"link-in-text-block\",evaluate:function(a,b,c){function d(a,b){var c=a.getRelativeLuminance(),d=b.getRelativeLuminance();return(Math.max(c,d)+.05)/(Math.min(c,d)+.05)}function e(a){var b=window.getComputedStyle(a).getPropertyValue(\"display\");return-1!==i.indexOf(b)||\"table-\"===b.substr(0,6)}var f=axe.commons,g=f.color,h=f.dom,i=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];if(e(a))return!1;for(var j=h.getComposedParent(a);1===j.nodeType&&!e(j);)j=h.getComposedParent(j);if(this.relatedNodes([j]),g.elementIsDistinct(a,j))return!0;var k,l;if(k=g.getForegroundColor(a),l=g.getForegroundColor(j),k&&l){var m=d(k,l);if(1===m)return!0;if(m>=3)return axe.commons.color.incompleteData.set(\"fgColor\",\"bgContrast\"),this.data({missingData:axe.commons.color.incompleteData.get(\"fgColor\")}),void axe.commons.color.incompleteData.clear();if(k=g.getBackgroundColor(a),l=g.getBackgroundColor(j),!k||!l||d(k,l)>=3){var n=void 0;return n=k&&l?\"bgContrast\":axe.commons.color.incompleteData.get(\"bgColor\"),axe.commons.color.incompleteData.set(\"fgColor\",n),this.data({missingData:axe.commons.color.incompleteData.get(\"fgColor\")}),void axe.commons.color.incompleteData.clear()}return!1}}},{id:\"fieldset\",evaluate:function(a,b,c){function d(a,b){return axe.commons.utils.toArray(a.querySelectorAll('select,textarea,button,input:not([name=\"'+b+'\"]):not([type=\"hidden\"])'))}function e(a,b){var c=a.firstElementChild;if(!c||\"LEGEND\"!==c.nodeName.toUpperCase())return i.relatedNodes([a]),h=\"no-legend\",!1;if(!axe.commons.text.accessibleText(c))return i.relatedNodes([c]),h=\"empty-legend\",!1;var e=d(a,b);return!e.length||(i.relatedNodes(e),h=\"mixed-inputs\",!1)}function f(a,b){var c=axe.commons.dom.idrefs(a,\"aria-labelledby\").some(function(a){return a&&axe.commons.text.accessibleText(a)}),e=a.getAttribute(\"aria-label\");if(!(c||e&&axe.commons.text.sanitize(e)))return i.relatedNodes(a),h=\"no-group-label\",!1;var f=d(a,b);return!f.length||(i.relatedNodes(f),h=\"group-mixed-inputs\",!1)}function g(a,b){return axe.commons.utils.toArray(a).filter(function(a){return a!==b})}var h,i=this,j={name:a.getAttribute(\"name\"),type:a.getAttribute(\"type\")},k=function(a){var b=axe.commons.utils.escapeSelector(a.actualNode.name),c=axe.commons.dom.getRootNode(a.actualNode),d=c.querySelectorAll('input[type=\"'+axe.commons.utils.escapeSelector(a.actualNode.type)+'\"][name=\"'+b+'\"]');if(d.length<2)return!0;var j=axe.commons.dom.findUpVirtual(a,\"fieldset\"),k=axe.commons.dom.findUpVirtual(a,'[role=\"group\"]'+(\"radio\"===a.actualNode.type?',[role=\"radiogroup\"]':\"\"));return k||j?j?e(j,b):f(k,b):(h=\"no-group\",i.relatedNodes(g(d,a.actualNode)),!1)}(c);return k||(j.failureCode=h),this.data(j),k},after:function(a,b){var c={};return a.filter(function(a){if(a.result)return!0;var b=a.data;if(b){if(c[b.type]=c[b.type]||{},!c[b.type][b.name])return c[b.type][b.name]=[b],!0;var d=c[b.type][b.name].some(function(a){return a.failureCode===b.failureCode});return d||c[b.type][b.name].push(b),!d}return!1})}},{id:\"group-labelledby\",evaluate:function(a,b,c){this.data({name:a.getAttribute(\"name\"),type:a.getAttribute(\"type\")});var d=axe.commons.dom.getRootNode(a),e=d.querySelectorAll('input[type=\"'+axe.commons.utils.escapeSelector(a.type)+'\"][name=\"'+axe.commons.utils.escapeSelector(a.name)+'\"]');return e.length<=1||0!==[].map.call(e,function(a){var b=a.getAttribute(\"aria-labelledby\");return b?b.split(/\\s+/):[]}).reduce(function(a,b){return a.filter(function(a){return b.includes(a)})}).filter(function(a){var b=d.getElementById(a);return b&&axe.commons.text.accessibleText(b,!0)}).length},after:function(a,b){var c={};return a.filter(function(a){var b=a.data;return!(!b||(c[b.type]=c[b.type]||{},c[b.type][b.name]))&&(c[b.type][b.name]=!0,!0)})}},{id:\"accesskeys\",evaluate:function(a,b,c){return axe.commons.dom.isVisible(a,!1)&&(this.data(a.getAttribute(\"accesskey\")),this.relatedNodes([a])),!0},after:function(a,b){var c={};return a.filter(function(a){if(!a.data)return!1;var b=a.data.toUpperCase();return c[b]?(c[b].relatedNodes.push(a.relatedNodes[0]),!1):(c[b]=a,a.relatedNodes=[],!0)}).map(function(a){return a.result=!!a.relatedNodes.length,a})}},{id:\"focusable-no-name\",evaluate:function(a,b,c){var d=a.getAttribute(\"tabindex\");return!!(axe.commons.dom.isFocusable(a)&&d>-1)&&!axe.commons.text.accessibleTextVirtual(c)}},{id:\"has-at-least-one-main\",evaluate:function(a,b,c){var d=axe.utils.querySelectorAll(c,\"main,[role=main]\");return this.data(!!d[0]),!!d[0]},after:function(a,b){for(var c=!1,d=0;d<a.length&&!c;d++)c=a[d].data;for(var d=0;d<a.length;d++)a[d].result=c;return a}},{id:\"has-no-more-than-one-main\",evaluate:function(a,b,c){return axe.utils.querySelectorAll(c,\"main,[role=main]\").length<=1}},{id:\"main-is-top-level\",evaluate:function(a,b,c){for(var d=axe.commons.aria.getRolesByType(\"landmark\"),e=axe.commons.dom.getComposedParent(a);e;){var f=e.getAttribute(\"role\");if(f||\"form\"===e.tagName.toLowerCase()||(f=axe.commons.aria.implicitRole(e)),f&&d.includes(f))return!1;e=axe.commons.dom.getComposedParent(e)}return!0}},{id:\"tabindex\",evaluate:function(a,b,c){return a.tabIndex<=0}},{id:\"duplicate-img-label\",evaluate:function(a,b,c){var d=axe.commons.text.visibleVirtual(c,!0).toLowerCase();return\"\"!==d&&axe.utils.querySelectorAll(c,\"img\").filter(function(a){var b=a.actualNode;return axe.commons.dom.isVisible(b)&&![\"none\",\"presentation\"].includes(b.getAttribute(\"role\"))}).some(function(a){return d===axe.commons.text.accessibleTextVirtual(a).toLowerCase()})}},{id:\"explicit-label\",evaluate:function(a,b,c){if(a.getAttribute(\"id\")){var d=axe.commons.dom.getRootNode(a),e=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),f=d.querySelector('label[for=\"'+e+'\"]');if(f)return!!axe.commons.text.accessibleText(f)}return!1}},{id:\"help-same-as-label\",evaluate:function(a,b,c){var d=axe.commons.text.labelVirtual(c),e=a.getAttribute(\"title\");if(!d)return!1;if(!e&&(e=\"\",a.getAttribute(\"aria-describedby\"))){e=axe.commons.dom.idrefs(a,\"aria-describedby\").map(function(a){return a?axe.commons.text.accessibleText(a):\"\"}).join(\"\")}return axe.commons.text.sanitize(e)===axe.commons.text.sanitize(d)},enabled:!1},{id:\"implicit-label\",evaluate:function(a,b,c){var d=axe.commons.dom.findUpVirtual(c,\"label\");return!!d&&!!axe.commons.text.accessibleTextVirtual(d)}},{id:\"multiple-label\",evaluate:function(a,b,c){var d=axe.commons.utils.escapeSelector(a.getAttribute(\"id\")),e=Array.from(document.querySelectorAll('label[for=\"'+d+'\"]')),f=a.parentNode;for(e.length&&(e=e.filter(function(a,b){if(0===b&&!axe.commons.dom.isVisible(a,!0)||axe.commons.dom.isVisible(a,!0))return a}));f;)\"LABEL\"===f.tagName&&-1===e.indexOf(f)&&e.push(f),f=f.parentNode;return this.relatedNodes(e),e.length>1}},{id:\"title-only\",evaluate:function(a,b,c){return!(axe.commons.text.labelVirtual(c)||!a.getAttribute(\"title\")&&!a.getAttribute(\"aria-describedby\"))}},{id:\"has-lang\",evaluate:function(a,b,c){return!!(a.getAttribute(\"lang\")||a.getAttribute(\"xml:lang\")||\"\").trim()}},{id:\"valid-lang\",evaluate:function(a,b,c){function d(a){return a.trim().split(\"-\")[0].toLowerCase()}var e,f;return e=(b||axe.commons.utils.validLangs()).map(d),f=[\"lang\",\"xml:lang\"].reduce(function(b,c){var f=a.getAttribute(c);if(\"string\"!=typeof f)return b;var g=d(f);return\"\"!==g&&-1===e.indexOf(g)&&b.push(c+'=\"'+a.getAttribute(c)+'\"'),b},[]),!!f.length&&(this.data(f),!0)}},{id:\"dlitem\",evaluate:function(a,b,c){return\"DL\"===axe.commons.dom.getComposedParent(a).nodeName.toUpperCase()}},{id:\"has-listitem\",evaluate:function(a,b,c){return c.children.every(function(a){return\"LI\"!==a.actualNode.nodeName.toUpperCase()})}},{id:\"listitem\",evaluate:function(a,b,c){var d=axe.commons.dom.getComposedParent(a);return[\"UL\",\"OL\"].includes(d.nodeName.toUpperCase())||\"list\"===(d.getAttribute(\"role\")||\"\").toLowerCase()}},{id:\"only-dlitems\",evaluate:function(a,b,c){var d=[],e=[\"STYLE\",\"META\",\"LINK\",\"MAP\",\"AREA\",\"SCRIPT\",\"DATALIST\",\"TEMPLATE\"],f=!1;return c.children.forEach(function(a){var b=a.actualNode,c=b.nodeName.toUpperCase();1===b.nodeType&&\"DT\"!==c&&\"DD\"!==c&&-1===e.indexOf(c)?d.push(b):3===b.nodeType&&\"\"!==b.nodeValue.trim()&&(f=!0)}),d.length&&this.relatedNodes(d),!!d.length||f}},{id:\"only-listitems\",evaluate:function(a,b,c){var d=[],e=[\"STYLE\",\"META\",\"LINK\",\"MAP\",\"AREA\",\"SCRIPT\",\"DATALIST\",\"TEMPLATE\"],f=!1;return c.children.forEach(function(a){var b=a.actualNode,c=b.nodeName.toUpperCase();1===b.nodeType&&\"LI\"!==c&&-1===e.indexOf(c)?d.push(b):3===b.nodeType&&\"\"!==b.nodeValue.trim()&&(f=!0)}),d.length&&this.relatedNodes(d),!!d.length||f}},{id:\"structured-dlitems\",\nevaluate:function(a,b,c){var d=c.children;if(!d||!d.length)return!1;for(var e,f=!1,g=!1,h=0;h<d.length;h++){if(e=d[h].actualNode.nodeName.toUpperCase(),\"DT\"===e&&(f=!0),f&&\"DD\"===e)return!1;\"DD\"===e&&(g=!0)}return f||g}},{id:\"caption\",evaluate:function(a,b,c){var d=axe.utils.querySelectorAll(c,\"track\");if(d.length)return!d.some(function(a){return\"captions\"===(a.actualNode.getAttribute(\"kind\")||\"\").toLowerCase()})}},{id:\"description\",evaluate:function(a,b,c){var d=axe.utils.querySelectorAll(c,\"track\");if(d.length){return!d.some(function(a){return\"descriptions\"===(a.actualNode.getAttribute(\"kind\")||\"\").toLowerCase()})}}},{id:\"meta-viewport-large\",evaluate:function(a,b,c){b=b||{};for(var d,e=a.getAttribute(\"content\")||\"\",f=e.split(/[;,]/),g={},h=b.scaleMinimum||2,i=b.lowerBound||!1,j=0,k=f.length;j<k;j++){d=f[j].split(\"=\");var l=d.shift().toLowerCase();l&&d.length&&(g[l.trim()]=d.shift().trim().toLowerCase())}return!!(i&&g[\"maximum-scale\"]&&parseFloat(g[\"maximum-scale\"])<i)||!(!i&&\"no\"===g[\"user-scalable\"])&&!(g[\"maximum-scale\"]&&parseFloat(g[\"maximum-scale\"])<h)},options:{scaleMinimum:5,lowerBound:2}},{id:\"meta-viewport\",evaluate:function(a,b,c){b=b||{};for(var d,e=a.getAttribute(\"content\")||\"\",f=e.split(/[;,]/),g={},h=b.scaleMinimum||2,i=b.lowerBound||!1,j=0,k=f.length;j<k;j++){d=f[j].split(\"=\");var l=d.shift().toLowerCase();l&&d.length&&(g[l.trim()]=d.shift().trim().toLowerCase())}return!!(i&&g[\"maximum-scale\"]&&parseFloat(g[\"maximum-scale\"])<i)||!(!i&&\"no\"===g[\"user-scalable\"])&&!(g[\"maximum-scale\"]&&parseFloat(g[\"maximum-scale\"])<h)},options:{scaleMinimum:2}},{id:\"header-present\",evaluate:function(a,b,c){return!!axe.utils.querySelectorAll(c,'h1, h2, h3, h4, h5, h6, [role=\"heading\"]')[0]}},{id:\"heading-order\",evaluate:function(a,b,c){var d=a.getAttribute(\"aria-level\");if(null!==d)return this.data(parseInt(d,10)),!0;var e=a.tagName.match(/H(\\d)/);return!e||(this.data(parseInt(e[1],10)),!0)},after:function(a,b){if(a.length<2)return a;for(var c=a[0].data,d=1;d<a.length;d++)a[d].result&&a[d].data>c+1&&(a[d].result=!1),c=a[d].data;return a}},{id:\"internal-link-present\",evaluate:function(a,b,c){return axe.utils.querySelectorAll(c,\"a[href]\").some(function(a){return\"#\"===a.actualNode.getAttribute(\"href\")[0]})}},{id:\"landmark\",evaluate:function(a,b,c){return axe.utils.querySelectorAll(c,'main, [role=\"main\"]').length>0}},{id:\"meta-refresh\",evaluate:function(a,b,c){var d=a.getAttribute(\"content\")||\"\",e=d.split(/[;,]/);return\"\"===d||\"0\"===e[0]}},{id:\"p-as-heading\",evaluate:function(a,b,c){function d(a){for(var b=a,c=a.textContent.trim(),d=c;d===c&&void 0!==b;){var e=-1;if(a=b,0===a.children.length)return a;do{e++,d=a.children[e].textContent.trim()}while(\"\"===d&&e+1<a.children.length);b=a.children[e]}return a}function e(a){switch(a){case\"lighter\":return 100;case\"normal\":return 400;case\"bold\":return 700;case\"bolder\":return 900}return a=parseInt(a),isNaN(a)?400:a}function f(a){var b=window.getComputedStyle(d(a));return{fontWeight:e(b.getPropertyValue(\"font-weight\")),fontSize:parseInt(b.getPropertyValue(\"font-size\")),isItalic:\"italic\"===b.getPropertyValue(\"font-style\")}}function g(a,b,c){return c.reduce(function(c,d){return c||(!d.size||a.fontSize/d.size>b.fontSize)&&(!d.weight||a.fontWeight-d.weight>b.fontWeight)&&(!d.italic||a.isItalic&&!b.isItalic)},!1)}var h=Array.from(a.parentNode.children),i=h.indexOf(a);b=b||{};var j=b.margins||[],k=h.slice(i+1).find(function(a){return\"P\"===a.nodeName.toUpperCase()}),l=h.slice(0,i).reverse().find(function(a){return\"P\"===a.nodeName.toUpperCase()}),m=f(a),n=k?f(k):null,o=l?f(l):null;if(!n||!g(m,n,j))return!0;var p=axe.commons.dom.findUpVirtual(c,\"blockquote\");return!!(p&&\"BLOCKQUOTE\"===p.nodeName.toUpperCase()||o&&!g(m,o,j))&&void 0},options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}]}},{id:\"region\",evaluate:function(a,b,c){function d(a){return j&&j===a}function e(a){return a.hasAttribute(\"role\")?k.includes(a.getAttribute(\"role\").toLowerCase()):l.some(function(b){return axe.utils.matchesSelector(a,b)})}function f(a){var b=a.actualNode;return e(b)||d(b)||!h.isVisible(b,!0)?[]:h.hasContent(b,!0)?[b]:a.children.filter(function(a){return 1===a.actualNode.nodeType}).map(f).reduce(function(a,b){return a.concat(b)},[])}var g=axe.commons,h=g.dom,i=g.aria,j=function(a){var b=axe.utils.querySelectorAll(a,\"a[href]\")[0];if(b&&axe.commons.dom.getElementByReference(b.actualNode,\"href\"))return b.actualNode}(c),k=i.getRolesByType(\"landmark\"),l=k.reduce(function(a,b){return a.concat(i.implicitNodes(b))},[]).filter(function(a){return null!==a}),m=f(c);return this.relatedNodes(m),0===m.length},after:function(a,b){return[a[0]]}},{id:\"skip-link\",evaluate:function(a,b,c){var d=axe.commons.dom.getElementByReference(a,\"href\");return!!d&&(axe.commons.dom.isVisible(d,!0)||void 0)}},{id:\"unique-frame-title\",evaluate:function(a,b,c){var d=axe.commons.text.sanitize(a.title).trim().toLowerCase();return this.data(d),!0},after:function(a,b){var c={};return a.forEach(function(a){c[a.data]=void 0!==c[a.data]?++c[a.data]:0}),a.forEach(function(a){a.result=!!c[a.data]}),a}},{id:\"aria-label\",evaluate:function(a,b,c){var d=a.getAttribute(\"aria-label\");return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"aria-labelledby\",evaluate:function(a,b,c){return(0,axe.commons.dom.idrefs)(a,\"aria-labelledby\").some(function(a){return a&&axe.commons.text.accessibleText(a,!0)})}},{id:\"button-has-visible-text\",evaluate:function(a,b,c){var d=a.nodeName.toUpperCase(),e=a.getAttribute(\"role\"),f=void 0;return(\"BUTTON\"===d||\"button\"===e&&\"INPUT\"!==d)&&(f=axe.commons.text.accessibleTextVirtual(c),this.data(f),!!f)}},{id:\"doc-has-title\",evaluate:function(a,b,c){var d=document.title;return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"duplicate-id\",evaluate:function(a,b,c){var d=a.getAttribute(\"id\").trim();if(!d)return!0;var e=axe.commons.dom.getRootNode(a),f=Array.from(e.querySelectorAll('[id=\"'+axe.commons.utils.escapeSelector(d)+'\"]')).filter(function(b){return b!==a});return f.length&&this.relatedNodes(f),this.data(d),0===f.length},after:function(a,b){var c=[];return a.filter(function(a){return-1===c.indexOf(a.data)&&(c.push(a.data),!0)})}},{id:\"exists\",evaluate:function(a,b,c){return!0}},{id:\"has-alt\",evaluate:function(a,b,c){var d=a.nodeName.toLowerCase();return a.hasAttribute(\"alt\")&&(\"img\"===d||\"input\"===d||\"area\"===d)}},{id:\"has-visible-text\",evaluate:function(a,b,c){return axe.commons.text.accessibleTextVirtual(c).length>0}},{id:\"is-on-screen\",evaluate:function(a,b,c){return axe.commons.dom.isVisible(a,!1)&&!axe.commons.dom.isOffscreen(a)}},{id:\"non-empty-alt\",evaluate:function(a,b,c){var d=a.getAttribute(\"alt\");return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"non-empty-if-present\",evaluate:function(a,b,c){var d=a.nodeName.toUpperCase(),e=(a.getAttribute(\"type\")||\"\").toLowerCase(),f=a.getAttribute(\"value\");return this.data(f),!(\"INPUT\"!==d||![\"submit\",\"reset\"].includes(e))&&null===f}},{id:\"non-empty-title\",evaluate:function(a,b,c){var d=a.getAttribute(\"title\");return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"non-empty-value\",evaluate:function(a,b,c){var d=a.getAttribute(\"value\");return!!(d?axe.commons.text.sanitize(d).trim():\"\")}},{id:\"role-none\",evaluate:function(a,b,c){return\"none\"===a.getAttribute(\"role\")}},{id:\"role-presentation\",evaluate:function(a,b,c){return\"presentation\"===a.getAttribute(\"role\")}},{id:\"caption-faked\",evaluate:function(a,b,c){var d=axe.commons.table.toGrid(a),e=d[0];return d.length<=1||e.length<=1||a.rows.length<=1||e.reduce(function(a,b,c){return a||b!==e[c+1]&&void 0!==e[c+1]},!1)}},{id:\"has-caption\",evaluate:function(a,b,c){return!!a.caption}},{id:\"has-summary\",evaluate:function(a,b,c){return!!a.summary}},{id:\"has-th\",evaluate:function(a,b,c){for(var d,e,f=[],g=0,h=a.rows.length;g<h;g++){d=a.rows[g];for(var i=0,j=d.cells.length;i<j;i++)e=d.cells[i],\"TH\"!==e.nodeName.toUpperCase()&&-1===[\"rowheader\",\"columnheader\"].indexOf(e.getAttribute(\"role\"))||f.push(e)}return!!f.length&&(this.relatedNodes(f),!0)}},{id:\"html5-scope\",evaluate:function(a,b,c){return!axe.commons.dom.isHTML5(document)||\"TH\"===a.nodeName.toUpperCase()}},{id:\"same-caption-summary\",evaluate:function(a,b,c){return!(!a.summary||!a.caption)&&a.summary===axe.commons.text.accessibleText(a.caption)}},{id:\"scope-value\",evaluate:function(a,b,c){b=b||{};var d=a.getAttribute(\"scope\").toLowerCase();return-1!==([\"row\",\"col\",\"rowgroup\",\"colgroup\"]||b.values).indexOf(d)}},{id:\"td-has-header\",evaluate:function(a,b,c){var d=axe.commons.table,e=[];return d.getAllCells(a).forEach(function(a){if(axe.commons.dom.hasContent(a)&&d.isDataCell(a)&&!axe.commons.aria.label(a)){var b=d.getHeaders(a);(b=b.reduce(function(a,b){return a||null!==b&&!!axe.commons.dom.hasContent(b)},!1))||e.push(a)}}),!e.length||(this.relatedNodes(e),!1)}},{id:\"td-headers-attr\",evaluate:function(a,b,c){for(var d=[],e=0,f=a.rows.length;e<f;e++)for(var g=a.rows[e],h=0,i=g.cells.length;h<i;h++)d.push(g.cells[h]);var j=d.reduce(function(a,b){return b.getAttribute(\"id\")&&a.push(b.getAttribute(\"id\")),a},[]),k=d.reduce(function(a,b){var c,d,e=(b.getAttribute(\"headers\")||\"\").split(/\\s/).reduce(function(a,b){return b=b.trim(),b&&a.push(b),a},[]);return 0!==e.length&&(b.getAttribute(\"id\")&&(c=-1!==e.indexOf(b.getAttribute(\"id\").trim())),d=e.reduce(function(a,b){return a||-1===j.indexOf(b)},!1),(c||d)&&a.push(b)),a},[]);return!(k.length>0)||(this.relatedNodes(k),!1)}},{id:\"th-has-data-cells\",evaluate:function(a,b,c){var d=axe.commons.table,e=d.getAllCells(a),f=this,g=[];e.forEach(function(a){var b=a.getAttribute(\"headers\");b&&(g=g.concat(b.split(/\\s+/)));var c=a.getAttribute(\"aria-labelledby\");c&&(g=g.concat(c.split(/\\s+/)))});var h=e.filter(function(a){return\"\"!==axe.commons.text.sanitize(a.textContent)&&(\"TH\"===a.nodeName.toUpperCase()||-1!==[\"rowheader\",\"columnheader\"].indexOf(a.getAttribute(\"role\")))}),i=d.toGrid(a);return!!h.reduce(function(a,b){if(b.getAttribute(\"id\")&&g.includes(b.getAttribute(\"id\")))return!!a||a;var c=!1,e=d.getCellPosition(b,i);return d.isColumnHeader(b)&&(c=d.traverse(\"down\",e,i).reduce(function(a,b){return a||axe.commons.dom.hasContent(b)&&!d.isColumnHeader(b)},!1)),!c&&d.isRowHeader(b)&&(c=d.traverse(\"right\",e,i).reduce(function(a,b){return a||axe.commons.dom.hasContent(b)&&!d.isRowHeader(b)},!1)),c||f.relatedNodes(b),a&&c},!0)||void 0}},{id:\"hidden-content\",evaluate:function(a,b,c){if(![\"SCRIPT\",\"HEAD\",\"TITLE\",\"NOSCRIPT\",\"STYLE\",\"TEMPLATE\"].includes(a.tagName.toUpperCase())&&axe.commons.dom.hasContentVirtual(c)){var d=window.getComputedStyle(a);if(\"none\"===d.getPropertyValue(\"display\"))return;if(\"hidden\"===d.getPropertyValue(\"visibility\")){var e=axe.commons.dom.getComposedParent(a),f=e&&window.getComputedStyle(e);if(!f||\"hidden\"!==f.getPropertyValue(\"visibility\"))return}}return!0}}],commons:function(){function a(a){return a.getPropertyValue(\"font-family\").split(/[,;]/g).map(function(a){return a.trim().toLowerCase()})}function b(b,c){var d=window.getComputedStyle(b);if(\"none\"!==d.getPropertyValue(\"background-image\"))return!0;if([\"border-bottom\",\"border-top\",\"outline\"].reduce(function(a,b){var c=new C.Color;return c.parseRgbString(d.getPropertyValue(b+\"-color\")),a||\"none\"!==d.getPropertyValue(b+\"-style\")&&parseFloat(d.getPropertyValue(b+\"-width\"))>0&&0!==c.alpha},!1))return!0;var e=window.getComputedStyle(c);if(a(d)[0]!==a(e)[0])return!0;var f=[\"text-decoration-line\",\"text-decoration-style\",\"font-weight\",\"font-style\",\"font-size\"].reduce(function(a,b){return a||d.getPropertyValue(b)!==e.getPropertyValue(b)},!1),g=d.getPropertyValue(\"text-decoration\");return g.split(\" \").length<3&&(f=f||g!==e.getPropertyValue(\"text-decoration\")),f}function c(a,b){var c=a.nodeName.toUpperCase();if(G.includes(c))return axe.commons.color.incompleteData.set(\"bgColor\",\"imgNode\"),!0;b=b||window.getComputedStyle(a);var d=b.getPropertyValue(\"background-image\"),e=\"none\"!==d;if(e){var f=/gradient/.test(d);axe.commons.color.incompleteData.set(\"bgColor\",f?\"bgGradient\":\"bgImage\")}return e}function d(a,b){b=b||window.getComputedStyle(a);var c=new C.Color;if(c.parseRgbString(b.getPropertyValue(\"background-color\")),0!==c.alpha){var d=b.getPropertyValue(\"opacity\");c.alpha=c.alpha*d}return c}function e(a,b){var c=a.getClientRects()[0],d=D.shadowElementsFromPoint(c.left,c.top);if(d)for(var e=0;e<d.length;e++)if(d[e]!==a&&d[e]===b)return!0;return!1}function f(a,b,c){var f=0;if(a>0)for(var g=a-1;g>=0;g--){var h=b[g],i=window.getComputedStyle(h),j=d(h,i);j.alpha&&e(c,h)?f+=j.alpha:b.splice(g,1)}return f}function g(a,b,c){var d=a!==b&&!D.visuallyContains(a,b)&&0!==c.alpha;return d&&axe.commons.color.incompleteData.set(\"bgColor\",\"elmPartiallyObscured\"),d}function h(a,b){var c={TD:[\"TR\",\"TBODY\"],TH:[\"TR\",\"THEAD\"],INPUT:[\"LABEL\"]},d=a.map(function(a){return a.tagName}),e=a;for(var f in c)if(d.includes(f))for(var g in c[f])if(f.hasOwnProperty(g)){var h=axe.commons.dom.findUp(b,c[f][g]);if(h&&-1===a.indexOf(h)){var i=axe.commons.dom.visuallyOverlaps(b.getBoundingClientRect(),h);i&&e.splice(d.indexOf(f)+1,0,h)}b.tagName===c[f][g]&&-1===d.indexOf(b.tagName)&&e.splice(d.indexOf(f)+1,0,b)}return e}function i(a){var b=a.indexOf(document.body),e=a;return b>1&&!c(document.documentElement)&&0===d(document.documentElement).alpha&&(e.splice(b,1),e.splice(a.indexOf(document.documentElement),1),e.push(document.body)),e}function j(a){if(!H.includes(a.actualNode.nodeName.toUpperCase()))return a.children.some(function(a){var b=a.actualNode;return 3===b.nodeType&&b.nodeValue.trim()})}function k(a){return a.disabled||!D.isVisible(a,!0)&&\"AREA\"!==a.nodeName.toUpperCase()}function l(a,b){!1!==b(a.actualNode)&&a.children.forEach(function(a){return l(a,b)})}function m(a){var b=window.getComputedStyle(a).getPropertyValue(\"display\");return I.includes(b)||\"table-\"===b.substr(0,6)}function n(a){for(var b=D.getComposedParent(a);b&&!m(b);)b=D.getComposedParent(b);return axe.utils.getNodeFromTree(axe._tree[0],b)}function o(a,b){for(a=D.getComposedParent(a);a&&\"html\"!==a.nodeName.toLowerCase();){if(a.scrollTop&&(b+=a.scrollTop)>=0)return!1;a=D.getComposedParent(a)}return!0}function p(a){\"use strict\";var b=a.match(/rect\\s*\\(([0-9]+)px,?\\s*([0-9]+)px,?\\s*([0-9]+)px,?\\s*([0-9]+)px\\s*\\)/);return!(!b||5!==b.length)&&(b[3]-b[1]<=0&&b[2]-b[4]<=0)}function q(a){var b=void 0;return b=a.actualNode.id?D.findElmsInContext({elm:\"label\",attr:\"for\",value:a.actualNode.id,context:a.actualNode})[0]:D.findUpVirtual(a,\"label\"),axe.utils.getNodeFromTree(axe._tree[0],b)}function r(a){return[\"button\",\"reset\",\"submit\"].includes(a.actualNode.type.toLowerCase())}function s(a){var b=a.actualNode,c=b.nodeName.toUpperCase();return\"TEXTAREA\"===c||\"SELECT\"===c||\"INPUT\"===c&&\"hidden\"!==b.type.toLowerCase()}function t(a){return[\"BUTTON\",\"SUMMARY\",\"A\"].includes(a.actualNode.nodeName.toUpperCase())}function u(a){return[\"TABLE\",\"FIGURE\"].includes(a.actualNode.nodeName.toUpperCase())}function v(a){var b=a.actualNode,c=b.nodeName.toUpperCase();if(\"INPUT\"===c)return!b.hasAttribute(\"type\")||L.includes(b.type.toLowerCase())?b.value:\"\";if(\"SELECT\"===c){var d=b.options;if(d&&d.length){for(var e=\"\",f=0;f<d.length;f++)d[f].selected&&(e+=\" \"+d[f].text);return F.sanitize(e)}return\"\"}return\"TEXTAREA\"===c&&b.value?b.value:\"\"}function w(a,b){var c=a.actualNode,d=c.querySelector(b.toLowerCase());return d?F.accessibleText(d):\"\"}function x(a){if(!a)return!1;var b=a.actualNode;switch(b.nodeName.toUpperCase()){case\"SELECT\":case\"TEXTAREA\":return!0;case\"INPUT\":return!b.hasAttribute(\"type\")||L.includes(b.getAttribute(\"type\").toLowerCase());default:return!1}}function y(a){var b=a.actualNode,c=b.nodeName.toUpperCase();return[\"IMG\",\"APPLET\",\"AREA\"].includes(c)||\"INPUT\"===c&&\"image\"===b.type.toLowerCase()}function z(a){return!!F.sanitize(a)}var commons={},A=commons.aria={},B=A.lookupTable={};B.attributes={\"aria-activedescendant\":{type:\"idref\"},\"aria-atomic\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-autocomplete\":{type:\"nmtoken\",values:[\"inline\",\"list\",\"both\",\"none\"]},\"aria-busy\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-checked\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"]},\"aria-colcount\":{type:\"int\"},\"aria-colindex\":{type:\"int\"},\"aria-colspan\":{type:\"int\"},\"aria-controls\":{type:\"idrefs\"},\"aria-current\":{type:\"nmtoken\",values:[\"page\",\"step\",\"location\",\"date\",\"time\",\"true\",\"false\"]},\"aria-describedby\":{type:\"idrefs\"},\"aria-disabled\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-dropeffect\":{type:\"nmtokens\",values:[\"copy\",\"move\",\"reference\",\"execute\",\"popup\",\"none\"]},\"aria-errormessage\":{type:\"idref\"},\"aria-expanded\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-flowto\":{type:\"idrefs\"},\"aria-grabbed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-haspopup\":{type:\"nmtoken\",values:[\"true\",\"false\",\"menu\",\"listbox\",\"tree\",\"grid\",\"dialog\"]},\"aria-hidden\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-invalid\":{type:\"nmtoken\",values:[\"true\",\"false\",\"spelling\",\"grammar\"]},\"aria-keyshortcuts\":{type:\"string\"},\"aria-label\":{type:\"string\"},\"aria-labelledby\":{type:\"idrefs\"},\"aria-level\":{type:\"int\"},\"aria-live\":{type:\"nmtoken\",values:[\"off\",\"polite\",\"assertive\"]},\"aria-modal\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-multiline\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-multiselectable\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-orientation\":{type:\"nmtoken\",values:[\"horizontal\",\"vertical\"]},\"aria-owns\":{type:\"idrefs\"},\"aria-placeholder\":{type:\"string\"},\"aria-posinset\":{type:\"int\"},\"aria-pressed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"]},\"aria-readonly\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-relevant\":{type:\"nmtokens\",values:[\"additions\",\"removals\",\"text\",\"all\"]},\"aria-required\":{type:\"boolean\",values:[\"true\",\"false\"]},\"aria-rowcount\":{type:\"int\"},\"aria-rowindex\":{type:\"int\"},\"aria-rowspan\":{type:\"int\"},\"aria-selected\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-setsize\":{type:\"int\"},\"aria-sort\":{type:\"nmtoken\",values:[\"ascending\",\"descending\",\"other\",\"none\"]},\"aria-valuemax\":{type:\"decimal\"},\"aria-valuemin\":{type:\"decimal\"},\"aria-valuenow\":{type:\"decimal\"},\"aria-valuetext\":{type:\"string\"}},B.globalAttributes=[\"aria-atomic\",\"aria-busy\",\"aria-controls\",\"aria-current\",\"aria-describedby\",\"aria-disabled\",\"aria-dropeffect\",\"aria-flowto\",\"aria-grabbed\",\"aria-haspopup\",\"aria-hidden\",\"aria-invalid\",\"aria-keyshortcuts\",\"aria-label\",\"aria-labelledby\",\"aria-live\",\"aria-owns\",\"aria-relevant\"],B.role={alert:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},alertdialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\"]},owned:null,nameFrom:[\"author\"],context:null},application:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},article:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"article\"]},banner:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"header\"]},button:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-pressed\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"button\",'input[type=\"button\"]','input[type=\"image\"]','input[type=\"reset\"]','input[type=\"submit\"]',\"summary\"]},cell:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-rowindex\",\"aria-rowspan\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"]},checkbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"checkbox\"]']},columnheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"]},combobox:{type:\"composite\",attributes:{allowed:[\"aria-expanded\",\"aria-autocomplete\",\"aria-required\",\"aria-activedescendant\",\"aria-orientation\"]},owned:{all:[\"listbox\",\"textbox\"]},nameFrom:[\"author\"],context:null},command:{nameFrom:[\"author\"],type:\"abstract\"},complementary:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"aside\"]},composite:{nameFrom:[\"author\"],type:\"abstract\"},contentinfo:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"footer\"]},definition:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dd\",\"dfn\"]},dialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dialog\"]},directory:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},document:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"body\"]},feed:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:{one:[\"article\"]},nameFrom:[\"author\"],context:null},form:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"form\"]},grid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-colcount\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-rowcount\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"]},gridcell:{type:\"widget\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-selected\",\"aria-readonly\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"]},group:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"details\",\"optgroup\"]},heading:{type:\"structure\",attributes:{allowed:[\"aria-level\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"]},img:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"img\"]},input:{nameFrom:[\"author\"],type:\"abstract\"},landmark:{nameFrom:[\"author\"],type:\"abstract\"},link:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"a[href]\"]},list:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:{all:[\"listitem\"]},nameFrom:[\"author\"],context:null,implicit:[\"ol\",\"ul\",\"dl\"]},listbox:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\"]},owned:{all:[\"option\"]},nameFrom:[\"author\"],context:null,implicit:[\"select\"]},listitem:{type:\"structure\",attributes:{allowed:[\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"list\"],implicit:[\"li\",\"dt\"]},log:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},main:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"main\"]},marquee:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},math:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"math\"]},menu:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"]},owned:{one:[\"menuitem\",\"menuitemradio\",\"menuitemcheckbox\"]},nameFrom:[\"author\"],context:null,implicit:['menu[type=\"context\"]']},menubar:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null},menuitem:{type:\"widget\",attributes:{allowed:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"command\"]']},menuitemcheckbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"checkbox\"]']},menuitemradio:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"radio\"]']},navigation:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"nav\"]},none:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null},note:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},option:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"listbox\"],implicit:[\"option\"]},presentation:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null},progressbar:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"progress\"]},radio:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-required\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"radio\"]']},radiogroup:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-required\",\"aria-expanded\"]},owned:{all:[\"radio\"]},nameFrom:[\"author\"],context:null},range:{nameFrom:[\"author\"],type:\"abstract\"},region:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"section[aria-label]\",\"section[aria-labelledby]\",\"section[title]\"]},roletype:{type:\"abstract\"},row:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colindex\",\"aria-expanded\",\"aria-level\",\"aria-selected\",\"aria-rowindex\"]},owned:{one:[\"cell\",\"columnheader\",\"rowheader\",\"gridcell\"]},nameFrom:[\"author\",\"contents\"],context:[\"rowgroup\",\"grid\",\"treegrid\",\"table\"],implicit:[\"tr\"]},rowgroup:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:{all:[\"row\"]},nameFrom:[\"author\",\"contents\"],context:[\"grid\",\"table\"],implicit:[\"tbody\",\"thead\",\"tfoot\"]},rowheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"]},scrollbar:{type:\"widget\",attributes:{required:[\"aria-controls\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"],allowed:[\"aria-valuetext\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null},search:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},searchbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"search\"]']},section:{nameFrom:[\"author\",\"contents\"],type:\"abstract\"},sectionhead:{nameFrom:[\"author\",\"contents\"],type:\"abstract\"},select:{nameFrom:[\"author\"],type:\"abstract\"},separator:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-orientation\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"hr\"]},slider:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-orientation\"],required:[\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"range\"]']},spinbutton:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-required\"],required:[\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"number\"]']},status:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"output\"]},structure:{type:\"abstract\"},switch:{type:\"widget\",attributes:{required:[\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},tab:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-expanded\",\"aria-setsize\",\"aria-posinset\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"tablist\"]},table:{type:\"structure\",attributes:{allowed:[\"aria-colcount\",\"aria-rowcount\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"]},tablist:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-orientation\"]},owned:{all:[\"tab\"]},nameFrom:[\"author\"],context:null},tabpanel:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},term:{type:\"structure\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"dt\"]},text:{type:\"structure\",owned:null,nameFrom:[\"author\",\"contents\"],context:null},textbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"text\"]','input[type=\"email\"]','input[type=\"password\"]','input[type=\"tel\"]','input[type=\"url\"]',\"input:not([type])\",\"textarea\"]},timer:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null},toolbar:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['menu[type=\"toolbar\"]']},tooltip:{type:\"widget\",attributes:{allowed:[\"aria-expanded\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null},tree:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\"]},owned:{all:[\"treeitem\"]},nameFrom:[\"author\"],context:null},treegrid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colcount\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-required\",\"aria-rowcount\",\"aria-orientation\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null},treeitem:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"group\",\"tree\"]},widget:{type:\"abstract\"},window:{nameFrom:[\"author\"],type:\"abstract\"}};var C={};commons.color=C;var D=commons.dom={},E=commons.table={},F=commons.text={EdgeFormDefaults:{}};commons.utils=axe.utils;A.requiredAttr=function(a){\"use strict\";var b=A.lookupTable.role[a];return b&&b.attributes&&b.attributes.required||[]},A.allowedAttr=function(a){\"use strict\";var b=A.lookupTable.role[a],c=b&&b.attributes&&b.attributes.allowed||[],d=b&&b.attributes&&b.attributes.required||[];return c.concat(A.lookupTable.globalAttributes).concat(d)},A.validateAttr=function(a){\"use strict\";return!!A.lookupTable.attributes[a]},A.validateAttrValue=function(a,b){\"use strict\";var c,d,e=a.getAttribute(b),f=A.lookupTable.attributes[b],g=D.getRootNode(a);if(!f)return!0;switch(f.type){case\"boolean\":case\"nmtoken\":return\"string\"==typeof e&&-1!==f.values.indexOf(e.toLowerCase());case\"nmtokens\":return d=axe.utils.tokenList(e),d.reduce(function(a,b){return a&&-1!==f.values.indexOf(b)},0!==d.length);case\"idref\":return!(!e||!g.getElementById(e));case\"idrefs\":return d=axe.utils.tokenList(e),d.reduce(function(a,b){return!(!a||!g.getElementById(b))},0!==d.length);case\"string\":return!0;case\"decimal\":return!(!(c=e.match(/^[-+]?([0-9]*)\\.?([0-9]*)$/))||!c[1]&&!c[2]);case\"int\":return/^[-+]?[0-9]+$/.test(e)}},A.labelVirtual=function(a){var b=a.actualNode,c=void 0,d=void 0;return b.getAttribute(\"aria-labelledby\")&&(c=D.idrefs(b,\"aria-labelledby\"),d=c.map(function(a){\nvar b=axe.utils.getNodeFromTree(axe._tree[0],a);return b?F.visibleVirtual(b,!0):\"\"}).join(\" \").trim())?d:(d=b.getAttribute(\"aria-label\"),d&&(d=F.sanitize(d).trim())?d:null)},A.label=function(a){return a=axe.utils.getNodeFromTree(axe._tree[0],a),A.labelVirtual(a)},A.isValidRole=function(a){\"use strict\";return!!A.lookupTable.role[a]},A.getRolesWithNameFromContents=function(){return Object.keys(A.lookupTable.role).filter(function(a){return A.lookupTable.role[a].nameFrom&&-1!==A.lookupTable.role[a].nameFrom.indexOf(\"contents\")})},A.getRolesByType=function(a){return Object.keys(A.lookupTable.role).filter(function(b){return A.lookupTable.role[b].type===a})},A.getRoleType=function(a){var b=A.lookupTable.role[a];return b&&b.type||null},A.requiredOwned=function(a){\"use strict\";var b=null,c=A.lookupTable.role[a];return c&&(b=axe.utils.clone(c.owned)),b},A.requiredContext=function(a){\"use strict\";var b=null,c=A.lookupTable.role[a];return c&&(b=axe.utils.clone(c.context)),b},A.implicitNodes=function(a){\"use strict\";var b=null,c=A.lookupTable.role[a];return c&&c.implicit&&(b=axe.utils.clone(c.implicit)),b},A.implicitRole=function(a){\"use strict\";var b=function(b,c){var d=function(b){return axe.utils.matchesSelector(a,b)};return c.implicit&&c.implicit.some(d)&&b.push(c.name),b},c=Object.keys(A.lookupTable.role).map(function(a){var b=A.lookupTable.role[a];return{name:a,implicit:b&&b.implicit}}),d=c.reduce(b,[]);if(!d.length)return null;for(var e=a.attributes,f=[],g=0,h=e.length;g<h;g++){var i=e[g];i.name.match(/^aria-/)&&f.push(i.name)}return function(a,b){var c=function(a){return A.allowedAttr(a).reduce(function(a,c){return a+(b.indexOf(c)>-1?1:0)},0)};return a.map(function(a){return{score:c(a),name:a}}).sort(function(a,b){return b.score-a.score}).map(function(a){return a.name})}(d,f).shift()},C.Color=function(a,b,c,d){this.red=a,this.green=b,this.blue=c,this.alpha=d,this.toHexString=function(){var a=Math.round(this.red).toString(16),b=Math.round(this.green).toString(16),c=Math.round(this.blue).toString(16);return\"#\"+(this.red>15.5?a:\"0\"+a)+(this.green>15.5?b:\"0\"+b)+(this.blue>15.5?c:\"0\"+c)};var e=/^rgb\\((\\d+), (\\d+), (\\d+)\\)$/,f=/^rgba\\((\\d+), (\\d+), (\\d+), (\\d*(\\.\\d+)?)\\)/;this.parseRgbString=function(a){if(\"transparent\"===a)return this.red=0,this.green=0,this.blue=0,void(this.alpha=0);var b=a.match(e);return b?(this.red=parseInt(b[1],10),this.green=parseInt(b[2],10),this.blue=parseInt(b[3],10),void(this.alpha=1)):(b=a.match(f),b?(this.red=parseInt(b[1],10),this.green=parseInt(b[2],10),this.blue=parseInt(b[3],10),void(this.alpha=parseFloat(b[4]))):void 0)},this.getRelativeLuminance=function(){var a=this.red/255,b=this.green/255,c=this.blue/255;return.2126*(a<=.03928?a/12.92:Math.pow((a+.055)/1.055,2.4))+.7152*(b<=.03928?b/12.92:Math.pow((b+.055)/1.055,2.4))+.0722*(c<=.03928?c/12.92:Math.pow((c+.055)/1.055,2.4))}},C.flattenColors=function(a,b){var c=a.alpha,d=(1-c)*b.red+c*a.red,e=(1-c)*b.green+c*a.green,f=(1-c)*b.blue+c*a.blue,g=a.alpha+b.alpha*(1-a.alpha);return new C.Color(d,e,f,g)},C.getContrast=function(a,b){if(!b||!a)return null;b.alpha<1&&(b=C.flattenColors(b,a));var c=a.getRelativeLuminance(),d=b.getRelativeLuminance();return(Math.max(d,c)+.05)/(Math.min(d,c)+.05)},C.hasValidContrastRatio=function(a,b,c,d){var e=C.getContrast(a,b),f=d&&Math.ceil(72*c)/96<14||!d&&Math.ceil(72*c)/96<18,g=f?4.5:3;return{isValid:e>g,contrastRatio:e,expectedContrastRatio:g}},C.elementIsDistinct=b;var G=[\"IMG\",\"CANVAS\",\"OBJECT\",\"IFRAME\",\"VIDEO\",\"SVG\"];C.getCoords=function(a){var b=void 0,c=void 0;if(!(a.left>window.innerWidth||a.top>window.innerHeight))return b=Math.min(Math.ceil(a.left+a.width/2),window.innerWidth-1),c=Math.min(Math.ceil(a.top+a.height/2),window.innerHeight-1),{x:b,y:c}},C.getRectStack=function(a){var b=C.getCoords(a.getBoundingClientRect());if(b){var c=D.shadowElementsFromPoint(b.x,b.y),d=Array.from(a.getClientRects());if(d&&d.length>1){var e=d.filter(function(a){return a.width&&a.width>0}).map(function(a){var b=C.getCoords(a);if(b)return D.shadowElementsFromPoint(b.x,b.y)});return e.splice(0,0,c),e}return[c]}return null},C.filteredRectStack=function(a){var b=C.getRectStack(a);if(b&&1===b.length)return b[0];if(b&&b.length>1){var c=b.shift(),d=void 0;return b.forEach(function(e,f){if(0!==f){var g=b[f-1],h=b[f];d=g.every(function(a,b){return a===h[b]})||c.includes(a)}}),d?b[0]:(axe.commons.color.incompleteData.set(\"bgColor\",\"elmPartiallyObscuring\"),null)}return axe.commons.color.incompleteData.set(\"bgColor\",\"outsideViewport\"),null},C.getBackgroundStack=function(a){var b=C.filteredRectStack(a);if(null===b)return null;b=h(b,a),b=D.reduceToElementsBelowFloating(b,a),b=i(b);var c=b.indexOf(a);return f(c,b,a)>=.99?(axe.commons.color.incompleteData.set(\"bgColor\",\"bgOverlap\"),null):-1!==c?b:null},C.getBackgroundColor=function(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];if(!0!==(arguments.length>2&&void 0!==arguments[2]&&arguments[2])){var e=a.clientHeight-2>=2*window.innerHeight;a.scrollIntoView(e)}var f=[],h=C.getBackgroundStack(a);if((h||[]).some(function(e){var h=window.getComputedStyle(e),i=d(e,h);return g(a,e,i)||c(e,h)?(f=null,b.push(e),!0):0!==i.alpha&&(b.push(e),f.push(i),1===i.alpha)}),null!==f&&null!==h){f.push(new C.Color(255,255,255,1));return f.reduce(C.flattenColors)}return null},D.isOpaque=function(a){var b=window.getComputedStyle(a);return c(a,b)||1===d(a,b).alpha},C.getForegroundColor=function(a,b){var c=window.getComputedStyle(a),d=new C.Color;d.parseRgbString(c.getPropertyValue(\"color\"));var e=c.getPropertyValue(\"opacity\");if(d.alpha=d.alpha*e,1===d.alpha)return d;var f=C.getBackgroundColor(a,[],b);if(null===f){var g=axe.commons.color.incompleteData.get(\"bgColor\");return axe.commons.color.incompleteData.set(\"fgColor\",g),null}return C.flattenColors(d,f)},C.incompleteData=function(){var a={};return{set:function(b,c){if(\"string\"!=typeof b)throw new Error(\"Incomplete data: key must be a string\");return c&&(a[b]=c),a[b]},get:function(b){return a[b]},clear:function(){a={}}}}(),D.reduceToElementsBelowFloating=function(a,b){var c,d,e,f=[\"fixed\",\"sticky\"],g=[],h=!1;for(c=0;c<a.length;++c)d=a[c],d===b&&(h=!0),e=window.getComputedStyle(d),h||-1===f.indexOf(e.position)?g.push(d):g=[];return g},D.findElmsInContext=function(a){var b=a.context,c=a.value,d=a.attr,e=a.elm,f=void 0===e?\"\":e,g=void 0,h=axe.utils.escapeSelector(c);return g=9===b.nodeType||11===b.nodeType?b:D.getRootNode(b),Array.from(g.querySelectorAll(f+\"[\"+d+\"=\"+h+\"]\"))},D.findUp=function(a,b){return D.findUpVirtual(axe.utils.getNodeFromTree(axe._tree[0],a),b)},D.findUpVirtual=function(a,b){var c=void 0;if(c=a.actualNode,!a.shadowId&&\"function\"==typeof a.actualNode.closest){var d=a.actualNode.closest(b);return d||null}do{(c=c.assignedSlot?c.assignedSlot:c.parentNode)&&11===c.nodeType&&(c=c.host)}while(c&&!axe.utils.matchesSelector(c,b)&&c!==document.documentElement);return axe.utils.matchesSelector(c,b)?c:null},D.getComposedParent=function a(b){if(b.assignedSlot)return a(b.assignedSlot);if(b.parentNode){var c=b.parentNode;if(1===c.nodeType)return c;if(c.host)return c.host}return null},D.getElementByReference=function(a,b){var c=a.getAttribute(b);if(c&&\"#\"===c.charAt(0)){c=c.substring(1);var d=document.getElementById(c);if(d)return d;if(d=document.getElementsByName(c),d.length)return d[0]}return null},D.getElementCoordinates=function(a){\"use strict\";var b=D.getScrollOffset(document),c=b.left,d=b.top,e=a.getBoundingClientRect();return{top:e.top+d,right:e.right+c,bottom:e.bottom+d,left:e.left+c,width:e.right-e.left,height:e.bottom-e.top}},D.getRootNode=function(a){var b=a.getRootNode&&a.getRootNode()||document;return b===a&&(b=document),b},D.getScrollOffset=function(a){\"use strict\";if(!a.nodeType&&a.document&&(a=a.document),9===a.nodeType){var b=a.documentElement,c=a.body;return{left:b&&b.scrollLeft||c&&c.scrollLeft||0,top:b&&b.scrollTop||c&&c.scrollTop||0}}return{left:a.scrollLeft,top:a.scrollTop}},D.getViewportSize=function(a){\"use strict\";var b,c=a.document,d=c.documentElement;return a.innerWidth?{width:a.innerWidth,height:a.innerHeight}:d?{width:d.clientWidth,height:d.clientHeight}:(b=c.body,{width:b.clientWidth,height:b.clientHeight})};var H=[\"HEAD\",\"TITLE\",\"TEMPLATE\",\"SCRIPT\",\"STYLE\",\"IFRAME\",\"OBJECT\",\"VIDEO\",\"AUDIO\",\"NOSCRIPT\"];D.hasContentVirtual=function(a,b){return j(a)||D.isVisualContent(a.actualNode)||!!A.labelVirtual(a)||!b&&a.children.some(function(a){return 1===a.actualNode.nodeType&&D.hasContentVirtual(a)})},D.hasContent=function(a,b){return a=axe.utils.getNodeFromTree(axe._tree[0],a),D.hasContentVirtual(a,b)},D.idrefs=function(a,b){\"use strict\";var c,d,e=D.getRootNode(a),f=[],g=a.getAttribute(b);if(g)for(g=axe.utils.tokenList(g),c=0,d=g.length;c<d;c++)f.push(e.getElementById(g[c]));return f},D.isFocusable=function(a){\"use strict\";if(k(a))return!1;if(D.isNativelyFocusable(a))return!0;var b=a.getAttribute(\"tabindex\");return!(!b||isNaN(parseInt(b,10)))},D.isNativelyFocusable=function(a){\"use strict\";if(!a||k(a))return!1;switch(a.nodeName.toUpperCase()){case\"A\":case\"AREA\":if(a.href)return!0;break;case\"INPUT\":return\"hidden\"!==a.type;case\"TEXTAREA\":case\"SELECT\":case\"DETAILS\":case\"BUTTON\":return!0}return!1},D.insertedIntoFocusOrder=function(a){return a.tabIndex>-1&&D.isFocusable(a)&&!D.isNativelyFocusable(a)},D.isHTML5=function(a){var b=a.doctype;return null!==b&&(\"html\"===b.name&&!b.publicId&&!b.systemId)};var I=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];D.isInTextBlock=function(a){if(m(a))return!1;var b=n(a),c=\"\",d=\"\",e=0;return l(b,function(b){if(2===e)return!1;if(3===b.nodeType&&(c+=b.nodeValue),1===b.nodeType){var f=(b.nodeName||\"\").toUpperCase();if([\"BR\",\"HR\"].includes(f))0===e?(c=\"\",d=\"\"):e=2;else{if(\"none\"===b.style.display||\"hidden\"===b.style.overflow||![\"\",null,\"none\"].includes(b.style.float)||![\"\",null,\"relative\"].includes(b.style.position))return!1;if(\"A\"===f&&b.href||\"link\"===(b.getAttribute(\"role\")||\"\").toLowerCase())return b===a&&(e=1),d+=b.textContent,!1}}}),c=axe.commons.text.sanitize(c),d=axe.commons.text.sanitize(d),c.length>d.length},D.isNode=function(a){\"use strict\";return a instanceof Node},D.isOffscreen=function(a){var b=void 0,c=document.documentElement,d=window.getComputedStyle(a),e=window.getComputedStyle(document.body||c).getPropertyValue(\"direction\"),f=D.getElementCoordinates(a);if(f.bottom<0&&(o(a,f.bottom)||\"absolute\"===d.position))return!0;if(0===f.left&&0===f.right)return!1;if(\"ltr\"===e){if(f.right<=0)return!0}else if(b=Math.max(c.scrollWidth,D.getViewportSize(window).width),f.left>=b)return!0;return!1},D.isVisible=function(a,b,c){\"use strict\";var d,e,f;return 9===a.nodeType||(11===a.nodeType&&(a=a.host),null!==(d=window.getComputedStyle(a,null))&&(e=a.nodeName.toUpperCase(),!(\"none\"===d.getPropertyValue(\"display\")||\"STYLE\"===e.toUpperCase()||\"SCRIPT\"===e.toUpperCase()||!b&&p(d.getPropertyValue(\"clip\"))||!c&&(\"hidden\"===d.getPropertyValue(\"visibility\")||!b&&D.isOffscreen(a))||b&&\"true\"===a.getAttribute(\"aria-hidden\"))&&(!!(f=a.assignedSlot?a.assignedSlot:a.parentNode)&&D.isVisible(f,b,!0))))};var J=[\"checkbox\",\"img\",\"radio\",\"range\",\"slider\",\"spinbutton\",\"textbox\"];D.isVisualContent=function(a){var b=a.getAttribute(\"role\");if(b)return-1!==J.indexOf(b);switch(a.tagName.toUpperCase()){case\"IMG\":case\"IFRAME\":case\"OBJECT\":case\"VIDEO\":case\"AUDIO\":case\"CANVAS\":case\"SVG\":case\"MATH\":case\"BUTTON\":case\"SELECT\":case\"TEXTAREA\":case\"KEYGEN\":case\"PROGRESS\":case\"METER\":return!0;case\"INPUT\":return\"hidden\"!==a.type;default:return!1}},D.shadowElementsFromPoint=function(a,b){return(arguments.length>2&&void 0!==arguments[2]?arguments[2]:document).elementsFromPoint(a,b).reduce(function(c,d){if(axe.utils.isShadowRoot(d)){var e=D.shadowElementsFromPoint(a,b,d.shadowRoot);c=c.concat(e),c.length&&axe.commons.dom.visuallyContains(c[0],d)&&c.push(d)}else c.push(d);return c},[])},D.visuallyContains=function(a,b){var c=a.getBoundingClientRect(),d={top:c.top+.01,bottom:c.bottom-.01,left:c.left+.01,right:c.right-.01},e=b.getBoundingClientRect(),f=e.top,g=e.left,h={top:f-b.scrollTop,bottom:f-b.scrollTop+b.scrollHeight,left:g-b.scrollLeft,right:g-b.scrollLeft+b.scrollWidth},i=window.getComputedStyle(b);return\"inline\"===i.getPropertyValue(\"display\")||!(d.left<h.left&&d.left<e.left||d.top<h.top&&d.top<e.top||d.right>h.right&&d.right>e.right||d.bottom>h.bottom&&d.bottom>e.bottom)&&(!(d.right>e.right||d.bottom>e.bottom)||(\"scroll\"===i.overflow||\"auto\"===i.overflow||\"hidden\"===i.overflow||b instanceof HTMLBodyElement||b instanceof HTMLHtmlElement))},D.visuallyOverlaps=function(a,b){var c=b.getBoundingClientRect(),d=c.top,e=c.left,f={top:d-b.scrollTop,bottom:d-b.scrollTop+b.scrollHeight,left:e-b.scrollLeft,right:e-b.scrollLeft+b.scrollWidth};if(a.left>f.right&&a.left>c.right||a.top>f.bottom&&a.top>c.bottom||a.right<f.left&&a.right<c.left||a.bottom<f.top&&a.bottom<c.top)return!1;var g=window.getComputedStyle(b);return!(a.left>c.right||a.top>c.bottom)||(\"scroll\"===g.overflow||\"auto\"===g.overflow||b instanceof HTMLBodyElement||b instanceof HTMLHtmlElement)},E.getAllCells=function(a){var b,c,d,e,f=[];for(b=0,d=a.rows.length;b<d;b++)for(c=0,e=a.rows[b].cells.length;c<e;c++)f.push(a.rows[b].cells[c]);return f},E.getCellPosition=function(a,b){var c,d;for(b||(b=E.toGrid(D.findUp(a,\"table\"))),c=0;c<b.length;c++)if(b[c]&&-1!==(d=b[c].indexOf(a)))return{x:d,y:c}},E.getHeaders=function(a){if(a.hasAttribute(\"headers\"))return commons.dom.idrefs(a,\"headers\");var b=commons.table.toGrid(commons.dom.findUp(a,\"table\")),c=commons.table.getCellPosition(a,b);return[].concat(E.traverse(\"left\",c,b).filter(function(a){return E.isRowHeader(a)}),E.traverse(\"up\",c,b).filter(function(a){return E.isColumnHeader(a)})).reverse()},E.getScope=function(a){var b=a.getAttribute(\"scope\"),c=a.getAttribute(\"role\");if(a instanceof Element==!1||-1===[\"TD\",\"TH\"].indexOf(a.nodeName.toUpperCase()))throw new TypeError(\"Expected TD or TH element\");if(\"columnheader\"===c)return\"col\";if(\"rowheader\"===c)return\"row\";if(\"col\"===b||\"row\"===b)return b;if(\"TH\"!==a.nodeName.toUpperCase())return!1;var d=E.toGrid(D.findUp(a,\"table\")),e=E.getCellPosition(a);return d[e.y].reduce(function(a,b){return a&&\"TH\"===b.nodeName.toUpperCase()},!0)?\"col\":d.map(function(a){return a[e.x]}).reduce(function(a,b){return a&&\"TH\"===b.nodeName.toUpperCase()},!0)?\"row\":\"auto\"},E.isColumnHeader=function(a){return-1!==[\"col\",\"auto\"].indexOf(E.getScope(a))},E.isDataCell=function(a){return!(!a.children.length&&!a.textContent.trim())&&\"TD\"===a.nodeName.toUpperCase()},E.isDataTable=function(a){var b=(a.getAttribute(\"role\")||\"\").toLowerCase();if((\"presentation\"===b||\"none\"===b)&&!D.isFocusable(a))return!1;if(\"true\"===a.getAttribute(\"contenteditable\")||D.findUp(a,'[contenteditable=\"true\"]'))return!0;if(\"grid\"===b||\"treegrid\"===b||\"table\"===b)return!0;if(\"landmark\"===commons.aria.getRoleType(b))return!0;if(\"0\"===a.getAttribute(\"datatable\"))return!1;if(a.getAttribute(\"summary\"))return!0;if(a.tHead||a.tFoot||a.caption)return!0;for(var c=0,d=a.children.length;c<d;c++)if(\"COLGROUP\"===a.children[c].nodeName.toUpperCase())return!0;for(var e,f,g=0,h=a.rows.length,i=!1,j=0;j<h;j++){e=a.rows[j];for(var k=0,l=e.cells.length;k<l;k++){if(f=e.cells[k],\"TH\"===f.nodeName.toUpperCase())return!0;if(i||f.offsetWidth===f.clientWidth&&f.offsetHeight===f.clientHeight||(i=!0),f.getAttribute(\"scope\")||f.getAttribute(\"headers\")||f.getAttribute(\"abbr\"))return!0;if([\"columnheader\",\"rowheader\"].includes((f.getAttribute(\"role\")||\"\").toLowerCase()))return!0;if(1===f.children.length&&\"ABBR\"===f.children[0].nodeName.toUpperCase())return!0;g++}}if(a.getElementsByTagName(\"table\").length)return!1;if(h<2)return!1;var m=a.rows[Math.ceil(h/2)];if(1===m.cells.length&&1===m.cells[0].colSpan)return!1;if(m.cells.length>=5)return!0;if(i)return!0;var n,o;for(j=0;j<h;j++){if(e=a.rows[j],n&&n!==window.getComputedStyle(e).getPropertyValue(\"background-color\"))return!0;if(n=window.getComputedStyle(e).getPropertyValue(\"background-color\"),o&&o!==window.getComputedStyle(e).getPropertyValue(\"background-image\"))return!0;o=window.getComputedStyle(e).getPropertyValue(\"background-image\")}return h>=20||!(D.getElementCoordinates(a).width>.95*D.getViewportSize(window).width)&&(!(g<10)&&!a.querySelector(\"object, embed, iframe, applet\"))},E.isHeader=function(a){if(E.isColumnHeader(a)||E.isRowHeader(a))return!0;if(a.getAttribute(\"id\")){var b=axe.utils.escapeSelector(a.getAttribute(\"id\"));return!!document.querySelector('[headers~=\"'+b+'\"]')}return!1},E.isRowHeader=function(a){return[\"row\",\"auto\"].includes(E.getScope(a))},E.toGrid=function(a){for(var b=[],c=a.rows,d=0,e=c.length;d<e;d++){var f=c[d].cells;b[d]=b[d]||[];for(var g=0,h=0,i=f.length;h<i;h++)for(var j=0;j<f[h].colSpan;j++){for(var k=0;k<f[h].rowSpan;k++){for(b[d+k]=b[d+k]||[];b[d+k][g];)g++;b[d+k][g]=f[h]}g++}}return b},E.toArray=E.toGrid,function(a){var b=function a(b,c,d,e){var f,g=d[c.y]?d[c.y][c.x]:void 0;return g?\"function\"==typeof e&&!0===(f=e(g,c,d))?[g]:(f=a(b,{x:c.x+b.x,y:c.y+b.y},d,e),f.unshift(g),f):[]};a.traverse=function(a,c,d,e){if(Array.isArray(c)&&(e=d,d=c,c={x:0,y:0}),\"string\"==typeof a)switch(a){case\"left\":a={x:-1,y:0};break;case\"up\":a={x:0,y:-1};break;case\"right\":a={x:1,y:0};break;case\"down\":a={x:0,y:1}}return b(a,{x:c.x+a.x,y:c.y+a.y},d,e)}}(E);var K={submit:\"Submit\",reset:\"Reset\"},L=[\"text\",\"search\",\"tel\",\"url\",\"email\",\"date\",\"time\",\"number\",\"range\",\"color\"],M=[\"A\",\"EM\",\"STRONG\",\"SMALL\",\"MARK\",\"ABBR\",\"DFN\",\"I\",\"B\",\"S\",\"U\",\"CODE\",\"VAR\",\"SAMP\",\"KBD\",\"SUP\",\"SUB\",\"Q\",\"CITE\",\"SPAN\",\"BDO\",\"BDI\",\"BR\",\"WBR\",\"INS\",\"DEL\",\"IMG\",\"EMBED\",\"OBJECT\",\"IFRAME\",\"MAP\",\"AREA\",\"SCRIPT\",\"NOSCRIPT\",\"RUBY\",\"VIDEO\",\"AUDIO\",\"INPUT\",\"TEXTAREA\",\"SELECT\",\"BUTTON\",\"LABEL\",\"OUTPUT\",\"DATALIST\",\"KEYGEN\",\"PROGRESS\",\"COMMAND\",\"CANVAS\",\"TIME\",\"METER\"];F.accessibleText=function(a,b){var c=axe.utils.getNodeFromTree(axe._tree[0],a);return axe.commons.text.accessibleTextVirtual(c,b)},F.accessibleTextVirtual=function(a,b){function c(a,b,c){return a.children.reduce(function(a,d){var e=d.actualNode;return 3===e.nodeType?a+=e.nodeValue:1===e.nodeType&&(M.includes(e.nodeName.toUpperCase())||(a+=\" \"),a+=g(d,b,c)),a},\"\")}function d(a){return axe.commons.table.isDataTable(a.actualNode)||1!==axe.commons.table.getAllCells(a.actualNode).length?\"\":c(a,!1,!1).trim()}function e(a,b,e){var f=\"\",h=a.actualNode,i=h.nodeName.toUpperCase();if(t(a)&&(f=c(a,!1,!1)||\"\",z(f)))return f;if(\"FIGURE\"===i&&(f=w(a,\"figcaption\"),z(f)))return f;if(\"TABLE\"===i){if(f=w(a,\"caption\"),z(f))return f;if(f=h.getAttribute(\"title\")||h.getAttribute(\"summary\")||d(a)||\"\",z(f))return f}if(y(a))return h.getAttribute(\"alt\")||\"\";if(s(a)&&!e){if(r(a))return h.value||h.title||K[h.type]||\"\";var j=q(a);if(j)return g(j,b,!0)}return\"\"}function f(a,b,c){var d=\"\",e=a.actualNode;return!b&&e.hasAttribute(\"aria-labelledby\")&&(d=F.sanitize(D.idrefs(e,\"aria-labelledby\").map(function(a){if(null!==a){e===a&&h.pop();var b=axe.utils.getNodeFromTree(axe._tree[0],a);return g(b,!0,e!==a)}return\"\"}).join(\" \"))),d||c&&x(a)||!e.hasAttribute(\"aria-label\")?d:F.sanitize(e.getAttribute(\"aria-label\"))}var g=void 0,h=[];return a instanceof Node&&(a=axe.utils.getNodeFromTree(axe._tree[0],a)),g=function(a,b,d){var g=void 0;if(!a||h.includes(a))return\"\";if(null!==a&&a.actualNode instanceof Node!=!0)throw new Error(\"Invalid argument. Virtual Node must be provided\");if(!b&&!D.isVisible(a.actualNode,!0))return\"\";h.push(a);var i=a.actualNode.getAttribute(\"role\");return g=f(a,b,d),z(g)?g:(g=e(a,b,d),z(g)?g:d&&(g=v(a),z(g))?g:u(a)||i&&-1===A.getRolesWithNameFromContents().indexOf(i)||(g=c(a,b,d),!z(g))?a.actualNode.hasAttribute(\"title\")?a.actualNode.getAttribute(\"title\"):\"\":g)},F.sanitize(g(a,b))},F.labelVirtual=function(a){var b,c,d;if(c=A.labelVirtual(a))return c;if(a.actualNode.id){var e=axe.commons.utils.escapeSelector(a.actualNode.getAttribute(\"id\"));if(d=axe.commons.dom.getRootNode(a.actualNode),b=d.querySelector('label[for=\"'+e+'\"]'),c=b&&F.visible(b,!0))return c}return b=D.findUpVirtual(a,\"label\"),(c=b&&F.visible(b,!0))||null},F.label=function(a){return a=axe.utils.getNodeFromTree(axe._tree[0],a),F.labelVirtual(a)},F.sanitize=function(a){\"use strict\";return a.replace(/\\r\\n/g,\"\\n\").replace(/\\u00A0/g,\" \").replace(/[\\s]{2,}/g,\" \").trim()},F.visibleVirtual=function(a,b,c){var d=a.children.map(function(d){if(3===d.actualNode.nodeType){var e=d.actualNode.nodeValue;if(e&&D.isVisible(a.actualNode,b))return e}else if(!c)return F.visibleVirtual(d,b)}).join(\"\");return F.sanitize(d)},F.visible=function(a,b,c){return a=axe.utils.getNodeFromTree(axe._tree[0],a),F.visibleVirtual(a,b,c)},axe.utils.tokenList=function(a){\"use strict\";return a.trim().replace(/\\s{2,}/g,\" \").split(\" \")}\n;var N=[\"aa\",\"ab\",\"ae\",\"af\",\"ak\",\"am\",\"an\",\"ar\",\"as\",\"av\",\"ay\",\"az\",\"ba\",\"be\",\"bg\",\"bh\",\"bi\",\"bm\",\"bn\",\"bo\",\"br\",\"bs\",\"ca\",\"ce\",\"ch\",\"co\",\"cr\",\"cs\",\"cu\",\"cv\",\"cy\",\"da\",\"de\",\"dv\",\"dz\",\"ee\",\"el\",\"en\",\"eo\",\"es\",\"et\",\"eu\",\"fa\",\"ff\",\"fi\",\"fj\",\"fo\",\"fr\",\"fy\",\"ga\",\"gd\",\"gl\",\"gn\",\"gu\",\"gv\",\"ha\",\"he\",\"hi\",\"ho\",\"hr\",\"ht\",\"hu\",\"hy\",\"hz\",\"ia\",\"id\",\"ie\",\"ig\",\"ii\",\"ik\",\"in\",\"io\",\"is\",\"it\",\"iu\",\"iw\",\"ja\",\"ji\",\"jv\",\"jw\",\"ka\",\"kg\",\"ki\",\"kj\",\"kk\",\"kl\",\"km\",\"kn\",\"ko\",\"kr\",\"ks\",\"ku\",\"kv\",\"kw\",\"ky\",\"la\",\"lb\",\"lg\",\"li\",\"ln\",\"lo\",\"lt\",\"lu\",\"lv\",\"mg\",\"mh\",\"mi\",\"mk\",\"ml\",\"mn\",\"mo\",\"mr\",\"ms\",\"mt\",\"my\",\"na\",\"nb\",\"nd\",\"ne\",\"ng\",\"nl\",\"nn\",\"no\",\"nr\",\"nv\",\"ny\",\"oc\",\"oj\",\"om\",\"or\",\"os\",\"pa\",\"pi\",\"pl\",\"ps\",\"pt\",\"qu\",\"rm\",\"rn\",\"ro\",\"ru\",\"rw\",\"sa\",\"sc\",\"sd\",\"se\",\"sg\",\"sh\",\"si\",\"sk\",\"sl\",\"sm\",\"sn\",\"so\",\"sq\",\"sr\",\"ss\",\"st\",\"su\",\"sv\",\"sw\",\"ta\",\"te\",\"tg\",\"th\",\"ti\",\"tk\",\"tl\",\"tn\",\"to\",\"tr\",\"ts\",\"tt\",\"tw\",\"ty\",\"ug\",\"uk\",\"ur\",\"uz\",\"ve\",\"vi\",\"vo\",\"wa\",\"wo\",\"xh\",\"yi\",\"yo\",\"za\",\"zh\",\"zu\",\"aaa\",\"aab\",\"aac\",\"aad\",\"aae\",\"aaf\",\"aag\",\"aah\",\"aai\",\"aak\",\"aal\",\"aam\",\"aan\",\"aao\",\"aap\",\"aaq\",\"aas\",\"aat\",\"aau\",\"aav\",\"aaw\",\"aax\",\"aaz\",\"aba\",\"abb\",\"abc\",\"abd\",\"abe\",\"abf\",\"abg\",\"abh\",\"abi\",\"abj\",\"abl\",\"abm\",\"abn\",\"abo\",\"abp\",\"abq\",\"abr\",\"abs\",\"abt\",\"abu\",\"abv\",\"abw\",\"abx\",\"aby\",\"abz\",\"aca\",\"acb\",\"acd\",\"ace\",\"acf\",\"ach\",\"aci\",\"ack\",\"acl\",\"acm\",\"acn\",\"acp\",\"acq\",\"acr\",\"acs\",\"act\",\"acu\",\"acv\",\"acw\",\"acx\",\"acy\",\"acz\",\"ada\",\"adb\",\"add\",\"ade\",\"adf\",\"adg\",\"adh\",\"adi\",\"adj\",\"adl\",\"adn\",\"ado\",\"adp\",\"adq\",\"adr\",\"ads\",\"adt\",\"adu\",\"adw\",\"adx\",\"ady\",\"adz\",\"aea\",\"aeb\",\"aec\",\"aed\",\"aee\",\"aek\",\"ael\",\"aem\",\"aen\",\"aeq\",\"aer\",\"aes\",\"aeu\",\"aew\",\"aey\",\"aez\",\"afa\",\"afb\",\"afd\",\"afe\",\"afg\",\"afh\",\"afi\",\"afk\",\"afn\",\"afo\",\"afp\",\"afs\",\"aft\",\"afu\",\"afz\",\"aga\",\"agb\",\"agc\",\"agd\",\"age\",\"agf\",\"agg\",\"agh\",\"agi\",\"agj\",\"agk\",\"agl\",\"agm\",\"agn\",\"ago\",\"agp\",\"agq\",\"agr\",\"ags\",\"agt\",\"agu\",\"agv\",\"agw\",\"agx\",\"agy\",\"agz\",\"aha\",\"ahb\",\"ahg\",\"ahh\",\"ahi\",\"ahk\",\"ahl\",\"ahm\",\"ahn\",\"aho\",\"ahp\",\"ahr\",\"ahs\",\"aht\",\"aia\",\"aib\",\"aic\",\"aid\",\"aie\",\"aif\",\"aig\",\"aih\",\"aii\",\"aij\",\"aik\",\"ail\",\"aim\",\"ain\",\"aio\",\"aip\",\"aiq\",\"air\",\"ais\",\"ait\",\"aiw\",\"aix\",\"aiy\",\"aja\",\"ajg\",\"aji\",\"ajn\",\"ajp\",\"ajt\",\"aju\",\"ajw\",\"ajz\",\"akb\",\"akc\",\"akd\",\"ake\",\"akf\",\"akg\",\"akh\",\"aki\",\"akj\",\"akk\",\"akl\",\"akm\",\"ako\",\"akp\",\"akq\",\"akr\",\"aks\",\"akt\",\"aku\",\"akv\",\"akw\",\"akx\",\"aky\",\"akz\",\"ala\",\"alc\",\"ald\",\"ale\",\"alf\",\"alg\",\"alh\",\"ali\",\"alj\",\"alk\",\"all\",\"alm\",\"aln\",\"alo\",\"alp\",\"alq\",\"alr\",\"als\",\"alt\",\"alu\",\"alv\",\"alw\",\"alx\",\"aly\",\"alz\",\"ama\",\"amb\",\"amc\",\"ame\",\"amf\",\"amg\",\"ami\",\"amj\",\"amk\",\"aml\",\"amm\",\"amn\",\"amo\",\"amp\",\"amq\",\"amr\",\"ams\",\"amt\",\"amu\",\"amv\",\"amw\",\"amx\",\"amy\",\"amz\",\"ana\",\"anb\",\"anc\",\"and\",\"ane\",\"anf\",\"ang\",\"anh\",\"ani\",\"anj\",\"ank\",\"anl\",\"anm\",\"ann\",\"ano\",\"anp\",\"anq\",\"anr\",\"ans\",\"ant\",\"anu\",\"anv\",\"anw\",\"anx\",\"any\",\"anz\",\"aoa\",\"aob\",\"aoc\",\"aod\",\"aoe\",\"aof\",\"aog\",\"aoh\",\"aoi\",\"aoj\",\"aok\",\"aol\",\"aom\",\"aon\",\"aor\",\"aos\",\"aot\",\"aou\",\"aox\",\"aoz\",\"apa\",\"apb\",\"apc\",\"apd\",\"ape\",\"apf\",\"apg\",\"aph\",\"api\",\"apj\",\"apk\",\"apl\",\"apm\",\"apn\",\"apo\",\"app\",\"apq\",\"apr\",\"aps\",\"apt\",\"apu\",\"apv\",\"apw\",\"apx\",\"apy\",\"apz\",\"aqa\",\"aqc\",\"aqd\",\"aqg\",\"aql\",\"aqm\",\"aqn\",\"aqp\",\"aqr\",\"aqt\",\"aqz\",\"arb\",\"arc\",\"ard\",\"are\",\"arh\",\"ari\",\"arj\",\"ark\",\"arl\",\"arn\",\"aro\",\"arp\",\"arq\",\"arr\",\"ars\",\"art\",\"aru\",\"arv\",\"arw\",\"arx\",\"ary\",\"arz\",\"asa\",\"asb\",\"asc\",\"asd\",\"ase\",\"asf\",\"asg\",\"ash\",\"asi\",\"asj\",\"ask\",\"asl\",\"asn\",\"aso\",\"asp\",\"asq\",\"asr\",\"ass\",\"ast\",\"asu\",\"asv\",\"asw\",\"asx\",\"asy\",\"asz\",\"ata\",\"atb\",\"atc\",\"atd\",\"ate\",\"atg\",\"ath\",\"ati\",\"atj\",\"atk\",\"atl\",\"atm\",\"atn\",\"ato\",\"atp\",\"atq\",\"atr\",\"ats\",\"att\",\"atu\",\"atv\",\"atw\",\"atx\",\"aty\",\"atz\",\"aua\",\"aub\",\"auc\",\"aud\",\"aue\",\"auf\",\"aug\",\"auh\",\"aui\",\"auj\",\"auk\",\"aul\",\"aum\",\"aun\",\"auo\",\"aup\",\"auq\",\"aur\",\"aus\",\"aut\",\"auu\",\"auw\",\"aux\",\"auy\",\"auz\",\"avb\",\"avd\",\"avi\",\"avk\",\"avl\",\"avm\",\"avn\",\"avo\",\"avs\",\"avt\",\"avu\",\"avv\",\"awa\",\"awb\",\"awc\",\"awd\",\"awe\",\"awg\",\"awh\",\"awi\",\"awk\",\"awm\",\"awn\",\"awo\",\"awr\",\"aws\",\"awt\",\"awu\",\"awv\",\"aww\",\"awx\",\"awy\",\"axb\",\"axe\",\"axg\",\"axk\",\"axl\",\"axm\",\"axx\",\"aya\",\"ayb\",\"ayc\",\"ayd\",\"aye\",\"ayg\",\"ayh\",\"ayi\",\"ayk\",\"ayl\",\"ayn\",\"ayo\",\"ayp\",\"ayq\",\"ayr\",\"ays\",\"ayt\",\"ayu\",\"ayx\",\"ayy\",\"ayz\",\"aza\",\"azb\",\"azc\",\"azd\",\"azg\",\"azj\",\"azm\",\"azn\",\"azo\",\"azt\",\"azz\",\"baa\",\"bab\",\"bac\",\"bad\",\"bae\",\"baf\",\"bag\",\"bah\",\"bai\",\"baj\",\"bal\",\"ban\",\"bao\",\"bap\",\"bar\",\"bas\",\"bat\",\"bau\",\"bav\",\"baw\",\"bax\",\"bay\",\"baz\",\"bba\",\"bbb\",\"bbc\",\"bbd\",\"bbe\",\"bbf\",\"bbg\",\"bbh\",\"bbi\",\"bbj\",\"bbk\",\"bbl\",\"bbm\",\"bbn\",\"bbo\",\"bbp\",\"bbq\",\"bbr\",\"bbs\",\"bbt\",\"bbu\",\"bbv\",\"bbw\",\"bbx\",\"bby\",\"bbz\",\"bca\",\"bcb\",\"bcc\",\"bcd\",\"bce\",\"bcf\",\"bcg\",\"bch\",\"bci\",\"bcj\",\"bck\",\"bcl\",\"bcm\",\"bcn\",\"bco\",\"bcp\",\"bcq\",\"bcr\",\"bcs\",\"bct\",\"bcu\",\"bcv\",\"bcw\",\"bcy\",\"bcz\",\"bda\",\"bdb\",\"bdc\",\"bdd\",\"bde\",\"bdf\",\"bdg\",\"bdh\",\"bdi\",\"bdj\",\"bdk\",\"bdl\",\"bdm\",\"bdn\",\"bdo\",\"bdp\",\"bdq\",\"bdr\",\"bds\",\"bdt\",\"bdu\",\"bdv\",\"bdw\",\"bdx\",\"bdy\",\"bdz\",\"bea\",\"beb\",\"bec\",\"bed\",\"bee\",\"bef\",\"beg\",\"beh\",\"bei\",\"bej\",\"bek\",\"bem\",\"beo\",\"bep\",\"beq\",\"ber\",\"bes\",\"bet\",\"beu\",\"bev\",\"bew\",\"bex\",\"bey\",\"bez\",\"bfa\",\"bfb\",\"bfc\",\"bfd\",\"bfe\",\"bff\",\"bfg\",\"bfh\",\"bfi\",\"bfj\",\"bfk\",\"bfl\",\"bfm\",\"bfn\",\"bfo\",\"bfp\",\"bfq\",\"bfr\",\"bfs\",\"bft\",\"bfu\",\"bfw\",\"bfx\",\"bfy\",\"bfz\",\"bga\",\"bgb\",\"bgc\",\"bgd\",\"bge\",\"bgf\",\"bgg\",\"bgi\",\"bgj\",\"bgk\",\"bgl\",\"bgm\",\"bgn\",\"bgo\",\"bgp\",\"bgq\",\"bgr\",\"bgs\",\"bgt\",\"bgu\",\"bgv\",\"bgw\",\"bgx\",\"bgy\",\"bgz\",\"bha\",\"bhb\",\"bhc\",\"bhd\",\"bhe\",\"bhf\",\"bhg\",\"bhh\",\"bhi\",\"bhj\",\"bhk\",\"bhl\",\"bhm\",\"bhn\",\"bho\",\"bhp\",\"bhq\",\"bhr\",\"bhs\",\"bht\",\"bhu\",\"bhv\",\"bhw\",\"bhx\",\"bhy\",\"bhz\",\"bia\",\"bib\",\"bic\",\"bid\",\"bie\",\"bif\",\"big\",\"bij\",\"bik\",\"bil\",\"bim\",\"bin\",\"bio\",\"bip\",\"biq\",\"bir\",\"bit\",\"biu\",\"biv\",\"biw\",\"bix\",\"biy\",\"biz\",\"bja\",\"bjb\",\"bjc\",\"bjd\",\"bje\",\"bjf\",\"bjg\",\"bjh\",\"bji\",\"bjj\",\"bjk\",\"bjl\",\"bjm\",\"bjn\",\"bjo\",\"bjp\",\"bjq\",\"bjr\",\"bjs\",\"bjt\",\"bju\",\"bjv\",\"bjw\",\"bjx\",\"bjy\",\"bjz\",\"bka\",\"bkb\",\"bkc\",\"bkd\",\"bkf\",\"bkg\",\"bkh\",\"bki\",\"bkj\",\"bkk\",\"bkl\",\"bkm\",\"bkn\",\"bko\",\"bkp\",\"bkq\",\"bkr\",\"bks\",\"bkt\",\"bku\",\"bkv\",\"bkw\",\"bkx\",\"bky\",\"bkz\",\"bla\",\"blb\",\"blc\",\"bld\",\"ble\",\"blf\",\"blg\",\"blh\",\"bli\",\"blj\",\"blk\",\"bll\",\"blm\",\"bln\",\"blo\",\"blp\",\"blq\",\"blr\",\"bls\",\"blt\",\"blv\",\"blw\",\"blx\",\"bly\",\"blz\",\"bma\",\"bmb\",\"bmc\",\"bmd\",\"bme\",\"bmf\",\"bmg\",\"bmh\",\"bmi\",\"bmj\",\"bmk\",\"bml\",\"bmm\",\"bmn\",\"bmo\",\"bmp\",\"bmq\",\"bmr\",\"bms\",\"bmt\",\"bmu\",\"bmv\",\"bmw\",\"bmx\",\"bmy\",\"bmz\",\"bna\",\"bnb\",\"bnc\",\"bnd\",\"bne\",\"bnf\",\"bng\",\"bni\",\"bnj\",\"bnk\",\"bnl\",\"bnm\",\"bnn\",\"bno\",\"bnp\",\"bnq\",\"bnr\",\"bns\",\"bnt\",\"bnu\",\"bnv\",\"bnw\",\"bnx\",\"bny\",\"bnz\",\"boa\",\"bob\",\"boe\",\"bof\",\"bog\",\"boh\",\"boi\",\"boj\",\"bok\",\"bol\",\"bom\",\"bon\",\"boo\",\"bop\",\"boq\",\"bor\",\"bot\",\"bou\",\"bov\",\"bow\",\"box\",\"boy\",\"boz\",\"bpa\",\"bpb\",\"bpd\",\"bpg\",\"bph\",\"bpi\",\"bpj\",\"bpk\",\"bpl\",\"bpm\",\"bpn\",\"bpo\",\"bpp\",\"bpq\",\"bpr\",\"bps\",\"bpt\",\"bpu\",\"bpv\",\"bpw\",\"bpx\",\"bpy\",\"bpz\",\"bqa\",\"bqb\",\"bqc\",\"bqd\",\"bqf\",\"bqg\",\"bqh\",\"bqi\",\"bqj\",\"bqk\",\"bql\",\"bqm\",\"bqn\",\"bqo\",\"bqp\",\"bqq\",\"bqr\",\"bqs\",\"bqt\",\"bqu\",\"bqv\",\"bqw\",\"bqx\",\"bqy\",\"bqz\",\"bra\",\"brb\",\"brc\",\"brd\",\"brf\",\"brg\",\"brh\",\"bri\",\"brj\",\"brk\",\"brl\",\"brm\",\"brn\",\"bro\",\"brp\",\"brq\",\"brr\",\"brs\",\"brt\",\"bru\",\"brv\",\"brw\",\"brx\",\"bry\",\"brz\",\"bsa\",\"bsb\",\"bsc\",\"bse\",\"bsf\",\"bsg\",\"bsh\",\"bsi\",\"bsj\",\"bsk\",\"bsl\",\"bsm\",\"bsn\",\"bso\",\"bsp\",\"bsq\",\"bsr\",\"bss\",\"bst\",\"bsu\",\"bsv\",\"bsw\",\"bsx\",\"bsy\",\"bta\",\"btb\",\"btc\",\"btd\",\"bte\",\"btf\",\"btg\",\"bth\",\"bti\",\"btj\",\"btk\",\"btl\",\"btm\",\"btn\",\"bto\",\"btp\",\"btq\",\"btr\",\"bts\",\"btt\",\"btu\",\"btv\",\"btw\",\"btx\",\"bty\",\"btz\",\"bua\",\"bub\",\"buc\",\"bud\",\"bue\",\"buf\",\"bug\",\"buh\",\"bui\",\"buj\",\"buk\",\"bum\",\"bun\",\"buo\",\"bup\",\"buq\",\"bus\",\"but\",\"buu\",\"buv\",\"buw\",\"bux\",\"buy\",\"buz\",\"bva\",\"bvb\",\"bvc\",\"bvd\",\"bve\",\"bvf\",\"bvg\",\"bvh\",\"bvi\",\"bvj\",\"bvk\",\"bvl\",\"bvm\",\"bvn\",\"bvo\",\"bvp\",\"bvq\",\"bvr\",\"bvt\",\"bvu\",\"bvv\",\"bvw\",\"bvx\",\"bvy\",\"bvz\",\"bwa\",\"bwb\",\"bwc\",\"bwd\",\"bwe\",\"bwf\",\"bwg\",\"bwh\",\"bwi\",\"bwj\",\"bwk\",\"bwl\",\"bwm\",\"bwn\",\"bwo\",\"bwp\",\"bwq\",\"bwr\",\"bws\",\"bwt\",\"bwu\",\"bww\",\"bwx\",\"bwy\",\"bwz\",\"bxa\",\"bxb\",\"bxc\",\"bxd\",\"bxe\",\"bxf\",\"bxg\",\"bxh\",\"bxi\",\"bxj\",\"bxk\",\"bxl\",\"bxm\",\"bxn\",\"bxo\",\"bxp\",\"bxq\",\"bxr\",\"bxs\",\"bxu\",\"bxv\",\"bxw\",\"bxx\",\"bxz\",\"bya\",\"byb\",\"byc\",\"byd\",\"bye\",\"byf\",\"byg\",\"byh\",\"byi\",\"byj\",\"byk\",\"byl\",\"bym\",\"byn\",\"byo\",\"byp\",\"byq\",\"byr\",\"bys\",\"byt\",\"byv\",\"byw\",\"byx\",\"byy\",\"byz\",\"bza\",\"bzb\",\"bzc\",\"bzd\",\"bze\",\"bzf\",\"bzg\",\"bzh\",\"bzi\",\"bzj\",\"bzk\",\"bzl\",\"bzm\",\"bzn\",\"bzo\",\"bzp\",\"bzq\",\"bzr\",\"bzs\",\"bzt\",\"bzu\",\"bzv\",\"bzw\",\"bzx\",\"bzy\",\"bzz\",\"caa\",\"cab\",\"cac\",\"cad\",\"cae\",\"caf\",\"cag\",\"cah\",\"cai\",\"caj\",\"cak\",\"cal\",\"cam\",\"can\",\"cao\",\"cap\",\"caq\",\"car\",\"cas\",\"cau\",\"cav\",\"caw\",\"cax\",\"cay\",\"caz\",\"cba\",\"cbb\",\"cbc\",\"cbd\",\"cbe\",\"cbg\",\"cbh\",\"cbi\",\"cbj\",\"cbk\",\"cbl\",\"cbn\",\"cbo\",\"cbq\",\"cbr\",\"cbs\",\"cbt\",\"cbu\",\"cbv\",\"cbw\",\"cby\",\"cca\",\"ccc\",\"ccd\",\"cce\",\"ccg\",\"cch\",\"ccj\",\"ccl\",\"ccm\",\"ccn\",\"cco\",\"ccp\",\"ccq\",\"ccr\",\"ccs\",\"cda\",\"cdc\",\"cdd\",\"cde\",\"cdf\",\"cdg\",\"cdh\",\"cdi\",\"cdj\",\"cdm\",\"cdn\",\"cdo\",\"cdr\",\"cds\",\"cdy\",\"cdz\",\"cea\",\"ceb\",\"ceg\",\"cek\",\"cel\",\"cen\",\"cet\",\"cfa\",\"cfd\",\"cfg\",\"cfm\",\"cga\",\"cgc\",\"cgg\",\"cgk\",\"chb\",\"chc\",\"chd\",\"chf\",\"chg\",\"chh\",\"chj\",\"chk\",\"chl\",\"chm\",\"chn\",\"cho\",\"chp\",\"chq\",\"chr\",\"cht\",\"chw\",\"chx\",\"chy\",\"chz\",\"cia\",\"cib\",\"cic\",\"cid\",\"cie\",\"cih\",\"cik\",\"cim\",\"cin\",\"cip\",\"cir\",\"ciw\",\"ciy\",\"cja\",\"cje\",\"cjh\",\"cji\",\"cjk\",\"cjm\",\"cjn\",\"cjo\",\"cjp\",\"cjr\",\"cjs\",\"cjv\",\"cjy\",\"cka\",\"ckb\",\"ckh\",\"ckl\",\"ckn\",\"cko\",\"ckq\",\"ckr\",\"cks\",\"ckt\",\"cku\",\"ckv\",\"ckx\",\"cky\",\"ckz\",\"cla\",\"clc\",\"cld\",\"cle\",\"clh\",\"cli\",\"clj\",\"clk\",\"cll\",\"clm\",\"clo\",\"clt\",\"clu\",\"clw\",\"cly\",\"cma\",\"cmc\",\"cme\",\"cmg\",\"cmi\",\"cmk\",\"cml\",\"cmm\",\"cmn\",\"cmo\",\"cmr\",\"cms\",\"cmt\",\"cna\",\"cnb\",\"cnc\",\"cng\",\"cnh\",\"cni\",\"cnk\",\"cnl\",\"cno\",\"cns\",\"cnt\",\"cnu\",\"cnw\",\"cnx\",\"coa\",\"cob\",\"coc\",\"cod\",\"coe\",\"cof\",\"cog\",\"coh\",\"coj\",\"cok\",\"col\",\"com\",\"con\",\"coo\",\"cop\",\"coq\",\"cot\",\"cou\",\"cov\",\"cow\",\"cox\",\"coy\",\"coz\",\"cpa\",\"cpb\",\"cpc\",\"cpe\",\"cpf\",\"cpg\",\"cpi\",\"cpn\",\"cpo\",\"cpp\",\"cps\",\"cpu\",\"cpx\",\"cpy\",\"cqd\",\"cqu\",\"cra\",\"crb\",\"crc\",\"crd\",\"crf\",\"crg\",\"crh\",\"cri\",\"crj\",\"crk\",\"crl\",\"crm\",\"crn\",\"cro\",\"crp\",\"crq\",\"crr\",\"crs\",\"crt\",\"crv\",\"crw\",\"crx\",\"cry\",\"crz\",\"csa\",\"csb\",\"csc\",\"csd\",\"cse\",\"csf\",\"csg\",\"csh\",\"csi\",\"csj\",\"csk\",\"csl\",\"csm\",\"csn\",\"cso\",\"csq\",\"csr\",\"css\",\"cst\",\"csu\",\"csv\",\"csw\",\"csy\",\"csz\",\"cta\",\"ctc\",\"ctd\",\"cte\",\"ctg\",\"cth\",\"ctl\",\"ctm\",\"ctn\",\"cto\",\"ctp\",\"cts\",\"ctt\",\"ctu\",\"ctz\",\"cua\",\"cub\",\"cuc\",\"cug\",\"cuh\",\"cui\",\"cuj\",\"cuk\",\"cul\",\"cum\",\"cuo\",\"cup\",\"cuq\",\"cur\",\"cus\",\"cut\",\"cuu\",\"cuv\",\"cuw\",\"cux\",\"cvg\",\"cvn\",\"cwa\",\"cwb\",\"cwd\",\"cwe\",\"cwg\",\"cwt\",\"cya\",\"cyb\",\"cyo\",\"czh\",\"czk\",\"czn\",\"czo\",\"czt\",\"daa\",\"dac\",\"dad\",\"dae\",\"daf\",\"dag\",\"dah\",\"dai\",\"daj\",\"dak\",\"dal\",\"dam\",\"dao\",\"dap\",\"daq\",\"dar\",\"das\",\"dau\",\"dav\",\"daw\",\"dax\",\"day\",\"daz\",\"dba\",\"dbb\",\"dbd\",\"dbe\",\"dbf\",\"dbg\",\"dbi\",\"dbj\",\"dbl\",\"dbm\",\"dbn\",\"dbo\",\"dbp\",\"dbq\",\"dbr\",\"dbt\",\"dbu\",\"dbv\",\"dbw\",\"dby\",\"dcc\",\"dcr\",\"dda\",\"ddd\",\"dde\",\"ddg\",\"ddi\",\"ddj\",\"ddn\",\"ddo\",\"ddr\",\"dds\",\"ddw\",\"dec\",\"ded\",\"dee\",\"def\",\"deg\",\"deh\",\"dei\",\"dek\",\"del\",\"dem\",\"den\",\"dep\",\"deq\",\"der\",\"des\",\"dev\",\"dez\",\"dga\",\"dgb\",\"dgc\",\"dgd\",\"dge\",\"dgg\",\"dgh\",\"dgi\",\"dgk\",\"dgl\",\"dgn\",\"dgo\",\"dgr\",\"dgs\",\"dgt\",\"dgu\",\"dgw\",\"dgx\",\"dgz\",\"dha\",\"dhd\",\"dhg\",\"dhi\",\"dhl\",\"dhm\",\"dhn\",\"dho\",\"dhr\",\"dhs\",\"dhu\",\"dhv\",\"dhw\",\"dhx\",\"dia\",\"dib\",\"dic\",\"did\",\"dif\",\"dig\",\"dih\",\"dii\",\"dij\",\"dik\",\"dil\",\"dim\",\"din\",\"dio\",\"dip\",\"diq\",\"dir\",\"dis\",\"dit\",\"diu\",\"diw\",\"dix\",\"diy\",\"diz\",\"dja\",\"djb\",\"djc\",\"djd\",\"dje\",\"djf\",\"dji\",\"djj\",\"djk\",\"djl\",\"djm\",\"djn\",\"djo\",\"djr\",\"dju\",\"djw\",\"dka\",\"dkk\",\"dkl\",\"dkr\",\"dks\",\"dkx\",\"dlg\",\"dlk\",\"dlm\",\"dln\",\"dma\",\"dmb\",\"dmc\",\"dmd\",\"dme\",\"dmg\",\"dmk\",\"dml\",\"dmm\",\"dmn\",\"dmo\",\"dmr\",\"dms\",\"dmu\",\"dmv\",\"dmw\",\"dmx\",\"dmy\",\"dna\",\"dnd\",\"dne\",\"dng\",\"dni\",\"dnj\",\"dnk\",\"dnn\",\"dnr\",\"dnt\",\"dnu\",\"dnv\",\"dnw\",\"dny\",\"doa\",\"dob\",\"doc\",\"doe\",\"dof\",\"doh\",\"doi\",\"dok\",\"dol\",\"don\",\"doo\",\"dop\",\"doq\",\"dor\",\"dos\",\"dot\",\"dov\",\"dow\",\"dox\",\"doy\",\"doz\",\"dpp\",\"dra\",\"drb\",\"drc\",\"drd\",\"dre\",\"drg\",\"drh\",\"dri\",\"drl\",\"drn\",\"dro\",\"drq\",\"drr\",\"drs\",\"drt\",\"dru\",\"drw\",\"dry\",\"dsb\",\"dse\",\"dsh\",\"dsi\",\"dsl\",\"dsn\",\"dso\",\"dsq\",\"dta\",\"dtb\",\"dtd\",\"dth\",\"dti\",\"dtk\",\"dtm\",\"dtn\",\"dto\",\"dtp\",\"dtr\",\"dts\",\"dtt\",\"dtu\",\"dty\",\"dua\",\"dub\",\"duc\",\"dud\",\"due\",\"duf\",\"dug\",\"duh\",\"dui\",\"duj\",\"duk\",\"dul\",\"dum\",\"dun\",\"duo\",\"dup\",\"duq\",\"dur\",\"dus\",\"duu\",\"duv\",\"duw\",\"dux\",\"duy\",\"duz\",\"dva\",\"dwa\",\"dwl\",\"dwr\",\"dws\",\"dwu\",\"dww\",\"dwy\",\"dya\",\"dyb\",\"dyd\",\"dyg\",\"dyi\",\"dym\",\"dyn\",\"dyo\",\"dyu\",\"dyy\",\"dza\",\"dzd\",\"dze\",\"dzg\",\"dzl\",\"dzn\",\"eaa\",\"ebg\",\"ebk\",\"ebo\",\"ebr\",\"ebu\",\"ecr\",\"ecs\",\"ecy\",\"eee\",\"efa\",\"efe\",\"efi\",\"ega\",\"egl\",\"ego\",\"egx\",\"egy\",\"ehu\",\"eip\",\"eit\",\"eiv\",\"eja\",\"eka\",\"ekc\",\"eke\",\"ekg\",\"eki\",\"ekk\",\"ekl\",\"ekm\",\"eko\",\"ekp\",\"ekr\",\"eky\",\"ele\",\"elh\",\"eli\",\"elk\",\"elm\",\"elo\",\"elp\",\"elu\",\"elx\",\"ema\",\"emb\",\"eme\",\"emg\",\"emi\",\"emk\",\"emm\",\"emn\",\"emo\",\"emp\",\"ems\",\"emu\",\"emw\",\"emx\",\"emy\",\"ena\",\"enb\",\"enc\",\"end\",\"enf\",\"enh\",\"enl\",\"enm\",\"enn\",\"eno\",\"enq\",\"enr\",\"enu\",\"env\",\"enw\",\"enx\",\"eot\",\"epi\",\"era\",\"erg\",\"erh\",\"eri\",\"erk\",\"ero\",\"err\",\"ers\",\"ert\",\"erw\",\"ese\",\"esg\",\"esh\",\"esi\",\"esk\",\"esl\",\"esm\",\"esn\",\"eso\",\"esq\",\"ess\",\"esu\",\"esx\",\"esy\",\"etb\",\"etc\",\"eth\",\"etn\",\"eto\",\"etr\",\"ets\",\"ett\",\"etu\",\"etx\",\"etz\",\"euq\",\"eve\",\"evh\",\"evn\",\"ewo\",\"ext\",\"eya\",\"eyo\",\"eza\",\"eze\",\"faa\",\"fab\",\"fad\",\"faf\",\"fag\",\"fah\",\"fai\",\"faj\",\"fak\",\"fal\",\"fam\",\"fan\",\"fap\",\"far\",\"fat\",\"fau\",\"fax\",\"fay\",\"faz\",\"fbl\",\"fcs\",\"fer\",\"ffi\",\"ffm\",\"fgr\",\"fia\",\"fie\",\"fil\",\"fip\",\"fir\",\"fit\",\"fiu\",\"fiw\",\"fkk\",\"fkv\",\"fla\",\"flh\",\"fli\",\"fll\",\"fln\",\"flr\",\"fly\",\"fmp\",\"fmu\",\"fnb\",\"fng\",\"fni\",\"fod\",\"foi\",\"fom\",\"fon\",\"for\",\"fos\",\"fox\",\"fpe\",\"fqs\",\"frc\",\"frd\",\"frk\",\"frm\",\"fro\",\"frp\",\"frq\",\"frr\",\"frs\",\"frt\",\"fse\",\"fsl\",\"fss\",\"fub\",\"fuc\",\"fud\",\"fue\",\"fuf\",\"fuh\",\"fui\",\"fuj\",\"fum\",\"fun\",\"fuq\",\"fur\",\"fut\",\"fuu\",\"fuv\",\"fuy\",\"fvr\",\"fwa\",\"fwe\",\"gaa\",\"gab\",\"gac\",\"gad\",\"gae\",\"gaf\",\"gag\",\"gah\",\"gai\",\"gaj\",\"gak\",\"gal\",\"gam\",\"gan\",\"gao\",\"gap\",\"gaq\",\"gar\",\"gas\",\"gat\",\"gau\",\"gav\",\"gaw\",\"gax\",\"gay\",\"gaz\",\"gba\",\"gbb\",\"gbc\",\"gbd\",\"gbe\",\"gbf\",\"gbg\",\"gbh\",\"gbi\",\"gbj\",\"gbk\",\"gbl\",\"gbm\",\"gbn\",\"gbo\",\"gbp\",\"gbq\",\"gbr\",\"gbs\",\"gbu\",\"gbv\",\"gbw\",\"gbx\",\"gby\",\"gbz\",\"gcc\",\"gcd\",\"gce\",\"gcf\",\"gcl\",\"gcn\",\"gcr\",\"gct\",\"gda\",\"gdb\",\"gdc\",\"gdd\",\"gde\",\"gdf\",\"gdg\",\"gdh\",\"gdi\",\"gdj\",\"gdk\",\"gdl\",\"gdm\",\"gdn\",\"gdo\",\"gdq\",\"gdr\",\"gds\",\"gdt\",\"gdu\",\"gdx\",\"gea\",\"geb\",\"gec\",\"ged\",\"geg\",\"geh\",\"gei\",\"gej\",\"gek\",\"gel\",\"gem\",\"geq\",\"ges\",\"gev\",\"gew\",\"gex\",\"gey\",\"gez\",\"gfk\",\"gft\",\"gfx\",\"gga\",\"ggb\",\"ggd\",\"gge\",\"ggg\",\"ggk\",\"ggl\",\"ggn\",\"ggo\",\"ggr\",\"ggt\",\"ggu\",\"ggw\",\"gha\",\"ghc\",\"ghe\",\"ghh\",\"ghk\",\"ghl\",\"ghn\",\"gho\",\"ghr\",\"ghs\",\"ght\",\"gia\",\"gib\",\"gic\",\"gid\",\"gie\",\"gig\",\"gih\",\"gil\",\"gim\",\"gin\",\"gio\",\"gip\",\"giq\",\"gir\",\"gis\",\"git\",\"giu\",\"giw\",\"gix\",\"giy\",\"giz\",\"gji\",\"gjk\",\"gjm\",\"gjn\",\"gjr\",\"gju\",\"gka\",\"gke\",\"gkn\",\"gko\",\"gkp\",\"gku\",\"glc\",\"gld\",\"glh\",\"gli\",\"glj\",\"glk\",\"gll\",\"glo\",\"glr\",\"glu\",\"glw\",\"gly\",\"gma\",\"gmb\",\"gmd\",\"gme\",\"gmg\",\"gmh\",\"gml\",\"gmm\",\"gmn\",\"gmq\",\"gmu\",\"gmv\",\"gmw\",\"gmx\",\"gmy\",\"gmz\",\"gna\",\"gnb\",\"gnc\",\"gnd\",\"gne\",\"gng\",\"gnh\",\"gni\",\"gnk\",\"gnl\",\"gnm\",\"gnn\",\"gno\",\"gnq\",\"gnr\",\"gnt\",\"gnu\",\"gnw\",\"gnz\",\"goa\",\"gob\",\"goc\",\"god\",\"goe\",\"gof\",\"gog\",\"goh\",\"goi\",\"goj\",\"gok\",\"gol\",\"gom\",\"gon\",\"goo\",\"gop\",\"goq\",\"gor\",\"gos\",\"got\",\"gou\",\"gow\",\"gox\",\"goy\",\"goz\",\"gpa\",\"gpe\",\"gpn\",\"gqa\",\"gqi\",\"gqn\",\"gqr\",\"gqu\",\"gra\",\"grb\",\"grc\",\"grd\",\"grg\",\"grh\",\"gri\",\"grj\",\"grk\",\"grm\",\"gro\",\"grq\",\"grr\",\"grs\",\"grt\",\"gru\",\"grv\",\"grw\",\"grx\",\"gry\",\"grz\",\"gse\",\"gsg\",\"gsl\",\"gsm\",\"gsn\",\"gso\",\"gsp\",\"gss\",\"gsw\",\"gta\",\"gti\",\"gtu\",\"gua\",\"gub\",\"guc\",\"gud\",\"gue\",\"guf\",\"gug\",\"guh\",\"gui\",\"guk\",\"gul\",\"gum\",\"gun\",\"guo\",\"gup\",\"guq\",\"gur\",\"gus\",\"gut\",\"guu\",\"guv\",\"guw\",\"gux\",\"guz\",\"gva\",\"gvc\",\"gve\",\"gvf\",\"gvj\",\"gvl\",\"gvm\",\"gvn\",\"gvo\",\"gvp\",\"gvr\",\"gvs\",\"gvy\",\"gwa\",\"gwb\",\"gwc\",\"gwd\",\"gwe\",\"gwf\",\"gwg\",\"gwi\",\"gwj\",\"gwm\",\"gwn\",\"gwr\",\"gwt\",\"gwu\",\"gww\",\"gwx\",\"gxx\",\"gya\",\"gyb\",\"gyd\",\"gye\",\"gyf\",\"gyg\",\"gyi\",\"gyl\",\"gym\",\"gyn\",\"gyr\",\"gyy\",\"gza\",\"gzi\",\"gzn\",\"haa\",\"hab\",\"hac\",\"had\",\"hae\",\"haf\",\"hag\",\"hah\",\"hai\",\"haj\",\"hak\",\"hal\",\"ham\",\"han\",\"hao\",\"hap\",\"haq\",\"har\",\"has\",\"hav\",\"haw\",\"hax\",\"hay\",\"haz\",\"hba\",\"hbb\",\"hbn\",\"hbo\",\"hbu\",\"hca\",\"hch\",\"hdn\",\"hds\",\"hdy\",\"hea\",\"hed\",\"heg\",\"heh\",\"hei\",\"hem\",\"hgm\",\"hgw\",\"hhi\",\"hhr\",\"hhy\",\"hia\",\"hib\",\"hid\",\"hif\",\"hig\",\"hih\",\"hii\",\"hij\",\"hik\",\"hil\",\"him\",\"hio\",\"hir\",\"hit\",\"hiw\",\"hix\",\"hji\",\"hka\",\"hke\",\"hkk\",\"hks\",\"hla\",\"hlb\",\"hld\",\"hle\",\"hlt\",\"hlu\",\"hma\",\"hmb\",\"hmc\",\"hmd\",\"hme\",\"hmf\",\"hmg\",\"hmh\",\"hmi\",\"hmj\",\"hmk\",\"hml\",\"hmm\",\"hmn\",\"hmp\",\"hmq\",\"hmr\",\"hms\",\"hmt\",\"hmu\",\"hmv\",\"hmw\",\"hmx\",\"hmy\",\"hmz\",\"hna\",\"hnd\",\"hne\",\"hnh\",\"hni\",\"hnj\",\"hnn\",\"hno\",\"hns\",\"hnu\",\"hoa\",\"hob\",\"hoc\",\"hod\",\"hoe\",\"hoh\",\"hoi\",\"hoj\",\"hok\",\"hol\",\"hom\",\"hoo\",\"hop\",\"hor\",\"hos\",\"hot\",\"hov\",\"how\",\"hoy\",\"hoz\",\"hpo\",\"hps\",\"hra\",\"hrc\",\"hre\",\"hrk\",\"hrm\",\"hro\",\"hrp\",\"hrr\",\"hrt\",\"hru\",\"hrw\",\"hrx\",\"hrz\",\"hsb\",\"hsh\",\"hsl\",\"hsn\",\"hss\",\"hti\",\"hto\",\"hts\",\"htu\",\"htx\",\"hub\",\"huc\",\"hud\",\"hue\",\"huf\",\"hug\",\"huh\",\"hui\",\"huj\",\"huk\",\"hul\",\"hum\",\"huo\",\"hup\",\"huq\",\"hur\",\"hus\",\"hut\",\"huu\",\"huv\",\"huw\",\"hux\",\"huy\",\"huz\",\"hvc\",\"hve\",\"hvk\",\"hvn\",\"hvv\",\"hwa\",\"hwc\",\"hwo\",\"hya\",\"hyx\",\"iai\",\"ian\",\"iap\",\"iar\",\"iba\",\"ibb\",\"ibd\",\"ibe\",\"ibg\",\"ibh\",\"ibi\",\"ibl\",\"ibm\",\"ibn\",\"ibr\",\"ibu\",\"iby\",\"ica\",\"ich\",\"icl\",\"icr\",\"ida\",\"idb\",\"idc\",\"idd\",\"ide\",\"idi\",\"idr\",\"ids\",\"idt\",\"idu\",\"ifa\",\"ifb\",\"ife\",\"iff\",\"ifk\",\"ifm\",\"ifu\",\"ify\",\"igb\",\"ige\",\"igg\",\"igl\",\"igm\",\"ign\",\"igo\",\"igs\",\"igw\",\"ihb\",\"ihi\",\"ihp\",\"ihw\",\"iin\",\"iir\",\"ijc\",\"ije\",\"ijj\",\"ijn\",\"ijo\",\"ijs\",\"ike\",\"iki\",\"ikk\",\"ikl\",\"iko\",\"ikp\",\"ikr\",\"iks\",\"ikt\",\"ikv\",\"ikw\",\"ikx\",\"ikz\",\"ila\",\"ilb\",\"ilg\",\"ili\",\"ilk\",\"ill\",\"ilm\",\"ilo\",\"ilp\",\"ils\",\"ilu\",\"ilv\",\"ilw\",\"ima\",\"ime\",\"imi\",\"iml\",\"imn\",\"imo\",\"imr\",\"ims\",\"imy\",\"inb\",\"inc\",\"ine\",\"ing\",\"inh\",\"inj\",\"inl\",\"inm\",\"inn\",\"ino\",\"inp\",\"ins\",\"int\",\"inz\",\"ior\",\"iou\",\"iow\",\"ipi\",\"ipo\",\"iqu\",\"iqw\",\"ira\",\"ire\",\"irh\",\"iri\",\"irk\",\"irn\",\"iro\",\"irr\",\"iru\",\"irx\",\"iry\",\"isa\",\"isc\",\"isd\",\"ise\",\"isg\",\"ish\",\"isi\",\"isk\",\"ism\",\"isn\",\"iso\",\"isr\",\"ist\",\"isu\",\"itb\",\"itc\",\"itd\",\"ite\",\"iti\",\"itk\",\"itl\",\"itm\",\"ito\",\"itr\",\"its\",\"itt\",\"itv\",\"itw\",\"itx\",\"ity\",\"itz\",\"ium\",\"ivb\",\"ivv\",\"iwk\",\"iwm\",\"iwo\",\"iws\",\"ixc\",\"ixl\",\"iya\",\"iyo\",\"iyx\",\"izh\",\"izi\",\"izr\",\"izz\",\"jaa\",\"jab\",\"jac\",\"jad\",\"jae\",\"jaf\",\"jah\",\"jaj\",\"jak\",\"jal\",\"jam\",\"jan\",\"jao\",\"jaq\",\"jar\",\"jas\",\"jat\",\"jau\",\"jax\",\"jay\",\"jaz\",\"jbe\",\"jbi\",\"jbj\",\"jbk\",\"jbn\",\"jbo\",\"jbr\",\"jbt\",\"jbu\",\"jbw\",\"jcs\",\"jct\",\"jda\",\"jdg\",\"jdt\",\"jeb\",\"jee\",\"jeg\",\"jeh\",\"jei\",\"jek\",\"jel\",\"jen\",\"jer\",\"jet\",\"jeu\",\"jgb\",\"jge\",\"jgk\",\"jgo\",\"jhi\",\"jhs\",\"jia\",\"jib\",\"jic\",\"jid\",\"jie\",\"jig\",\"jih\",\"jii\",\"jil\",\"jim\",\"jio\",\"jiq\",\"jit\",\"jiu\",\"jiv\",\"jiy\",\"jje\",\"jjr\",\"jka\",\"jkm\",\"jko\",\"jkp\",\"jkr\",\"jku\",\"jle\",\"jls\",\"jma\",\"jmb\",\"jmc\",\"jmd\",\"jmi\",\"jml\",\"jmn\",\"jmr\",\"jms\",\"jmw\",\"jmx\",\"jna\",\"jnd\",\"jng\",\"jni\",\"jnj\",\"jnl\",\"jns\",\"job\",\"jod\",\"jog\",\"jor\",\"jos\",\"jow\",\"jpa\",\"jpr\",\"jpx\",\"jqr\",\"jra\",\"jrb\",\"jrr\",\"jrt\",\"jru\",\"jsl\",\"jua\",\"jub\",\"juc\",\"jud\",\"juh\",\"jui\",\"juk\",\"jul\",\"jum\",\"jun\",\"juo\",\"jup\",\"jur\",\"jus\",\"jut\",\"juu\",\"juw\",\"juy\",\"jvd\",\"jvn\",\"jwi\",\"jya\",\"jye\",\"jyy\",\"kaa\",\"kab\",\"kac\",\"kad\",\"kae\",\"kaf\",\"kag\",\"kah\",\"kai\",\"kaj\",\"kak\",\"kam\",\"kao\",\"kap\",\"kaq\",\"kar\",\"kav\",\"kaw\",\"kax\",\"kay\",\"kba\",\"kbb\",\"kbc\",\"kbd\",\"kbe\",\"kbf\",\"kbg\",\"kbh\",\"kbi\",\"kbj\",\"kbk\",\"kbl\",\"kbm\",\"kbn\",\"kbo\",\"kbp\",\"kbq\",\"kbr\",\"kbs\",\"kbt\",\"kbu\",\"kbv\",\"kbw\",\"kbx\",\"kby\",\"kbz\",\"kca\",\"kcb\",\"kcc\",\"kcd\",\"kce\",\"kcf\",\"kcg\",\"kch\",\"kci\",\"kcj\",\"kck\",\"kcl\",\"kcm\",\"kcn\",\"kco\",\"kcp\",\"kcq\",\"kcr\",\"kcs\",\"kct\",\"kcu\",\"kcv\",\"kcw\",\"kcx\",\"kcy\",\"kcz\",\"kda\",\"kdc\",\"kdd\",\"kde\",\"kdf\",\"kdg\",\"kdh\",\"kdi\",\"kdj\",\"kdk\",\"kdl\",\"kdm\",\"kdn\",\"kdo\",\"kdp\",\"kdq\",\"kdr\",\"kdt\",\"kdu\",\"kdv\",\"kdw\",\"kdx\",\"kdy\",\"kdz\",\"kea\",\"keb\",\"kec\",\"ked\",\"kee\",\"kef\",\"keg\",\"keh\",\"kei\",\"kej\",\"kek\",\"kel\",\"kem\",\"ken\",\"keo\",\"kep\",\"keq\",\"ker\",\"kes\",\"ket\",\"keu\",\"kev\",\"kew\",\"kex\",\"key\",\"kez\",\"kfa\",\"kfb\",\"kfc\",\"kfd\",\"kfe\",\"kff\",\"kfg\",\"kfh\",\"kfi\",\"kfj\",\"kfk\",\"kfl\",\"kfm\",\"kfn\",\"kfo\",\"kfp\",\"kfq\",\"kfr\",\"kfs\",\"kft\",\"kfu\",\"kfv\",\"kfw\",\"kfx\",\"kfy\",\"kfz\",\"kga\",\"kgb\",\"kgc\",\"kgd\",\"kge\",\"kgf\",\"kgg\",\"kgh\",\"kgi\",\"kgj\",\"kgk\",\"kgl\",\"kgm\",\"kgn\",\"kgo\",\"kgp\",\"kgq\",\"kgr\",\"kgs\",\"kgt\",\"kgu\",\"kgv\",\"kgw\",\"kgx\",\"kgy\",\"kha\",\"khb\",\"khc\",\"khd\",\"khe\",\"khf\",\"khg\",\"khh\",\"khi\",\"khj\",\"khk\",\"khl\",\"khn\",\"kho\",\"khp\",\"khq\",\"khr\",\"khs\",\"kht\",\"khu\",\"khv\",\"khw\",\"khx\",\"khy\",\"khz\",\"kia\",\"kib\",\"kic\",\"kid\",\"kie\",\"kif\",\"kig\",\"kih\",\"kii\",\"kij\",\"kil\",\"kim\",\"kio\",\"kip\",\"kiq\",\"kis\",\"kit\",\"kiu\",\"kiv\",\"kiw\",\"kix\",\"kiy\",\"kiz\",\"kja\",\"kjb\",\"kjc\",\"kjd\",\"kje\",\"kjf\",\"kjg\",\"kjh\",\"kji\",\"kjj\",\"kjk\",\"kjl\",\"kjm\",\"kjn\",\"kjo\",\"kjp\",\"kjq\",\"kjr\",\"kjs\",\"kjt\",\"kju\",\"kjv\",\"kjx\",\"kjy\",\"kjz\",\"kka\",\"kkb\",\"kkc\",\"kkd\",\"kke\",\"kkf\",\"kkg\",\"kkh\",\"kki\",\"kkj\",\"kkk\",\"kkl\",\"kkm\",\"kkn\",\"kko\",\"kkp\",\"kkq\",\"kkr\",\"kks\",\"kkt\",\"kku\",\"kkv\",\"kkw\",\"kkx\",\"kky\",\"kkz\",\"kla\",\"klb\",\"klc\",\"kld\",\"kle\",\"klf\",\"klg\",\"klh\",\"kli\",\"klj\",\"klk\",\"kll\",\"klm\",\"kln\",\"klo\",\"klp\",\"klq\",\"klr\",\"kls\",\"klt\",\"klu\",\"klv\",\"klw\",\"klx\",\"kly\",\"klz\",\"kma\",\"kmb\",\"kmc\",\"kmd\",\"kme\",\"kmf\",\"kmg\",\"kmh\",\"kmi\",\"kmj\",\"kmk\",\"kml\",\"kmm\",\"kmn\",\"kmo\",\"kmp\",\"kmq\",\"kmr\",\"kms\",\"kmt\",\"kmu\",\"kmv\",\"kmw\",\"kmx\",\"kmy\",\"kmz\",\"kna\",\"knb\",\"knc\",\"knd\",\"kne\",\"knf\",\"kng\",\"kni\",\"knj\",\"knk\",\"knl\",\"knm\",\"knn\",\"kno\",\"knp\",\"knq\",\"knr\",\"kns\",\"knt\",\"knu\",\"knv\",\"knw\",\"knx\",\"kny\",\"knz\",\"koa\",\"koc\",\"kod\",\"koe\",\"kof\",\"kog\",\"koh\",\"koi\",\"koj\",\"kok\",\"kol\",\"koo\",\"kop\",\"koq\",\"kos\",\"kot\",\"kou\",\"kov\",\"kow\",\"kox\",\"koy\",\"koz\",\"kpa\",\"kpb\",\"kpc\",\"kpd\",\"kpe\",\"kpf\",\"kpg\",\"kph\",\"kpi\",\"kpj\",\"kpk\",\"kpl\",\"kpm\",\"kpn\",\"kpo\",\"kpp\",\"kpq\",\"kpr\",\"kps\",\"kpt\",\"kpu\",\"kpv\",\"kpw\",\"kpx\",\"kpy\",\"kpz\",\"kqa\",\"kqb\",\"kqc\",\"kqd\",\"kqe\",\"kqf\",\"kqg\",\"kqh\",\"kqi\",\"kqj\",\"kqk\",\"kql\",\"kqm\",\"kqn\",\"kqo\",\"kqp\",\"kqq\",\"kqr\",\"kqs\",\"kqt\",\"kqu\",\"kqv\",\"kqw\",\"kqx\",\"kqy\",\"kqz\",\"kra\",\"krb\",\"krc\",\"krd\",\"kre\",\"krf\",\"krh\",\"kri\",\"krj\",\"krk\",\"krl\",\"krm\",\"krn\",\"kro\",\"krp\",\"krr\",\"krs\",\"krt\",\"kru\",\"krv\",\"krw\",\"krx\",\"kry\",\"krz\",\"ksa\",\"ksb\",\"ksc\",\"ksd\",\"kse\",\"ksf\",\"ksg\",\"ksh\",\"ksi\",\"ksj\",\"ksk\",\"ksl\",\"ksm\",\"ksn\",\"kso\",\"ksp\",\"ksq\",\"ksr\",\"kss\",\"kst\",\"ksu\",\"ksv\",\"ksw\",\"ksx\",\"ksy\",\"ksz\",\"kta\",\"ktb\",\"ktc\",\"ktd\",\"kte\",\"ktf\",\"ktg\",\"kth\",\"kti\",\"ktj\",\"ktk\",\"ktl\",\"ktm\",\"ktn\",\"kto\",\"ktp\",\"ktq\",\"ktr\",\"kts\",\"ktt\",\"ktu\",\"ktv\",\"ktw\",\"ktx\",\"kty\",\"ktz\",\"kub\",\"kuc\",\"kud\",\"kue\",\"kuf\",\"kug\",\"kuh\",\"kui\",\"kuj\",\"kuk\",\"kul\",\"kum\",\"kun\",\"kuo\",\"kup\",\"kuq\",\"kus\",\"kut\",\"kuu\",\"kuv\",\"kuw\",\"kux\",\"kuy\",\"kuz\",\"kva\",\"kvb\",\"kvc\",\"kvd\",\"kve\",\"kvf\",\"kvg\",\"kvh\",\"kvi\",\"kvj\",\"kvk\",\"kvl\",\"kvm\",\"kvn\",\"kvo\",\"kvp\",\"kvq\",\"kvr\",\"kvs\",\"kvt\",\"kvu\",\"kvv\",\"kvw\",\"kvx\",\"kvy\",\"kvz\",\"kwa\",\"kwb\",\"kwc\",\"kwd\",\"kwe\",\"kwf\",\"kwg\",\"kwh\",\"kwi\",\"kwj\",\"kwk\",\"kwl\",\"kwm\",\"kwn\",\"kwo\",\"kwp\",\"kwq\",\"kwr\",\"kws\",\"kwt\",\"kwu\",\"kwv\",\"kww\",\"kwx\",\"kwy\",\"kwz\",\"kxa\",\"kxb\",\"kxc\",\"kxd\",\"kxe\",\"kxf\",\"kxh\",\"kxi\",\"kxj\",\"kxk\",\"kxl\",\"kxm\",\"kxn\",\"kxo\",\"kxp\",\"kxq\",\"kxr\",\"kxs\",\"kxt\",\"kxu\",\"kxv\",\"kxw\",\"kxx\",\"kxy\",\"kxz\",\"kya\",\"kyb\",\"kyc\",\"kyd\",\"kye\",\"kyf\",\"kyg\",\"kyh\",\"kyi\",\"kyj\",\"kyk\",\"kyl\",\"kym\",\"kyn\",\"kyo\",\"kyp\",\"kyq\",\"kyr\",\"kys\",\"kyt\",\"kyu\",\"kyv\",\"kyw\",\"kyx\",\"kyy\",\"kyz\",\"kza\",\"kzb\",\"kzc\",\"kzd\",\"kze\",\"kzf\",\"kzg\",\"kzh\",\"kzi\",\"kzj\",\"kzk\",\"kzl\",\"kzm\",\"kzn\",\"kzo\",\"kzp\",\"kzq\",\"kzr\",\"kzs\",\"kzt\",\"kzu\",\"kzv\",\"kzw\",\"kzx\",\"kzy\",\"kzz\",\"laa\",\"lab\",\"lac\",\"lad\",\"lae\",\"laf\",\"lag\",\"lah\",\"lai\",\"laj\",\"lak\",\"lal\",\"lam\",\"lan\",\"lap\",\"laq\",\"lar\",\"las\",\"lau\",\"law\",\"lax\",\"lay\",\"laz\",\"lba\",\"lbb\",\"lbc\",\"lbe\",\"lbf\",\"lbg\",\"lbi\",\"lbj\",\"lbk\",\"lbl\",\"lbm\",\"lbn\",\"lbo\",\"lbq\",\"lbr\",\"lbs\",\"lbt\",\"lbu\",\"lbv\",\"lbw\",\"lbx\",\"lby\",\"lbz\",\"lcc\",\"lcd\",\"lce\",\"lcf\",\"lch\",\"lcl\",\"lcm\",\"lcp\",\"lcq\",\"lcs\",\"lda\",\"ldb\",\"ldd\",\"ldg\",\"ldh\",\"ldi\",\"ldj\",\"ldk\",\"ldl\",\"ldm\",\"ldn\",\"ldo\",\"ldp\",\"ldq\",\"lea\",\"leb\",\"lec\",\"led\",\"lee\",\"lef\",\"leg\",\"leh\",\"lei\",\"lej\",\"lek\",\"lel\",\"lem\",\"len\",\"leo\",\"lep\",\"leq\",\"ler\",\"les\",\"let\",\"leu\",\"lev\",\"lew\",\"lex\",\"ley\",\"lez\",\"lfa\",\"lfn\",\"lga\",\"lgb\",\"lgg\",\"lgh\",\"lgi\",\"lgk\",\"lgl\",\"lgm\",\"lgn\",\"lgq\",\"lgr\",\"lgt\",\"lgu\",\"lgz\",\"lha\",\"lhh\",\"lhi\",\"lhl\",\"lhm\",\"lhn\",\"lhp\",\"lhs\",\"lht\",\"lhu\",\"lia\",\"lib\",\"lic\",\"lid\",\"lie\",\"lif\",\"lig\",\"lih\",\"lii\",\"lij\",\"lik\",\"lil\",\"lio\",\"lip\",\"liq\",\"lir\",\"lis\",\"liu\",\"liv\",\"liw\",\"lix\",\"liy\",\"liz\",\"lja\",\"lje\",\"lji\",\"ljl\",\"ljp\",\"ljw\",\"ljx\",\"lka\",\"lkb\",\"lkc\",\"lkd\",\"lke\",\"lkh\",\"lki\",\"lkj\",\"lkl\",\"lkm\",\"lkn\",\"lko\",\"lkr\",\"lks\",\"lkt\",\"lku\",\"lky\",\"lla\",\"llb\",\"llc\",\"lld\",\"lle\",\"llf\",\"llg\",\"llh\",\"lli\",\"llj\",\"llk\",\"lll\",\"llm\",\"lln\",\"llo\",\"llp\",\"llq\",\"lls\",\"llu\",\"llx\",\"lma\",\"lmb\",\"lmc\",\"lmd\",\"lme\",\"lmf\",\"lmg\",\"lmh\",\"lmi\",\"lmj\",\"lmk\",\"lml\",\"lmm\",\"lmn\",\"lmo\",\"lmp\",\"lmq\",\"lmr\",\"lmu\",\"lmv\",\"lmw\",\"lmx\",\"lmy\",\"lmz\",\"lna\",\"lnb\",\"lnd\",\"lng\",\"lnh\",\"lni\",\"lnj\",\"lnl\",\"lnm\",\"lnn\",\"lno\",\"lns\",\"lnu\",\"lnw\",\"lnz\",\"loa\",\"lob\",\"loc\",\"loe\",\"lof\",\"log\",\"loh\",\"loi\",\"loj\",\"lok\",\"lol\",\"lom\",\"lon\",\"loo\",\"lop\",\"loq\",\"lor\",\"los\",\"lot\",\"lou\",\"lov\",\"low\",\"lox\",\"loy\",\"loz\",\"lpa\",\"lpe\",\"lpn\",\"lpo\",\"lpx\",\"lra\",\"lrc\",\"lre\",\"lrg\",\"lri\",\"lrk\",\"lrl\",\"lrm\",\"lrn\",\"lro\",\"lrr\",\"lrt\",\"lrv\",\"lrz\",\"lsa\",\"lsd\",\"lse\",\"lsg\",\"lsh\",\"lsi\",\"lsl\",\"lsm\",\"lso\",\"lsp\",\"lsr\",\"lss\",\"lst\",\"lsy\",\"ltc\",\"ltg\",\"lth\",\"lti\",\"ltn\",\"lto\",\"lts\",\"ltu\",\"lua\",\"luc\",\"lud\",\"lue\",\"luf\",\"lui\",\"luj\",\"luk\",\"lul\",\"lum\",\"lun\",\"luo\",\"lup\",\"luq\",\"lur\",\"lus\",\"lut\",\"luu\",\"luv\",\"luw\",\"luy\",\"luz\",\"lva\",\"lvk\",\"lvs\",\"lvu\",\"lwa\",\"lwe\",\"lwg\",\"lwh\",\"lwl\",\"lwm\",\"lwo\",\"lwt\",\"lwu\",\"lww\",\"lya\",\"lyg\",\"lyn\",\"lzh\",\"lzl\",\"lzn\",\"lzz\",\"maa\",\"mab\",\"mad\",\"mae\",\"maf\",\"mag\",\"mai\",\"maj\",\"mak\",\"mam\",\"man\",\"map\",\"maq\",\"mas\",\"mat\",\"mau\",\"mav\",\"maw\",\"max\",\"maz\",\"mba\",\"mbb\",\"mbc\",\"mbd\",\"mbe\",\"mbf\",\"mbh\",\"mbi\",\"mbj\",\"mbk\",\"mbl\",\"mbm\",\"mbn\",\"mbo\",\"mbp\",\"mbq\",\"mbr\",\"mbs\",\"mbt\",\"mbu\",\"mbv\",\"mbw\",\"mbx\",\"mby\",\"mbz\",\"mca\",\"mcb\",\"mcc\",\"mcd\",\"mce\",\"mcf\",\"mcg\",\"mch\",\"mci\",\"mcj\",\"mck\",\"mcl\",\"mcm\",\"mcn\",\"mco\",\"mcp\",\"mcq\",\"mcr\",\"mcs\",\"mct\",\"mcu\",\"mcv\",\"mcw\",\"mcx\",\"mcy\",\"mcz\",\"mda\",\"mdb\",\"mdc\",\"mdd\",\"mde\",\"mdf\",\"mdg\",\"mdh\",\"mdi\",\"mdj\",\"mdk\",\"mdl\",\"mdm\",\"mdn\",\"mdp\",\"mdq\",\"mdr\",\"mds\",\"mdt\",\"mdu\",\"mdv\",\"mdw\",\"mdx\",\"mdy\",\"mdz\",\"mea\",\"meb\",\"mec\",\"med\",\"mee\",\"mef\",\"meg\",\"meh\",\"mei\",\"mej\",\"mek\",\"mel\",\"mem\",\"men\",\"meo\",\"mep\",\"meq\",\"mer\",\"mes\",\"met\",\"meu\",\"mev\",\"mew\",\"mey\",\"mez\",\"mfa\",\"mfb\",\"mfc\",\"mfd\",\"mfe\",\"mff\",\"mfg\",\"mfh\",\"mfi\",\"mfj\",\"mfk\",\"mfl\",\"mfm\",\"mfn\",\"mfo\",\"mfp\",\"mfq\",\"mfr\",\"mfs\",\"mft\",\"mfu\",\"mfv\",\"mfw\",\"mfx\",\"mfy\",\"mfz\",\"mga\",\"mgb\",\"mgc\",\"mgd\",\"mge\",\"mgf\",\"mgg\",\"mgh\",\"mgi\",\"mgj\",\"mgk\",\"mgl\",\"mgm\",\"mgn\",\"mgo\",\"mgp\",\"mgq\",\"mgr\",\"mgs\",\"mgt\",\"mgu\",\"mgv\",\"mgw\",\"mgx\",\"mgy\",\"mgz\",\"mha\",\"mhb\",\"mhc\",\"mhd\",\"mhe\",\"mhf\",\"mhg\",\"mhh\",\"mhi\",\"mhj\",\"mhk\",\"mhl\",\"mhm\",\"mhn\",\"mho\",\"mhp\",\"mhq\",\"mhr\",\"mhs\",\"mht\",\"mhu\",\"mhw\",\"mhx\",\"mhy\",\"mhz\",\"mia\",\"mib\",\"mic\",\"mid\",\"mie\",\"mif\",\"mig\",\"mih\",\"mii\",\"mij\",\"mik\",\"mil\",\"mim\",\"min\",\"mio\",\"mip\",\"miq\",\"mir\",\"mis\",\"mit\",\"miu\",\"miw\",\"mix\",\"miy\",\"miz\",\"mja\",\"mjb\",\"mjc\",\"mjd\",\"mje\",\"mjg\",\"mjh\",\"mji\",\"mjj\",\"mjk\",\"mjl\",\"mjm\",\"mjn\",\"mjo\",\"mjp\",\"mjq\",\"mjr\",\"mjs\",\"mjt\",\"mju\",\"mjv\",\"mjw\",\"mjx\",\"mjy\",\"mjz\",\"mka\",\"mkb\",\"mkc\",\"mke\",\"mkf\",\"mkg\",\"mkh\",\"mki\",\"mkj\",\"mkk\",\"mkl\",\"mkm\",\"mkn\",\"mko\",\"mkp\",\"mkq\",\"mkr\",\"mks\",\"mkt\",\"mku\",\"mkv\",\"mkw\",\"mkx\",\"mky\",\"mkz\",\"mla\",\"mlb\",\"mlc\",\"mld\",\"mle\",\"mlf\",\"mlh\",\"mli\",\"mlj\",\"mlk\",\"mll\",\"mlm\",\"mln\",\"mlo\",\"mlp\",\"mlq\",\"mlr\",\"mls\",\"mlu\",\"mlv\",\"mlw\",\"mlx\",\"mlz\",\"mma\",\"mmb\",\"mmc\",\"mmd\",\"mme\",\"mmf\",\"mmg\",\"mmh\",\"mmi\",\"mmj\",\"mmk\",\"mml\",\"mmm\",\"mmn\",\"mmo\",\"mmp\",\"mmq\",\"mmr\",\"mmt\",\"mmu\",\"mmv\",\"mmw\",\"mmx\",\"mmy\",\"mmz\",\"mna\",\"mnb\",\"mnc\",\"mnd\",\"mne\",\"mnf\",\"mng\",\"mnh\",\"mni\",\"mnj\",\"mnk\",\"mnl\",\"mnm\",\"mnn\",\"mno\",\"mnp\",\"mnq\",\"mnr\",\"mns\",\"mnt\",\"mnu\",\"mnv\",\"mnw\",\"mnx\",\"mny\",\"mnz\",\"moa\",\"moc\",\"mod\",\"moe\",\"mof\",\"mog\",\"moh\",\"moi\",\"moj\",\"mok\",\"mom\",\"moo\",\"mop\",\"moq\",\"mor\",\"mos\",\"mot\",\"mou\",\"mov\",\"mow\",\"mox\",\"moy\",\"moz\",\"mpa\",\"mpb\",\"mpc\",\"mpd\",\"mpe\",\"mpg\",\"mph\",\"mpi\",\"mpj\",\"mpk\",\"mpl\",\"mpm\",\"mpn\",\"mpo\",\"mpp\",\"mpq\",\"mpr\",\"mps\",\"mpt\",\"mpu\",\"mpv\",\"mpw\",\"mpx\",\"mpy\",\"mpz\",\"mqa\",\"mqb\",\"mqc\",\"mqe\",\"mqf\",\"mqg\",\"mqh\",\"mqi\",\"mqj\",\"mqk\",\"mql\",\"mqm\",\"mqn\",\"mqo\",\"mqp\",\"mqq\",\"mqr\",\"mqs\",\"mqt\",\"mqu\",\"mqv\",\"mqw\",\"mqx\",\"mqy\",\"mqz\",\"mra\",\"mrb\",\"mrc\",\"mrd\",\"mre\",\"mrf\",\"mrg\",\"mrh\",\"mrj\",\"mrk\",\"mrl\",\"mrm\",\"mrn\",\"mro\",\"mrp\",\"mrq\",\"mrr\",\"mrs\",\"mrt\",\"mru\",\"mrv\",\"mrw\",\"mrx\",\"mry\",\"mrz\",\"msb\",\"msc\",\"msd\",\"mse\",\"msf\",\"msg\",\"msh\",\"msi\",\"msj\",\"msk\",\"msl\",\"msm\",\"msn\",\"mso\",\"msp\",\"msq\",\"msr\",\"mss\",\"mst\",\"msu\",\"msv\",\"msw\",\"msx\",\"msy\",\"msz\",\"mta\",\"mtb\",\"mtc\",\"mtd\",\"mte\",\"mtf\",\"mtg\",\"mth\",\"mti\",\"mtj\",\"mtk\",\"mtl\",\"mtm\",\"mtn\",\"mto\",\"mtp\",\"mtq\",\"mtr\",\"mts\",\"mtt\",\"mtu\",\"mtv\",\"mtw\",\"mtx\",\"mty\",\"mua\",\"mub\",\"muc\",\"mud\",\"mue\",\"mug\",\"muh\",\"mui\",\"muj\",\"muk\",\"mul\",\"mum\",\"mun\",\"muo\",\"mup\",\"muq\",\"mur\",\"mus\",\"mut\",\"muu\",\"muv\",\"mux\",\"muy\",\"muz\",\"mva\",\"mvb\",\"mvd\",\"mve\",\"mvf\",\"mvg\",\"mvh\",\"mvi\",\"mvk\",\"mvl\",\"mvm\",\"mvn\",\"mvo\",\"mvp\",\"mvq\",\"mvr\",\"mvs\",\"mvt\",\"mvu\",\"mvv\",\"mvw\",\"mvx\",\"mvy\",\"mvz\",\"mwa\",\"mwb\",\"mwc\",\"mwd\",\"mwe\",\"mwf\",\"mwg\",\"mwh\",\"mwi\",\"mwj\",\"mwk\",\"mwl\",\"mwm\",\"mwn\",\"mwo\",\"mwp\",\"mwq\",\"mwr\",\"mws\",\"mwt\",\"mwu\",\"mwv\",\"mww\",\"mwx\",\"mwy\",\"mwz\",\"mxa\",\"mxb\",\"mxc\",\"mxd\",\"mxe\",\"mxf\",\"mxg\",\"mxh\",\"mxi\",\"mxj\",\"mxk\",\"mxl\",\"mxm\",\"mxn\",\"mxo\",\"mxp\",\"mxq\",\"mxr\",\"mxs\",\"mxt\",\"mxu\",\"mxv\",\"mxw\",\"mxx\",\"mxy\",\"mxz\",\"myb\",\"myc\",\"myd\",\"mye\",\"myf\",\"myg\",\"myh\",\"myi\",\"myj\",\"myk\",\"myl\",\"mym\",\"myn\",\"myo\",\"myp\",\"myq\",\"myr\",\"mys\",\"myt\",\"myu\",\"myv\",\"myw\",\"myx\",\"myy\",\"myz\",\"mza\",\"mzb\",\"mzc\",\"mzd\",\"mze\",\"mzg\",\"mzh\",\"mzi\",\"mzj\",\"mzk\",\"mzl\",\"mzm\",\"mzn\",\"mzo\",\"mzp\",\"mzq\",\"mzr\",\"mzs\",\"mzt\",\"mzu\",\"mzv\",\"mzw\",\"mzx\",\"mzy\",\"mzz\",\"naa\",\"nab\",\"nac\",\"nad\",\"nae\",\"naf\",\"nag\",\"nah\",\"nai\",\"naj\",\"nak\",\"nal\",\"nam\",\"nan\",\"nao\",\"nap\",\"naq\",\"nar\",\"nas\",\"nat\",\"naw\",\"nax\",\"nay\",\"naz\",\"nba\",\"nbb\",\"nbc\",\"nbd\",\"nbe\",\"nbf\",\"nbg\",\"nbh\",\"nbi\",\"nbj\",\"nbk\",\"nbm\",\"nbn\",\"nbo\",\"nbp\",\"nbq\",\"nbr\",\"nbs\",\"nbt\",\"nbu\",\"nbv\",\"nbw\",\"nbx\",\"nby\",\"nca\",\"ncb\",\"ncc\",\"ncd\",\"nce\",\"ncf\",\"ncg\",\"nch\",\"nci\",\"ncj\",\"nck\",\"ncl\",\"ncm\",\"ncn\",\"nco\",\"ncp\",\"ncq\",\"ncr\",\"ncs\",\"nct\",\"ncu\",\"ncx\",\"ncz\",\"nda\",\"ndb\",\"ndc\",\"ndd\",\"ndf\",\"ndg\",\"ndh\",\"ndi\",\"ndj\",\"ndk\",\"ndl\",\"ndm\",\"ndn\",\"ndp\",\"ndq\",\"ndr\",\"nds\",\"ndt\",\"ndu\",\"ndv\",\"ndw\",\"ndx\",\"ndy\",\"ndz\",\"nea\",\"neb\",\"nec\",\"ned\",\"nee\",\"nef\",\"neg\",\"neh\",\"nei\",\"nej\",\"nek\",\"nem\",\"nen\",\"neo\",\"neq\",\"ner\",\"nes\",\"net\",\"neu\",\"nev\",\"new\",\"nex\",\"ney\",\"nez\",\"nfa\",\"nfd\",\"nfl\",\"nfr\",\"nfu\",\"nga\",\"ngb\",\"ngc\",\"ngd\",\"nge\",\"ngf\",\"ngg\",\"ngh\",\"ngi\",\"ngj\",\"ngk\",\"ngl\",\"ngm\",\"ngn\",\"ngo\",\"ngp\",\"ngq\",\"ngr\",\"ngs\",\"ngt\",\"ngu\",\"ngv\",\"ngw\",\"ngx\",\"ngy\",\"ngz\",\"nha\",\"nhb\",\"nhc\",\"nhd\",\"nhe\",\"nhf\",\"nhg\",\"nhh\",\"nhi\",\"nhk\",\"nhm\",\"nhn\",\"nho\",\"nhp\",\"nhq\",\"nhr\",\"nht\",\"nhu\",\"nhv\",\"nhw\",\"nhx\",\"nhy\",\"nhz\",\"nia\",\"nib\",\"nic\",\"nid\",\"nie\",\"nif\",\"nig\",\"nih\",\"nii\",\"nij\",\"nik\",\"nil\",\"nim\",\"nin\",\"nio\",\"niq\",\"nir\",\"nis\",\"nit\",\"niu\",\"niv\",\"niw\",\"nix\",\"niy\",\"niz\",\"nja\",\"njb\",\"njd\",\"njh\",\"nji\",\"njj\",\"njl\",\"njm\",\"njn\",\"njo\",\"njr\",\"njs\",\"njt\",\"nju\",\"njx\",\"njy\",\"njz\",\"nka\",\"nkb\",\"nkc\",\"nkd\",\"nke\",\"nkf\",\"nkg\",\"nkh\",\"nki\",\"nkj\",\"nkk\",\"nkm\",\"nkn\",\"nko\",\"nkp\",\"nkq\",\"nkr\",\"nks\",\"nkt\",\"nku\",\"nkv\",\"nkw\",\"nkx\",\"nkz\",\"nla\",\"nlc\",\"nle\",\"nlg\",\"nli\",\"nlj\",\"nlk\",\"nll\",\"nln\",\"nlo\",\"nlq\",\"nlr\",\"nlu\",\"nlv\",\"nlw\",\"nlx\",\"nly\",\"nlz\",\"nma\",\"nmb\",\"nmc\",\"nmd\",\"nme\",\"nmf\",\"nmg\",\"nmh\",\"nmi\",\"nmj\",\"nmk\",\"nml\",\"nmm\",\"nmn\",\"nmo\",\"nmp\",\"nmq\",\"nmr\",\"nms\",\"nmt\",\"nmu\",\"nmv\",\"nmw\",\"nmx\",\"nmy\",\"nmz\",\"nna\",\"nnb\",\"nnc\",\"nnd\",\"nne\",\"nnf\",\"nng\",\"nnh\",\"nni\",\"nnj\",\"nnk\",\"nnl\",\"nnm\",\"nnn\",\"nnp\",\"nnq\",\"nnr\",\"nns\",\"nnt\",\"nnu\",\"nnv\",\"nnw\",\"nnx\",\"nny\",\"nnz\",\"noa\",\"noc\",\"nod\",\"noe\",\"nof\",\"nog\",\"noh\",\"noi\",\"noj\",\"nok\",\"nol\",\"nom\",\"non\",\"noo\",\"nop\",\"noq\",\"nos\",\"not\",\"nou\",\"nov\",\"now\",\"noy\",\"noz\",\"npa\",\"npb\",\"npg\",\"nph\",\"npi\",\"npl\",\"npn\",\"npo\",\"nps\",\"npu\",\"npx\",\"npy\",\"nqg\",\"nqk\",\"nql\",\"nqm\",\"nqn\",\"nqo\",\"nqq\",\"nqy\",\"nra\",\"nrb\",\"nrc\",\"nre\",\"nrf\",\"nrg\",\"nri\",\"nrk\",\"nrl\",\"nrm\",\"nrn\",\"nrp\",\"nrr\",\"nrt\",\"nru\",\"nrx\",\"nrz\",\"nsa\",\"nsc\",\"nsd\",\"nse\",\"nsf\",\"nsg\",\"nsh\",\"nsi\",\"nsk\",\"nsl\",\"nsm\",\"nsn\",\"nso\",\"nsp\",\"nsq\",\"nsr\",\"nss\",\"nst\",\"nsu\",\"nsv\",\"nsw\",\"nsx\",\"nsy\",\"nsz\",\"ntd\",\"nte\",\"ntg\",\"nti\",\"ntj\",\"ntk\",\"ntm\",\"nto\",\"ntp\",\"ntr\",\"nts\",\"ntu\",\"ntw\",\"ntx\",\"nty\",\"ntz\",\"nua\",\"nub\",\"nuc\",\"nud\",\"nue\",\"nuf\",\"nug\",\"nuh\",\"nui\",\"nuj\",\"nuk\",\"nul\",\"num\",\"nun\",\"nuo\",\"nup\",\"nuq\",\"nur\",\"nus\",\"nut\",\"nuu\",\"nuv\",\"nuw\",\"nux\",\"nuy\",\"nuz\",\"nvh\",\"nvm\",\"nvo\",\"nwa\",\"nwb\",\"nwc\",\"nwe\",\"nwg\",\"nwi\",\"nwm\",\"nwo\",\"nwr\",\"nwx\",\"nwy\",\"nxa\",\"nxd\",\"nxe\",\"nxg\",\"nxi\",\"nxk\",\"nxl\",\"nxm\",\"nxn\",\"nxo\",\"nxq\",\"nxr\",\"nxu\",\"nxx\",\"nyb\",\"nyc\",\"nyd\",\"nye\",\"nyf\",\"nyg\",\"nyh\",\"nyi\",\"nyj\",\"nyk\",\"nyl\",\"nym\",\"nyn\",\"nyo\",\"nyp\",\"nyq\",\"nyr\",\"nys\",\"nyt\",\"nyu\",\"nyv\",\"nyw\",\"nyx\",\"nyy\",\"nza\",\"nzb\",\"nzi\",\"nzk\",\"nzm\",\"nzs\",\"nzu\",\"nzy\",\"nzz\",\"oaa\",\"oac\",\"oar\",\"oav\",\"obi\",\"obk\",\"obl\",\"obm\",\"obo\",\"obr\",\"obt\",\"obu\",\"oca\",\"och\",\"oco\",\"ocu\",\"oda\",\"odk\",\"odt\",\"odu\",\"ofo\",\"ofs\",\"ofu\",\"ogb\",\"ogc\",\"oge\",\"ogg\",\"ogo\",\"ogu\",\"oht\",\"ohu\",\"oia\",\"oin\",\"ojb\",\"ojc\",\"ojg\",\"ojp\",\"ojs\",\"ojv\",\"ojw\",\"oka\",\"okb\",\"okd\",\"oke\",\"okg\",\"okh\",\"oki\",\"okj\",\"okk\",\"okl\",\"okm\",\"okn\",\"oko\",\"okr\",\"oks\",\"oku\",\"okv\",\"okx\",\"ola\",\"old\",\"ole\",\"olk\",\"olm\",\"olo\",\"olr\",\"olt\",\"olu\",\"oma\",\"omb\",\"omc\",\"ome\",\"omg\",\"omi\",\"omk\",\"oml\",\"omn\",\"omo\",\"omp\",\"omq\",\"omr\",\"omt\",\"omu\",\"omv\",\"omw\",\"omx\",\"ona\",\"onb\",\"one\",\"ong\",\"oni\",\"onj\",\"onk\",\"onn\",\"ono\",\"onp\",\"onr\",\"ons\",\"ont\",\"onu\",\"onw\",\"onx\",\"ood\",\"oog\",\"oon\",\"oor\",\"oos\",\"opa\",\"opk\",\"opm\",\"opo\",\"opt\",\"opy\",\"ora\",\"orc\",\"ore\",\"org\",\"orh\",\"orn\",\"oro\",\"orr\",\"ors\",\"ort\",\"oru\",\"orv\",\"orw\",\"orx\",\"ory\",\"orz\",\"osa\",\"osc\",\"osi\",\"oso\",\"osp\",\"ost\",\"osu\",\"osx\",\"ota\",\"otb\",\"otd\",\"ote\",\"oti\",\"otk\",\"otl\",\"otm\",\"otn\",\"oto\",\"otq\",\"otr\",\"ots\",\"ott\",\"otu\",\"otw\",\"otx\",\"oty\",\"otz\",\"oua\",\"oub\",\"oue\",\"oui\",\"oum\",\"oun\",\"ovd\",\"owi\",\"owl\",\"oyb\",\"oyd\",\"oym\",\"oyy\",\"ozm\",\"paa\",\"pab\",\"pac\",\"pad\",\"pae\",\"paf\",\"pag\",\"pah\",\"pai\",\"pak\",\"pal\",\"pam\",\"pao\",\"pap\",\"paq\",\"par\",\"pas\",\"pat\",\"pau\",\"pav\",\"paw\",\"pax\",\"pay\",\"paz\",\"pbb\",\"pbc\",\"pbe\",\"pbf\",\"pbg\",\"pbh\",\"pbi\",\"pbl\",\"pbn\",\"pbo\",\"pbp\",\"pbr\",\"pbs\",\"pbt\",\"pbu\",\"pbv\",\"pby\",\"pbz\",\"pca\",\"pcb\",\"pcc\",\"pcd\",\"pce\",\"pcf\",\"pcg\",\"pch\",\"pci\",\"pcj\",\"pck\",\"pcl\",\"pcm\",\"pcn\",\"pcp\",\"pcr\",\"pcw\",\"pda\",\"pdc\",\"pdi\",\"pdn\",\"pdo\",\"pdt\",\"pdu\",\"pea\",\"peb\",\"ped\",\"pee\",\"pef\",\"peg\",\"peh\",\"pei\",\"pej\",\"pek\",\"pel\",\"pem\",\"peo\",\"pep\",\"peq\",\"pes\",\"pev\",\"pex\",\"pey\",\"pez\",\"pfa\",\"pfe\",\"pfl\",\"pga\",\"pgd\",\"pgg\",\"pgi\",\"pgk\",\"pgl\",\"pgn\",\"pgs\",\"pgu\",\"pgy\",\"pgz\",\"pha\",\"phd\",\"phg\",\"phh\",\"phi\",\"phk\",\"phl\",\"phm\",\"phn\",\"pho\",\"phq\",\"phr\",\"pht\",\"phu\",\"phv\",\"phw\",\"pia\",\"pib\",\"pic\",\"pid\",\"pie\",\"pif\",\"pig\",\"pih\",\"pii\",\"pij\",\"pil\",\"pim\",\"pin\",\"pio\",\"pip\",\"pir\",\"pis\",\"pit\",\"piu\",\"piv\",\"piw\",\"pix\",\"piy\",\"piz\",\"pjt\",\"pka\",\"pkb\",\"pkc\",\"pkg\",\"pkh\",\"pkn\",\"pko\",\"pkp\",\"pkr\",\"pks\",\"pkt\",\"pku\",\"pla\",\"plb\",\"plc\",\"pld\",\"ple\",\"plf\",\"plg\",\"plh\",\"plj\",\"plk\",\"pll\",\"pln\",\"plo\",\"plp\",\"plq\",\"plr\",\"pls\",\"plt\",\"plu\",\"plv\",\"plw\",\"ply\",\"plz\",\"pma\",\"pmb\",\"pmc\",\"pmd\",\"pme\",\"pmf\",\"pmh\",\"pmi\",\"pmj\",\"pmk\",\"pml\",\"pmm\",\"pmn\",\"pmo\",\"pmq\",\"pmr\",\"pms\",\"pmt\",\"pmu\",\"pmw\",\"pmx\",\"pmy\",\"pmz\",\"pna\",\"pnb\",\"pnc\",\"pne\",\"png\",\"pnh\",\"pni\",\"pnj\",\"pnk\",\"pnl\",\"pnm\",\"pnn\",\"pno\",\"pnp\",\"pnq\",\"pnr\",\"pns\",\"pnt\",\"pnu\",\"pnv\",\"pnw\",\"pnx\",\"pny\",\"pnz\",\"poc\",\"pod\",\"poe\",\"pof\",\"pog\",\"poh\",\"poi\",\"pok\",\"pom\",\"pon\",\"poo\",\"pop\",\"poq\",\"pos\",\"pot\",\"pov\",\"pow\",\"pox\",\"poy\",\"poz\",\"ppa\",\"ppe\",\"ppi\",\"ppk\",\"ppl\",\"ppm\",\"ppn\",\"ppo\",\"ppp\",\"ppq\",\"ppr\",\"pps\",\"ppt\",\"ppu\",\"pqa\",\"pqe\",\"pqm\",\"pqw\",\"pra\",\"prb\",\"prc\",\"prd\",\"pre\",\"prf\",\"prg\",\"prh\",\"pri\",\"prk\",\"prl\",\"prm\",\"prn\",\"pro\",\"prp\",\"prq\",\"prr\",\"prs\",\"prt\",\"pru\",\"prw\",\"prx\",\"pry\",\"prz\",\"psa\",\"psc\",\"psd\",\"pse\",\"psg\",\"psh\",\"psi\",\"psl\",\"psm\",\"psn\",\"pso\",\"psp\",\"psq\",\"psr\",\"pss\",\"pst\",\"psu\",\"psw\",\"psy\",\"pta\",\"pth\",\"pti\",\"ptn\",\"pto\",\"ptp\",\"ptq\",\"ptr\",\"ptt\",\"ptu\",\"ptv\",\"ptw\",\"pty\",\"pua\",\"pub\",\"puc\",\"pud\",\"pue\",\"puf\",\"pug\",\"pui\",\"puj\",\"puk\",\"pum\",\"puo\",\"pup\",\"puq\",\"pur\",\"put\",\"puu\",\"puw\",\"pux\",\"puy\",\"puz\",\"pwa\",\"pwb\",\"pwg\",\"pwi\",\"pwm\",\"pwn\",\"pwo\",\"pwr\",\"pww\",\"pxm\",\"pye\",\"pym\",\"pyn\",\"pys\",\"pyu\",\"pyx\",\"pyy\",\"pzn\",\"qaa..qtz\",\"qua\",\"qub\",\"quc\",\"qud\",\"quf\",\"qug\",\"quh\",\"qui\",\"quk\",\"qul\",\"qum\",\"qun\",\"qup\",\"quq\",\"qur\",\"qus\",\"quv\",\"quw\",\"qux\",\"quy\",\"quz\",\"qva\",\"qvc\",\"qve\",\"qvh\",\"qvi\",\"qvj\",\"qvl\",\"qvm\",\"qvn\",\"qvo\",\"qvp\",\"qvs\",\"qvw\",\"qvy\",\"qvz\",\"qwa\",\"qwc\",\"qwe\",\"qwh\",\"qwm\",\"qws\",\"qwt\",\"qxa\",\"qxc\",\"qxh\",\"qxl\",\"qxn\",\"qxo\",\"qxp\",\"qxq\",\"qxr\",\"qxs\",\"qxt\",\"qxu\",\"qxw\",\"qya\",\"qyp\",\"raa\",\"rab\",\"rac\",\"rad\",\"raf\",\"rag\",\"rah\",\"rai\",\"raj\",\"rak\",\"ral\",\"ram\",\"ran\",\"rao\",\"rap\",\"raq\",\"rar\",\"ras\",\"rat\",\"rau\",\"rav\",\"raw\",\"rax\",\"ray\",\"raz\",\"rbb\",\"rbk\",\"rbl\",\"rbp\",\"rcf\",\"rdb\",\"rea\",\"reb\",\"ree\",\"reg\",\"rei\",\"rej\",\"rel\",\"rem\",\"ren\",\"rer\",\"res\",\"ret\",\"rey\",\"rga\",\"rge\",\"rgk\",\"rgn\",\"rgr\",\"rgs\",\"rgu\",\"rhg\",\"rhp\",\"ria\",\"rie\",\"rif\",\"ril\",\"rim\",\"rin\",\"rir\",\"rit\",\"riu\",\"rjg\",\"rji\",\"rjs\",\"rka\",\"rkb\",\"rkh\",\"rki\",\"rkm\",\"rkt\",\"rkw\",\"rma\",\"rmb\",\"rmc\",\"rmd\",\"rme\",\"rmf\",\"rmg\",\"rmh\",\"rmi\",\"rmk\",\"rml\",\"rmm\",\"rmn\",\"rmo\",\"rmp\",\"rmq\",\"rmr\",\"rms\",\"rmt\",\"rmu\",\"rmv\",\"rmw\",\"rmx\",\"rmy\",\"rmz\",\"rna\",\"rnd\",\"rng\",\"rnl\",\"rnn\",\"rnp\",\"rnr\",\"rnw\",\"roa\",\"rob\",\"roc\",\"rod\",\"roe\",\"rof\",\"rog\",\"rol\",\"rom\",\"roo\",\"rop\",\"ror\",\"rou\",\"row\",\"rpn\",\"rpt\",\"rri\",\"rro\",\"rrt\",\"rsb\",\"rsi\",\"rsl\",\"rsm\",\"rtc\",\"rth\",\"rtm\",\"rts\",\"rtw\",\"rub\",\"ruc\",\"rue\",\"ruf\",\"rug\",\"ruh\",\"rui\",\"ruk\",\"ruo\",\"rup\",\"ruq\",\"rut\",\"ruu\",\"ruy\",\"ruz\",\"rwa\",\"rwk\",\"rwm\",\"rwo\",\"rwr\",\"rxd\",\"rxw\",\"ryn\",\"rys\",\"ryu\",\"rzh\",\"saa\",\"sab\",\"sac\",\"sad\",\"sae\",\"saf\",\"sah\",\"sai\",\"saj\",\"sak\",\"sal\",\"sam\",\"sao\",\"sap\",\"saq\",\"sar\",\"sas\",\"sat\",\"sau\",\"sav\",\"saw\",\"sax\",\"say\",\"saz\",\"sba\",\"sbb\",\"sbc\",\"sbd\",\"sbe\",\"sbf\",\"sbg\",\"sbh\",\"sbi\",\"sbj\",\"sbk\",\"sbl\",\"sbm\",\"sbn\",\"sbo\",\"sbp\",\"sbq\",\"sbr\",\"sbs\",\"sbt\",\"sbu\",\"sbv\",\"sbw\",\"sbx\",\"sby\",\"sbz\",\"sca\",\"scb\",\"sce\",\"scf\",\"scg\",\"sch\",\"sci\",\"sck\",\"scl\",\"scn\",\"sco\",\"scp\",\"scq\",\"scs\",\"sct\",\"scu\",\"scv\",\"scw\",\"scx\",\"sda\",\"sdb\",\"sdc\",\"sde\",\"sdf\",\"sdg\",\"sdh\",\"sdj\",\"sdk\",\"sdl\",\"sdm\",\"sdn\",\"sdo\",\"sdp\",\"sdr\",\"sds\",\"sdt\",\"sdu\",\"sdv\",\"sdx\",\"sdz\",\"sea\",\"seb\",\"sec\",\"sed\",\"see\",\"sef\",\"seg\",\"seh\",\"sei\",\"sej\",\"sek\",\"sel\",\"sem\",\"sen\",\"seo\",\"sep\",\"seq\",\"ser\",\"ses\",\"set\",\"seu\",\"sev\",\"sew\",\"sey\",\"sez\",\"sfb\",\"sfe\",\"sfm\",\"sfs\",\"sfw\",\"sga\",\"sgb\",\"sgc\",\"sgd\",\"sge\",\"sgg\",\"sgh\",\"sgi\",\"sgj\",\"sgk\",\"sgl\",\"sgm\",\"sgn\",\"sgo\",\"sgp\",\"sgr\",\"sgs\",\"sgt\",\"sgu\",\"sgw\",\"sgx\",\"sgy\",\"sgz\",\"sha\",\"shb\",\"shc\",\"shd\",\"she\",\"shg\",\"shh\",\"shi\",\"shj\",\"shk\",\"shl\",\"shm\",\"shn\",\"sho\",\"shp\",\"shq\",\"shr\",\"shs\",\"sht\",\"shu\",\"shv\",\"shw\",\"shx\",\"shy\",\"shz\",\"sia\",\"sib\",\"sid\",\"sie\",\"sif\",\"sig\",\"sih\",\"sii\",\"sij\",\"sik\",\"sil\",\"sim\",\"sio\",\"sip\",\"siq\",\"sir\",\"sis\",\"sit\",\"siu\",\"siv\",\"siw\",\"six\",\"siy\",\"siz\",\"sja\",\"sjb\",\"sjd\",\"sje\",\"sjg\",\"sjk\",\"sjl\",\"sjm\",\"sjn\",\"sjo\",\"sjp\",\"sjr\",\"sjs\",\"sjt\",\"sju\",\"sjw\",\"ska\",\"skb\",\"skc\",\"skd\",\"ske\",\"skf\",\"skg\",\"skh\",\"ski\",\"skj\",\"skk\",\"skm\",\"skn\",\"sko\",\"skp\",\"skq\",\"skr\",\"sks\",\"skt\",\"sku\",\"skv\",\"skw\",\"skx\",\"sky\",\"skz\",\"sla\",\"slc\",\"sld\",\"sle\",\"slf\",\"slg\",\"slh\",\"sli\",\"slj\",\"sll\",\"slm\",\"sln\",\"slp\",\"slq\",\"slr\",\"sls\",\"slt\",\"slu\",\"slw\",\"slx\",\"sly\",\"slz\",\"sma\",\"smb\",\"smc\",\"smd\",\"smf\",\"smg\",\"smh\",\"smi\",\"smj\",\"smk\",\"sml\",\"smm\",\"smn\",\"smp\",\"smq\",\"smr\",\"sms\",\"smt\",\"smu\",\"smv\",\"smw\",\"smx\",\"smy\",\"smz\",\"snb\",\"snc\",\"sne\",\"snf\",\"sng\",\"snh\",\"sni\",\"snj\",\"snk\",\"snl\",\"snm\",\"snn\",\"sno\",\"snp\",\"snq\",\"snr\",\"sns\",\"snu\",\"snv\",\"snw\",\"snx\",\"sny\",\"snz\",\"soa\",\"sob\",\"soc\",\"sod\",\"soe\",\"sog\",\"soh\",\"soi\",\"soj\",\"sok\",\"sol\",\"son\",\"soo\",\"sop\",\"soq\",\"sor\",\"sos\",\"sou\",\"sov\",\"sow\",\"sox\",\"soy\",\"soz\",\"spb\",\"spc\",\"spd\",\"spe\",\"spg\",\"spi\",\"spk\",\"spl\",\"spm\",\"spn\",\"spo\",\"spp\",\"spq\",\"spr\",\"sps\",\"spt\",\"spu\",\"spv\",\"spx\",\"spy\",\"sqa\",\"sqh\",\"sqj\",\"sqk\",\"sqm\",\"sqn\",\"sqo\",\"sqq\",\"sqr\",\"sqs\",\"sqt\",\"squ\",\"sra\",\"srb\",\"src\",\"sre\",\"srf\",\"srg\",\"srh\",\"sri\",\"srk\",\"srl\",\"srm\",\"srn\",\"sro\",\"srq\",\"srr\",\"srs\",\"srt\",\"sru\",\"srv\",\"srw\",\"srx\",\"sry\",\"srz\",\"ssa\",\"ssb\",\"ssc\",\"ssd\",\"sse\",\"ssf\",\"ssg\",\"ssh\",\"ssi\",\"ssj\",\"ssk\",\"ssl\",\"ssm\",\"ssn\",\"sso\",\"ssp\",\"ssq\",\"ssr\",\"sss\",\"sst\",\"ssu\",\"ssv\",\"ssx\",\"ssy\",\"ssz\",\"sta\",\"stb\",\"std\",\"ste\",\"stf\",\"stg\",\"sth\",\"sti\",\"stj\",\"stk\",\"stl\",\"stm\",\"stn\",\"sto\",\"stp\",\"stq\",\"str\",\"sts\",\"stt\",\"stu\",\"stv\",\"stw\",\"sty\",\"sua\",\"sub\",\"suc\",\"sue\",\"sug\",\"sui\",\"suj\",\"suk\",\"sul\",\"sum\",\"suq\",\"sur\",\"sus\",\"sut\",\"suv\",\"suw\",\"sux\",\"suy\",\"suz\",\"sva\",\"svb\",\"svc\",\"sve\",\"svk\",\"svm\",\"svr\",\"svs\",\"svx\",\"swb\",\"swc\",\"swf\",\"swg\",\"swh\",\"swi\",\"swj\",\"swk\",\"swl\",\"swm\",\"swn\",\"swo\",\"swp\",\"swq\",\"swr\",\"sws\",\"swt\",\"swu\",\"swv\",\"sww\",\"swx\",\"swy\",\"sxb\",\"sxc\",\"sxe\",\"sxg\",\"sxk\",\"sxl\",\"sxm\",\"sxn\",\"sxo\",\"sxr\",\"sxs\",\"sxu\",\"sxw\",\"sya\",\"syb\",\"syc\",\"syd\",\"syi\",\"syk\",\"syl\",\"sym\",\"syn\",\"syo\",\"syr\",\"sys\",\"syw\",\"syx\",\"syy\",\"sza\",\"szb\",\"szc\",\"szd\",\"sze\",\"szg\",\"szl\",\"szn\",\"szp\",\"szs\",\"szv\",\"szw\",\"taa\",\"tab\",\"tac\",\"tad\",\"tae\",\"taf\",\"tag\",\"tai\",\"taj\",\"tak\",\"tal\",\"tan\",\"tao\",\"tap\",\"taq\",\"tar\",\"tas\",\"tau\",\"tav\",\"taw\",\"tax\",\"tay\",\"taz\",\"tba\",\"tbb\",\"tbc\",\"tbd\",\"tbe\",\"tbf\",\"tbg\",\"tbh\",\"tbi\",\"tbj\",\"tbk\",\"tbl\",\"tbm\",\"tbn\",\"tbo\",\"tbp\",\"tbq\",\"tbr\",\"tbs\",\"tbt\",\"tbu\",\"tbv\",\"tbw\",\"tbx\",\"tby\",\"tbz\",\"tca\",\"tcb\",\"tcc\",\"tcd\",\"tce\",\"tcf\",\"tcg\",\"tch\",\"tci\",\"tck\",\"tcl\",\"tcm\",\"tcn\",\"tco\",\"tcp\",\"tcq\",\"tcs\",\"tct\",\"tcu\",\"tcw\",\"tcx\",\"tcy\",\"tcz\",\"tda\",\"tdb\",\"tdc\",\"tdd\",\"tde\",\"tdf\",\"tdg\",\"tdh\",\"tdi\",\"tdj\",\"tdk\",\"tdl\",\"tdm\",\"tdn\",\"tdo\",\"tdq\",\"tdr\",\"tds\",\"tdt\",\"tdu\",\"tdv\",\"tdx\",\"tdy\",\"tea\",\"teb\",\"tec\",\"ted\",\"tee\",\"tef\",\"teg\",\"teh\",\"tei\",\"tek\",\"tem\",\"ten\",\"teo\",\"tep\",\"teq\",\"ter\",\"tes\",\"tet\",\"teu\",\"tev\",\"tew\",\"tex\",\"tey\",\"tfi\",\"tfn\",\"tfo\",\"tfr\",\"tft\",\"tga\",\"tgb\",\"tgc\",\"tgd\",\"tge\",\"tgf\",\"tgg\",\"tgh\",\"tgi\",\"tgj\",\"tgn\",\"tgo\",\"tgp\",\"tgq\",\"tgr\",\"tgs\",\"tgt\",\"tgu\",\"tgv\",\"tgw\",\"tgx\",\"tgy\",\"tgz\",\"thc\",\"thd\",\"the\",\"thf\",\"thh\",\"thi\",\"thk\",\"thl\",\"thm\",\"thn\",\"thp\",\"thq\",\"thr\",\"ths\",\"tht\",\"thu\",\"thv\",\"thw\",\"thx\",\"thy\",\"thz\",\"tia\",\"tic\",\"tid\",\"tie\",\"tif\",\"tig\",\"tih\",\"tii\",\"tij\",\"tik\",\"til\",\"tim\",\"tin\",\"tio\",\"tip\",\"tiq\",\"tis\",\"tit\",\"tiu\",\"tiv\",\"tiw\",\"tix\",\"tiy\",\"tiz\",\"tja\",\"tjg\",\"tji\",\"tjl\",\"tjm\",\"tjn\",\"tjo\",\"tjs\",\"tju\",\"tjw\",\"tka\",\"tkb\",\"tkd\",\"tke\",\"tkf\",\"tkg\",\"tkk\",\"tkl\",\"tkm\",\"tkn\",\"tkp\",\"tkq\",\"tkr\",\"tks\",\"tkt\",\"tku\",\"tkv\",\"tkw\",\"tkx\",\"tkz\",\"tla\",\"tlb\",\"tlc\",\"tld\",\"tlf\",\"tlg\",\"tlh\",\"tli\",\"tlj\",\"tlk\",\"tll\",\"tlm\",\"tln\",\"tlo\",\"tlp\",\"tlq\",\"tlr\",\"tls\",\"tlt\",\"tlu\",\"tlv\",\"tlw\",\"tlx\",\"tly\",\"tma\",\"tmb\",\"tmc\",\"tmd\",\"tme\",\"tmf\",\"tmg\",\"tmh\",\"tmi\",\"tmj\",\"tmk\",\"tml\",\"tmm\",\"tmn\",\"tmo\",\"tmp\",\"tmq\",\"tmr\",\"tms\",\"tmt\",\"tmu\",\"tmv\",\"tmw\",\"tmy\",\"tmz\",\"tna\",\"tnb\",\"tnc\",\"tnd\",\"tne\",\"tnf\",\"tng\",\"tnh\",\"tni\",\"tnk\",\"tnl\",\"tnm\",\"tnn\",\"tno\",\"tnp\",\"tnq\",\"tnr\",\"tns\",\"tnt\",\"tnu\",\"tnv\",\"tnw\",\"tnx\",\"tny\",\"tnz\",\"tob\",\"toc\",\"tod\",\"toe\",\"tof\",\"tog\",\"toh\",\"toi\",\"toj\",\"tol\",\"tom\",\"too\",\"top\",\"toq\",\"tor\",\"tos\",\"tou\",\"tov\",\"tow\",\"tox\",\"toy\",\"toz\",\"tpa\",\"tpc\",\"tpe\",\"tpf\",\"tpg\",\"tpi\",\"tpj\",\"tpk\",\"tpl\",\"tpm\",\"tpn\",\"tpo\",\"tpp\",\"tpq\",\"tpr\",\"tpt\",\"tpu\",\"tpv\",\"tpw\",\"tpx\",\"tpy\",\"tpz\",\"tqb\",\"tql\",\"tqm\",\"tqn\",\"tqo\",\"tqp\",\"tqq\",\"tqr\",\"tqt\",\"tqu\",\"tqw\",\"tra\",\"trb\",\"trc\",\"trd\",\"tre\",\"trf\",\"trg\",\"trh\",\"tri\",\"trj\",\"trk\",\"trl\",\"trm\",\"trn\",\"tro\",\"trp\",\"trq\",\"trr\",\"trs\",\"trt\",\"tru\",\"trv\",\"trw\",\"trx\",\"try\",\"trz\",\"tsa\",\"tsb\",\"tsc\",\"tsd\",\"tse\",\"tsf\",\"tsg\",\"tsh\",\"tsi\",\"tsj\",\"tsk\",\"tsl\",\"tsm\",\"tsp\",\"tsq\",\"tsr\",\"tss\",\"tst\",\"tsu\",\"tsv\",\"tsw\",\"tsx\",\"tsy\",\"tsz\",\"tta\",\"ttb\",\"ttc\",\"ttd\",\"tte\",\"ttf\",\"ttg\",\"tth\",\"tti\",\"ttj\",\"ttk\",\"ttl\",\"ttm\",\"ttn\",\"tto\",\"ttp\",\"ttq\",\"ttr\",\"tts\",\"ttt\",\"ttu\",\"ttv\",\"ttw\",\"tty\",\"ttz\",\"tua\",\"tub\",\"tuc\",\"tud\",\"tue\",\"tuf\",\"tug\",\"tuh\",\"tui\",\"tuj\",\"tul\",\"tum\",\"tun\",\"tuo\",\"tup\",\"tuq\",\"tus\",\"tut\",\"tuu\",\"tuv\",\"tuw\",\"tux\",\"tuy\",\"tuz\",\"tva\",\"tvd\",\"tve\",\"tvk\",\"tvl\",\"tvm\",\"tvn\",\"tvo\",\"tvs\",\"tvt\",\"tvu\",\"tvw\",\"tvy\",\"twa\",\"twb\",\"twc\",\"twd\",\"twe\",\"twf\",\"twg\",\"twh\",\"twl\",\"twm\",\"twn\",\"two\",\"twp\",\"twq\",\"twr\",\"twt\",\"twu\",\"tww\",\"twx\",\"twy\",\"txa\",\"txb\",\"txc\",\"txe\",\"txg\",\"txh\",\"txi\",\"txj\",\"txm\",\"txn\",\"txo\",\"txq\",\"txr\",\"txs\",\"txt\",\"txu\",\"txx\",\"txy\",\"tya\",\"tye\",\"tyh\",\"tyi\",\"tyj\",\"tyl\",\"tyn\",\"typ\",\"tyr\",\"tys\",\"tyt\",\"tyu\",\"tyv\",\"tyx\",\"tyz\",\"tza\",\"tzh\",\"tzj\",\"tzl\",\"tzm\",\"tzn\",\"tzo\",\"tzx\",\"uam\",\"uan\",\"uar\",\"uba\",\"ubi\",\"ubl\",\"ubr\",\"ubu\",\"uby\",\"uda\",\"ude\",\"udg\",\"udi\",\"udj\",\"udl\",\"udm\",\"udu\",\"ues\",\"ufi\",\"uga\",\"ugb\",\"uge\",\"ugn\",\"ugo\",\"ugy\",\"uha\",\"uhn\",\"uis\",\"uiv\",\"uji\",\"uka\",\"ukg\",\"ukh\",\"ukk\",\"ukl\",\"ukp\",\"ukq\",\"uks\",\"uku\",\"ukw\",\"uky\",\"ula\",\"ulb\",\"ulc\",\"ule\",\"ulf\",\"uli\",\"ulk\",\"ull\",\"ulm\",\"uln\",\"ulu\",\"ulw\",\"uma\",\"umb\",\"umc\",\"umd\",\"umg\",\"umi\",\"umm\",\"umn\",\"umo\",\"ump\",\"umr\",\"ums\",\"umu\",\"una\",\"und\",\"une\",\"ung\",\"unk\",\"unm\",\"unn\",\"unp\",\"unr\",\"unu\",\"unx\",\"unz\",\"uok\",\"upi\",\"upv\",\"ura\",\"urb\",\"urc\",\"ure\",\"urf\",\"urg\",\"urh\",\"uri\",\"urj\",\"urk\",\"url\",\"urm\",\"urn\",\"uro\",\"urp\",\"urr\",\"urt\",\"uru\",\"urv\",\"urw\",\"urx\",\"ury\",\"urz\",\"usa\",\"ush\",\"usi\",\"usk\",\"usp\",\"usu\",\"uta\",\"ute\",\"utp\",\"utr\",\"utu\",\"uum\",\"uun\",\"uur\",\"uuu\",\"uve\",\"uvh\",\"uvl\",\"uwa\",\"uya\",\"uzn\",\"uzs\",\"vaa\",\"vae\",\"vaf\",\"vag\",\"vah\",\"vai\",\"vaj\",\"val\",\"vam\",\"van\",\"vao\",\"vap\",\"var\",\"vas\",\"vau\",\"vav\",\"vay\",\"vbb\",\"vbk\",\"vec\",\"ved\",\"vel\",\"vem\",\"veo\",\"vep\",\"ver\",\"vgr\",\"vgt\",\"vic\",\"vid\",\"vif\",\"vig\",\"vil\",\"vin\",\"vis\",\"vit\",\"viv\",\"vka\",\"vki\",\"vkj\",\"vkk\",\"vkl\",\"vkm\",\"vko\",\"vkp\",\"vkt\",\"vku\",\"vlp\",\"vls\",\"vma\",\"vmb\",\"vmc\",\"vmd\",\"vme\",\"vmf\",\"vmg\",\"vmh\",\"vmi\",\"vmj\",\"vmk\",\"vml\",\"vmm\",\"vmp\",\"vmq\",\"vmr\",\"vms\",\"vmu\",\"vmv\",\"vmw\",\"vmx\",\"vmy\",\"vmz\",\"vnk\",\"vnm\",\"vnp\",\"vor\",\"vot\",\"vra\",\"vro\",\"vrs\",\"vrt\",\"vsi\",\"vsl\",\"vsv\",\"vto\",\"vum\",\"vun\",\"vut\",\"vwa\",\"waa\",\"wab\",\"wac\",\"wad\",\"wae\",\"waf\",\"wag\",\"wah\",\"wai\",\"waj\",\"wak\",\"wal\",\"wam\",\"wan\",\"wao\",\"wap\",\"waq\",\"war\",\"was\",\"wat\",\"wau\",\"wav\",\"waw\",\"wax\",\"way\",\"waz\",\"wba\",\"wbb\",\"wbe\",\"wbf\",\"wbh\",\"wbi\",\"wbj\",\"wbk\",\"wbl\",\"wbm\",\"wbp\",\"wbq\",\"wbr\",\"wbs\",\"wbt\",\"wbv\",\"wbw\",\"wca\",\"wci\",\"wdd\",\"wdg\",\"wdj\",\"wdk\",\"wdu\",\"wdy\",\"wea\",\"wec\",\"wed\",\"weg\",\"weh\",\"wei\",\"wem\",\"wen\",\"weo\",\"wep\",\"wer\",\"wes\",\"wet\",\"weu\",\"wew\",\"wfg\",\"wga\",\"wgb\",\"wgg\",\"wgi\",\"wgo\",\"wgu\",\"wgw\",\"wgy\",\"wha\",\"whg\",\"whk\",\"whu\",\"wib\",\"wic\",\"wie\",\"wif\",\"wig\",\"wih\",\"wii\",\"wij\",\"wik\",\"wil\",\"wim\",\"win\",\"wir\",\"wit\",\"wiu\",\"wiv\",\"wiw\",\"wiy\",\"wja\",\"wji\",\"wka\",\"wkb\",\"wkd\",\"wkl\",\"wku\",\"wkw\",\"wky\",\"wla\",\"wlc\",\"wle\",\"wlg\",\"wli\",\"wlk\",\"wll\",\"wlm\",\"wlo\",\"wlr\",\"wls\",\"wlu\",\"wlv\",\"wlw\",\"wlx\",\"wly\",\"wma\",\"wmb\",\"wmc\",\"wmd\",\"wme\",\"wmh\",\"wmi\",\"wmm\",\"wmn\",\"wmo\",\"wms\",\"wmt\",\"wmw\",\"wmx\",\"wnb\",\"wnc\",\"wnd\",\"wne\",\"wng\",\"wni\",\"wnk\",\"wnm\",\"wnn\",\"wno\",\"wnp\",\"wnu\",\"wnw\",\"wny\",\"woa\",\"wob\",\"woc\",\"wod\",\"woe\",\"wof\",\"wog\",\"woi\",\"wok\",\"wom\",\"won\",\"woo\",\"wor\",\"wos\",\"wow\",\"woy\",\"wpc\",\"wra\",\"wrb\",\"wrd\",\"wrg\",\"wrh\",\"wri\",\"wrk\",\"wrl\",\"wrm\",\"wrn\",\"wro\",\"wrp\",\"wrr\",\"wrs\",\"wru\",\"wrv\",\"wrw\",\"wrx\",\"wry\",\"wrz\",\"wsa\",\"wsg\",\"wsi\",\"wsk\",\"wsr\",\"wss\",\"wsu\",\"wsv\",\"wtf\",\"wth\",\"wti\",\"wtk\",\"wtm\",\"wtw\",\"wua\",\"wub\",\"wud\",\"wuh\",\"wul\",\"wum\",\"wun\",\"wur\",\"wut\",\"wuu\",\"wuv\",\"wux\",\"wuy\",\"wwa\",\"wwb\",\"wwo\",\"wwr\",\"www\",\"wxa\",\"wxw\",\"wya\",\"wyb\",\"wyi\",\"wym\",\"wyr\",\"wyy\",\"xaa\",\"xab\",\"xac\",\"xad\",\"xae\",\"xag\",\"xai\",\"xaj\",\"xak\",\"xal\",\"xam\",\"xan\",\"xao\",\"xap\",\"xaq\",\"xar\",\"xas\",\"xat\",\"xau\",\"xav\",\"xaw\",\"xay\",\"xba\",\"xbb\",\"xbc\",\"xbd\",\"xbe\",\"xbg\",\"xbi\",\"xbj\",\"xbm\",\"xbn\",\"xbo\",\"xbp\",\"xbr\",\"xbw\",\"xbx\",\"xby\",\"xcb\",\"xcc\",\"xce\",\"xcg\",\"xch\",\"xcl\",\"xcm\",\"xcn\",\"xco\",\"xcr\",\"xct\",\"xcu\",\"xcv\",\"xcw\",\"xcy\",\"xda\",\"xdc\",\"xdk\",\"xdm\",\"xdo\",\"xdy\",\"xeb\",\"xed\",\"xeg\",\"xel\",\"xem\",\"xep\",\"xer\",\"xes\",\"xet\",\"xeu\",\"xfa\",\"xga\",\"xgb\",\"xgd\",\"xgf\",\"xgg\",\"xgi\",\"xgl\",\"xgm\",\"xgn\",\"xgr\",\"xgu\",\"xgw\",\"xha\",\"xhc\",\"xhd\",\"xhe\",\"xhr\",\"xht\",\"xhu\",\"xhv\",\"xia\",\"xib\",\"xii\",\"xil\",\"xin\",\"xip\",\"xir\",\"xis\",\"xiv\",\"xiy\",\"xjb\",\"xjt\",\"xka\",\"xkb\",\"xkc\",\"xkd\",\"xke\",\"xkf\",\"xkg\",\"xkh\",\"xki\",\"xkj\",\"xkk\",\"xkl\",\"xkn\",\"xko\",\"xkp\",\"xkq\",\"xkr\",\"xks\",\"xkt\",\"xku\",\"xkv\",\"xkw\",\"xkx\",\"xky\",\"xkz\",\"xla\",\"xlb\",\"xlc\",\"xld\",\"xle\",\"xlg\",\"xli\",\"xln\",\"xlo\",\"xlp\",\"xls\",\"xlu\",\"xly\",\"xma\",\"xmb\",\"xmc\",\"xmd\",\"xme\",\"xmf\",\"xmg\",\"xmh\",\"xmj\",\"xmk\",\"xml\",\"xmm\",\"xmn\",\"xmo\",\"xmp\",\"xmq\",\"xmr\",\"xms\",\"xmt\",\"xmu\",\"xmv\",\"xmw\",\"xmx\",\"xmy\",\"xmz\",\"xna\",\"xnb\",\"xnd\",\"xng\",\"xnh\",\"xni\",\"xnk\",\"xnn\",\"xno\",\"xnr\",\"xns\",\"xnt\",\"xnu\",\"xny\",\"xnz\",\"xoc\",\"xod\",\"xog\",\"xoi\",\"xok\",\"xom\",\"xon\",\"xoo\",\"xop\",\"xor\",\"xow\",\"xpa\",\"xpc\",\"xpe\",\"xpg\",\"xpi\",\"xpj\",\"xpk\",\"xpm\",\"xpn\",\"xpo\",\"xpp\",\"xpq\",\"xpr\",\"xps\",\"xpt\",\"xpu\",\"xpy\",\"xqa\",\"xqt\",\"xra\",\"xrb\",\"xrd\",\"xre\",\"xrg\",\"xri\",\"xrm\",\"xrn\",\"xrq\",\"xrr\",\"xrt\",\"xru\",\"xrw\",\"xsa\",\"xsb\",\"xsc\",\"xsd\",\"xse\",\"xsh\",\"xsi\",\"xsj\",\"xsl\",\"xsm\",\"xsn\",\"xso\",\"xsp\",\"xsq\",\"xsr\",\"xss\",\"xsu\",\"xsv\",\"xsy\",\"xta\",\"xtb\",\"xtc\",\"xtd\",\"xte\",\"xtg\",\"xth\",\"xti\",\"xtj\",\"xtl\",\"xtm\",\"xtn\",\"xto\",\"xtp\",\"xtq\",\"xtr\",\"xts\",\"xtt\",\"xtu\",\"xtv\",\"xtw\",\"xty\",\"xtz\",\"xua\",\"xub\",\"xud\",\"xug\",\"xuj\",\"xul\",\"xum\",\"xun\",\"xuo\",\"xup\",\"xur\",\"xut\",\"xuu\",\"xve\",\"xvi\",\"xvn\",\"xvo\",\"xvs\",\"xwa\",\"xwc\",\"xwd\",\"xwe\",\"xwg\",\"xwj\",\"xwk\",\"xwl\",\"xwo\",\"xwr\",\"xwt\",\"xww\",\"xxb\",\"xxk\",\"xxm\",\"xxr\",\"xxt\",\"xya\",\"xyb\",\"xyj\",\"xyk\",\"xyl\",\"xyt\",\"xyy\",\"xzh\",\"xzm\",\"xzp\",\"yaa\",\"yab\",\"yac\",\"yad\",\"yae\",\"yaf\",\"yag\",\"yah\",\"yai\",\"yaj\",\"yak\",\"yal\",\"yam\",\"yan\",\"yao\",\"yap\",\"yaq\",\"yar\",\"yas\",\"yat\",\"yau\",\"yav\",\"yaw\",\"yax\",\"yay\",\"yaz\",\"yba\",\"ybb\",\"ybd\",\"ybe\",\"ybh\",\"ybi\",\"ybj\",\"ybk\",\"ybl\",\"ybm\",\"ybn\",\"ybo\",\"ybx\",\"yby\",\"ych\",\"ycl\",\"ycn\",\"ycp\",\"yda\",\"ydd\",\"yde\",\"ydg\",\"ydk\",\"yds\",\"yea\",\"yec\",\"yee\",\"yei\",\"yej\",\"yel\",\"yen\",\"yer\",\"yes\",\"yet\",\"yeu\",\"yev\",\"yey\",\"yga\",\"ygi\",\"ygl\",\"ygm\",\"ygp\",\"ygr\",\"ygs\",\"ygu\",\"ygw\",\"yha\",\"yhd\",\"yhl\",\"yhs\",\"yia\",\"yif\",\"yig\",\"yih\",\"yii\",\"yij\",\"yik\",\"yil\",\"yim\",\"yin\",\"yip\",\"yiq\",\"yir\",\"yis\",\"yit\",\"yiu\",\"yiv\",\"yix\",\"yiy\",\"yiz\",\"yka\",\"ykg\",\"yki\",\"ykk\",\"ykl\",\"ykm\",\"ykn\",\"yko\",\"ykr\",\"ykt\",\"yku\",\"yky\",\"yla\",\"ylb\",\"yle\",\"ylg\",\"yli\",\"yll\",\"ylm\",\"yln\",\"ylo\",\"ylr\",\"ylu\",\"yly\",\"yma\",\"ymb\",\"ymc\",\"ymd\",\"yme\",\"ymg\",\"ymh\",\"ymi\",\"ymk\",\"yml\",\"ymm\",\"ymn\",\"ymo\",\"ymp\",\"ymq\",\"ymr\",\"yms\",\"ymt\",\"ymx\",\"ymz\",\"yna\",\"ynd\",\"yne\",\"yng\",\"ynh\",\"ynk\",\"ynl\",\"ynn\",\"yno\",\"ynq\",\"yns\",\"ynu\",\"yob\",\"yog\",\"yoi\",\"yok\",\"yol\",\"yom\",\"yon\",\"yos\",\"yot\",\"yox\",\"yoy\",\"ypa\",\"ypb\",\"ypg\",\"yph\",\"ypk\",\"ypm\",\"ypn\",\"ypo\",\"ypp\",\"ypz\",\"yra\",\"yrb\",\"yre\",\"yri\",\"yrk\",\"yrl\",\"yrm\",\"yrn\",\"yro\",\"yrs\",\"yrw\",\"yry\",\"ysc\",\"ysd\",\"ysg\",\"ysl\",\"ysn\",\"yso\",\"ysp\",\"ysr\",\"yss\",\"ysy\",\"yta\",\"ytl\",\"ytp\",\"ytw\",\"yty\",\"yua\",\"yub\",\"yuc\",\"yud\",\"yue\",\"yuf\",\"yug\",\"yui\",\"yuj\",\"yuk\",\"yul\",\"yum\",\"yun\",\"yup\",\"yuq\",\"yur\",\"yut\",\"yuu\",\"yuw\",\"yux\",\"yuy\",\"yuz\",\"yva\",\"yvt\",\"ywa\",\"ywg\",\"ywl\",\"ywn\",\"ywq\",\"ywr\",\"ywt\",\"ywu\",\"yww\",\"yxa\",\"yxg\",\"yxl\",\"yxm\",\"yxu\",\"yxy\",\"yyr\",\"yyu\",\"yyz\",\"yzg\",\"yzk\",\"zaa\",\"zab\",\"zac\",\"zad\",\"zae\",\"zaf\",\"zag\",\"zah\",\"zai\",\"zaj\",\"zak\",\"zal\",\"zam\",\"zao\",\"zap\",\"zaq\",\"zar\",\"zas\",\"zat\",\"zau\",\"zav\",\"zaw\",\"zax\",\"zay\",\"zaz\",\"zbc\",\"zbe\",\"zbl\",\"zbt\",\"zbw\",\"zca\",\"zch\",\"zdj\",\"zea\",\"zeg\",\"zeh\",\"zen\",\"zga\",\"zgb\",\"zgh\",\"zgm\",\"zgn\",\"zgr\",\"zhb\",\"zhd\",\"zhi\",\"zhn\",\"zhw\",\"zhx\",\"zia\",\"zib\",\"zik\",\"zil\",\"zim\",\"zin\",\"zir\",\"ziw\",\"ziz\",\"zka\",\"zkb\",\"zkd\",\"zkg\",\"zkh\",\"zkk\",\"zkn\",\"zko\",\"zkp\",\"zkr\",\"zkt\",\"zku\",\"zkv\",\"zkz\",\"zle\",\"zlj\",\"zlm\",\"zln\",\"zlq\",\"zls\",\"zlw\",\"zma\",\"zmb\",\"zmc\",\"zmd\",\"zme\",\"zmf\",\"zmg\",\"zmh\",\"zmi\",\"zmj\",\"zmk\",\"zml\",\"zmm\",\"zmn\",\"zmo\",\"zmp\",\"zmq\",\"zmr\",\"zms\",\"zmt\",\"zmu\",\"zmv\",\"zmw\",\"zmx\",\"zmy\",\"zmz\",\"zna\",\"znd\",\"zne\",\"zng\",\"znk\",\"zns\",\"zoc\",\"zoh\",\"zom\",\"zoo\",\"zoq\",\"zor\",\"zos\",\"zpa\",\"zpb\",\"zpc\",\"zpd\",\"zpe\",\"zpf\",\"zpg\",\"zph\",\"zpi\",\"zpj\",\"zpk\",\"zpl\",\"zpm\",\"zpn\",\"zpo\",\"zpp\",\"zpq\",\"zpr\",\"zps\",\"zpt\",\"zpu\",\"zpv\",\"zpw\",\"zpx\",\"zpy\",\"zpz\",\"zqe\",\"zra\",\"zrg\",\"zrn\",\"zro\",\"zrp\",\"zrs\",\"zsa\",\"zsk\",\"zsl\",\"zsm\",\"zsr\",\"zsu\",\"zte\",\"ztg\",\"ztl\",\"ztm\",\"ztn\",\"ztp\",\"ztq\",\"zts\",\"ztt\",\"ztu\",\"ztx\",\"zty\",\"zua\",\"zuh\",\"zum\",\"zun\",\"zuy\",\"zwa\",\"zxx\",\"zyb\",\"zyg\",\"zyj\",\"zyn\",\"zyp\",\"zza\",\"zzj\"]\n;return axe.utils.validLangs=function(){\"use strict\";return N},commons}()})}(\"object\"==typeof window?window:this);";
+
+
+
 
 
 
 
 
 function runA11yChecks(){
+
 return window.axe.run(document,{
 elementRef:true,
 runOnly:{
@@ -9835,8 +9267,10 @@
 'blink':{enabled:false},
 'server-side-image-map':{enabled:false}}}).
 
+
 then(axeResult=>{
 
+
 axeResult.violations.forEach(v=>v.nodes.forEach(node=>{
 node.path=getNodePath(node.element);
 node.snippet=getOuterHTMLSnippet(node.element);
@@ -9852,12 +9286,18 @@
 
 
 
+
+
+
 function getNodePath(node){
+
 function getNodeIndex(node){
 let index=0;
-while(node=node.previousSibling){
+let prevNode;
+while(prevNode=node.previousSibling){
+node=prevNode;
 
-if(node.nodeType===Node.TEXT_NODE&&
+if(node.nodeType===Node.TEXT_NODE&&node.textContent&&
 node.textContent.trim().length===0)continue;
 index++;
 }
@@ -9879,10 +9319,11 @@
 
 
 
-function getOuterHTMLSnippet(node){
+function getOuterHTMLSnippet(el){
 const reOpeningTag=/^.*?>/;
-const match=node.outerHTML.match(reOpeningTag);
-return match&&match[0];
+const match=el.outerHTML.match(reOpeningTag);
+
+return match&&match[0]||'';
 }
 }
 
@@ -9891,8 +9332,8 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+afterPass(passContext){
+const driver=passContext.driver;
 const expression=`(function () {
       ${axeLibSource};
       return (${runA11yChecks.toString()}());
@@ -9912,7 +9353,7 @@
 
 module.exports=Accessibility;
 
-},{"./gatherer":16}],"./gatherers/cache-contents":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/cache-contents":[function(require,module,exports){
 
 
 
@@ -9926,6 +9367,9 @@
 
 
 
+
+
+
 function getCacheContents(){
 
 return caches.keys().
@@ -9934,6 +9378,7 @@
 then(cacheNames=>Promise.all(cacheNames.map(cacheName=>caches.open(cacheName)))).
 
 then(caches=>{
+
 const requests=[];
 
 
@@ -9954,23 +9399,22 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+async afterPass(passContext){
+const driver=passContext.driver;
 
-return driver.
-evaluateAsync(`(${getCacheContents.toString()}())`).
-then(returnedValue=>{
-if(!returnedValue||!Array.isArray(returnedValue)){
+
+const cacheUrls=await driver.evaluateAsync(`(${getCacheContents.toString()}())`);
+if(!cacheUrls||!Array.isArray(cacheUrls)){
 throw new Error('Unable to retrieve cache contents');
 }
-return returnedValue;
-});
+
+return cacheUrls;
 }}
 
 
 module.exports=CacheContents;
 
-},{"./gatherer":16}],"./gatherers/chrome-console-messages":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/chrome-console-messages":[function(require,module,exports){
 
 
 
@@ -9988,35 +9432,45 @@
 class ChromeConsoleMessages extends Gatherer{
 constructor(){
 super();
+
 this._logEntries=[];
 this._onConsoleEntryAdded=this.onConsoleEntry.bind(this);
 }
 
+
+
+
 onConsoleEntry(entry){
 this._logEntries.push(entry);
 }
 
-beforePass(options){
-const driver=options.driver;
+
+
+
+async beforePass(passContext){
+const driver=passContext.driver;
 driver.on('Log.entryAdded',this._onConsoleEntryAdded);
-return driver.sendCommand('Log.enable').
-then(()=>driver.sendCommand('Log.startViolationsReport',{
-config:[{name:'discouragedAPIUse',threshold:-1}]}));
+await driver.sendCommand('Log.enable');
+await driver.sendCommand('Log.startViolationsReport',{
+config:[{name:'discouragedAPIUse',threshold:-1}]});
 
 }
 
-afterPass(options){
-return Promise.resolve().
-then(_=>options.driver.sendCommand('Log.stopViolationsReport')).
-then(_=>options.driver.off('Log.entryAdded',this._onConsoleEntryAdded)).
-then(_=>options.driver.sendCommand('Log.disable')).
-then(_=>this._logEntries);
+
+
+
+
+async afterPass(passContext){
+await passContext.driver.sendCommand('Log.stopViolationsReport');
+await passContext.driver.off('Log.entryAdded',this._onConsoleEntryAdded);
+await passContext.driver.sendCommand('Log.disable');
+return this._logEntries;
 }}
 
 
 module.exports=ChromeConsoleMessages;
 
-},{"./gatherer":16}],"./gatherers/css-usage":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/css-usage":[function(require,module,exports){
 
 
 
@@ -10030,45 +9484,54 @@
 
 
 class CSSUsage extends Gatherer{
-afterPass(options){
-const driver=options.driver;
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+
 
 const stylesheets=[];
+
 const onStylesheetAdded=sheet=>stylesheets.push(sheet);
 driver.on('CSS.styleSheetAdded',onStylesheetAdded);
 
-return driver.
-sendCommand('DOM.enable').
-then(_=>driver.sendCommand('CSS.enable')).
-then(_=>driver.sendCommand('CSS.startRuleUsageTracking')).
-then(_=>driver.evaluateAsync('getComputedStyle(document.body)')).
-then(_=>{
+await driver.sendCommand('DOM.enable');
+await driver.sendCommand('CSS.enable');
+await driver.sendCommand('CSS.startRuleUsageTracking');
+await driver.evaluateAsync('getComputedStyle(document.body)');
 driver.off('CSS.styleSheetAdded',onStylesheetAdded);
+
+
 const promises=stylesheets.map(sheet=>{
 const styleSheetId=sheet.header.styleSheetId;
 return driver.sendCommand('CSS.getStyleSheetText',{styleSheetId}).then(content=>{
-sheet.content=content.text;
-});
-});
+return{
+header:sheet.header,
+content:content.text};
 
-return Promise.all(promises);
-}).
-then(_=>driver.sendCommand('CSS.stopRuleUsageTracking')).
-then(results=>{
-return driver.
-sendCommand('CSS.disable').
-then(_=>driver.sendCommand('DOM.disable')).
-then(_=>{
-const dedupedStylesheets=new Map(stylesheets.map(sheet=>[sheet.content,sheet]));
-return{rules:results.ruleUsage,stylesheets:Array.from(dedupedStylesheets.values())};
 });
 });
+const styleSheetInfo=await Promise.all(promises);
+
+const ruleUsageResponse=await driver.sendCommand('CSS.stopRuleUsageTracking');
+await driver.sendCommand('CSS.disable');
+await driver.sendCommand('DOM.disable');
+
+const dedupedStylesheets=new Map(styleSheetInfo.map(sheet=>{
+return[sheet.content,sheet];
+}));
+return{
+rules:ruleUsageResponse.ruleUsage,
+stylesheets:Array.from(dedupedStylesheets.values())};
+
 }}
 
 
 module.exports=CSSUsage;
 
-},{"./gatherer":16}],"./gatherers/dobetterweb/all-event-listeners":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/dobetterweb/all-event-listeners":[function(require,module,exports){
 
 
 
@@ -10082,19 +9545,28 @@
 'use strict';
 
 const Gatherer=require('../gatherer');
+const Driver=require('../../driver.js');
+const Element=require('../../../lib/element.js');
 
 class EventListeners extends Gatherer{
-listenForScriptParsedEvents(){
-this._listener=script=>{
-this._parsedScripts.set(script.scriptId,script);
+
+
+
+async listenForScriptParsedEvents(driver){
+
+const parsedScripts=new Map();
+
+const scriptListener=script=>{
+parsedScripts.set(script.scriptId,script);
 };
-this.driver.on('Debugger.scriptParsed',this._listener);
-return this.driver.sendCommand('Debugger.enable');
-}
 
-unlistenForScriptParsedEvents(){
-this.driver.off('Debugger.scriptParsed',this._listener);
-return this.driver.sendCommand('Debugger.disable');
+
+driver.on('Debugger.scriptParsed',scriptListener);
+await driver.sendCommand('Debugger.enable');
+await driver.sendCommand('Debugger.disable');
+driver.off('Debugger.scriptParsed',scriptListener);
+
+return parsedScripts;
 }
 
 
@@ -10103,27 +9575,33 @@
 
 
 
-_listEventListeners(nodeIdOrObject){
+
+_listEventListeners(driver,nodeIdOrObject){
 let promise;
 
 if(typeof nodeIdOrObject==='string'){
-promise=this.driver.sendCommand('Runtime.evaluate',{
+promise=driver.sendCommand('Runtime.evaluate',{
 expression:nodeIdOrObject,
-objectGroup:'event-listeners-gatherer'});
-
+objectGroup:'event-listeners-gatherer'}).
+then(result=>result.result);
 }else{
-promise=this.driver.sendCommand('DOM.resolveNode',{
+promise=driver.sendCommand('DOM.resolveNode',{
 nodeId:nodeIdOrObject,
-objectGroup:'event-listeners-gatherer'});
-
+objectGroup:'event-listeners-gatherer'}).
+then(result=>result.object);
 }
 
-return promise.then(result=>{
-const obj=result.object||result.result;
-return this.driver.sendCommand('DOMDebugger.getEventListeners',{
-objectId:obj.objectId}).
+return promise.then(obj=>{
+const objectId=obj.objectId;
+const description=obj.description;
+if(!objectId||!description){
+return{listeners:[],tagName:''};
+}
+
+return driver.sendCommand('DOMDebugger.getEventListeners',{
+objectId}).
 then(results=>{
-return{listeners:results.listeners,tagName:obj.description};
+return{listeners:results.listeners,tagName:description};
 });
 });
 }
@@ -10136,27 +9614,31 @@
 
 
 
-getEventListeners(nodeId){
+
+
+getEventListeners(driver,parsedScripts,nodeId){
+
 const matchedListeners=[];
 
-return this._listEventListeners(nodeId).then(results=>{
+return this._listEventListeners(driver,nodeId).then(results=>{
 results.listeners.forEach(listener=>{
 
 
-const script=this._parsedScripts.get(listener.scriptId);
+const script=parsedScripts.get(listener.scriptId);
 if(script){
 
 
 
-const combo=Object.assign(listener,script);
-combo.objectName=results.tagName;
+matchedListeners.push({
+url:script.url,
+type:listener.type,
+handler:listener.handler,
+objectName:results.tagName,
 
 
+line:listener.lineNumber+1,
+col:listener.columnNumber+1});
 
-combo.line=combo.lineNumber+1;
-combo.col=combo.columnNumber+1;
-
-matchedListeners.push(combo);
 }
 });
 
@@ -10170,37 +9652,35 @@
 
 
 
-collectListeners(nodes){
 
-return Promise.all(nodes.map(node=>{
-return this.getEventListeners(node.element?node.element.nodeId:node);
-})).then(nestedListeners=>[].concat(...nestedListeners));
+
+collectListeners(driver,parsedScripts,nodeIds){
+
+return Promise.all(nodeIds.map(node=>this.getEventListeners(driver,parsedScripts,node))).
+then(nestedListeners=>nestedListeners.reduce((prev,curr)=>prev.concat(curr)));
 }
 
 
 
 
 
-afterPass(options){
-this.driver=options.driver;
-this._parsedScripts=new Map();
-return options.driver.sendCommand('DOM.enable').
-then(()=>this.listenForScriptParsedEvents()).
-then(()=>this.unlistenForScriptParsedEvents()).
-then(()=>options.driver.getElementsInDocument()).
-then(nodes=>{
-nodes.push('document','window');
-return this.collectListeners(nodes);
-}).then(listeners=>{
-return options.driver.sendCommand('DOM.disable').
-then(()=>listeners);
-});
+async afterPass(passContext){
+const driver=passContext.driver;
+await passContext.driver.sendCommand('DOM.enable');
+const parsedScripts=await this.listenForScriptParsedEvents(driver);
+
+const elements=await passContext.driver.getElementsInDocument();
+const elementIds=[...elements.map(el=>el.getNodeId()),'document','window'];
+
+const listeners=await this.collectListeners(driver,parsedScripts,elementIds);
+await passContext.driver.sendCommand('DOM.disable');
+return listeners;
 }}
 
 
 module.exports=EventListeners;
 
-},{"../gatherer":16}],"./gatherers/dobetterweb/anchors-with-no-rel-noopener":[function(require,module,exports){
+},{"../../../lib/element.js":31,"../../driver.js":17,"../gatherer":19}],"../gather/gatherers/dobetterweb/anchors-with-no-rel-noopener":[function(require,module,exports){
 
 
 
@@ -10216,10 +9696,10 @@
 
 
 
-afterPass(options){
+afterPass(passContext){
 const expression=`(function() {
       ${DOMHelpers.getElementsInDocumentFnString}; // define function on page
-      const selector = 'a[target="_blank"]:not([rel~="noopener"])';
+      const selector = 'a[target="_blank"]:not([rel~="noopener"]):not([rel~="noreferrer"])';
       const elements = getElementsInDocument(selector);
       return elements.map(node => ({
         href: node.href,
@@ -10228,13 +9708,13 @@
       }));
     })()`;
 
-return options.driver.evaluateAsync(expression);
+return passContext.driver.evaluateAsync(expression);
 }}
 
 
 module.exports=AnchorsWithNoRelNoopener;
 
-},{"../../../lib/dom-helpers.js":25,"../gatherer":16}],"./gatherers/dobetterweb/appcache":[function(require,module,exports){
+},{"../../../lib/dom-helpers.js":30,"../gatherer":19}],"../gather/gatherers/dobetterweb/appcache":[function(require,module,exports){
 
 
 
@@ -10251,8 +9731,8 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+afterPass(passContext){
+const driver=passContext.driver;
 
 return driver.querySelector('html').
 then(node=>node&&node.getAttribute('manifest'));
@@ -10261,7 +9741,7 @@
 
 module.exports=AppCacheManifest;
 
-},{"../gatherer":16}],"./gatherers/dobetterweb/domstats":[function(require,module,exports){
+},{"../gatherer":19}],"../gather/gatherers/dobetterweb/domstats":[function(require,module,exports){
 
 
 
@@ -10285,6 +9765,18 @@
 
 
 
+function getOuterHTMLSnippet(element){
+const reOpeningTag=/^.*?>/;
+const match=element.outerHTML.match(reOpeningTag);
+return match&&match[0];
+}
+
+
+
+
+
+
+
 
 function createSelectorsLabel(element){
 let name=element.localName||'';
@@ -10353,6 +9845,10 @@
 let maxWidth=0;
 let parentWithMostChildren=null;
 
+
+
+
+
 const _calcDOMWidthAndHeight=function(element,depth=1){
 if(depth>maxDepth){
 deepestNode=element;
@@ -10381,11 +9877,13 @@
 return{
 depth:{
 max:result.maxDepth,
-pathToElement:elementPathInDOM(deepestNode)},
+pathToElement:elementPathInDOM(deepestNode),
+snippet:getOuterHTMLSnippet(deepestNode)},
 
 width:{
 max:result.maxWidth,
-pathToElement:elementPathInDOM(parentWithMostChildren)}};
+pathToElement:elementPathInDOM(parentWithMostChildren),
+snippet:getOuterHTMLSnippet(parentWithMostChildren)}};
 
 
 }
@@ -10395,24 +9893,25 @@
 
 
 
-afterPass(options){
+afterPass(passContext){
 const expression=`(function() {
+      ${getOuterHTMLSnippet.toString()};
       ${createSelectorsLabel.toString()};
       ${elementPathInDOM.toString()};
       return (${getDOMStats.toString()}(document.documentElement));
     })()`;
-return options.driver.sendCommand('DOM.enable').
-then(()=>options.driver.evaluateAsync(expression)).
-then(results=>options.driver.getElementsInDocument().then(allNodes=>{
+return passContext.driver.sendCommand('DOM.enable').
+then(()=>passContext.driver.evaluateAsync(expression,{useIsolation:true})).
+then(results=>passContext.driver.getElementsInDocument().then(allNodes=>{
 results.totalDOMNodes=allNodes.length;
-return options.driver.sendCommand('DOM.disable').then(()=>results);
+return passContext.driver.sendCommand('DOM.disable').then(()=>results);
 }));
 }}
 
 
 module.exports=DOMStats;
 
-},{"../gatherer":16}],"./gatherers/dobetterweb/js-libraries":[function(require,module,exports){
+},{"../gatherer":19}],"../gather/gatherers/dobetterweb/js-libraries":[function(require,module,exports){
 
 
 
@@ -10436,13 +9935,13 @@
 
 
 
-
-
 function detectLibraries(){
+
 const libraries=[];
 
 
 
+
 Object.entries(d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests).forEach(([name,lib])=>{
 try{
 const result=lib.test(window);
@@ -10459,25 +9958,24 @@
 return libraries;
 }
 
-
 class JSLibraries extends Gatherer{
 
 
 
 
-afterPass(options){
+afterPass(passContext){
 const expression=`(function () {
       ${libDetectorSource};
       return (${detectLibraries.toString()}());
     })()`;
 
-return options.driver.evaluateAsync(expression);
+return passContext.driver.evaluateAsync(expression);
 }}
 
 
 module.exports=JSLibraries;
 
-},{"../gatherer":16}],"./gatherers/dobetterweb/optimized-images":[function(require,module,exports){
+},{"../gatherer":19}],"../gather/gatherers/dobetterweb/optimized-images":[function(require,module,exports){
 
 
 
@@ -10493,6 +9991,7 @@
 const Gatherer=require('../gatherer');
 const URL=require('../../../lib/url-shim');
 const Sentry=require('../../../lib/sentry');
+const Driver=require('../../driver.js');
 
 const JPEG_QUALITY=0.92;
 const WEBP_QUALITY=0.85;
@@ -10507,11 +10006,21 @@
 
 
 
+
+
 function getOptimizedNumBytes(url){
 return new Promise(function(resolve,reject){
 const img=new Image();
 const canvas=document.createElement('canvas');
 const context=canvas.getContext('2d');
+if(!context){
+return reject(new Error('unable to create canvas context'));
+}
+
+
+
+
+
 
 function getTypeStats(type,quality){
 const dataURI=canvas.toDataURL(type,quality);
@@ -10546,6 +10055,7 @@
 
 
 static filterImageRequests(pageUrl,networkRecords){
+
 const seenUrls=new Set();
 return networkRecords.reduce((prev,record)=>{
 if(seenUrls.has(record._url)||!record.finished){
@@ -10559,14 +10069,15 @@
 const isSameOrigin=URL.originsMatch(pageUrl,record._url);
 const isBase64DataUri=/^data:.{2,40}base64\s*,/.test(record._url);
 
-if(isOptimizableImage&&record._resourceSize>MINIMUM_IMAGE_SIZE){
+const actualResourceSize=Math.min(record._resourceSize||0,record._transferSize||0);
+if(isOptimizableImage&&actualResourceSize>MINIMUM_IMAGE_SIZE){
 prev.push({
 isSameOrigin,
 isBase64DataUri,
 requestId:record._requestId,
 url:record._url,
 mimeType:record._mimeType,
-resourceSize:record._resourceSize});
+resourceSize:actualResourceSize});
 
 }
 
@@ -10640,11 +10151,23 @@
 
 
 
-computeOptimizedImages(driver,imageRecords){
-return imageRecords.reduce((promise,record)=>{
-return promise.then(results=>{
-return this.calculateImageStats(driver,record).
-catch(err=>{
+async computeOptimizedImages(driver,imageRecords){
+
+const results=[];
+
+for(const record of imageRecords){
+try{
+const stats=await this.calculateImageStats(driver,record);
+if(stats===null){
+continue;
+}
+
+
+
+const image=Object.assign({failed:false},stats,record);
+results.push(image);
+}catch(err){
+
 
 
 Sentry.captureException(err,{
@@ -10652,30 +10175,28 @@
 extra:{imageUrl:URL.elideDataURI(record.url)},
 level:'warning'});
 
-return{failed:true,err};
-}).
-then(stats=>{
-if(!stats){
+
+
+
+const imageError=Object.assign({failed:true,errMsg:err.message},record);
+results.push(imageError);
+}
+}
+
 return results;
 }
 
-return results.concat(Object.assign(stats,record));
-});
-});
-},Promise.resolve([]));
-}
 
 
 
 
 
-
-afterPass(options,traceData){
-const networkRecords=traceData.networkRecords;
-const imageRecords=OptimizedImages.filterImageRequests(options.url,networkRecords);
+afterPass(passContext,loadData){
+const networkRecords=loadData.networkRecords;
+const imageRecords=OptimizedImages.filterImageRequests(passContext.url,networkRecords);
 
 return Promise.resolve().
-then(_=>this.computeOptimizedImages(options.driver,imageRecords)).
+then(_=>this.computeOptimizedImages(passContext.driver,imageRecords)).
 then(results=>{
 const successfulResults=results.filter(result=>!result.failed);
 if(results.length&&!successfulResults.length){
@@ -10689,7 +10210,7 @@
 
 module.exports=OptimizedImages;
 
-},{"../../../lib/sentry":33,"../../../lib/url-shim":41,"../gatherer":16}],"./gatherers/dobetterweb/password-inputs-with-prevented-paste":[function(require,module,exports){
+},{"../../../lib/sentry":39,"../../../lib/url-shim":"url","../../driver.js":17,"../gatherer":19}],"../gather/gatherers/dobetterweb/password-inputs-with-prevented-paste":[function(require,module,exports){
 
 
 
@@ -10703,15 +10224,19 @@
 
 
 
+
+
+
 function findPasswordInputsWithPreventedPaste(){
 
 
 
 
 
-function getOuterHTMLSnippet(node){
+function getOuterHTMLSnippet(element){
 const reOpeningTag=/^.*?>/;
-const match=node.outerHTML.match(reOpeningTag);
+const match=element.outerHTML.match(reOpeningTag);
+
 return match&&match[0];
 }
 
@@ -10731,9 +10256,8 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
-return driver.evaluateAsync(
+afterPass(passContext){
+return passContext.driver.evaluateAsync(
 `(${findPasswordInputsWithPreventedPaste.toString()}())`);
 
 }}
@@ -10742,7 +10266,7 @@
 
 module.exports=PasswordInputsWithPreventedPaste;
 
-},{"../gatherer":16}],"./gatherers/dobetterweb/response-compression":[function(require,module,exports){
+},{"../gatherer":19}],"../gather/gatherers/dobetterweb/response-compression":[function(require,module,exports){
 (function(Buffer){
 
 
@@ -10759,6 +10283,7 @@
 const Gatherer=require('../gatherer');
 const gzip=require('zlib').gzip;
 
+const compressionHeaders=['content-encoding','x-original-content-encoding'];
 const compressionTypes=['gzip','br','deflate'];
 const binaryMimeTypes=['image','audio','video'];
 const CHROME_EXTENSION_PROTOCOL='chrome-extension:';
@@ -10769,23 +10294,25 @@
 
 
 static filterUnoptimizedResponses(networkRecords){
+
 const unoptimizedResponses=[];
 
 networkRecords.forEach(record=>{
-const mimeType=record.mimeType;
-const resourceType=record.resourceType();
+const mimeType=record._mimeType;
+const resourceType=record._resourceType;
+const resourceSize=record._resourceSize;
 
 const isBinaryResource=mimeType&&binaryMimeTypes.some(type=>mimeType.startsWith(type));
 const isTextBasedResource=!isBinaryResource&&resourceType&&resourceType.isTextType();
 const isChromeExtensionResource=record.url.startsWith(CHROME_EXTENSION_PROTOCOL);
 
-if(!isTextBasedResource||!record.resourceSize||!record.finished||
+if(!isTextBasedResource||!resourceSize||!record.finished||
 isChromeExtensionResource||!record.transferSize||record.statusCode===304){
 return;
 }
 
-const isContentEncoded=record.responseHeaders.find(header=>
-header.name.toLowerCase()==='content-encoding'&&
+const isContentEncoded=(record._responseHeaders||[]).find(header=>
+compressionHeaders.includes(header.name.toLowerCase())&&
 compressionTypes.includes(header.value));
 
 
@@ -10793,9 +10320,10 @@
 unoptimizedResponses.push({
 requestId:record.requestId,
 url:record.url,
-mimeType:record.mimeType,
+mimeType:mimeType,
 transferSize:record.transferSize,
-resourceSize:record.resourceSize});
+resourceSize:resourceSize,
+gzipSize:0});
 
 }
 });
@@ -10803,19 +10331,20 @@
 return unoptimizedResponses;
 }
 
-afterPass(options,traceData){
-const networkRecords=traceData.networkRecords;
+
+
+
+
+
+afterPass(passContext,loadData){
+const networkRecords=loadData.networkRecords;
 const textRecords=ResponseCompression.filterUnoptimizedResponses(networkRecords);
 
-const driver=options.driver;
+const driver=passContext.driver;
 return Promise.all(textRecords.map(record=>{
-const contentPromise=driver.getRequestContent(record.requestId);
-const timeoutPromise=new Promise(resolve=>setTimeout(resolve,3000));
-return Promise.race([contentPromise,timeoutPromise]).then(content=>{
+return driver.getRequestContent(record.requestId).then(content=>{
 
 if(!content){
-record.gzipSize=0;
-
 return record;
 }
 
@@ -10839,7 +10368,7 @@
 module.exports=ResponseCompression;
 
 }).call(this,require("buffer").Buffer);
-},{"../gatherer":16,"buffer":54,"zlib":51}],"./gatherers/dobetterweb/tags-blocking-first-paint":[function(require,module,exports){
+},{"../gatherer":19,"buffer":60,"zlib":57}],"../gather/gatherers/dobetterweb/tags-blocking-first-paint":[function(require,module,exports){
 
 
 
@@ -10862,6 +10391,27 @@
 'use strict';
 
 const Gatherer=require('../gatherer');
+const Driver=require('../../driver.js');
+
+
+
+
+function installMediaListener(){
+window.___linkMediaChanges=[];
+Object.defineProperty(HTMLLinkElement.prototype,'media',{
+set:function(val){
+window.___linkMediaChanges.push({
+href:this.href,
+media:val,
+msSinceHTMLEnd:Date.now()-window.performance.timing.responseEnd,
+matches:window.matchMedia(val).matches});
+
+
+return this.setAttribute('media',val);
+}});
+
+}
+
 
 
 
@@ -10872,19 +10422,25 @@
 const tagList=[...document.querySelectorAll('link, head script[src]')].
 filter(tag=>{
 if(tag.tagName==='SCRIPT'){
-return!tag.hasAttribute('async')&&
-!tag.hasAttribute('defer')&&
-!/^data:/.test(tag.src)&&
-tag.getAttribute('type')!=='module';
+const scriptTag=tag;
+return(
+!scriptTag.hasAttribute('async')&&
+!scriptTag.hasAttribute('defer')&&
+!/^data:/.test(scriptTag.src)&&
+scriptTag.getAttribute('type')!=='module');
+
+}else if(tag.tagName==='LINK'){
+
+
+
+const linkTag=tag;
+const blockingStylesheet=linkTag.rel==='stylesheet'&&
+window.matchMedia(linkTag.media).matches&&!linkTag.disabled;
+const blockingImport=linkTag.rel==='import'&&!linkTag.hasAttribute('async');
+return blockingStylesheet||blockingImport;
 }
 
-
-
-
-const blockingStylesheet=tag.rel==='stylesheet'&&
-window.matchMedia(tag.media).matches&&!tag.disabled;
-const blockingImport=tag.rel==='import'&&!tag.hasAttribute('async');
-return blockingStylesheet||blockingImport;
+return false;
 }).
 map(tag=>{
 return{
@@ -10894,7 +10450,8 @@
 href:tag.href,
 rel:tag.rel,
 media:tag.media,
-disabled:tag.disabled};
+disabled:tag.disabled,
+mediaChanges:window.___linkMediaChanges.filter(item=>item.href===tag.href)};
 
 });
 resolve(tagList);
@@ -10905,7 +10462,14 @@
 });
 }
 
-function filteredAndIndexedByUrl(networkRecords){
+class TagsBlockingFirstPaint extends Gatherer{
+
+
+
+static _filteredAndIndexedByUrl(networkRecords){
+
+const result={};
+
 return networkRecords.reduce((prev,record)=>{
 if(!record.finished){
 return prev;
@@ -10930,28 +10494,42 @@
 }
 
 return prev;
-},{});
+},result);
 }
 
-class TagsBlockingFirstPaint extends Gatherer{
-constructor(){
-super();
-this._filteredAndIndexedByUrl=filteredAndIndexedByUrl;
-}
+
+
+
 
 static findBlockingTags(driver,networkRecords){
 const scriptSrc=`(${collectTagsThatBlockFirstPaint.toString()}())`;
+const firstRequestEndTime=networkRecords.reduce(
+(min,record)=>Math.min(min,record._endTime),
+Infinity);
+
 return driver.evaluateAsync(scriptSrc).then(tags=>{
-const requests=filteredAndIndexedByUrl(networkRecords);
+const requests=TagsBlockingFirstPaint._filteredAndIndexedByUrl(networkRecords);
 
 return tags.reduce((prev,tag)=>{
 const request=requests[tag.url];
 if(request&&!request.isLinkPreload){
+
+
+
+const timesResourceBecameNonBlocking=(tag.mediaChanges||[]).
+filter(change=>!change.matches).
+map(change=>change.msSinceHTMLEnd);
+const earliestNonBlockingTime=Math.min(...timesResourceBecameNonBlocking);
+const lastTimeResourceWasBlocking=Math.max(
+request.startTime,
+firstRequestEndTime+earliestNonBlockingTime/1000);
+
+
 prev.push({
 tag,
 transferSize:request.transferSize||0,
 startTime:request.startTime,
-endTime:request.endTime});
+endTime:Math.min(request.endTime,lastTimeResourceWasBlocking)});
 
 
 
@@ -10966,16 +10544,23 @@
 
 
 
+beforePass(passContext){
+return passContext.driver.evaluteScriptOnNewDocument(`(${installMediaListener.toString()})()`);
+}
 
 
-afterPass(options,tracingData){
-return TagsBlockingFirstPaint.findBlockingTags(options.driver,tracingData.networkRecords);
+
+
+
+
+afterPass(passContext,loadData){
+return TagsBlockingFirstPaint.findBlockingTags(passContext.driver,loadData.networkRecords);
 }}
 
 
 module.exports=TagsBlockingFirstPaint;
 
-},{"../gatherer":16}],"./gatherers/dobetterweb/websql":[function(require,module,exports){
+},{"../../driver.js":17,"../gatherer":19}],"../gather/gatherers/dobetterweb/websql":[function(require,module,exports){
 
 
 
@@ -10984,11 +10569,17 @@
 'use strict';
 
 const Gatherer=require('../gatherer');
+const Driver=require('../../driver.js');
 
 const MAX_WAIT_TIMEOUT=500;
 
 class WebSQL extends Gatherer{
+
+
+
+
 listenForDatabaseEvents(driver){
+
 let timeout;
 
 return new Promise((resolve,reject)=>{
@@ -11013,8 +10604,8 @@
 
 
 
-afterPass(options){
-return this.listenForDatabaseEvents(options.driver).
+afterPass(passContext){
+return this.listenForDatabaseEvents(passContext.driver).
 then(result=>{
 return result&&result.database;
 });
@@ -11023,7 +10614,9 @@
 
 module.exports=WebSQL;
 
-},{"../gatherer":16}],"./gatherers/fonts":[function(require,module,exports){
+},{"../../driver.js":17,"../gatherer":19}],"../gather/gatherers/fonts":[function(require,module,exports){
+
+
 
 
 
@@ -11033,6 +10626,13 @@
 
 const Gatherer=require('./gatherer');
 const Sentry=require('../../lib/sentry');
+
+
+
+
+
+
+
 const fontFaceDescriptors=[
 'display',
 'family',
@@ -11052,8 +10652,12 @@
 
 
 function getAllLoadedFonts(descriptors){
+
 const getFont=fontFace=>{
-const fontRule={};
+
+const fontRule={
+src:[]};
+
 descriptors.forEach(descriptor=>{
 fontRule[descriptor]=fontFace[descriptor];
 });
@@ -11081,27 +10685,38 @@
 function getSheetsFontFaces(stylesheet){
 const fontUrlRegex='url\\((?:")([^"]+)(?:"|\')\\)';
 const fontFaceRules=[];
+
 if(stylesheet.cssRules){
-for(const rule of stylesheet.cssRules){
+for(const rule of Array.from(stylesheet.cssRules)){
 if(rule instanceof CSSFontFaceRule){
 const fontsObject={
+
+
 display:rule.style.fontDisplay||'auto',
-family:rule.style.fontFamily.replace(/"|'/g,''),
+family:rule.style.fontFamily?rule.style.fontFamily.replace(/"|'/g,''):'',
 stretch:rule.style.fontStretch||'normal',
 style:rule.style.fontStyle||'normal',
 weight:rule.style.fontWeight||'normal',
 variant:rule.style.fontVariant||'normal',
+
 unicodeRange:rule.style.unicodeRange||'U+0-10FFFF',
+
 featureSettings:rule.style.featureSettings||'normal',
+
 src:[]};
 
 
-if(rule.style.src){
-const matches=rule.style.src.match(new RegExp(fontUrlRegex,'g'));
+
+
+const src=rule.style.src;
+if(src){
+const matches=src.match(new RegExp(fontUrlRegex,'g'));
 if(matches){
-fontsObject.src=matches.map(match=>{
+matches.forEach(match=>{
 const res=new RegExp(fontUrlRegex).exec(match);
-return new URL(res[1],location.href).href;
+if(res){
+fontsObject.src.push(new URL(res[1],location.href).href);
+}
 });
 }
 }
@@ -11129,32 +10744,43 @@
 resolve(getFontFaceFromStylesheets());
 });
 newNode.crossOrigin='anonymous';
-oldNode.parentNode.insertBefore(newNode,oldNode);
+oldNode.parentNode&&oldNode.parentNode.insertBefore(newNode,oldNode);
 oldNode.remove();
 });
 }
 
-const promises=[];
 
-for(const stylesheet of document.styleSheets){
+const data=[];
+
+const corsDataPromises=[];
+
+for(const stylesheet of Array.from(document.styleSheets)){
 try{
+const cssStylesheet=stylesheet;
 
-if(stylesheet.cssRules===null&&stylesheet.href&&stylesheet.ownerNode&&
-!stylesheet.ownerNode.crossOrigin){
-promises.push(loadStylesheetWithCORS(stylesheet.ownerNode));
+if(cssStylesheet.cssRules===null&&cssStylesheet.href&&cssStylesheet.ownerNode&&
+
+!cssStylesheet.ownerNode.crossOrigin){
+const ownerLinkEl=cssStylesheet.ownerNode;
+corsDataPromises.push(loadStylesheetWithCORS(ownerLinkEl));
 }else{
-promises.push(Promise.resolve(getSheetsFontFaces(stylesheet)));
+data.push(...getSheetsFontFaces(cssStylesheet));
 }
 }catch(err){
-promises.push({err:{message:err.message,stack:err.stack}});
+data.push({err:{message:err.message,stack:err.stack}});
 }
 }
 
-return Promise.all(promises).then(fontFaces=>[].concat(...fontFaces));
+return Promise.all(corsDataPromises).then(corsFontFaces=>data.concat(...corsFontFaces));
 }
 
 
 class Fonts extends Gatherer{
+
+
+
+
+
 _findSameFontFamily(fontFace,fontFacesList){
 return fontFacesList.find(fontItem=>{
 return!fontFaceDescriptors.find(descriptor=>{
@@ -11163,34 +10789,49 @@
 });
 }
 
-afterPass({driver}){
+
+
+
+
+afterPass(passContext){
+const driver=passContext.driver;
 const args=JSON.stringify(fontFaceDescriptors);
-return Promise.all(
+
+const fontData=Promise.all(
 [
 driver.evaluateAsync(`(${getAllLoadedFonts.toString()})(${args})`),
-driver.evaluateAsync(`(${getFontFaceFromStylesheets.toString()})()`)]).
+driver.evaluateAsync(`(${getFontFaceFromStylesheets.toString()})()`)]);
 
-then(([loadedFonts,fontFaces])=>{
-return loadedFonts.map(fontFace=>{
-if(fontFace.err){
-const err=new Error(fontFace.err.message);
-err.stack=fontFace.err.stack;
+
+return fontData.then(([loadedFonts,fontsAndErrors])=>{
+
+const fontFaces=fontsAndErrors.filter(
+fontOrError=>{
+
+const dataError=fontOrError;
+if(dataError.err){
+const err=new Error(dataError.err.message);
+err.stack=dataError.err.stack;
+
 Sentry.captureException(err,{tags:{gatherer:'Fonts'},level:'warning'});
-return null;
+return false;
 }
+return true;
+});
 
-const fontFaceItem=this._findSameFontFamily(fontFace,fontFaces);
-fontFace.src=fontFaceItem&&fontFaceItem.src||[];
+return loadedFonts.map(loadedFont=>{
+const fontFaceItem=this._findSameFontFamily(loadedFont,fontFaces);
+loadedFont.src=fontFaceItem&&fontFaceItem.src||[];
 
-return fontFace;
-}).filter(Boolean);
+return loadedFont;
+});
 });
 }}
 
 
 module.exports=Fonts;
 
-},{"../../lib/sentry":33,"./gatherer":16}],"./gatherers/html-without-javascript":[function(require,module,exports){
+},{"../../lib/sentry":39,"./gatherer":19}],"../gather/gatherers/html-without-javascript":[function(require,module,exports){
 
 
 
@@ -11215,30 +10856,35 @@
 }
 
 class HTMLWithoutJavaScript extends Gatherer{
-beforePass(options){
-options.disableJavaScript=true;
+
+
+
+beforePass(passContext){
+passContext.disableJavaScript=true;
 }
 
-afterPass(options){
 
-options.disableJavaScript=false;
 
-return options.driver.evaluateAsync(`(${getBodyText.toString()}())`).
-then(result=>{
-if(typeof result!=='string'){
+
+
+async afterPass(passContext){
+
+passContext.disableJavaScript=false;
+
+const bodyText=await passContext.driver.evaluateAsync(`(${getBodyText.toString()}())`);
+if(typeof bodyText!=='string'){
 throw new Error('document body innerText returned by protocol was not a string');
 }
 
 return{
-value:result};
+value:bodyText};
 
-});
 }}
 
 
 module.exports=HTMLWithoutJavaScript;
 
-},{"./gatherer":16}],"./gatherers/http-redirect":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/http-redirect":[function(require,module,exports){
 
 
 
@@ -11256,55 +10902,36 @@
 class HTTPRedirect extends Gatherer{
 constructor(){
 super();
-this._preRedirectURL=undefined;
+this._preRedirectURL='';
 }
 
-beforePass(options){
-this._preRedirectURL=options.url;
-options.url=this._preRedirectURL.replace(/^https/,'http');
+
+
+
+beforePass(passContext){
+this._preRedirectURL=passContext.url;
+passContext.url=this._preRedirectURL.replace(/^https/,'http');
 }
 
-afterPass(options){
-
-options.url=this._preRedirectURL;
 
 
-const timeout=options._testTimeout||10000;
 
-const securityPromise=options.driver.getSecurityState().
-then(state=>{
+
+async afterPass(passContext){
+
+passContext.url=this._preRedirectURL;
+
+const expression=`new URL(window.location).protocol === 'https:'`;
+const isHttps=await passContext.driver.evaluateAsync(expression,{useIsolation:true});
 return{
-value:state.schemeIsCryptographic};
+value:isHttps};
 
-});
-
-let noSecurityChangesTimeout;
-const timeoutPromise=new Promise((resolve,reject)=>{
-
-
-noSecurityChangesTimeout=setTimeout(_=>{
-reject(new Error('Timed out waiting for HTTP redirection.'));
-},timeout);
-});
-
-return Promise.race([
-securityPromise,
-timeoutPromise]).
-then(result=>{
-
-clearTimeout(noSecurityChangesTimeout);
-return result;
-}).catch(err=>{
-clearTimeout(noSecurityChangesTimeout);
-throw err;
-});
 }}
 
 
 module.exports=HTTPRedirect;
 
-},{"./gatherer":16}],"./gatherers/image-usage":[function(require,module,exports){
-
+},{"./gatherer":19}],"../gather/gatherers/image-usage":[function(require,module,exports){
 
 
 
@@ -11318,11 +10945,14 @@
 
 const Gatherer=require('./gatherer');
 const DOMHelpers=require('../../lib/dom-helpers.js');
+const Driver=require('../driver.js');
+
 
 
 
 
 function collectImageElementInfo(){
+
 function getClientRect(element){
 const clientRect=element.getBoundingClientRect();
 return{
@@ -11334,8 +10964,13 @@
 
 }
 
+
+
 const allElements=getElementsInDocument();
-const allImageElements=allElements.filter(element=>element.localName==='img');
+const allImageElements=allElements.filter(element=>{
+return element.localName==='img';
+});
+
 
 const htmlImages=allImageElements.map(element=>{
 const computedStyle=window.getComputedStyle(element);
@@ -11365,12 +11000,13 @@
 
 const cssImages=allElements.reduce((images,element)=>{
 const style=window.getComputedStyle(element);
-if(!CSS_URL_REGEX.test(style.backgroundImage)||
-!CSS_SIZE_REGEX.test(style.backgroundSize)){
+if(!style.backgroundImage||!CSS_URL_REGEX.test(style.backgroundImage)||
+!style.backgroundSize||!CSS_SIZE_REGEX.test(style.backgroundSize)){
 return images;
 }
 
 const imageMatch=style.backgroundImage.match(CSS_URL_REGEX);
+
 const url=imageMatch[1];
 
 
@@ -11399,10 +11035,14 @@
 }
 
 
+
+
+
+
 function determineNaturalSize(url){
 return new Promise((resolve,reject)=>{
 const img=new Image();
-img.addEventListener('error',reject);
+img.addEventListener('error',_=>reject(new Error('determineNaturalSize failed img load')));
 img.addEventListener('load',()=>{
 resolve({
 naturalWidth:img.naturalWidth,
@@ -11419,24 +11059,34 @@
 
 
 
-fetchElementWithSizeInformation(element){
+
+async fetchElementWithSizeInformation(driver,element){
 const url=JSON.stringify(element.src);
-return this.driver.evaluateAsync(`(${determineNaturalSize.toString()})(${url})`).
-then(size=>{
+try{
+
+const size=await driver.evaluateAsync(`(${determineNaturalSize.toString()})(${url})`);
 return Object.assign(element,size);
-});
+}catch(_){
+
+return Object.assign(element,{naturalWidth:0,naturalHeight:0});
+}
 }
 
-afterPass(options,traceData){
-const driver=this.driver=options.driver;
-const indexedNetworkRecords=traceData.networkRecords.reduce((map,record)=>{
+
+
+
+
+
+async afterPass(passContext,loadData){
+const driver=passContext.driver;
+const indexedNetworkRecords=loadData.networkRecords.reduce((map,record)=>{
 if(/^image/.test(record._mimeType)&&record.finished){
 map[record._url]={
 url:record.url,
-resourceSize:record.resourceSize,
+resourceSize:Math.min(record._resourceSize||0,record.transferSize),
 startTime:record.startTime,
 endTime:record.endTime,
-responseReceivedTime:record.responseReceivedTime,
+responseReceivedTime:record._responseReceivedTime,
 mimeType:record._mimeType};
 
 }
@@ -11449,33 +11099,31 @@
       return (${collectImageElementInfo.toString()})();
     })()`;
 
-return driver.evaluateAsync(expression).
-then(elements=>{
-return elements.reduce((promise,element)=>{
-return promise.then(collector=>{
+
+const elements=await driver.evaluateAsync(expression);
+
+const imageUsage=[];
+for(let element of elements){
 
 element.networkRecord=indexedNetworkRecords[element.src];
 
 
 
 
-const elementPromise=(element.isPicture||element.isCss)&&element.networkRecord?
-this.fetchElementWithSizeInformation(element):
-Promise.resolve(element);
+if((element.isPicture||element.isCss)&&element.networkRecord){
+element=await this.fetchElementWithSizeInformation(driver,element);
+}
 
-return elementPromise.then(element=>{
-collector.push(element);
-return collector;
-});
-});
-},Promise.resolve([]));
-});
+imageUsage.push(element);
+}
+
+return imageUsage;
 }}
 
 
 module.exports=ImageUsage;
 
-},{"../../lib/dom-helpers.js":25,"./gatherer":16}],"./gatherers/js-usage":[function(require,module,exports){
+},{"../../lib/dom-helpers.js":30,"../driver.js":17,"./gatherer":19}],"../gather/gatherers/js-usage":[function(require,module,exports){
 
 
 
@@ -11489,32 +11137,31 @@
 
 
 class JsUsage extends Gatherer{
-beforePass(options){
-return options.driver.sendCommand('Profiler.enable').
-then(_=>options.driver.sendCommand('Profiler.startPreciseCoverage'));
+
+
+
+async beforePass(passContext){
+await passContext.driver.sendCommand('Profiler.enable');
+await passContext.driver.sendCommand('Profiler.startPreciseCoverage');
 }
 
 
 
 
 
-afterPass(options){
-const driver=options.driver;
+async afterPass(passContext){
+const driver=passContext.driver;
 
-return driver.sendCommand('Profiler.takePreciseCoverage').then(results=>{
-return driver.sendCommand('Profiler.stopPreciseCoverage').
-then(_=>driver.sendCommand('Profiler.disable')).
-then(_=>results.result);
-});
+const coverageResponse=await driver.sendCommand('Profiler.takePreciseCoverage');
+await driver.sendCommand('Profiler.stopPreciseCoverage');
+await driver.sendCommand('Profiler.disable');
+return coverageResponse.result;
 }}
 
 
 module.exports=JsUsage;
 
-
-JsUsage.JsUsageArtifact;
-
-},{"./gatherer":16}],"./gatherers/manifest":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/manifest":[function(require,module,exports){
 (function(Buffer){
 
 
@@ -11542,11 +11189,12 @@
 
 
 
-afterPass(options){
-const manifestPromise=options.driver.getAppManifest();
+async afterPass(passContext){
+const manifestPromise=passContext.driver.getAppManifest();
+
 const timeoutPromise=new Promise(resolve=>setTimeout(resolve,3000));
-return Promise.race([manifestPromise,timeoutPromise]).
-then(response=>{
+
+const response=await Promise.race([manifestPromise,timeoutPromise]);
 if(!response){
 return null;
 }
@@ -11556,15 +11204,14 @@
 response.data=Buffer.from(response.data).slice(BOM_LENGTH).toString();
 }
 
-return manifestParser(response.data,response.url,options.url);
-});
+return manifestParser(response.data,response.url,passContext.url);
 }}
 
 
 module.exports=Manifest;
 
 }).call(this,require("buffer").Buffer);
-},{"../../lib/manifest-parser":31,"./gatherer":16,"buffer":54}],"./gatherers/mixed-content":[function(require,module,exports){
+},{"../../lib/manifest-parser":36,"./gatherer":19,"buffer":60}],"../gather/gatherers/mixed-content":[function(require,module,exports){
 (function(Buffer){
 
 
@@ -11576,6 +11223,8 @@
 const Gatherer=require('./gatherer');
 const URL=require('../../lib/url-shim');
 
+const Driver=require('../driver.js');
+
 
 
 
@@ -11593,6 +11242,7 @@
 super();
 this.ids=new Set();
 this.url=undefined;
+this._onRequestIntercepted=undefined;
 }
 
 
@@ -11615,12 +11265,18 @@
 return parsedURL.href;
 }
 
-_onRequestIntercepted(driver,event){
+
+
+
+
+_getRequestInterceptor(pageUrl,driver){
+
+const onRequestIntercepted=event=>{
 
 
 
 if(new URL(event.request.url).protocol==='http:'&&
-!URL.equalWithExcludedFragments(event.request.url,this.url)&&
+!URL.equalWithExcludedFragments(event.request.url,pageUrl)&&
 !this.ids.has(event.interceptionId)){
 this.ids.add(event.interceptionId);
 event.request.url=this.upgradeURL(event.request.url);
@@ -11635,45 +11291,51 @@
 interceptionId:event.interceptionId});
 
 }
+};
+
+return onRequestIntercepted;
 }
 
-beforePass(options){
-const driver=options.driver;
+
+
+
+async beforePass(passContext){
+const driver=passContext.driver;
 
 
 
 
 
-options.url=this.downgradeURL(options.url);
-this.url=options.url;
+passContext.url=this.downgradeURL(passContext.url);
+this.url=passContext.url;
+this._onRequestIntercepted=this._getRequestInterceptor(this.url,driver);
 
-driver.sendCommand('Network.enable',{});
-driver.on('Network.requestIntercepted',
-this._onRequestIntercepted.bind(this,driver));
-driver.sendCommand('Network.setCacheDisabled',{cacheDisabled:true});
-driver.sendCommand('Network.setRequestInterception',
-{patterns:[{urlPattern:'*'}]});
+await driver.sendCommand('Network.enable');
+driver.on('Network.requestIntercepted',this._onRequestIntercepted);
+await driver.sendCommand('Network.setCacheDisabled',{cacheDisabled:true});
+await driver.sendCommand('Network.setRequestInterception',{patterns:[{urlPattern:'*'}]});
 }
 
-afterPass(options,_){
-const driver=options.driver;
-return Promise.resolve().then(_=>driver.sendCommand(
-'Network.setRequestInterception',{patterns:[]})).
-then(_=>driver.off(
-'Network.requestIntercepted',
-this._onRequestIntercepted.bind(this,driver))).
-then(driver.sendCommand(
-'Network.setCacheDisabled',{cacheDisabled:false})).
-then(_=>{
-return{url:options.url};
-});
+
+
+
+
+async afterPass(passContext){
+const driver=passContext.driver;
+await driver.sendCommand('Network.setRequestInterception',{patterns:[]});
+if(this._onRequestIntercepted){
+driver.off('Network.requestIntercepted',this._onRequestIntercepted);
+}
+await driver.sendCommand('Network.setCacheDisabled',{cacheDisabled:false});
+
+return{url:passContext.url};
 }}
 
 
 module.exports=MixedContent;
 
 }).call(this,require("buffer").Buffer);
-},{"../../lib/url-shim":41,"./gatherer":16,"buffer":54}],"./gatherers/offline":[function(require,module,exports){
+},{"../../lib/url-shim":"url","../driver.js":17,"./gatherer":19,"buffer":60}],"../gather/gatherers/offline":[function(require,module,exports){
 
 
 
@@ -11685,24 +11347,32 @@
 const URL=require('../../lib/url-shim');
 
 class Offline extends Gatherer{
-beforePass(options){
-return options.driver.goOffline();
+
+
+
+beforePass(passContext){
+return passContext.driver.goOffline();
 }
 
-afterPass(options,tracingData){
-const navigationRecord=tracingData.networkRecords.filter(record=>{
-return URL.equalWithExcludedFragments(record._url,options.url)&&
+
+
+
+
+
+afterPass(passContext,loadData){
+const navigationRecord=loadData.networkRecords.filter(record=>{
+return URL.equalWithExcludedFragments(record._url,passContext.url)&&
 record._fetchedViaServiceWorker;
 }).pop();
 
-return options.driver.goOnline(options).
+return passContext.driver.goOnline(passContext).
 then(_=>navigationRecord?navigationRecord.statusCode:-1);
 }}
 
 
 module.exports=Offline;
 
-},{"../../lib/url-shim":41,"./gatherer":16}],"./gatherers/runtime-exceptions":[function(require,module,exports){
+},{"../../lib/url-shim":"url","./gatherer":19}],"../gather/gatherers/runtime-exceptions":[function(require,module,exports){
 
 
 
@@ -11720,29 +11390,39 @@
 class RuntimeExceptions extends Gatherer{
 constructor(){
 super();
+
 this._exceptions=[];
 this._onRuntimeExceptionThrown=this.onRuntimeExceptionThrown.bind(this);
 }
 
+
+
+
 onRuntimeExceptionThrown(entry){
 this._exceptions.push(entry);
 }
 
-beforePass(options){
-const driver=options.driver;
+
+
+
+beforePass(passContext){
+const driver=passContext.driver;
 driver.on('Runtime.exceptionThrown',this._onRuntimeExceptionThrown);
 }
 
-afterPass(options){
-return Promise.resolve().
-then(_=>options.driver.off('Runtime.exceptionThrown',this._onRuntimeExceptionThrown)).
-then(_=>this._exceptions);
+
+
+
+
+async afterPass(passContext){
+await passContext.driver.off('Runtime.exceptionThrown',this._onRuntimeExceptionThrown);
+return this._exceptions;
 }}
 
 
 module.exports=RuntimeExceptions;
 
-},{"./gatherer":16}],"./gatherers/scripts":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/scripts":[function(require,module,exports){
 
 
 
@@ -11762,31 +11442,30 @@
 
 
 
-afterPass(options,traceData){
-const driver=options.driver;
+async afterPass(passContext,loadData){
+const driver=passContext.driver;
+
 
 const scriptContentMap={};
-const scriptRecords=traceData.networkRecords.
-filter(record=>record.resourceType()===WebInspector.resourceTypes.Script);
+const scriptRecords=loadData.networkRecords.
+filter(record=>record._resourceType===WebInspector.resourceTypes.Script);
 
-return scriptRecords.reduce((promise,record)=>{
-return promise.
-then(()=>{
-return driver.getRequestContent(record.requestId).
-catch(_=>null).
-then(content=>{
-if(!content)return;
+for(const record of scriptRecords){
+try{
+const content=await driver.getRequestContent(record.requestId);
+if(content){
 scriptContentMap[record.requestId]=content;
-});
-}).
-then(()=>scriptContentMap);
-},Promise.resolve(scriptContentMap));
+}
+}catch(e){}
+}
+
+return scriptContentMap;
 }}
 
 
 module.exports=Scripts;
 
-},{"../../lib/web-inspector":42,"./gatherer":16}],"./gatherers/seo/canonical":[function(require,module,exports){
+},{"../../lib/web-inspector":47,"./gatherer":19}],"../gather/gatherers/seo/canonical":[function(require,module,exports){
 
 
 
@@ -11801,8 +11480,8 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+afterPass(passContext){
+const driver=passContext.driver;
 
 return driver.querySelectorAll('head link[rel="canonical" i]').
 then(nodes=>Promise.all(nodes.map(node=>node.getAttribute('href'))));
@@ -11812,7 +11491,7 @@
 module.exports=Canonical;
 
 
-},{"../gatherer":16}],"./gatherers/seo/crawlable-links":[function(require,module,exports){
+},{"../gatherer":19}],"../gather/gatherers/seo/crawlable-links":[function(require,module,exports){
 
 
 
@@ -11828,7 +11507,7 @@
 
 
 
-afterPass(options){
+afterPass(passContext){
 const expression=`(function() {
       ${DOMHelpers.getElementsInDocumentFnString}; // define function on page
       const selector = 'a[href]:not([rel~="nofollow"])';
@@ -11840,14 +11519,14 @@
         }));
     })()`;
 
-return options.driver.evaluateAsync(expression);
+return passContext.driver.evaluateAsync(expression);
 }}
 
 
 module.exports=CrawlableLinks;
 
 
-},{"../../../lib/dom-helpers.js":25,"../gatherer":16}],"./gatherers/seo/embedded-content":[function(require,module,exports){
+},{"../../../lib/dom-helpers.js":30,"../gatherer":19}],"../gather/gatherers/seo/embedded-content":[function(require,module,exports){
 
 
 
@@ -11863,7 +11542,7 @@
 
 
 
-afterPass(options){
+afterPass(passContext){
 const expression=`(function() {
       ${DOMHelpers.getElementsInDocumentFnString}; // define function on page
       const selector = 'object, embed, applet';
@@ -11884,19 +11563,20 @@
         }));
     })()`;
 
-return options.driver.evaluateAsync(expression);
+return passContext.driver.evaluateAsync(expression);
 }}
 
 
 module.exports=EmbeddedContent;
 
-},{"../../../lib/dom-helpers.js":25,"../gatherer":16}],"./gatherers/seo/font-size":[function(require,module,exports){
+},{"../../../lib/dom-helpers.js":30,"../gatherer":19}],"../gather/gatherers/seo/font-size":[function(require,module,exports){
 (function(global){
 
 
 
 
 
+
 'use strict';
 
 
@@ -11912,12 +11592,13 @@
 const Gatherer=require('../gatherer');
 const FONT_SIZE_PROPERTY_NAME='font-size';
 const TEXT_NODE_BLOCK_LIST=new Set(['SCRIPT','STYLE','NOSCRIPT']);
-
-const MINIMAL_LEGIBLE_FONT_SIZE_PX=16;
+const MINIMAL_LEGIBLE_FONT_SIZE_PX=12;
 
 const MAX_NODES_VISITED=500;
 const MAX_NODES_ANALYZED=50;
 
+const Driver=require('../../driver.js');
+
 
 
 
@@ -12046,20 +11727,22 @@
 
 
 
-afterPass(options){
-const stylesheets=new Map();
-const onStylesheetAdd=sheet=>stylesheets.set(sheet.header.styleSheetId,sheet.header);
-options.driver.on('CSS.styleSheetAdded',onStylesheetAdd);
+afterPass(passContext){
 
-const enableDOM=options.driver.sendCommand('DOM.enable');
-const enableCSS=options.driver.sendCommand('CSS.enable');
+const stylesheets=new Map();
+
+const onStylesheetAdd=sheet=>stylesheets.set(sheet.header.styleSheetId,sheet.header);
+passContext.driver.on('CSS.styleSheetAdded',onStylesheetAdd);
+
+const enableDOM=passContext.driver.sendCommand('DOM.enable');
+const enableCSS=passContext.driver.sendCommand('CSS.enable');
 
 let failingTextLength=0;
 let visitedTextLength=0;
 let totalTextLength=0;
 
 return Promise.all([enableDOM,enableCSS]).
-then(()=>getAllNodesFromBody(options.driver)).
+then(()=>getAllNodesFromBody(passContext.driver)).
 then(nodes=>{
 const textNodes=nodes.filter(isNonEmptyTextNode);
 totalTextLength=textNodes.reduce((sum,node)=>sum+=getNodeTextLength(node),0);
@@ -12070,7 +11753,7 @@
 return nodesToVisit;
 }).
 then(textNodes=>
-Promise.all(textNodes.map(node=>getFontSizeInformation(options.driver,node)))).
+Promise.all(textNodes.map(node=>getFontSizeInformation(passContext.driver,node)))).
 then(fontSizeInfo=>{
 const visitedNodes=fontSizeInfo.filter(Boolean);
 visitedTextLength=visitedNodes.reduce((sum,{textLength})=>sum+=textLength,0);
@@ -12082,7 +11765,7 @@
 sort((a,b)=>b.textLength-a.textLength).
 slice(0,MAX_NODES_ANALYZED).
 map(info=>
-getFontSizeSourceRule(options.driver,info.node).
+getFontSizeSourceRule(passContext.driver,info.node).
 then(sourceRule=>{
 if(sourceRule){
 info.cssRule={
@@ -12104,7 +11787,7 @@
 
 }).
 then(analyzedFailingNodesData=>{
-options.driver.off('CSS.styleSheetAdded',onStylesheetAdd);
+passContext.driver.off('CSS.styleSheetAdded',onStylesheetAdd);
 
 const analyzedFailingTextLength=analyzedFailingNodesData.
 reduce((sum,{textLength})=>sum+=textLength,0);
@@ -12114,8 +11797,8 @@
 forEach(data=>data.cssRule.stylesheet=stylesheets.get(data.cssRule.styleSheetId));
 
 return Promise.all([
-options.driver.sendCommand('DOM.disable'),
-options.driver.sendCommand('CSS.disable')]).
+passContext.driver.sendCommand('DOM.disable'),
+passContext.driver.sendCommand('CSS.disable')]).
 then(_=>({
 analyzedFailingNodesData,
 analyzedFailingTextLength,
@@ -12140,7 +11823,7 @@
 
 
 }).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"../../../lib/sentry.js":33,"../../../lib/web-inspector":42,"../gatherer":16}],"./gatherers/seo/hreflang":[function(require,module,exports){
+},{"../../../lib/sentry.js":39,"../../../lib/web-inspector":47,"../../driver.js":17,"../gatherer":19}],"../gather/gatherers/seo/hreflang":[function(require,module,exports){
 
 
 
@@ -12155,8 +11838,8 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+afterPass(passContext){
+const driver=passContext.driver;
 
 return driver.querySelectorAll('head link[rel="alternate" i][hreflang]').
 then(nodes=>Promise.all(nodes.map(node=>
@@ -12165,7 +11848,10 @@
 then(attributeValues=>attributeValues&&
 attributeValues.map(values=>{
 const[href,hreflang]=values;
-return{href,hreflang};
+return{
+href:href||'',
+hreflang:hreflang||''};
+
 }));
 
 }}
@@ -12174,7 +11860,7 @@
 module.exports=Hreflang;
 
 
-},{"../gatherer":16}],"./gatherers/seo/meta-description":[function(require,module,exports){
+},{"../gatherer":19}],"../gather/gatherers/seo/meta-description":[function(require,module,exports){
 
 
 
@@ -12189,8 +11875,8 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+afterPass(passContext){
+const driver=passContext.driver;
 
 return driver.querySelector('head meta[name="description" i]').
 then(node=>node&&node.getAttribute('content'));
@@ -12200,7 +11886,7 @@
 module.exports=MetaDescription;
 
 
-},{"../gatherer":16}],"./gatherers/seo/meta-robots":[function(require,module,exports){
+},{"../gatherer":19}],"../gather/gatherers/seo/meta-robots":[function(require,module,exports){
 
 
 
@@ -12215,8 +11901,8 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+afterPass(passContext){
+const driver=passContext.driver;
 
 return driver.querySelector('head meta[name="robots" i]').
 then(node=>node&&node.getAttribute('content'));
@@ -12225,7 +11911,48 @@
 
 module.exports=MetaRobots;
 
-},{"../gatherer":16}],"./gatherers/service-worker":[function(require,module,exports){
+},{"../gatherer":19}],"../gather/gatherers/seo/robots-txt":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Gatherer=require('../gatherer');
+
+
+
+
+
+async function getRobotsTxtContent(){
+try{
+const response=await fetch(new URL('/robots.txt',location.href).href);
+if(!response.ok){
+return{status:response.status,content:null};
+}
+
+const content=await response.text();
+return{status:response.status,content};
+}catch(_){
+return{status:null,content:null};
+}
+}
+
+
+class RobotsTxt extends Gatherer{
+
+
+
+
+afterPass(passContext){
+return passContext.driver.evaluateAsync(`(${getRobotsTxtContent.toString()}())`);
+}}
+
+
+module.exports=RobotsTxt;
+
+},{"../gatherer":19}],"../gather/gatherers/service-worker":[function(require,module,exports){
 
 
 
@@ -12236,21 +11963,21 @@
 const Gatherer=require('./gatherer');
 
 class ServiceWorker extends Gatherer{
-beforePass(options){
-const driver=options.driver;
-return driver.
-getServiceWorkerVersions().
-then(data=>{
-return{
-versions:data.versions};
 
-});
+
+
+
+async beforePass(passContext){
+const{versions}=await passContext.driver.getServiceWorkerVersions();
+return{
+versions};
+
 }}
 
 
 module.exports=ServiceWorker;
 
-},{"./gatherer":16}],"./gatherers/start-url":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/start-url":[function(require,module,exports){
 
 
 
@@ -12259,83 +11986,105 @@
 'use strict';
 
 const Gatherer=require('./gatherer');
-const URL=require('../../lib/url-shim');
 const manifestParser=require('../../lib/manifest-parser');
+const Driver=require('../driver.js');
 
 class StartUrl extends Gatherer{
-constructor(){
-super();
 
-this.startUrl=null;
-this.err=null;
-}
 
-executeFetchRequest(driver,url){
-return driver.evaluateAsync(
-`fetch('${url}')
-        .then(response => response.status)
-        .catch(err => ({fetchFailed: true, message: err.message}))`);
 
-}
 
-pass(options){
-return options.driver.getAppManifest().
-then(response=>{
-return response&&manifestParser(response.data,response.url,options.url);
-}).
+
+afterPass(passContext){
+const driver=passContext.driver;
+return driver.goOnline(passContext).
+then(()=>driver.getAppManifest()).
+then(response=>driver.goOffline().then(()=>response)).
+then(response=>response&&manifestParser(response.data,response.url,passContext.url)).
 then(manifest=>{
+const startUrlInfo=this._readManifestStartUrl(manifest);
+if(startUrlInfo.isReadFailure){
+return{statusCode:-1,debugString:startUrlInfo.reason};
+}
+
+return this._attemptManifestFetch(passContext.driver,startUrlInfo.startUrl);
+}).catch(()=>{
+return{statusCode:-1,debugString:'Unable to fetch start URL via service worker'};
+});
+}
+
+
+
+
+
+
+_readManifestStartUrl(manifest){
 if(!manifest||!manifest.value){
 const detailedMsg=manifest&&manifest.debugString;
-this.debugString=detailedMsg?
-`Error fetching web app manifest: ${detailedMsg}`:
-`No usable web app manifest found on page ${options.url}`;
-return;
+
+if(detailedMsg){
+return{isReadFailure:true,reason:`Error fetching web app manifest: ${detailedMsg}`};
+}else{
+return{isReadFailure:true,reason:`No usable web app manifest found on page`};
 }
+}
+
+
 
 if(manifest.value.start_url.debugString){
-
-
-this.debugString=manifest.value.start_url.debugString;
+return{isReadFailure:true,reason:manifest.value.start_url.debugString};
 }
 
-this.startUrl=manifest.value.start_url.value;
-return this.executeFetchRequest(options.driver,this.startUrl);
-});
+
+return{isReadFailure:false,startUrl:manifest.value.start_url.value};
 }
 
-afterPass(options,tracingData){
-const networkRecords=tracingData.networkRecords;
-const navigationRecord=networkRecords.filter(record=>{
-return URL.equalWithExcludedFragments(record._url,this.startUrl)&&
-record._fetchedViaServiceWorker;
-}).pop();
 
-const msgWithExtraDebugString=msg=>this.debugString?`${msg}: ${this.debugString}`:msg;
-return options.driver.goOnline(options).
-then(_=>{
-if(!this.startUrl){
-return{
+
+
+
+
+
+
+_attemptManifestFetch(driver,startUrl){
+
+const timeoutPromise=new Promise(resolve=>
+setTimeout(
+()=>resolve({statusCode:-1,debugString:'Timed out waiting for fetched start_url'}),
+3000));
+
+
+
+const fetchPromise=new Promise(resolve=>{
+driver.on('Network.responseReceived',onResponseReceived);
+
+
+function onResponseReceived(responseEvent){
+const{response}=responseEvent;
+
+if(response.url!==startUrl)return;
+driver.off('Network.responseReceived',onResponseReceived);
+
+if(!response.fromServiceWorker){
+return resolve({
 statusCode:-1,
-debugString:msgWithExtraDebugString('No start URL to fetch')};
+debugString:'Unable to fetch start URL via service worker'});
 
-}else if(!navigationRecord){
-return{
-statusCode:-1,
-debugString:msgWithExtraDebugString('Unable to fetch start URL via service worker')};
+}
 
-}else{
-return{
-statusCode:navigationRecord.statusCode,
-debugString:this.debugString};
-
+return resolve({statusCode:response.status});
 }
 });
+
+return driver.
+evaluateAsync(`window.location = '${startUrl}'`).
+then(()=>Promise.race([fetchPromise,timeoutPromise]));
 }}
 
 
 module.exports=StartUrl;
 
-},{"../../lib/manifest-parser":31,"../../lib/url-shim":41,"./gatherer":16}],"./gatherers/theme-color":[function(require,module,exports){
+},{"../../lib/manifest-parser":36,"../driver.js":17,"./gatherer":19}],"../gather/gatherers/theme-color":[function(require,module,exports){
 
 
 
@@ -12350,17 +12099,17 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+async afterPass(passContext){
+const driver=passContext.driver;
 
-return driver.querySelector('head meta[name="theme-color" i]').
-then(node=>node&&node.getAttribute('content'));
+const metaEl=await driver.querySelector('head meta[name="theme-color" i]');
+return metaEl&&metaEl.getAttribute('content');
 }}
 
 
 module.exports=ThemeColor;
 
-},{"./gatherer":16}],"./gatherers/url":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/viewport-dimensions":[function(require,module,exports){
 
 
 
@@ -12370,32 +12119,10 @@
 
 const Gatherer=require('./gatherer');
 
-class URL extends Gatherer{
-afterPass(options){
 
 
 
 
-return{
-initialUrl:options.initialUrl,
-finalUrl:options.url};
-
-}}
-
-
-module.exports=URL;
-
-},{"./gatherer":16}],"./gatherers/viewport-dimensions":[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Gatherer=require('./gatherer');
-
-
 
 
 function getViewportDimensions(){
@@ -12416,26 +12143,26 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+async afterPass(passContext){
+const driver=passContext.driver;
 
-return driver.evaluateAsync(`(${getViewportDimensions.toString()}())`,{useIsolation:true}).
 
-then(dimensions=>{
-const allNumeric=Object.keys(dimensions).every(key=>Number.isFinite(dimensions[key]));
+const dimensions=await driver.evaluateAsync(`(${getViewportDimensions.toString()}())`,
+{useIsolation:true});
+
+const allNumeric=Object.values(dimensions).every(Number.isFinite);
 if(!allNumeric){
 const results=JSON.stringify(dimensions);
 throw new Error(`ViewportDimensions results were not numeric: ${results}`);
 }
 
 return dimensions;
-});
 }}
 
 
 module.exports=ViewportDimensions;
 
-},{"./gatherer":16}],"./gatherers/viewport":[function(require,module,exports){
+},{"./gatherer":19}],"../gather/gatherers/viewport":[function(require,module,exports){
 
 
 
@@ -12450,17 +12177,2396 @@
 
 
 
-afterPass(options){
-const driver=options.driver;
+async afterPass(passContext){
+const driver=passContext.driver;
 
-return driver.querySelector('head meta[name="viewport" i]').
-then(node=>node&&node.getAttribute('content'));
+const metaEl=await driver.querySelector('head meta[name="viewport" i]');
+return metaEl&&metaEl.getAttribute('content');
 }}
 
 
 module.exports=Viewport;
 
-},{"./gatherer":16}],1:[function(require,module,exports){
+},{"./gatherer":19}],"./gather/computed/critical-request-chains":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+const WebInspector=require('../../lib/web-inspector');
+const assert=require('assert');
+
+class CriticalRequestChains extends ComputedArtifact{
+get name(){
+return'CriticalRequestChains';
+}
+
+
+
+
+
+
+
+
+
+static isCritical(request,mainResource){
+assert.ok(mainResource,'mainResource not provided');
+
+
+if(request._isLinkPreload){
+return false;
+}
+
+const resourceTypeCategory=request._resourceType&&request._resourceType._category;
+
+
+const isIframe=request._resourceType===WebInspector.resourceTypes.Document&&
+request._frameId!==mainResource._frameId;
+
+
+
+const nonCriticalResourceTypes=[
+WebInspector.resourceTypes.Image._category,
+WebInspector.resourceTypes.XHR._category];
+
+if(nonCriticalResourceTypes.includes(resourceTypeCategory)||
+isIframe||
+request._mimeType&&request._mimeType.startsWith('image/')){
+return false;
+}
+
+return['VeryHigh','High','Medium'].includes(request.priority());
+}
+
+
+
+
+
+
+static extractChain(networkRecords,mainResource){
+networkRecords=networkRecords.filter(req=>req.finished);
+
+
+
+const requestIdToRequests=new Map();
+for(const request of networkRecords){
+requestIdToRequests.set(request.requestId,request);
+}
+
+
+
+const criticalRequests=networkRecords.filter(request=>
+CriticalRequestChains.isCritical(request,mainResource));
+
+
+
+const criticalRequestChains={};
+for(const request of criticalRequests){
+
+
+
+
+const ancestors=[];
+let ancestorRequest=request.initiatorRequest();
+
+let node=criticalRequestChains;
+while(ancestorRequest){
+const ancestorIsCritical=CriticalRequestChains.isCritical(ancestorRequest,mainResource);
+
+
+
+
+
+if(!ancestorIsCritical||ancestors.includes(ancestorRequest.requestId)){
+
+
+ancestors.length=0;
+node=undefined;
+break;
+}
+ancestors.push(ancestorRequest.requestId);
+ancestorRequest=ancestorRequest.initiatorRequest();
+}
+
+
+
+let ancestor=ancestors.pop();
+while(ancestor&&node){
+const parentRequest=requestIdToRequests.get(ancestor);
+if(!parentRequest){
+throw new Error(`request with id ${ancestor} not found.`);
+}
+
+const parentRequestId=parentRequest.requestId;
+if(!node[parentRequestId]){
+node[parentRequestId]={
+request:parentRequest,
+children:{}};
+
+}
+
+
+ancestor=ancestors.pop();
+node=node[parentRequestId].children;
+}
+
+if(!node){
+continue;
+}
+
+
+if(node[request.requestId]){
+continue;
+}
+
+
+node[request.requestId]={
+request,
+children:{}};
+
+}
+
+return criticalRequestChains;
+}
+
+
+
+
+
+
+async compute_(data,artifacts){
+const[networkRecords,mainResource]=await Promise.all([
+artifacts.requestNetworkRecords(data.devtoolsLog),
+artifacts.requestMainResource(data)]);
+
+
+return CriticalRequestChains.extractChain(networkRecords,mainResource);
+}}
+
+
+module.exports=CriticalRequestChains;
+
+},{"../../lib/web-inspector":47,"./computed-artifact":11,"assert":53}],"./gather/computed/dtm-model":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+const DTM=require('../../lib/traces/devtools-timeline-model');
+
+class DevtoolsTimelineModel extends ComputedArtifact{
+get name(){
+return'DevtoolsTimelineModel';
+}
+
+
+
+
+
+async compute_(trace){
+return new DTM(trace);
+}}
+
+
+module.exports=DevtoolsTimelineModel;
+
+},{"../../lib/traces/devtools-timeline-model":43,"./computed-artifact":11}],"./gather/computed/load-simulator":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+const constants=require('../../config/constants');
+const Simulator=require('../../lib/dependency-graph/simulator/simulator');
+
+class LoadSimulatorArtifact extends ComputedArtifact{
+get name(){
+return'LoadSimulator';
+}
+
+
+
+
+
+
+async compute_(data,artifacts){
+const{throttlingMethod,throttling}=data.settings;
+const networkAnalysis=await artifacts.requestNetworkAnalysis(data.devtoolsLog);
+
+const options={
+additionalRttByOrigin:networkAnalysis.additionalRttByOrigin,
+serverResponseTimeByOrigin:networkAnalysis.serverResponseTimeByOrigin};
+
+
+switch(throttlingMethod){
+case'provided':
+options.rtt=networkAnalysis.rtt;
+options.throughput=networkAnalysis.throughput;
+options.cpuSlowdownMultiplier=1;
+options.layoutTaskMultiplier=1;
+break;
+case'devtools':
+if(throttling){
+options.rtt=
+throttling.requestLatencyMs/constants.throttling.DEVTOOLS_RTT_ADJUSTMENT_FACTOR;
+options.throughput=
+throttling.downloadThroughputKbps*1024/
+constants.throttling.DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR;
+}
+
+options.cpuSlowdownMultiplier=1;
+options.layoutTaskMultiplier=1;
+break;
+case'simulate':
+if(throttling){
+options.rtt=throttling.rttMs;
+options.throughput=throttling.throughputKbps*1024;
+options.cpuSlowdownMultiplier=throttling.cpuSlowdownMultiplier;
+}
+break;
+default:
+
+break;}
+
+
+return new Simulator(options);
+}}
+
+
+module.exports=LoadSimulatorArtifact;
+
+},{"../../config/constants":8,"../../lib/dependency-graph/simulator/simulator":28,"./computed-artifact":11}],"./gather/computed/main-resource":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+
+
+
+
+
+class MainResource extends ComputedArtifact{
+get name(){
+return'MainResource';
+}
+
+
+
+
+
+
+compute_(data,artifacts){
+const{URL,devtoolsLog}=data;
+return artifacts.requestNetworkRecords(devtoolsLog).
+then(requests=>{
+const mainResource=requests.find(request=>request.url===URL.finalUrl);
+
+if(!mainResource){
+throw new Error('Unable to identify the main resource');
+}
+
+return mainResource;
+});
+}}
+
+
+module.exports=MainResource;
+
+},{"./computed-artifact":11}],"./gather/computed/manifest-values":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+const icons=require('../../lib/icons');
+
+const PWA_DISPLAY_VALUES=['minimal-ui','fullscreen','standalone'];
+
+
+
+const SUGGESTED_SHORTNAME_LENGTH=12;
+
+class ManifestValues extends ComputedArtifact{
+get name(){
+return'ManifestValues';
+}
+
+static get validityIds(){
+return['hasManifest','hasParseableManifest'];
+}
+
+
+
+
+
+
+static get manifestChecks(){
+return[
+{
+id:'hasStartUrl',
+failureText:'Manifest does not contain a `start_url`',
+validate:manifestValue=>!!manifestValue.start_url.value},
+
+{
+id:'hasIconsAtLeast192px',
+failureText:'Manifest does not have icons at least 192px',
+validate:manifestValue=>icons.doExist(manifestValue)&&
+icons.sizeAtLeast(192,manifestValue).length>0},
+
+{
+id:'hasIconsAtLeast512px',
+failureText:'Manifest does not have icons at least 512px',
+validate:manifestValue=>icons.doExist(manifestValue)&&
+icons.sizeAtLeast(512,manifestValue).length>0},
+
+{
+id:'hasPWADisplayValue',
+failureText:'Manifest\'s `display` value is not one of: '+PWA_DISPLAY_VALUES.join(' | '),
+validate:manifestValue=>PWA_DISPLAY_VALUES.includes(manifestValue.display.value)},
+
+{
+id:'hasBackgroundColor',
+failureText:'Manifest does not have `background_color`',
+validate:manifestValue=>!!manifestValue.background_color.value},
+
+{
+id:'hasThemeColor',
+failureText:'Manifest does not have `theme_color`',
+validate:manifestValue=>!!manifestValue.theme_color.value},
+
+{
+id:'hasShortName',
+failureText:'Manifest does not have `short_name`',
+validate:manifestValue=>!!manifestValue.short_name.value},
+
+{
+id:'shortNameLength',
+failureText:'Manifest `short_name` will be truncated when displayed on the homescreen',
+validate:manifestValue=>!!manifestValue.short_name.value&&
+manifestValue.short_name.value.length<=SUGGESTED_SHORTNAME_LENGTH},
+
+{
+id:'hasName',
+failureText:'Manifest does not have `name`',
+validate:manifestValue=>!!manifestValue.name.value}];
+
+
+}
+
+
+
+
+
+
+async compute_(manifest){
+
+let parseFailureReason;
+
+if(manifest===null){
+return{
+isParseFailure:true,
+parseFailureReason:'No manifest was fetched',
+allChecks:[]};
+
+}
+const manifestValue=manifest.value;
+if(manifestValue===undefined){
+return{
+isParseFailure:true,
+parseFailureReason:'Manifest failed to parse as valid JSON',
+allChecks:[]};
+
+}
+
+
+const remainingChecks=ManifestValues.manifestChecks.map(item=>{
+return{
+id:item.id,
+failureText:item.failureText,
+passing:item.validate(manifestValue)};
+
+});
+
+return{
+isParseFailure:false,
+parseFailureReason,
+allChecks:remainingChecks};
+
+}}
+
+
+module.exports=ManifestValues;
+
+},{"../../lib/icons":35,"./computed-artifact":11}],"./gather/computed/metrics/estimated-input-latency":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./metric');
+const LHError=require('../../../lib/errors');
+const TracingProcessor=require('../../../lib/traces/tracing-processor');
+
+const ROLLING_WINDOW_SIZE=5000;
+
+
+
+
+
+
+class EstimatedInputLatency extends MetricArtifact{
+get name(){
+return'EstimatedInputLatency';
+}
+
+
+
+
+
+static calculateRollingWindowEIL(events){
+const candidateStartEvts=events.filter(evt=>evt.duration>=10);
+
+let worst90thPercentileLatency=16;
+for(const startEvt of candidateStartEvts){
+const latencyPercentiles=TracingProcessor.getRiskToResponsiveness(
+events,
+startEvt.start,
+startEvt.start+ROLLING_WINDOW_SIZE,
+[0.9]);
+
+
+worst90thPercentileLatency=Math.max(latencyPercentiles[0].time,worst90thPercentileLatency);
+}
+
+return worst90thPercentileLatency;
+}
+
+
+
+
+
+computeObservedMetric(data){
+const{firstMeaningfulPaint}=data.traceOfTab.timings;
+if(!firstMeaningfulPaint){
+throw new LHError(LHError.errors.NO_FMP);
+}
+
+const events=TracingProcessor.getMainThreadTopLevelEvents(
+data.traceOfTab,
+firstMeaningfulPaint).
+filter(evt=>evt.duration>=1);
+
+return Promise.resolve({
+timing:EstimatedInputLatency.calculateRollingWindowEIL(events)});
+
+}}
+
+
+module.exports=EstimatedInputLatency;
+
+},{"../../../lib/errors":33,"../../../lib/traces/tracing-processor":46,"./metric":13}],"./gather/computed/metrics/first-contentful-paint":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./metric');
+const LHError=require('../../../lib/errors');
+
+class FirstContentfulPaint extends MetricArtifact{
+get name(){
+return'FirstContentfulPaint';
+}
+
+
+
+
+
+computeObservedMetric(data){
+const{traceOfTab}=data;
+if(!traceOfTab.timestamps.firstContentfulPaint){
+throw new LHError(LHError.errors.NO_FCP);
+}
+
+return Promise.resolve({
+timing:traceOfTab.timings.firstContentfulPaint,
+timestamp:traceOfTab.timestamps.firstContentfulPaint});
+
+}}
+
+
+module.exports=FirstContentfulPaint;
+
+},{"../../../lib/errors":33,"./metric":13}],"./gather/computed/metrics/first-cpu-idle":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+const MetricArtifact=require('./metric');
+const TracingProcessor=require('../../../lib/traces/tracing-processor');
+const LHError=require('../../../lib/errors');
+
+const LONG_TASK_THRESHOLD=50;
+
+const MAX_TASK_CLUSTER_DURATION=250;
+const MIN_TASK_CLUSTER_PADDING=1000;
+const MIN_TASK_CLUSTER_FMP_DISTANCE=5000;
+
+const MAX_QUIET_WINDOW_SIZE=5000;
+
+
+const EXPONENTIATION_COEFFICIENT=-Math.log(3-1)/15;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class FirstCPUIdle extends MetricArtifact{
+get name(){
+return'FirstCPUIdle';
+}
+
+
+
+
+
+static getRequiredWindowSizeInMs(t){
+const tInSeconds=t/1000;
+const exponentiationComponent=Math.exp(EXPONENTIATION_COEFFICIENT*tInSeconds);
+return(4*exponentiationComponent+1)*1000;
+}
+
+
+
+
+
+
+
+
+
+
+static getTaskClustersInWindow(tasks,startIndex,windowEnd){
+const clusters=[];
+
+let previousTaskEndTime=-Infinity;
+
+let currentCluster=[];
+
+
+
+
+
+const clusteringWindowEnd=windowEnd+MIN_TASK_CLUSTER_PADDING;
+
+const isInClusteringWindow=task=>task.start<clusteringWindowEnd;
+for(let i=startIndex;i<tasks.length;i++){
+if(!isInClusteringWindow(tasks[i])){
+break;
+}
+
+const task=tasks[i];
+
+
+if(task.start-previousTaskEndTime>MIN_TASK_CLUSTER_PADDING){
+currentCluster=[];
+clusters.push(currentCluster);
+}
+
+currentCluster.push(task);
+previousTaskEndTime=task.end;
+}
+
+return clusters.
+
+map(tasks=>{
+const start=tasks[0].start;
+const end=tasks[tasks.length-1].end;
+const duration=end-start;
+return{start,end,duration};
+}).
+
+filter(cluster=>cluster.start<windowEnd);
+}
+
+
+
+
+
+
+
+
+
+
+static findQuietWindow(FMP,traceEnd,longTasks){
+
+if(longTasks.length===0||
+longTasks[0].start>FMP+FirstCPUIdle.getRequiredWindowSizeInMs(0)){
+return FMP;
+}
+
+
+const isTooCloseToFMP=cluster=>cluster.start<FMP+MIN_TASK_CLUSTER_FMP_DISTANCE;
+
+const isTooLong=cluster=>cluster.duration>MAX_TASK_CLUSTER_DURATION;
+
+const isBadCluster=cluster=>isTooCloseToFMP(cluster)||isTooLong(cluster);
+
+
+
+for(let i=0;i<longTasks.length;i++){
+const windowStart=longTasks[i].end;
+const windowSize=FirstCPUIdle.getRequiredWindowSizeInMs(windowStart-FMP);
+const windowEnd=windowStart+windowSize;
+
+
+if(windowEnd>traceEnd){
+throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
+}
+
+
+if(i+1<longTasks.length&&
+longTasks[i+1].start-windowStart<=MIN_TASK_CLUSTER_PADDING){
+continue;
+}
+
+const taskClusters=FirstCPUIdle.getTaskClustersInWindow(longTasks,i+1,windowEnd);
+const hasBadTaskClusters=taskClusters.some(isBadCluster);
+
+if(!hasBadTaskClusters){
+return windowStart;
+}
+}
+
+throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
+}
+
+
+
+
+
+computeObservedMetric(data){
+const{traceOfTab}=data;
+const navStart=traceOfTab.timestamps.navigationStart;
+const FMP=traceOfTab.timings.firstMeaningfulPaint;
+const DCL=traceOfTab.timings.domContentLoaded;
+const traceEnd=traceOfTab.timings.traceEnd;
+
+if(traceEnd-FMP<MAX_QUIET_WINDOW_SIZE){
+throw new LHError(LHError.errors.FMP_TOO_LATE_FOR_FCPUI);
+}
+
+if(!FMP||!DCL){
+throw new LHError(FMP?LHError.errors.NO_DCL:LHError.errors.NO_FMP);
+}
+
+const longTasksAfterFMP=TracingProcessor.getMainThreadTopLevelEvents(traceOfTab,FMP).
+filter(evt=>evt.duration>=LONG_TASK_THRESHOLD);
+const firstInteractive=FirstCPUIdle.findQuietWindow(FMP,traceEnd,longTasksAfterFMP);
+
+const valueInMs=Math.max(firstInteractive,DCL);
+
+return Promise.resolve({
+timing:valueInMs,
+timestamp:valueInMs*1000+navStart});
+
+}}
+
+
+
+
+
+
+
+module.exports=FirstCPUIdle;
+
+},{"../../../lib/errors":33,"../../../lib/traces/tracing-processor":46,"./metric":13}],"./gather/computed/metrics/first-meaningful-paint":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./metric');
+const LHError=require('../../../lib/errors');
+
+class FirstMeaningfulPaint extends MetricArtifact{
+get name(){
+return'FirstMeaningfulPaint';
+}
+
+
+
+
+
+computeObservedMetric(data){
+const{traceOfTab}=data;
+if(!traceOfTab.timestamps.firstMeaningfulPaint){
+throw new LHError(LHError.errors.NO_FMP);
+}
+
+return Promise.resolve({
+timing:traceOfTab.timings.firstMeaningfulPaint,
+timestamp:traceOfTab.timestamps.firstMeaningfulPaint});
+
+}}
+
+
+module.exports=FirstMeaningfulPaint;
+
+},{"../../../lib/errors":33,"./metric":13}],"./gather/computed/metrics/interactive":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./metric');
+
+const NetworkRecorder=require('../../../lib/network-recorder');
+const TracingProcessor=require('../../../lib/traces/tracing-processor');
+const LHError=require('../../../lib/errors');
+
+const REQUIRED_QUIET_WINDOW=5000;
+const ALLOWED_CONCURRENT_REQUESTS=2;
+
+
+
+
+
+
+class Interactive extends MetricArtifact{
+get name(){
+return'Interactive';
+}
+
+
+
+
+
+
+
+
+static _findNetworkQuietPeriods(networkRecords,traceOfTab){
+const traceEndTsInMs=traceOfTab.timestamps.traceEnd/1000;
+
+const filteredNetworkRecords=networkRecords.filter(record=>{
+return record.finished&&record.requestMethod==='GET'&&!record.failed&&
+
+record.statusCode<400;
+});
+return NetworkRecorder.findNetworkQuietPeriods(filteredNetworkRecords,
+ALLOWED_CONCURRENT_REQUESTS,traceEndTsInMs);
+}
+
+
+
+
+
+
+
+static _findCPUQuietPeriods(longTasks,traceOfTab){
+const navStartTsInMs=traceOfTab.timestamps.navigationStart/1000;
+const traceEndTsInMs=traceOfTab.timestamps.traceEnd/1000;
+if(longTasks.length===0){
+return[{start:0,end:traceEndTsInMs}];
+}
+
+
+const quietPeriods=[];
+longTasks.forEach((task,index)=>{
+if(index===0){
+quietPeriods.push({
+start:0,
+end:task.start+navStartTsInMs});
+
+}
+
+if(index===longTasks.length-1){
+quietPeriods.push({
+start:task.end+navStartTsInMs,
+end:traceEndTsInMs});
+
+}else{
+quietPeriods.push({
+start:task.end+navStartTsInMs,
+end:longTasks[index+1].start+navStartTsInMs});
+
+}
+});
+
+return quietPeriods;
+}
+
+
+
+
+
+
+
+
+static findOverlappingQuietPeriods(longTasks,networkRecords,traceOfTab){
+const FcpTsInMs=traceOfTab.timestamps.firstContentfulPaint/1000;
+
+
+const isLongEnoughQuietPeriod=period=>
+period.end>FcpTsInMs+REQUIRED_QUIET_WINDOW&&
+period.end-period.start>=REQUIRED_QUIET_WINDOW;
+const networkQuietPeriods=this._findNetworkQuietPeriods(networkRecords,traceOfTab).
+filter(isLongEnoughQuietPeriod);
+const cpuQuietPeriods=this._findCPUQuietPeriods(longTasks,traceOfTab).
+filter(isLongEnoughQuietPeriod);
+
+const cpuQueue=cpuQuietPeriods.slice();
+const networkQueue=networkQuietPeriods.slice();
+
+
+let cpuCandidate=cpuQueue.shift();
+let networkCandidate=networkQueue.shift();
+while(cpuCandidate&&networkCandidate){
+if(cpuCandidate.start>=networkCandidate.start){
+
+if(networkCandidate.end>=cpuCandidate.start+REQUIRED_QUIET_WINDOW){
+return{
+cpuQuietPeriod:cpuCandidate,
+networkQuietPeriod:networkCandidate,
+cpuQuietPeriods,
+networkQuietPeriods};
+
+}else{
+networkCandidate=networkQueue.shift();
+}
+}else{
+
+if(cpuCandidate.end>=networkCandidate.start+REQUIRED_QUIET_WINDOW){
+return{
+cpuQuietPeriod:cpuCandidate,
+networkQuietPeriod:networkCandidate,
+cpuQuietPeriods,
+networkQuietPeriods};
+
+}else{
+cpuCandidate=cpuQueue.shift();
+}
+}
+}
+
+throw new LHError(
+cpuCandidate?
+LHError.errors.NO_TTI_NETWORK_IDLE_PERIOD:
+LHError.errors.NO_TTI_CPU_IDLE_PERIOD);
+
+}
+
+
+
+
+
+computeObservedMetric(data){
+const{traceOfTab,networkRecords}=data;
+if(!traceOfTab.timestamps.firstContentfulPaint){
+throw new LHError(LHError.errors.NO_FCP);
+}
+
+if(!traceOfTab.timestamps.domContentLoaded){
+throw new LHError(LHError.errors.NO_DCL);
+}
+
+const longTasks=TracingProcessor.getMainThreadTopLevelEvents(traceOfTab).
+filter(event=>event.duration>=50);
+const quietPeriodInfo=Interactive.findOverlappingQuietPeriods(
+longTasks,
+networkRecords,
+traceOfTab);
+
+
+const cpuQuietPeriod=quietPeriodInfo.cpuQuietPeriod;
+
+const timestamp=Math.max(
+cpuQuietPeriod.start,
+traceOfTab.timestamps.firstContentfulPaint/1000,
+traceOfTab.timestamps.domContentLoaded/1000)*
+1000;
+const timing=(timestamp-traceOfTab.timestamps.navigationStart)/1000;
+return Promise.resolve({timing,timestamp});
+}}
+
+
+module.exports=Interactive;
+
+
+
+
+
+
+
+},{"../../../lib/errors":33,"../../../lib/network-recorder":37,"../../../lib/traces/tracing-processor":46,"./metric":13}],"./gather/computed/metrics/lantern-estimated-input-latency":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const LanternMetricArtifact=require('./lantern-metric');
+const Node=require('../../../lib/dependency-graph/node');
+const EstimatedInputLatency=require('./estimated-input-latency');
+
+class LanternEstimatedInputLatency extends LanternMetricArtifact{
+get name(){
+return'LanternEstimatedInputLatency';
+}
+
+
+
+
+get COEFFICIENTS(){
+return{
+intercept:0,
+optimistic:0.4,
+pessimistic:0.4};
+
+}
+
+
+
+
+
+getOptimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+getPessimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+
+getEstimateFromSimulation(simulation,extras){
+
+
+const fmpTimeInMs=extras.optimistic?
+extras.fmpResult.pessimisticEstimate.timeInMs:
+extras.fmpResult.optimisticEstimate.timeInMs;
+
+const events=LanternEstimatedInputLatency.getEventsAfterFMP(
+simulation.nodeTimings,
+fmpTimeInMs);
+
+
+return{
+timeInMs:EstimatedInputLatency.calculateRollingWindowEIL(events),
+nodeTimings:simulation.nodeTimings};
+
+}
+
+
+
+
+
+
+async compute_(data,artifacts){
+const fmpResult=await artifacts.requestLanternFirstMeaningfulPaint(data);
+return this.computeMetricWithGraphs(data,artifacts,{fmpResult});
+}
+
+
+
+
+
+static getEventsAfterFMP(nodeTimings,fmpTimeInMs){
+
+const events=[];
+for(const[node,timing]of nodeTimings.entries()){
+if(node.type!==Node.TYPES.CPU)continue;
+if(!timing.endTime||!timing.startTime)continue;
+if(timing.endTime<fmpTimeInMs)continue;
+
+events.push({
+start:timing.startTime,
+end:timing.endTime,
+duration:timing.endTime-timing.startTime});
+
+}
+
+return events;
+}}
+
+
+module.exports=LanternEstimatedInputLatency;
+
+},{"../../../lib/dependency-graph/node":25,"./estimated-input-latency":"./gather/computed/metrics/estimated-input-latency","./lantern-metric":12}],"./gather/computed/metrics/lantern-first-contentful-paint":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./lantern-metric');
+const Node=require('../../../lib/dependency-graph/node');
+const CPUNode=require('../../../lib/dependency-graph/cpu-node');
+const NetworkNode=require('../../../lib/dependency-graph/network-node');
+
+class FirstContentfulPaint extends MetricArtifact{
+get name(){
+return'LanternFirstContentfulPaint';
+}
+
+
+
+
+get COEFFICIENTS(){
+return{
+intercept:600,
+optimistic:0.6,
+pessimistic:0.5};
+
+}
+
+
+
+
+
+
+getOptimisticGraph(dependencyGraph,traceOfTab){
+const fcp=traceOfTab.timestamps.firstContentfulPaint;
+const blockingScriptUrls=MetricArtifact.getScriptUrls(dependencyGraph,node=>{
+return(
+node.endTime<=fcp&&node.hasRenderBlockingPriority()&&node.initiatorType!=='script');
+
+});
+
+return dependencyGraph.cloneWithRelationships(node=>{
+if(node.endTime>fcp&&!node.isMainDocument())return false;
+
+if(node.type===Node.TYPES.CPU){
+return node.isEvaluateScriptFor(blockingScriptUrls);
+}
+
+const asNetworkNode=node;
+
+return asNetworkNode.hasRenderBlockingPriority()&&asNetworkNode.initiatorType!=='script';
+});
+}
+
+
+
+
+
+
+getPessimisticGraph(dependencyGraph,traceOfTab){
+const fcp=traceOfTab.timestamps.firstContentfulPaint;
+const blockingScriptUrls=MetricArtifact.getScriptUrls(dependencyGraph,node=>{
+return node.endTime<=fcp&&node.hasRenderBlockingPriority();
+});
+
+return dependencyGraph.cloneWithRelationships(node=>{
+if(node.endTime>fcp&&!node.isMainDocument())return false;
+
+if(node.type===Node.TYPES.CPU){
+return node.isEvaluateScriptFor(blockingScriptUrls);
+}
+
+
+return node.hasRenderBlockingPriority();
+});
+}}
+
+
+module.exports=FirstContentfulPaint;
+
+},{"../../../lib/dependency-graph/cpu-node":23,"../../../lib/dependency-graph/network-node":24,"../../../lib/dependency-graph/node":25,"./lantern-metric":12}],"./gather/computed/metrics/lantern-first-cpu-idle":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Node=require('../../../lib/dependency-graph/node');
+const CPUNode=require('../../../lib/dependency-graph/cpu-node');
+const NetworkNode=require('../../../lib/dependency-graph/network-node');
+
+const FirstCPUIdle=require('./first-cpu-idle');
+const LanternInteractive=require('./lantern-interactive');
+
+class LanternFirstCPUIdle extends LanternInteractive{
+get name(){
+return'LanternFirstCPUIdle';
+}
+
+
+
+
+
+
+getEstimateFromSimulation(simulation,extras){
+const fmpTimeInMs=extras.optimistic?
+extras.fmpResult.optimisticEstimate.timeInMs:
+extras.fmpResult.pessimisticEstimate.timeInMs;
+
+return{
+timeInMs:LanternFirstCPUIdle.getFirstCPUIdleWindowStart(simulation.nodeTimings,fmpTimeInMs),
+nodeTimings:simulation.nodeTimings};
+
+}
+
+
+
+
+
+
+static getFirstCPUIdleWindowStart(nodeTimings,fmpTimeInMs,longTaskLength=50){
+
+const longTasks=[];
+for(const[node,timing]of nodeTimings.entries()){
+if(node.type!==Node.TYPES.CPU)continue;
+if(!timing.endTime||!timing.startTime)continue;
+if(timing.endTime-timing.startTime<longTaskLength)continue;
+longTasks.push({start:timing.startTime,end:timing.endTime});
+}
+
+return FirstCPUIdle.findQuietWindow(fmpTimeInMs,Infinity,longTasks);
+}}
+
+
+module.exports=LanternFirstCPUIdle;
+
+},{"../../../lib/dependency-graph/cpu-node":23,"../../../lib/dependency-graph/network-node":24,"../../../lib/dependency-graph/node":25,"./first-cpu-idle":"./gather/computed/metrics/first-cpu-idle","./lantern-interactive":"./gather/computed/metrics/lantern-interactive"}],"./gather/computed/metrics/lantern-first-meaningful-paint":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./lantern-metric');
+const Node=require('../../../lib/dependency-graph/node');
+const CPUNode=require('../../../lib/dependency-graph/cpu-node');
+const NetworkNode=require('../../../lib/dependency-graph/network-node');
+
+class FirstMeaningfulPaint extends MetricArtifact{
+get name(){
+return'LanternFirstMeaningfulPaint';
+}
+
+
+
+
+get COEFFICIENTS(){
+return{
+intercept:900,
+optimistic:0.45,
+pessimistic:0.6};
+
+}
+
+
+
+
+
+
+getOptimisticGraph(dependencyGraph,traceOfTab){
+const fmp=traceOfTab.timestamps.firstMeaningfulPaint;
+const blockingScriptUrls=MetricArtifact.getScriptUrls(dependencyGraph,node=>{
+return(
+node.endTime<=fmp&&node.hasRenderBlockingPriority()&&node.initiatorType!=='script');
+
+});
+
+return dependencyGraph.cloneWithRelationships(node=>{
+if(node.endTime>fmp&&!node.isMainDocument())return false;
+
+if(node.type===Node.TYPES.CPU){
+return node.isEvaluateScriptFor(blockingScriptUrls);
+}
+
+const asNetworkNode=node;
+
+return asNetworkNode.hasRenderBlockingPriority()&&asNetworkNode.initiatorType!=='script';
+});
+}
+
+
+
+
+
+
+getPessimisticGraph(dependencyGraph,traceOfTab){
+const fmp=traceOfTab.timestamps.firstMeaningfulPaint;
+const requiredScriptUrls=MetricArtifact.getScriptUrls(dependencyGraph,node=>{
+return node.endTime<=fmp&&node.hasRenderBlockingPriority();
+});
+
+return dependencyGraph.cloneWithRelationships(node=>{
+if(node.endTime>fmp&&!node.isMainDocument())return false;
+
+
+if(node.type===Node.TYPES.CPU){
+const asCpuNode=node;
+return asCpuNode.didPerformLayout()||asCpuNode.isEvaluateScriptFor(requiredScriptUrls);
+}
+
+
+return node.hasRenderBlockingPriority();
+});
+}
+
+
+
+
+
+
+async compute_(data,artifacts){
+const fcpResult=await artifacts.requestLanternFirstContentfulPaint(data);
+const metricResult=await this.computeMetricWithGraphs(data,artifacts);
+metricResult.timing=Math.max(metricResult.timing,fcpResult.timing);
+return metricResult;
+}}
+
+
+module.exports=FirstMeaningfulPaint;
+
+},{"../../../lib/dependency-graph/cpu-node":23,"../../../lib/dependency-graph/network-node":24,"../../../lib/dependency-graph/node":25,"./lantern-metric":12}],"./gather/computed/metrics/lantern-interactive":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./lantern-metric');
+const Node=require('../../../lib/dependency-graph/node');
+const CPUNode=require('../../../lib/dependency-graph/cpu-node');
+const NetworkNode=require('../../../lib/dependency-graph/network-node');
+const WebInspector=require('../../../lib/web-inspector');
+
+
+const CRITICAL_LONG_TASK_THRESHOLD=20;
+
+class Interactive extends MetricArtifact{
+get name(){
+return'LanternInteractive';
+}
+
+
+
+
+get COEFFICIENTS(){
+return{
+intercept:1600,
+optimistic:0.6,
+pessimistic:0.45};
+
+}
+
+
+
+
+
+getOptimisticGraph(dependencyGraph){
+
+const minimumCpuTaskDuration=CRITICAL_LONG_TASK_THRESHOLD*1000;
+
+return dependencyGraph.cloneWithRelationships(node=>{
+
+if(node.type===Node.TYPES.CPU){
+return node.event.dur>minimumCpuTaskDuration;
+}
+
+const asNetworkNode=node;
+
+const isImage=asNetworkNode.record._resourceType===WebInspector.resourceTypes.Image;
+const isScript=asNetworkNode.record._resourceType===WebInspector.resourceTypes.Script;
+return(
+!isImage&&(
+isScript||
+asNetworkNode.record.priority()==='High'||
+asNetworkNode.record.priority()==='VeryHigh'));
+
+});
+}
+
+
+
+
+
+getPessimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+
+getEstimateFromSimulation(simulationResult,extras){
+const lastTaskAt=Interactive.getLastLongTaskEndTime(simulationResult.nodeTimings);
+const minimumTime=extras.optimistic?
+extras.fmpResult.optimisticEstimate.timeInMs:
+extras.fmpResult.pessimisticEstimate.timeInMs;
+return{
+timeInMs:Math.max(minimumTime,lastTaskAt),
+nodeTimings:simulationResult.nodeTimings};
+
+}
+
+
+
+
+
+
+async compute_(data,artifacts){
+const fmpResult=await artifacts.requestLanternFirstMeaningfulPaint(data);
+const metricResult=await this.computeMetricWithGraphs(data,artifacts,{fmpResult});
+metricResult.timing=Math.max(metricResult.timing,fmpResult.timing);
+return metricResult;
+}
+
+
+
+
+
+static getLastLongTaskEndTime(nodeTimings,duration=50){
+
+return Array.from(nodeTimings.entries()).
+filter(([node,timing])=>{
+if(node.type!==Node.TYPES.CPU)return false;
+if(!timing.endTime||!timing.startTime)return false;
+return timing.endTime-timing.startTime>duration;
+}).
+map(([_,timing])=>timing.endTime).
+reduce((max,x)=>Math.max(max||0,x||0),0);
+}}
+
+
+module.exports=Interactive;
+
+},{"../../../lib/dependency-graph/cpu-node":23,"../../../lib/dependency-graph/network-node":24,"../../../lib/dependency-graph/node":25,"../../../lib/web-inspector":47,"./lantern-metric":12}],"./gather/computed/metrics/lantern-speed-index":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./lantern-metric');
+const Node=require('../../../lib/dependency-graph/node');
+const CPUNode=require('../../../lib/dependency-graph/cpu-node');
+
+class SpeedIndex extends MetricArtifact{
+get name(){
+return'LanternSpeedIndex';
+}
+
+
+
+
+get COEFFICIENTS(){
+return{
+
+
+
+intercept:-250,
+optimistic:1.4,
+pessimistic:0.65};
+
+}
+
+
+
+
+
+getOptimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+getPessimisticGraph(dependencyGraph){
+return dependencyGraph;
+}
+
+
+
+
+
+
+getEstimateFromSimulation(simulationResult,extras){
+const fcpTimeInMs=extras.fcpResult.pessimisticEstimate.timeInMs;
+const estimate=extras.optimistic?
+extras.speedline.speedIndex:
+SpeedIndex.computeLayoutBasedSpeedIndex(simulationResult.nodeTimings,fcpTimeInMs);
+return{
+timeInMs:estimate,
+nodeTimings:simulationResult.nodeTimings};
+
+}
+
+
+
+
+
+
+async compute_(data,artifacts){
+const speedline=await artifacts.requestSpeedline(data.trace);
+const fcpResult=await artifacts.requestLanternFirstContentfulPaint(data);
+const metricResult=await this.computeMetricWithGraphs(data,artifacts,{
+speedline,
+fcpResult});
+
+metricResult.timing=Math.max(metricResult.timing,fcpResult.timing);
+return metricResult;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static computeLayoutBasedSpeedIndex(nodeTimings,fcpTimeInMs){
+
+const layoutWeights=[];
+for(const[node,timing]of nodeTimings.entries()){
+if(node.type!==Node.TYPES.CPU)continue;
+if(!timing.startTime||!timing.endTime)continue;
+
+const cpuNode=node;
+if(cpuNode.childEvents.some(x=>x.name==='Layout')){
+const timingWeight=Math.max(Math.log2(timing.endTime-timing.startTime),0);
+layoutWeights.push({time:timing.endTime,weight:timingWeight});
+}
+}
+
+if(!layoutWeights.length){
+return fcpTimeInMs;
+}
+
+const totalWeightedTime=layoutWeights.
+map(evt=>evt.weight*Math.max(evt.time,fcpTimeInMs)).
+reduce((a,b)=>a+b,0);
+const totalWeight=layoutWeights.map(evt=>evt.weight).reduce((a,b)=>a+b,0);
+return totalWeightedTime/totalWeight;
+}}
+
+
+module.exports=SpeedIndex;
+
+},{"../../../lib/dependency-graph/cpu-node":23,"../../../lib/dependency-graph/node":25,"./lantern-metric":12}],"./gather/computed/metrics/speed-index":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const MetricArtifact=require('./metric');
+
+class SpeedIndex extends MetricArtifact{
+get name(){
+return'SpeedIndex';
+}
+
+
+
+
+
+
+async computeObservedMetric(data,artifacts){
+const speedline=await artifacts.requestSpeedline(data.trace);
+const timing=Math.round(speedline.speedIndex);
+const timestamp=(timing+speedline.beginning)*1000;
+return Promise.resolve({timing,timestamp});
+}}
+
+
+module.exports=SpeedIndex;
+
+},{"./metric":13}],"./gather/computed/network-analysis":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+const NetworkAnalyzer=require('../../lib/dependency-graph/simulator/network-analyzer');
+
+class NetworkAnalysis extends ComputedArtifact{
+get name(){
+return'NetworkAnalysis';
+}
+
+
+
+
+
+static computeRTTAndServerResponseTime(records){
+
+
+const rttByOrigin=new Map();
+for(const[origin,summary]of NetworkAnalyzer.estimateRTTByOrigin(records).entries()){
+rttByOrigin.set(origin,summary.min);
+}
+
+
+
+const minimumRtt=Math.min(...Array.from(rttByOrigin.values()));
+
+const responseTimeSummaries=NetworkAnalyzer.estimateServerResponseTimeByOrigin(records,{
+rttByOrigin});
+
+
+
+const additionalRttByOrigin=new Map();
+
+const serverResponseTimeByOrigin=new Map();
+for(const[origin,summary]of responseTimeSummaries.entries()){
+
+
+const rttForOrigin=rttByOrigin.get(origin);
+additionalRttByOrigin.set(origin,rttForOrigin-minimumRtt);
+serverResponseTimeByOrigin.set(origin,summary.median);
+}
+
+return{rtt:minimumRtt,additionalRttByOrigin,serverResponseTimeByOrigin,throughput:0};
+}
+
+
+
+
+
+
+async compute_(devtoolsLog,computedArtifacts){
+const records=await computedArtifacts.requestNetworkRecords(devtoolsLog);
+const throughput=await computedArtifacts.requestNetworkThroughput(devtoolsLog);
+const rttAndServerResponseTime=NetworkAnalysis.computeRTTAndServerResponseTime(records);
+rttAndServerResponseTime.throughput=throughput*8;
+return rttAndServerResponseTime;
+}}
+
+
+module.exports=NetworkAnalysis;
+
+},{"../../lib/dependency-graph/simulator/network-analyzer":27,"./computed-artifact":11}],"./gather/computed/network-records":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+const NetworkRecorder=require('../../lib/network-recorder');
+
+class NetworkRecords extends ComputedArtifact{
+get name(){
+return'NetworkRecords';
+}
+
+
+
+
+
+async compute_(devtoolsLog){
+return NetworkRecorder.recordsFromLogs(devtoolsLog);
+}}
+
+
+module.exports=NetworkRecords;
+
+},{"../../lib/network-recorder":37,"./computed-artifact":11}],"./gather/computed/network-throughput":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+
+class NetworkThroughput extends ComputedArtifact{
+get name(){
+return'NetworkThroughput';
+}
+
+
+
+
+
+
+
+
+
+static getThroughput(networkRecords){
+let totalBytes=0;
+const timeBoundaries=networkRecords.reduce((boundaries,record)=>{
+const scheme=record.parsedURL&&record.parsedURL.scheme;
+if(scheme==='data'||record.failed||!record.finished||
+record.statusCode>300||!record.transferSize){
+return boundaries;
+}
+
+totalBytes+=record.transferSize;
+boundaries.push({time:record._responseReceivedTime,isStart:true});
+boundaries.push({time:record.endTime,isStart:false});
+return boundaries;
+},[]).sort((a,b)=>a.time-b.time);
+
+if(!timeBoundaries.length){
+return Infinity;
+}
+
+let inflight=0;
+let currentStart=0;
+let totalDuration=0;
+timeBoundaries.forEach(boundary=>{
+if(boundary.isStart){
+if(inflight===0){
+currentStart=boundary.time;
+}
+inflight++;
+}else{
+inflight--;
+if(inflight===0){
+totalDuration+=boundary.time-currentStart;
+}
+}
+});
+
+return totalBytes/totalDuration;
+}
+
+
+
+
+
+
+compute_(devtoolsLog,computedArtifacts){
+
+return computedArtifacts.requestNetworkRecords(devtoolsLog).
+then(NetworkThroughput.getThroughput);
+}}
+
+
+module.exports=NetworkThroughput;
+
+},{"./computed-artifact":11}],"./gather/computed/page-dependency-graph":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+const NetworkNode=require('../../lib/dependency-graph/network-node');
+const CPUNode=require('../../lib/dependency-graph/cpu-node');
+const NetworkAnalyzer=require('../../lib/dependency-graph/simulator/network-analyzer');
+const TracingProcessor=require('../../lib/traces/tracing-processor');
+const WebInspector=require('../../lib/web-inspector');
+
+const Node=require('../../lib/dependency-graph/node.js');
+
+
+const MINIMUM_TASK_DURATION_OF_INTEREST=10;
+
+
+const IGNORED_MIME_TYPES_REGEX=/^video/;
+
+class PageDependencyGraphArtifact extends ComputedArtifact{
+get name(){
+return'PageDependencyGraph';
+}
+
+
+
+
+
+static getNetworkInitiators(record){
+if(!record._initiator)return[];
+if(record._initiator.url)return[record._initiator.url];
+if(record._initiator.type==='script'&&record._initiator.stack){
+const frames=record._initiator.stack.callFrames;
+return Array.from(new Set(frames.map(frame=>frame.url))).filter(Boolean);
+}
+
+return[];
+}
+
+
+
+
+
+static getNetworkNodeOutput(networkRecords){
+
+const nodes=[];
+const idToNodeMap=new Map();
+const urlToNodeMap=new Map();
+
+networkRecords.forEach(record=>{
+if(IGNORED_MIME_TYPES_REGEX.test(record._mimeType))return;
+
+
+
+while(idToNodeMap.has(record.requestId)){
+record._requestId+=':duplicate';
+}
+
+const node=new NetworkNode(record);
+nodes.push(node);
+
+const list=urlToNodeMap.get(record.url)||[];
+list.push(node);
+
+idToNodeMap.set(record.requestId,node);
+urlToNodeMap.set(record.url,list);
+});
+
+return{nodes,idToNodeMap,urlToNodeMap};
+}
+
+
+
+
+
+static getCPUNodes(traceOfTab){
+
+const nodes=[];
+let i=0;
+
+const minimumEvtDur=MINIMUM_TASK_DURATION_OF_INTEREST*1000;
+while(i<traceOfTab.mainThreadEvents.length){
+const evt=traceOfTab.mainThreadEvents[i];
+
+
+if(
+!TracingProcessor.isScheduleableTask(evt)||
+!evt.dur||
+evt.dur<minimumEvtDur)
+{
+i++;
+continue;
+}
+
+
+
+const children=[];
+i++;
+for(
+const endTime=evt.ts+evt.dur;
+i<traceOfTab.mainThreadEvents.length&&traceOfTab.mainThreadEvents[i].ts<endTime;
+i++)
+{
+children.push(traceOfTab.mainThreadEvents[i]);
+}
+
+nodes.push(new CPUNode(evt,children));
+}
+
+return nodes;
+}
+
+
+
+
+
+static linkNetworkNodes(rootNode,networkNodeOutput){
+networkNodeOutput.nodes.forEach(node=>{
+const initiators=PageDependencyGraphArtifact.getNetworkInitiators(node.record);
+if(initiators.length){
+initiators.forEach(initiator=>{
+const parentCandidates=networkNodeOutput.urlToNodeMap.get(initiator)||[rootNode];
+
+const parent=parentCandidates.length===1?parentCandidates[0]:rootNode;
+node.addDependency(parent);
+});
+}else if(node!==rootNode){
+rootNode.addDependent(node);
+}
+
+const redirects=Array.from(node.record.redirects||[]);
+redirects.push(node.record);
+
+for(let i=1;i<redirects.length;i++){
+const redirectNode=networkNodeOutput.idToNodeMap.get(redirects[i-1].requestId);
+const actualNode=networkNodeOutput.idToNodeMap.get(redirects[i].requestId);
+if(actualNode&&redirectNode){
+actualNode.addDependency(redirectNode);
+}
+}
+});
+}
+
+
+
+
+
+
+static linkCPUNodes(rootNode,networkNodeOutput,cpuNodes){
+
+function addDependentNetworkRequest(cpuNode,reqId){
+const networkNode=networkNodeOutput.idToNodeMap.get(reqId);
+if(!networkNode||
+
+networkNode.record._resourceType!==WebInspector.resourceTypes.XHR||
+
+
+networkNode.startTime<=cpuNode.startTime)return;
+cpuNode.addDependent(networkNode);
+}
+
+
+function addDependencyOnUrl(cpuNode,url){
+if(!url)return;
+
+
+const minimumAllowableTimeSinceNetworkNodeEnd=-100*1000;
+const candidates=networkNodeOutput.urlToNodeMap.get(url)||[];
+
+let minCandidate=null;
+let minDistance=Infinity;
+
+for(const candidate of candidates){
+
+
+if(cpuNode.startTime<=candidate.startTime)return;
+
+const distance=cpuNode.startTime-candidate.endTime;
+if(distance>=minimumAllowableTimeSinceNetworkNodeEnd&&distance<minDistance){
+minCandidate=candidate;
+minDistance=distance;
+}
+}
+
+if(!minCandidate)return;
+cpuNode.addDependency(minCandidate);
+}
+
+
+const timers=new Map();
+for(const node of cpuNodes){
+for(const evt of node.childEvents){
+if(!evt.args.data)continue;
+
+const argsUrl=evt.args.data.url;
+const stackTraceUrls=(evt.args.data.stackTrace||[]).map(l=>l.url).filter(Boolean);
+
+switch(evt.name){
+case'TimerInstall':
+
+timers.set(evt.args.data.timerId,node);
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;
+case'TimerFire':{
+
+const installer=timers.get(evt.args.data.timerId);
+if(!installer)break;
+installer.addDependent(node);
+break;
+}
+
+case'InvalidateLayout':
+case'ScheduleStyleRecalculation':
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;
+
+case'EvaluateScript':
+
+addDependencyOnUrl(node,argsUrl);
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;
+
+case'XHRReadyStateChange':
+
+
+if(evt.args.data.readyState!==4)break;
+
+
+addDependencyOnUrl(node,argsUrl);
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;
+
+case'FunctionCall':
+case'v8.compile':
+
+addDependencyOnUrl(node,argsUrl);
+break;
+
+case'ParseAuthorStyleSheet':
+
+addDependencyOnUrl(node,evt.args.data.styleSheetUrl);
+break;
+
+case'ResourceSendRequest':
+
+addDependentNetworkRequest(node,evt.args.data.requestId);
+stackTraceUrls.forEach(url=>addDependencyOnUrl(node,url));
+break;}
+
+}
+
+if(node.getNumberOfDependencies()===0){
+node.addDependency(rootNode);
+}
+}
+}
+
+
+
+
+
+
+static createGraph(traceOfTab,networkRecords){
+const networkNodeOutput=PageDependencyGraphArtifact.getNetworkNodeOutput(networkRecords);
+const cpuNodes=PageDependencyGraphArtifact.getCPUNodes(traceOfTab);
+
+const rootRequest=networkRecords.reduce((min,r)=>min.startTime<r.startTime?min:r);
+const rootNode=networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
+const mainDocumentRequest=NetworkAnalyzer.findMainDocument(networkRecords);
+const mainDocumentNode=networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
+
+if(!rootNode||!mainDocumentNode){
+
+throw new Error(`${rootNode?'mainDocument':'root'}Node not found.`);
+}
+
+PageDependencyGraphArtifact.linkNetworkNodes(rootNode,networkNodeOutput);
+PageDependencyGraphArtifact.linkCPUNodes(rootNode,networkNodeOutput,cpuNodes);
+mainDocumentNode.setIsMainDocument(true);
+
+if(NetworkNode.hasCycle(rootNode)){
+throw new Error('Invalid dependency graph created, cycle detected');
+}
+
+return rootNode;
+}
+
+
+
+
+
+static printGraph(rootNode,widthInCharacters=100){
+
+function padRight(str,target,padChar=' '){
+return str+padChar.repeat(Math.max(target-str.length,0));
+}
+
+
+const nodes=[];
+rootNode.traverse(node=>nodes.push(node));
+nodes.sort((a,b)=>a.startTime-b.startTime);
+
+const min=nodes[0].startTime;
+const max=nodes.reduce((max,node)=>Math.max(max,node.endTime),0);
+
+const totalTime=max-min;
+const timePerCharacter=totalTime/widthInCharacters;
+nodes.forEach(node=>{
+const offset=Math.round((node.startTime-min)/timePerCharacter);
+const length=Math.ceil((node.endTime-node.startTime)/timePerCharacter);
+const bar=padRight('',offset)+padRight('',length,'=');
+
+
+const displayName=node.record?node.record._url:node.type;
+
+console.log(padRight(bar,widthInCharacters),`| ${displayName.slice(0,30)}`);
+});
+}
+
+
+
+
+
+
+async compute_(data,artifacts){
+const trace=data.trace;
+const devtoolsLog=data.devtoolsLog;
+const[traceOfTab,networkRecords]=await Promise.all([
+artifacts.requestTraceOfTab(trace),
+artifacts.requestNetworkRecords(devtoolsLog)]);
+
+
+return PageDependencyGraphArtifact.createGraph(traceOfTab,networkRecords);
+}}
+
+
+module.exports=PageDependencyGraphArtifact;
+
+
+
+
+
+
+
+
+},{"../../lib/dependency-graph/cpu-node":23,"../../lib/dependency-graph/network-node":24,"../../lib/dependency-graph/node.js":25,"../../lib/dependency-graph/simulator/network-analyzer":27,"../../lib/traces/tracing-processor":46,"../../lib/web-inspector":47,"./computed-artifact":11}],"./gather/computed/pushed-requests":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+
+class PushedRequests extends ComputedArtifact{
+get name(){
+return'PushedRequests';
+}
+
+
+
+
+
+
+
+compute_(devtoolsLog,artifacts){
+return artifacts.requestNetworkRecords(devtoolsLog).then(records=>{
+const pushedRecords=records.filter(r=>r._timing&&!!r._timing.pushStart);
+return pushedRecords;
+});
+}}
+
+
+module.exports=PushedRequests;
+
+},{"./computed-artifact":11}],"./gather/computed/screenshots":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+
+class ScreenshotFilmstrip extends ComputedArtifact{
+get name(){
+return'Screenshots';
+}
+
+
+
+
+
+fetchScreenshot(frame){
+return frame.
+imageDataPromise().
+then(data=>'data:image/jpg;base64,'+data);
+}
+
+
+
+
+
+
+compute_(trace,computedArtifacts){
+return computedArtifacts.requestDevtoolsTimelineModel(trace).then(model=>{
+const filmStripFrames=model.filmStripModel().frames();
+const frameFetches=filmStripFrames.map(frame=>this.fetchScreenshot(frame));
+
+return Promise.all(frameFetches).then(images=>{
+const result=filmStripFrames.map((frame,i)=>({
+timestamp:frame.timestamp,
+datauri:images[i]}));
+
+return result;
+});
+});
+}}
+
+
+module.exports=ScreenshotFilmstrip;
+
+},{"./computed-artifact":11}],"./gather/computed/speedline":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('./computed-artifact');
+const speedline=require('speedline');
+const LHError=require('../../lib/errors');
+
+class Speedline extends ComputedArtifact{
+get name(){
+return'Speedline';
+}
+
+
+
+
+
+
+compute_(trace,computedArtifacts){
+
+
+return computedArtifacts.requestTraceOfTab(trace).then(traceOfTab=>{
+
+
+const traceEvents=trace.traceEvents.slice();
+
+
+const navStart=traceOfTab.timestamps.navigationStart;
+return speedline(traceEvents,{
+timeOrigin:navStart,
+fastMode:true,
+include:'speedIndex'});
+
+}).catch(err=>{
+if(/No screenshots found in trace/.test(err.message)){
+throw new LHError(LHError.errors.NO_SCREENSHOTS);
+}
+
+throw err;
+}).then(speedline=>{
+if(speedline.frames.length===0){
+throw new LHError(LHError.errors.NO_SPEEDLINE_FRAMES);
+}
+
+if(speedline.speedIndex===0){
+throw new LHError(LHError.errors.SPEEDINDEX_OF_ZERO);
+}
+
+return speedline;
+});
+}}
+
+
+module.exports=Speedline;
+
+},{"../../lib/errors":33,"./computed-artifact":11,"speedline":152}],"./gather/computed/trace-of-tab":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+const ComputedArtifact=require('./computed-artifact');
+const log=require('lighthouse-logger');
+const LHError=require('../../lib/errors');
+const Sentry=require('../../lib/sentry');
+
+
+
+
+const WebInspector=require('../../lib/web-inspector');
+
+class TraceOfTab extends ComputedArtifact{
+get name(){
+return'TraceOfTab';
+}
+
+
+
+
+
+
+
+async compute_(trace){
+
+
+
+const keyEvents=trace.traceEvents.
+filter(e=>{
+return e.cat.includes('blink.user_timing')||
+e.cat.includes('loading')||
+e.cat.includes('devtools.timeline')||
+e.name==='TracingStartedInPage';
+}).
+
+stableSort((event0,event1)=>event0.ts-event1.ts);
+
+
+
+const startedInPageEvt=keyEvents.find(e=>e.name==='TracingStartedInPage');
+if(!startedInPageEvt)throw new LHError(LHError.errors.NO_TRACING_STARTED);
+
+const frameId=startedInPageEvt.args.data.page;
+
+const frameEvents=keyEvents.filter(e=>e.args.frame===frameId);
+
+
+const navigationStart=frameEvents.filter(e=>e.name==='navigationStart').pop();
+if(!navigationStart)throw new LHError(LHError.errors.NO_NAVSTART);
+
+
+const firstPaint=frameEvents.find(e=>e.name==='firstPaint'&&e.ts>navigationStart.ts);
+
+
+const firstContentfulPaint=frameEvents.find(
+e=>e.name==='firstContentfulPaint'&&e.ts>navigationStart.ts);
+
+
+
+let firstMeaningfulPaint=frameEvents.find(
+e=>e.name==='firstMeaningfulPaint'&&e.ts>navigationStart.ts);
+
+let fmpFellBack=false;
+
+
+
+
+
+if(!firstMeaningfulPaint){
+
+
+Sentry.captureMessage('No firstMeaningfulPaint found, using fallback',{level:'warning'});
+
+const fmpCand='firstMeaningfulPaintCandidate';
+fmpFellBack=true;
+log.verbose('trace-of-tab',`No firstMeaningfulPaint found, falling back to last ${fmpCand}`);
+const lastCandidate=frameEvents.filter(e=>e.name===fmpCand).pop();
+if(!lastCandidate){
+log.verbose('trace-of-tab','No `firstMeaningfulPaintCandidate` events found in trace');
+}
+firstMeaningfulPaint=lastCandidate;
+}
+
+const load=frameEvents.find(e=>e.name==='loadEventEnd'&&e.ts>navigationStart.ts);
+const domContentLoaded=frameEvents.find(
+e=>e.name==='domContentLoadedEventEnd'&&e.ts>navigationStart.ts);
+
+
+
+
+
+const processEvents=trace.traceEvents.
+filter(e=>e.pid===startedInPageEvt.pid).
+
+stableSort((event0,event1)=>event0.ts-event1.ts);
+
+const mainThreadEvents=processEvents.
+filter(e=>e.tid===startedInPageEvt.tid);
+
+const traceEnd=trace.traceEvents.reduce((max,evt)=>{
+return max.ts>evt.ts?max:evt;
+});
+
+const metrics={
+navigationStart,
+firstPaint,
+firstContentfulPaint,
+firstMeaningfulPaint,
+traceEnd:{ts:traceEnd.ts+(traceEnd.dur||0)},
+load,
+domContentLoaded};
+
+
+const timings={};
+const timestamps={};
+
+Object.keys(metrics).forEach(metric=>{
+timestamps[metric]=metrics[metric]&&metrics[metric].ts;
+timings[metric]=(timestamps[metric]-navigationStart.ts)/1000;
+});
+
+
+
+
+return{
+timings:timings,
+timestamps:timestamps,
+processEvents,
+mainThreadEvents,
+startedInPageEvt,
+navigationStartEvt:navigationStart,
+firstPaintEvt:firstPaint,
+firstContentfulPaintEvt:firstContentfulPaint,
+firstMeaningfulPaintEvt:firstMeaningfulPaint,
+loadEvt:load,
+domContentLoadedEvt:domContentLoaded,
+fmpFellBack};
+
+}}
+
+
+module.exports=TraceOfTab;
+
+},{"../../lib/errors":33,"../../lib/sentry":39,"../../lib/web-inspector":47,"./computed-artifact":11,"lighthouse-logger":143}],1:[function(require,module,exports){
 
 
 
@@ -12489,7 +14595,7 @@
 const isNotApplicable=notApplicables.find(result=>result.id===this.meta.name);
 if(isNotApplicable){
 return{
-rawValue:false,
+rawValue:true,
 notApplicable:true};
 
 }
@@ -12497,29 +14603,29 @@
 const violations=artifacts.Accessibility.violations||[];
 const rule=violations.find(result=>result.id===this.meta.name);
 
-let nodeDetails=[];
+
+let items=[];
 if(rule&&rule.nodes){
-nodeDetails=rule.nodes.map(node=>({
+items=rule.nodes.map(node=>({
+node:{
 type:'node',
 selector:Array.isArray(node.target)?node.target.join(' '):'',
 path:node.path,
-snippet:node.snippet}));
+snippet:node.snippet}}));
+
 
 }
 
+const headings=[
+{key:'node',itemType:'node',text:'Failing Elements'}];
+
+
 return{
 rawValue:typeof rule==='undefined',
 extendedInfo:{
 value:rule},
 
-details:{
-type:'list',
-header:{
-type:'text',
-text:'View failing elements'},
-
-items:nodeDetails}};
-
+details:Audit.makeTableDetails(headings,items)};
 
 }}
 
@@ -12532,13 +14638,20 @@
 
 
 
-
 'use strict';
 
 const statistics=require('../lib/statistics');
+const Util=require('../report/html/renderer/util');
 
 const DEFAULT_PASS='defaultPass';
 
+
+
+
+
+
+const clampTo2Decimals=val=>Math.round(val*100)/100;
+
 class Audit{
 
 
@@ -12553,7 +14666,11 @@
 static get SCORING_MODES(){
 return{
 NUMERIC:'numeric',
-BINARY:'binary'};
+BINARY:'binary',
+MANUAL:'manual',
+INFORMATIVE:'informative',
+NOT_APPLICABLE:'not-applicable',
+ERROR:'error'};
 
 }
 
@@ -12567,6 +14684,27 @@
 
 
 
+static get defaultOptions(){
+return{};
+}
+
+
+
+
+
+
+
+
+
+static audit(artifacts,context){
+throw new Error('audit() method must be overriden');
+}
+
+
+
+
+
+
 
 
 
@@ -12580,10 +14718,10 @@
 diminishingReturnsValue);
 
 
-let score=100*distribution.computeComplementaryPercentile(measuredValue);
-score=Math.min(100,score);
+let score=distribution.computeComplementaryPercentile(measuredValue);
+score=Math.min(1,score);
 score=Math.max(0,score);
-return Math.round(score);
+return clampTo2Decimals(score);
 }
 
 
@@ -12591,11 +14729,10 @@
 
 
 
-static generateErrorAuditResult(audit,debugString){
+static generateErrorAuditResult(audit,errorMessage){
 return Audit.generateAuditResult(audit,{
 rawValue:null,
-error:true,
-debugString});
+errorMessage});
 
 }
 
@@ -12605,47 +14742,44 @@
 
 
 
-
-static makeTableRows(headings,results){
-const tableRows=results.map(item=>{
-return headings.map(heading=>{
-const value=item[heading.key];
-if(typeof value==='object'&&value&&value.type)return value;
-
-return{
-type:heading.itemType,
-text:value};
-
-});
-});
-return tableRows;
-}
-
-
-
-
-
-static makeTableHeaders(headings){
-return headings.map(heading=>({
-type:'text',
-itemType:heading.itemType,
-text:heading.text}));
-
-}
-
-
-
-
-
-
-static makeTableDetails(headings,results){
-const tableHeaders=Audit.makeTableHeaders(headings);
-const tableRows=Audit.makeTableRows(headings,results);
+static makeTableDetails(headings,results,summary){
+if(results.length===0){
 return{
 type:'table',
-header:'View Details',
-itemHeaders:tableHeaders,
-items:tableRows};
+headings:[],
+items:[],
+summary};
+
+}
+
+return{
+type:'table',
+headings:headings,
+items:results,
+summary};
+
+}
+
+
+
+
+
+
+static _normalizeAuditScore(audit,result){
+
+let score=result.score===undefined?Number(result.rawValue):result.score;
+
+if(!Number.isFinite(score))throw new Error(`Invalid score: ${score}`);
+if(score>1)throw new Error(`Audit score for ${audit.meta.name} is > 1`);
+if(score<0)throw new Error(`Audit score for ${audit.meta.name} is < 0`);
+
+score=clampTo2Decimals(score);
+
+const scoreDisplayMode=audit.meta.scoreDisplayMode||Audit.SCORING_MODES.BINARY;
+
+return{
+score,
+scoreDisplayMode};
 
 }
 
@@ -12659,36 +14793,45 @@
 throw new Error('generateAuditResult requires a rawValue');
 }
 
-const score=typeof result.score==='undefined'?result.rawValue:result.score;
-let displayValue=result.displayValue;
-if(typeof displayValue==='undefined'){
-displayValue=result.rawValue?result.rawValue:'';
-}
+
+let{score,scoreDisplayMode}=Audit._normalizeAuditScore(audit,result);
 
 
-if(displayValue===score){
-displayValue='';
+if(result.notApplicable){
+scoreDisplayMode=Audit.SCORING_MODES.NOT_APPLICABLE;
+result.rawValue=true;
 }
+
+if(result.errorMessage){
+scoreDisplayMode=Audit.SCORING_MODES.ERROR;
+}
+
 let auditDescription=audit.meta.description;
 if(audit.meta.failureDescription){
-if(!score||typeof score==='number'&&score<100){
+if(Number(score)<Util.PASS_THRESHOLD){
 auditDescription=audit.meta.failureDescription;
 }
 }
+
+if(scoreDisplayMode!==Audit.SCORING_MODES.BINARY&&
+scoreDisplayMode!==Audit.SCORING_MODES.NUMERIC){
+score=null;
+}
+
 return{
+id:audit.meta.name,
+title:auditDescription,
+description:audit.meta.helpText,
+
 score,
-displayValue:`${displayValue}`,
+scoreDisplayMode,
 rawValue:result.rawValue,
-error:result.error,
-debugString:result.debugString,
-extendedInfo:result.extendedInfo,
-scoringMode:audit.meta.scoringMode||Audit.SCORING_MODES.BINARY,
-informative:audit.meta.informative,
-manual:audit.meta.manual,
-notApplicable:result.notApplicable,
-name:audit.meta.name,
-description:auditDescription,
-helpText:audit.meta.helpText,
+
+displayValue:result.displayValue,
+explanation:result.explanation,
+errorMessage:result.errorMessage,
+warnings:result.warnings,
+
 details:result.details};
 
 }}
@@ -12696,26 +14839,7 @@
 
 module.exports=Audit;
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-},{"../lib/statistics":34}],3:[function(require,module,exports){
+},{"../lib/statistics":40,"../report/html/renderer/util":48}],3:[function(require,module,exports){
 
 
 
@@ -12724,7 +14848,11 @@
 'use strict';
 
 const Audit=require('../audit');
-const Util=require('../../report/v2/renderer/util');
+const Interactive=require('../../gather/computed/metrics/lantern-interactive');
+const Simulator=require('../../lib/dependency-graph/simulator/simulator');
+const Node=require('../../lib/dependency-graph/node.js');
+
+const NetworkNode=require('../../lib/dependency-graph/network-node.js');
 
 const KB_IN_BYTES=1024;
 
@@ -12741,9 +14869,9 @@
 
 
 static scoreForWastedMs(wastedMs){
-if(wastedMs===0)return 100;else
-if(wastedMs<WASTED_MS_FOR_AVERAGE)return 90;else
-if(wastedMs<WASTED_MS_FOR_POOR)return 65;else
+if(wastedMs===0)return 1;else
+if(wastedMs<WASTED_MS_FOR_AVERAGE)return 0.9;else
+if(wastedMs<WASTED_MS_FOR_POOR)return 0.65;else
 return 0;
 }
 
@@ -12751,28 +14879,10 @@
 
 
 
-static bytesToKbString(bytes){
-return Util.formatBytesToKB(bytes,0);
-}
 
-
-
-
-
-
-static toSavingsString(bytes=0,percent=0){
-const kbDisplay=this.bytesToKbString(bytes);
-const percentDisplay=Util.formatNumber(Math.round(percent))+'%';
-return`${kbDisplay} (${percentDisplay})`;
-}
-
-
-
-
-
-
-static bytesToMsString(bytes,networkThroughput){
-return Util.formatMilliseconds(bytes/networkThroughput*1000,10);
+static bytesToMs(bytes,networkThroughput){
+const milliseconds=bytes/networkThroughput*1000;
+return milliseconds;
 }
 
 
@@ -12793,11 +14903,13 @@
 return Math.round(totalBytes*compressionRatio);
 }else if(networkRecord._resourceType&&networkRecord._resourceType._name===resourceType){
 
-return networkRecord._transferSize;
+return networkRecord._transferSize||0;
 }else{
 
 
-const compressionRatio=networkRecord._transferSize/networkRecord._resourceSize||1;
+const transferSize=networkRecord._transferSize||0;
+const resourceSize=networkRecord._resourceSize;
+const compressionRatio=resourceSize!==undefined?transferSize/resourceSize:1;
 return Math.round(totalBytes*compressionRatio);
 }
 }
@@ -12806,14 +14918,86 @@
 
 
 
-static audit(artifacts){
+
+static audit(artifacts,context){
+const trace=artifacts.traces[Audit.DEFAULT_PASS];
 const devtoolsLog=artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
-return artifacts.requestNetworkRecords(devtoolsLog).
-then(networkRecords=>this.audit_(artifacts,networkRecords)).
-then(result=>{
-return artifacts.requestNetworkThroughput(devtoolsLog).
-then(networkThroughput=>this.createAuditResult(result,networkThroughput));
+const settings=context&&context.settings||{};
+const simulatorOptions={
+devtoolsLog,
+settings};
+
+
+return artifacts.
+requestNetworkRecords(devtoolsLog).
+then(networkRecords=>
+Promise.all([
+this.audit_(artifacts,networkRecords,context),
+artifacts.requestPageDependencyGraph({trace,devtoolsLog}),
+artifacts.requestLoadSimulator(simulatorOptions)])).
+
+
+then(([result,graph,simulator])=>this.createAuditProduct(result,graph,simulator));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+static computeWasteWithTTIGraph(results,graph,simulator,options){
+options=Object.assign({includeLoad:true},options);
+
+const simulationBeforeChanges=simulator.simulate(graph);
+
+const resultsByUrl=new Map();
+for(const result of results){
+resultsByUrl.set(result.url,result);
+}
+
+
+
+const originalTransferSizes=new Map();
+graph.traverse(node=>{
+if(node.type!=='network')return;
+const networkNode=node;
+const result=resultsByUrl.get(networkNode.record.url);
+if(!result)return;
+const original=networkNode.record.transferSize;
+
+originalTransferSizes.set(networkNode.record.requestId,original);
+
+const wastedBytes=result.wastedBytes;
+networkNode.record._transferSize=Math.max(original-wastedBytes,0);
 });
+
+const simulationAfterChanges=simulator.simulate(graph);
+
+
+graph.traverse(node=>{
+if(node.type!=='network')return;
+const networkNode=node;
+const originalTransferSize=originalTransferSizes.get(networkNode.record.requestId);
+if(originalTransferSize===undefined)return;
+networkNode.record._transferSize=originalTransferSize;
+});
+
+const savingsOnOverallLoad=simulationBeforeChanges.timeInMs-simulationAfterChanges.timeInMs;
+const savingsOnTTI=Interactive.getLastLongTaskEndTime(simulationBeforeChanges.nodeTimings)-
+Interactive.getLastLongTaskEndTime(simulationAfterChanges.nodeTimings);
+
+let savings=savingsOnTTI;
+if(options.includeLoad)savings=Math.max(savings,savingsOnOverallLoad);
+
+
+return Math.round(Math.max(savings,0)/10)*10;
 }
 
 
@@ -12821,39 +15005,31 @@
 
 
 
-static createAuditResult(result,networkThroughput){
-if(!Number.isFinite(networkThroughput)&&result.results.length){
-throw new Error('Invalid network timing information');
-}
 
-const debugString=result.debugString;
-const results=result.results.
-map(item=>{
-const wastedPercent=100*item.wastedBytes/item.totalBytes;
-item.wastedKb=this.bytesToKbString(item.wastedBytes);
-item.wastedMs=this.bytesToMsString(item.wastedBytes,networkThroughput);
-item.totalKb=this.bytesToKbString(item.totalBytes);
-item.totalMs=this.bytesToMsString(item.totalBytes,networkThroughput);
-item.potentialSavings=this.toSavingsString(item.wastedBytes,wastedPercent);
-return item;
-}).
-sort((itemA,itemB)=>itemB.wastedBytes-itemA.wastedBytes);
+static createAuditProduct(result,graph,simulator){
+const results=result.results.sort((itemA,itemB)=>itemB.wastedBytes-itemA.wastedBytes);
 
 const wastedBytes=results.reduce((sum,item)=>sum+item.wastedBytes,0);
 const wastedKb=Math.round(wastedBytes/KB_IN_BYTES);
-const wastedMs=Math.round(wastedBytes/networkThroughput*100)*10;
+const wastedMs=this.computeWasteWithTTIGraph(results,graph,simulator);
+
 
 let displayValue=result.displayValue||'';
-if(typeof result.displayValue==='undefined'&&wastedBytes){
-const wastedKbDisplay=this.bytesToKbString(wastedBytes);
-const wastedMsDisplay=this.bytesToMsString(wastedBytes,networkThroughput);
-displayValue=`Potential savings of ${wastedKbDisplay} (~${wastedMsDisplay})`;
+if(typeof result.displayValue==='undefined'&&wastedKb){
+displayValue=['Potential savings of %d\xa0KB',wastedKb];
 }
 
-const tableDetails=Audit.makeTableDetails(result.headings,results);
+const summary={
+wastedMs,
+wastedBytes};
+
+
+
+const details=Audit.makeTableDetails(result.headings,results,summary);
 
 return{
-debugString,
+explanation:result.explanation,
+warnings:result.warnings,
 displayValue,
 rawValue:wastedMs,
 score:UnusedBytes.scoreForWastedMs(wastedMs),
@@ -12864,7 +15040,7 @@
 results}},
 
 
-details:tableDetails};
+details};
 
 }
 
@@ -12872,14 +15048,20 @@
 
 
 
-static audit_(){
+
+
+
+
+static audit_(artifacts,networkRecords,context){
 throw new Error('audit_ unimplemented');
 }}
 
 
+
+
 module.exports=UnusedBytes;
 
-},{"../../report/v2/renderer/util":43,"../audit":2}],4:[function(require,module,exports){
+},{"../../gather/computed/metrics/lantern-interactive":"./gather/computed/metrics/lantern-interactive","../../lib/dependency-graph/network-node.js":24,"../../lib/dependency-graph/node.js":25,"../../lib/dependency-graph/simulator/simulator":28,"../audit":2}],4:[function(require,module,exports){
 
 
 
@@ -12898,10 +15080,9 @@
 
 
 
-static get meta(){
+static get partialMeta(){
 return{
-informative:true,
-manual:true,
+scoreDisplayMode:Audit.SCORING_MODES.MANUAL,
 requiredArtifacts:[]};
 
 }
@@ -12939,14 +15120,14 @@
 
 
 static audit(artifacts){
-return Promise.resolve(this.audit_(artifacts)).then(result=>this.createAuditResult(result));
+return Promise.resolve(this.audit_(artifacts)).then(result=>this.createAuditProduct(result));
 }
 
 
 
 
 
-static createAuditResult(result){
+static createAuditProduct(result){
 const extendedInfo={
 value:result};
 
@@ -12955,32 +15136,32 @@
 if(result.failures.length>0){
 return{
 rawValue:false,
-debugString:`Failures: ${result.failures.join(', ')}.`,
+explanation:`Failures: ${result.failures.join(',\n')}.`,
 extendedInfo};
 
 }
 
-let debugString;
-if(result.warnings&&result.warnings.length>0){
-debugString=`Warnings: ${result.warnings.join(', ')}`;
-}
-
 
 return{
 rawValue:true,
 extendedInfo,
-debugString};
+warnings:result.warnings};
 
 }
 
 
 
 
-static audit_(){
+
+
+
+static audit_(artifacts){
 throw new Error('audit_ unimplemented');
 }}
 
 
+
+
 module.exports=MultiCheckAudit;
 
 },{"./audit":2}],6:[function(require,module,exports){
@@ -13000,10 +15181,19 @@
 
 
 static getViolationResults(artifacts,pattern){
+const seen=new Set();
 return artifacts.ChromeConsoleMessages.
 map(message=>message.entry).
 filter(entry=>entry.url&&entry.source==='violation'&&pattern.test(entry.text)).
-map(entry=>Object.assign({label:`line: ${entry.lineNumber}`},entry));
+map(entry=>({label:`line: ${entry.lineNumber}`,url:entry.url})).
+filter(entry=>{
+
+
+const key=`${entry.url}!${entry.label}`;
+if(seen.has(key))return false;
+seen.add(key);
+return true;
+});
 }}
 
 
@@ -13019,102 +15209,18 @@
 
 'use strict';
 
-const defaultConfigPath='./default.js';
-const defaultConfig=require('./default.js');
+const defaultConfigPath='./default-config.js';
+const defaultConfig=require('./default-config.js');
 const fullConfig=require('./full-config.js');
+const constants=require('./constants');
 
-const GatherRunner=require('../gather/gather-runner');
+const isDeepEqual=require('lodash.isequal');
 const log=require('lighthouse-logger');
 const path=require('path');
 const Audit=require('../audits/audit');
 const Runner=require('../runner');
 
-const _flatten=arr=>[].concat(...arr);
-
-
-
-
-
-function cleanTrace(trace){
-const traceEvents=trace.traceEvents;
-
-const threads=[];
-const countsByThread={};
-const traceStartEvents=[];
-const makeMockEvent=(evt,ts)=>{
-return{
-pid:evt.pid,
-tid:evt.tid,
-ts:ts||0,
-ph:'I',
-cat:'disabled-by-default-devtools.timeline',
-name:'TracingStartedInPage',
-args:{
-data:{
-page:evt.frame}},
-
-
-s:'t'};
-
-};
-
-let frame;
-let data;
-let name;
-let counter;
-
-traceEvents.forEach((evt,idx)=>{
-if(evt.name.startsWith('TracingStartedIn')){
-traceStartEvents.push(idx);
-}
-
-
-data=evt.args&&(evt.args.data||evt.args.beginData||evt.args.counters);
-frame=evt.args&&evt.args.frame||data&&(data.frame||data.page);
-
-if(!frame){
-return;
-}
-
-
-name=`pid${evt.pid}-tid${evt.tid}-frame${frame}`;
-counter=countsByThread[name];
-if(!counter){
-counter={
-pid:evt.pid,
-tid:evt.tid,
-frame:frame,
-count:0};
-
-countsByThread[name]=counter;
-threads.push(counter);
-}
-counter.count++;
-});
-
-
-threads.sort((a,b)=>b.count-a.count);
-const mostActiveFrame=threads[0];
-
-
-
-const ts=traceEvents[traceStartEvents[0]]&&traceEvents[traceStartEvents[0]].ts;
-
-
-let i=0;
-for(const dup of traceStartEvents){
-traceEvents.splice(dup-i,1);
-i++;
-}
-
-
-
-traceEvents.unshift(makeMockEvent(mostActiveFrame,ts));
-
-return trace;
-}
-
-function validatePasses(passes,audits,rootPath){
+function validatePasses(passes,audits){
 if(!Array.isArray(passes)){
 return;
 }
@@ -13122,11 +15228,11 @@
 
 
 passes.forEach(pass=>{
-pass.gatherers.forEach(gatherer=>{
-const GathererClass=GatherRunner.getGathererClass(gatherer,rootPath);
-const isGatherRequiredByAudits=requiredGatherers.has(GathererClass.name);
+pass.gatherers.forEach(gathererDefn=>{
+const gatherer=gathererDefn.instance||gathererDefn.implementation;
+const isGatherRequiredByAudits=requiredGatherers.has(gatherer.name);
 if(isGatherRequiredByAudits===false){
-const msg=`${GathererClass.name} gatherer requested, however no audit requires it.`;
+const msg=`${gatherer.name} gatherer requested, however no audit requires it.`;
 log.warn('config',msg);
 }
 });
@@ -13134,18 +15240,8 @@
 
 
 const usedNames=new Set();
-let defaultUsed=false;
-passes.forEach((pass,index)=>{
-let passName=pass.passName;
-if(!passName){
-if(defaultUsed){
-throw new Error(`passes[${index}] requires a passName`);
-}
-
-passName=Audit.DEFAULT_PASS;
-defaultUsed=true;
-}
-
+passes.forEach(pass=>{
+const passName=pass.passName;
 if(usedNames.has(passName)){
 throw new Error(`Passes must have unique names (repeated passName: ${passName}.`);
 }
@@ -13158,32 +15254,39 @@
 return;
 }
 
-const auditIds=audits.map(audit=>audit.meta.name);
 Object.keys(categories).forEach(categoryId=>{
-categories[categoryId].audits.forEach((audit,index)=>{
-if(!audit.id){
+categories[categoryId].auditRefs.forEach((auditRef,index)=>{
+if(!auditRef.id){
 throw new Error(`missing an audit id at ${categoryId}[${index}]`);
 }
 
-if(!auditIds.includes(audit.id)){
-throw new Error(`could not find ${audit.id} audit for category ${categoryId}`);
+const audit=audits.find(a=>a.implementation.meta.name===auditRef.id);
+if(!audit){
+throw new Error(`could not find ${auditRef.id} audit for category ${categoryId}`);
 }
 
-if(categoryId==='accessibility'&&!audit.group){
-throw new Error(`${audit.id} accessibility audit does not have a group`);
+const auditImpl=audit.implementation;
+const isManual=auditImpl.meta.scoreDisplayMode==='manual';
+if(categoryId==='accessibility'&&!auditRef.group&&!isManual){
+throw new Error(`${auditRef.id} accessibility audit does not have a group`);
 }
 
-if(audit.group&&!groups[audit.group]){
-throw new Error(`${audit.id} references unknown group ${audit.group}`);
+if(auditRef.weight>0&&isManual){
+throw new Error(`${auditRef.id} is manual but has a positive weight`);
+}
+
+if(auditRef.group&&!groups[auditRef.group]){
+throw new Error(`${auditRef.id} references unknown group ${auditRef.group}`);
 }
 });
 });
 }
 
 function assertValidAudit(auditDefinition,auditPath){
-const auditName=auditPath||auditDefinition.meta.name;
+const auditName=auditPath||
+auditDefinition&&auditDefinition.meta&&auditDefinition.meta.name;
 
-if(typeof auditDefinition.audit!=='function'){
+if(typeof auditDefinition.audit!=='function'||auditDefinition.audit===Audit.audit){
 throw new Error(`${auditName} has no audit() method.`);
 }
 
@@ -13199,8 +15302,7 @@
 
 
 if(typeof auditDefinition.meta.failureDescription!=='string'&&
-auditDefinition.meta.informative!==true&&
-auditDefinition.meta.scoringMode!==Audit.SCORING_MODES.NUMERIC){
+auditDefinition.meta.scoreDisplayMode===Audit.SCORING_MODES.BINARY){
 throw new Error(`${auditName} has no failureDescription and should.`);
 }
 
@@ -13221,48 +15323,62 @@
 }
 }
 
-function expandArtifacts(artifacts){
-if(!artifacts){
-return null;
+function assertValidGatherer(gathererInstance,gathererName){
+gathererName=gathererName||gathererInstance.name||'gatherer';
+
+if(typeof gathererInstance.beforePass!=='function'){
+throw new Error(`${gathererName} has no beforePass() method.`);
 }
 
-if(artifacts.traces){
-Object.keys(artifacts.traces).forEach(key=>{
-log.log('info','Normalizng trace contents into expected state...');
-let trace=require(artifacts.traces[key]);
-
-
-
-if(Array.isArray(trace)){
-trace={
-traceEvents:trace};
-
-}
-trace=cleanTrace(trace);
-
-artifacts.traces[key]=trace;
-});
+if(typeof gathererInstance.pass!=='function'){
+throw new Error(`${gathererName} has no pass() method.`);
 }
 
-if(artifacts.devtoolsLogs){
-Object.keys(artifacts.devtoolsLogs).forEach(key=>{
-artifacts.devtoolsLogs[key]=require(artifacts.devtoolsLogs[key]);
-});
+if(typeof gathererInstance.afterPass!=='function'){
+throw new Error(`${gathererName} has no afterPass() method.`);
+}
 }
 
-return artifacts;
+
+
+
+
+
+
+
+function cleanFlagsForSettings(flags={}){
+const settings={};
+for(const key of Object.keys(flags)){
+if(typeof constants.defaultSettings[key]!=='undefined'){
+settings[key]=flags[key];
+}
 }
 
-function merge(base,extension){
-if(typeof base==='undefined'){
+return settings;
+}
+
+
+function merge(base,extension,overwriteArrays=false){
+
+if(typeof base==='undefined'||base===null){
 return extension;
+}else if(typeof extension==='undefined'){
+return base;
 }else if(Array.isArray(extension)){
+if(overwriteArrays)return extension;
 if(!Array.isArray(base))throw new TypeError(`Expected array but got ${typeof base}`);
-return base.concat(extension);
+const merged=base.slice();
+extension.forEach(item=>{
+if(!merged.some(candidate=>isDeepEqual(candidate,item)))merged.push(item);
+});
+
+return merged;
 }else if(typeof extension==='object'){
 if(typeof base!=='object')throw new TypeError(`Expected object but got ${typeof base}`);
 Object.keys(extension).forEach(key=>{
-base[key]=merge(base[key],extension[key]);
+const localOverwriteArrays=overwriteArrays||
+key==='settings'&&typeof base[key]==='object';
+base[key]=merge(base[key],extension[key],localOverwriteArrays);
 });
 return base;
 }
@@ -13270,8 +15386,28 @@
 return extension;
 }
 
+function cloneArrayWithPluginSafety(array){
+return array.map(item=>{
+return typeof item==='object'?Object.assign({},item):item;
+});
+}
+
 function deepClone(json){
-return JSON.parse(JSON.stringify(json));
+const cloned=JSON.parse(JSON.stringify(json));
+
+
+
+if(Array.isArray(json.passes)){
+cloned.passes.forEach((pass,i)=>{
+pass.gatherers=cloneArrayWithPluginSafety(json.passes[i].gatherers||[]);
+});
+}
+
+if(Array.isArray(json.audits)){
+cloned.audits=cloneArrayWithPluginSafety(json.audits);
+}
+
+return cloned;
 }
 
 class Config{
@@ -13280,7 +15416,9 @@
 
 
 
-constructor(configJSON,configPath){
+constructor(configJSON,flags){
+let configPath=flags&&flags.configPath;
+
 if(!configJSON){
 configJSON=defaultConfig;
 configPath=path.resolve(__dirname,defaultConfigPath);
@@ -13291,21 +15429,9 @@
 }
 
 
-const inputConfig=configJSON;
 configJSON=deepClone(configJSON);
 
 
-
-if(Array.isArray(inputConfig.passes)){
-configJSON.passes.forEach((pass,i)=>{
-pass.gatherers=Array.from(inputConfig.passes[i].gatherers);
-});
-}
-if(Array.isArray(inputConfig.audits)){
-configJSON.audits=Array.from(inputConfig.audits);
-}
-
-
 if(configJSON.extends==='lighthouse:full'){
 const explodedFullConfig=Config.extendConfigJSON(deepClone(defaultConfig),
 deepClone(fullConfig));
@@ -13315,10 +15441,19 @@
 }
 
 
-if(configJSON.settings&&(
-Array.isArray(configJSON.settings.onlyCategories)||
+configJSON=Config.augmentWithDefaults(configJSON);
+
+
+configJSON.audits=Config.expandAuditShorthandAndMergeOptions(configJSON.audits);
+configJSON.passes=Config.expandGathererShorthandAndMergeOptions(configJSON.passes);
+
+
+configJSON.settings=merge(configJSON.settings||{},cleanFlagsForSettings(flags),true);
+
+
+if(Array.isArray(configJSON.settings.onlyCategories)||
 Array.isArray(configJSON.settings.onlyAudits)||
-Array.isArray(configJSON.settings.skipAudits))){
+Array.isArray(configJSON.settings.skipAudits)){
 const categoryIds=configJSON.settings.onlyCategories;
 const auditIds=configJSON.settings.onlyAudits;
 const skipAuditIds=configJSON.settings.skipAudits;
@@ -13326,18 +15461,19 @@
 skipAuditIds);
 }
 
+Config.adjustDefaultPassForThrottling(configJSON);
+
 
 this._configDir=configPath?path.dirname(configPath):undefined;
 
-this._passes=configJSON.passes||null;
-
+this._passes=Config.requireGatherers(configJSON.passes,this._configDir);
 this._audits=Config.requireAudits(configJSON.audits,this._configDir);
-this._artifacts=expandArtifacts(configJSON.artifacts);
 this._categories=configJSON.categories;
 this._groups=configJSON.groups;
+this._settings=configJSON.settings||{};
 
 
-validatePasses(configJSON.passes,this._audits,this._configDir);
+validatePasses(configJSON.passes,this._audits);
 validateCategories(configJSON.categories,this._audits,this._groups);
 }
 
@@ -13349,8 +15485,11 @@
 static extendConfigJSON(baseJSON,extendJSON){
 if(extendJSON.passes){
 extendJSON.passes.forEach(pass=>{
-const basePass=baseJSON.passes.find(candidate=>candidate.passName===pass.passName);
-if(!basePass||!pass.passName){
+
+const passName=pass.passName||constants.defaultPassConfig.passName;
+const basePass=baseJSON.passes.find(candidate=>candidate.passName===passName);
+
+if(!basePass){
 baseJSON.passes.push(pass);
 }else{
 merge(basePass,pass);
@@ -13367,6 +15506,123 @@
 
 
 
+static augmentWithDefaults(config){
+const{defaultSettings,defaultPassConfig}=constants;
+config.settings=merge(deepClone(defaultSettings),config.settings,true);
+if(config.passes){
+config.passes=config.passes.map(pass=>merge(deepClone(defaultPassConfig),pass));
+}
+
+return config;
+}
+
+
+
+
+
+
+
+static expandAuditShorthandAndMergeOptions(audits){
+if(!audits){
+return audits;
+}
+
+const newAudits=audits.map(audit=>{
+if(typeof audit==='string'){
+return{path:audit,options:{}};
+}else if(audit&&typeof audit.audit==='function'){
+return{implementation:audit,options:{}};
+}else{
+return audit;
+}
+});
+
+return Config._mergeOptionsOfItems(newAudits);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+static expandGathererShorthandAndMergeOptions(passes){
+if(!passes){
+return passes;
+}
+
+passes.forEach(pass=>{
+pass.gatherers=pass.gatherers.map(gatherer=>{
+if(typeof gatherer==='string'){
+return{path:gatherer,options:{}};
+}else if(typeof gatherer==='function'){
+return{implementation:gatherer,options:{}};
+}else if(gatherer&&typeof gatherer.beforePass==='function'){
+return{instance:gatherer,options:{}};
+}else{
+return gatherer;
+}
+});
+
+pass.gatherers=Config._mergeOptionsOfItems(pass.gatherers);
+});
+
+return passes;
+}
+
+
+
+
+
+static _mergeOptionsOfItems(items){
+const mergedItems=[];
+
+for(const item of items){
+const existingItem=item.path&&mergedItems.find(candidate=>candidate.path===item.path);
+if(!existingItem){
+mergedItems.push(item);
+continue;
+}
+
+existingItem.options=Object.assign({},existingItem.options,item.options);
+}
+
+return mergedItems;
+}
+
+
+
+
+
+
+
+static adjustDefaultPassForThrottling(config){
+if(config.settings.throttlingMethod!=='devtools'&&
+config.settings.throttlingMethod!=='provided'){
+return;
+}
+
+const defaultPass=config.passes.find(pass=>pass.passName==='defaultPass');
+if(!defaultPass)return;
+
+const overrides=constants.nonSimulatedPassConfigOverrides;
+defaultPass.pauseAfterLoadMs=
+Math.max(overrides.pauseAfterLoadMs,defaultPass.pauseAfterLoadMs);
+defaultPass.cpuQuietThresholdMs=
+Math.max(overrides.cpuQuietThresholdMs,defaultPass.cpuQuietThresholdMs);
+defaultPass.networkQuietThresholdMs=
+Math.max(overrides.networkQuietThresholdMs,defaultPass.networkQuietThresholdMs);
+}
+
+
+
+
+
 
 
 
@@ -13374,15 +15630,27 @@
 static generateNewFilteredConfig(oldConfig,categoryIds,auditIds,skipAuditIds){
 
 const config=deepClone(oldConfig);
+config.audits=Config.expandAuditShorthandAndMergeOptions(config.audits);
+config.passes=Config.expandGathererShorthandAndMergeOptions(config.passes);
+config.passes=Config.requireGatherers(config.passes);
 
-config.categories=Config.filterCategoriesAndAudits(config.categories,categoryIds,auditIds,
+
+const{categories,audits:requestedAuditNames}=Config.filterCategoriesAndAudits(
+config.categories,
+categoryIds,
+auditIds,
 skipAuditIds);
 
 
-const requestedAuditNames=Config.getAuditIdsInCategories(config.categories);
+config.categories=categories;
+
+
 const auditPathToNameMap=Config.getMapOfAuditPathToName(config);
-config.audits=config.audits.filter(auditPath=>
-requestedAuditNames.has(auditPathToNameMap.get(auditPath)));
+const getAuditName=auditDefn=>auditDefn.implementation?
+auditDefn.implementation.meta.name:
+auditPathToNameMap.get(auditDefn.path);
+config.audits=config.audits.filter(auditDefn=>
+requestedAuditNames.has(getAuditName(auditDefn)));
 
 
 const auditObjectsSelected=Config.requireAudits(config.audits);
@@ -13424,8 +15692,8 @@
 const auditsToValidate=new Set(auditIds.concat(skipAuditIds));
 for(const auditId of auditsToValidate){
 const foundCategory=Object.keys(oldCategories).find(categoryId=>{
-const audits=oldCategories[categoryId].audits;
-return audits.find(candidate=>candidate.id===auditId);
+const auditRefs=oldCategories[categoryId].auditRefs;
+return auditRefs.find(candidate=>candidate.id===auditId);
 });
 
 if(!foundCategory){
@@ -13439,13 +15707,16 @@
 }
 }
 
+const includedAudits=new Set(auditIds);
+skipAuditIds.forEach(id=>includedAudits.delete(id));
+
 Object.keys(oldCategories).forEach(categoryId=>{
 const category=deepClone(oldCategories[categoryId]);
 
 if(filterByIncludedCategory&&filterByIncludedAudit){
 
 if(!categoryIds.includes(categoryId)){
-category.audits=category.audits.filter(audit=>auditIds.includes(audit.id));
+category.auditRefs=category.auditRefs.filter(audit=>auditIds.includes(audit.id));
 }
 }else if(filterByIncludedCategory){
 
@@ -13453,28 +15724,19 @@
 return;
 }
 }else if(filterByIncludedAudit){
-category.audits=category.audits.filter(audit=>auditIds.includes(audit.id));
+category.auditRefs=category.auditRefs.filter(audit=>auditIds.includes(audit.id));
 }
 
 
-category.audits=category.audits.filter(audit=>!skipAuditIds.includes(audit.id));
+category.auditRefs=category.auditRefs.filter(audit=>!skipAuditIds.includes(audit.id));
 
-if(category.audits.length){
+if(category.auditRefs.length){
 categories[categoryId]=category;
+category.auditRefs.forEach(audit=>includedAudits.add(audit.id));
 }
 });
 
-return categories;
-}
-
-
-
-
-
-
-static getAuditIdsInCategories(categories){
-const audits=_flatten(Object.keys(categories).map(id=>categories[id].audits));
-return new Set(audits.map(audit=>audit.id));
+return{categories,audits:includedAudits};
 }
 
 
@@ -13483,8 +15745,8 @@
 
 static getCategories(config){
 return Object.keys(config.categories).map(id=>{
-const name=config.categories[id].name;
-return{id,name};
+const title=config.categories[id].title;
+return{id,title};
 });
 }
 
@@ -13495,7 +15757,8 @@
 
 static getMapOfAuditPathToName(config){
 const auditObjectsAll=Config.requireAudits(config.audits);
-const auditPathToName=new Map(auditObjectsAll.map((AuditClass,index)=>{
+const auditPathToName=new Map(auditObjectsAll.map((auditDefn,index)=>{
+const AuditClass=auditDefn.implementation;
 const auditPath=config.audits[index];
 const auditName=AuditClass.meta.name;
 return[auditPath,auditName];
@@ -13515,8 +15778,8 @@
 return new Set();
 }
 
-return audits.reduce((list,audit)=>{
-audit.meta.requiredArtifacts.forEach(artifact=>list.add(artifact));
+return audits.reduce((list,auditDefn)=>{
+auditDefn.implementation.meta.requiredArtifacts.forEach(artifact=>list.add(artifact));
 return list;
 },new Set());
 }
@@ -13527,14 +15790,13 @@
 
 
 
-static generatePassesNeededByGatherers(oldPasses,requiredGatherers){
+static generatePassesNeededByGatherers(passes,requiredGatherers){
 const auditsNeedTrace=requiredGatherers.has('traces');
-const passes=JSON.parse(JSON.stringify(oldPasses));
 const filteredPasses=passes.map(pass=>{
 
-pass.gatherers=pass.gatherers.filter(gathererName=>{
-gathererName=GatherRunner.getGathererClass(gathererName).name;
-return requiredGatherers.has(gathererName);
+pass.gatherers=pass.gatherers.filter(gathererDefn=>{
+const gatherer=gathererDefn.instance||gathererDefn.implementation;
+return requiredGatherers.has(gatherer.name);
 });
 
 
@@ -13569,10 +15831,9 @@
 }
 
 const coreList=Runner.getAuditList();
-return audits.map(pathOrAuditClass=>{
-let AuditClass;
-if(typeof pathOrAuditClass==='string'){
-const path=pathOrAuditClass;
+return audits.map(auditDefn=>{
+if(!auditDefn.implementation){
+const path=auditDefn.path;
 
 const coreAudit=coreList.find(a=>a===`${path}.js`);
 let requirePath=`../audits/${path}`;
@@ -13580,18 +15841,57 @@
 
 requirePath=Runner.resolvePlugin(path,configPath,'audit');
 }
-AuditClass=require(requirePath);
-assertValidAudit(AuditClass,path);
-}else{
-AuditClass=pathOrAuditClass;
-assertValidAudit(AuditClass);
+
+auditDefn.implementation=require(requirePath);
 }
 
-return AuditClass;
+assertValidAudit(auditDefn.implementation,auditDefn.path);
+return auditDefn;
 });
 }
 
 
+
+
+
+
+
+static requireGatherers(passes,configPath){
+if(!passes){
+return null;
+}
+
+const coreList=Runner.getGathererList();
+passes.forEach(pass=>{
+pass.gatherers.forEach(gathererDefn=>{
+if(!gathererDefn.instance){
+let GathererClass=gathererDefn.implementation;
+if(!GathererClass){
+
+const name=gathererDefn.path;
+const coreGatherer=coreList.find(a=>a===`${name}.js`);
+
+let requirePath=`../gather/gatherers/${name}`;
+if(!coreGatherer){
+
+requirePath=Runner.resolvePlugin(name,configPath,'gatherer');
+}
+
+GathererClass=require(requirePath);
+}
+
+gathererDefn.implementation=GathererClass;
+gathererDefn.instance=new GathererClass();
+}
+
+assertValidGatherer(gathererDefn.instance,gathererDefn.path);
+});
+});
+
+return passes;
+}
+
+
 get configDir(){
 return this._configDir;
 }
@@ -13607,11 +15907,6 @@
 }
 
 
-get artifacts(){
-return this._artifacts;
-}
-
-
 get categories(){
 return this._categories;
 }
@@ -13619,13 +15914,33 @@
 
 get groups(){
 return this._groups;
+}
+
+
+get settings(){
+return this._settings;
 }}
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 module.exports=Config;
 
 }).call(this,"/../lighthouse-core/config");
-},{"../audits/audit":2,"../gather/gather-runner":15,"../runner":44,"./default.js":8,"./full-config.js":10,"lighthouse-logger":137,"path":69}],8:[function(require,module,exports){
+},{"../audits/audit":2,"../runner":50,"./constants":8,"./default-config.js":9,"./full-config.js":10,"lighthouse-logger":143,"lodash.isequal":144,"path":75}],8:[function(require,module,exports){
 
 
 
@@ -13635,17 +15950,94 @@
 
 
 
+
+
+
+const DEVTOOLS_RTT_ADJUSTMENT_FACTOR=3.75;
+const DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR=0.9;
+
+const throttling={
+DEVTOOLS_RTT_ADJUSTMENT_FACTOR,
+DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
+mobile3G:{
+rttMs:150,
+throughputKbps:1.6*1024,
+requestLatencyMs:150*DEVTOOLS_RTT_ADJUSTMENT_FACTOR,
+downloadThroughputKbps:1.6*1024*DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
+uploadThroughputKbps:750*DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
+cpuSlowdownMultiplier:4}};
+
+
+
+
+const defaultSettings={
+output:'json',
+maxWaitForLoad:45*1000,
+throttlingMethod:'simulate',
+throttling:throttling.mobile3G,
+auditMode:false,
+gatherMode:false,
+disableStorageReset:false,
+disableDeviceEmulation:false,
+
+
+
+blockedUrlPatterns:null,
+additionalTraceCategories:null,
+extraHeaders:null,
+onlyAudits:null,
+onlyCategories:null,
+skipAudits:null};
+
+
+const defaultPassConfig={
+passName:'defaultPass',
+recordTrace:false,
+useThrottling:false,
+pauseAfterLoadMs:0,
+networkQuietThresholdMs:0,
+cpuQuietThresholdMs:0,
+blockedUrlPatterns:[],
+blankPage:'about:blank',
+blankDuration:300,
+gatherers:[]};
+
+
+const nonSimulatedPassConfigOverrides={
+pauseAfterLoadMs:5250,
+networkQuietThresholdMs:5250,
+cpuQuietThresholdMs:5250};
+
+
 module.exports={
-settings:{},
+throttling,
+defaultSettings,
+defaultPassConfig,
+nonSimulatedPassConfigOverrides};
+
+
+},{}],9:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const constants=require('./constants');
+
+
+
+module.exports={
+settings:constants.defaultSettings,
 passes:[{
 passName:'defaultPass',
 recordTrace:true,
-pauseAfterLoadMs:5250,
-networkQuietThresholdMs:5250,
-cpuQuietThresholdMs:5250,
 useThrottling:true,
+pauseAfterLoadMs:1000,
+networkQuietThresholdMs:1000,
+cpuQuietThresholdMs:1000,
 gatherers:[
-'url',
 'scripts',
 'css-usage',
 'viewport',
@@ -13673,14 +16065,12 @@
 'seo/hreflang',
 'seo/embedded-content',
 'seo/canonical',
+'seo/robots-txt',
 'fonts']},
 
 
 {
 passName:'offlinePass',
-useThrottling:false,
-
-networkQuietThresholdMs:0,
 gatherers:[
 'service-worker',
 'offline',
@@ -13689,9 +16079,6 @@
 
 {
 passName:'redirectPass',
-useThrottling:false,
-
-networkQuietThresholdMs:0,
 
 blockedUrlPatterns:['*.css','*.jpg','*.jpeg','*.png','*.gif','*.svg','*.ttf','*.woff','*.woff2'],
 gatherers:[
@@ -13706,15 +16093,16 @@
 'works-offline',
 'viewport',
 'without-javascript',
+'first-contentful-paint',
 'first-meaningful-paint',
 'load-fast-enough-for-pwa',
-'speed-index-metric',
+'speed-index',
 'screenshot-thumbnails',
 'estimated-input-latency',
 'errors-in-console',
 'time-to-first-byte',
-'first-interactive',
-'consistently-interactive',
+'first-cpu-idle',
+'interactive',
 'user-timings',
 'critical-request-chains',
 'redirects',
@@ -13728,7 +16116,10 @@
 'mainthread-work-breakdown',
 'bootup-time',
 'uses-rel-preload',
+'uses-rel-preconnect',
 'font-display',
+'network-requests',
+'metrics',
 'manual/pwa-cross-browser',
 'manual/pwa-page-transitions',
 'manual/pwa-each-page-has-url',
@@ -13780,25 +16171,25 @@
 'byte-efficiency/uses-long-cache-ttl',
 'byte-efficiency/total-byte-weight',
 'byte-efficiency/offscreen-images',
+'byte-efficiency/render-blocking-resources',
 'byte-efficiency/unminified-css',
 'byte-efficiency/unminified-javascript',
 'byte-efficiency/unused-css-rules',
 'byte-efficiency/uses-webp-images',
 'byte-efficiency/uses-optimized-images',
-'byte-efficiency/uses-request-compression',
+'byte-efficiency/uses-text-compression',
 'byte-efficiency/uses-responsive-images',
+'byte-efficiency/efficient-animated-content',
 'dobetterweb/appcache-manifest',
 'dobetterweb/dom-size',
 'dobetterweb/external-anchors-use-rel-noopener',
 'dobetterweb/geolocation-on-start',
-'dobetterweb/link-blocking-first-paint',
 'dobetterweb/no-document-write',
 'dobetterweb/no-mutation-events',
 'dobetterweb/no-vulnerable-libraries',
 'dobetterweb/no-websql',
 'dobetterweb/notification-on-start',
 'dobetterweb/password-inputs-can-be-pasted-into',
-'dobetterweb/script-blocking-first-paint',
 'dobetterweb/uses-http2',
 'dobetterweb/uses-passive-event-listeners',
 'seo/meta-description',
@@ -13806,6 +16197,7 @@
 'seo/font-size',
 'seo/link-text',
 'seo/is-crawlable',
+'seo/robots-txt',
 'seo/hreflang',
 'seo/plugins',
 'seo/canonical',
@@ -13814,15 +16206,14 @@
 
 
 groups:{
-'perf-metric':{
-title:'Metrics',
-description:'These metrics encapsulate your web app\'s performance across a number of dimensions.'},
+'metrics':{
+title:'Metrics'},
 
-'perf-hint':{
+'load-opportunities':{
 title:'Opportunities',
 description:'These are opportunities to speed up your application by optimizing the following resources.'},
 
-'perf-info':{
+'diagnostics':{
 title:'Diagnostics',
 description:'More information about the performance of your application.'},
 
@@ -13858,16 +16249,6 @@
 title:'Meta Tags Used Properly',
 description:'These are opportunities to improve the user experience of your site.'},
 
-'manual-a11y-checks':{
-title:'Additional items to manually check',
-description:'These items address areas which an automated testing tool cannot cover. Learn more in our guide on [conducting an accessibility review](https://developers.google.com/web/fundamentals/accessibility/how-to-review).'},
-
-'manual-pwa-checks':{
-title:'Additional items to manually check',
-description:'These checks are required by the baseline '+
-'[PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist) but are '+
-'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.'},
-
 'seo-mobile':{
 title:'Mobile Friendly',
 description:'Make sure your pages are mobile friendly so users don’t have to pinch or zoom '+
@@ -13879,52 +16260,54 @@
 
 'seo-crawl':{
 title:'Crawling and Indexing',
-description:'To appear in search results, crawlers need access to your app.'},
-
-'manual-seo-checks':{
-title:'Additional items to manually check',
-description:'Run these additional validators on your site to check additional SEO best practices.'}},
+description:'To appear in search results, crawlers need access to your app.'}},
 
 
 categories:{
 'performance':{
-name:'Performance',
-description:'These encapsulate your web app\'s current performance and opportunities to improve it.',
-audits:[
-{id:'first-meaningful-paint',weight:5,group:'perf-metric'},
-{id:'first-interactive',weight:5,group:'perf-metric'},
-{id:'consistently-interactive',weight:5,group:'perf-metric'},
-{id:'speed-index-metric',weight:1,group:'perf-metric'},
-{id:'estimated-input-latency',weight:1,group:'perf-metric'},
-{id:'link-blocking-first-paint',weight:0,group:'perf-hint'},
-{id:'script-blocking-first-paint',weight:0,group:'perf-hint'},
-{id:'uses-responsive-images',weight:0,group:'perf-hint'},
-{id:'offscreen-images',weight:0,group:'perf-hint'},
-{id:'unminified-css',weight:0,group:'perf-hint'},
-{id:'unminified-javascript',weight:0,group:'perf-hint'},
-{id:'unused-css-rules',weight:0,group:'perf-hint'},
-{id:'uses-optimized-images',weight:0,group:'perf-hint'},
-{id:'uses-webp-images',weight:0,group:'perf-hint'},
-{id:'uses-request-compression',weight:0,group:'perf-hint'},
-{id:'time-to-first-byte',weight:0,group:'perf-hint'},
-{id:'redirects',weight:0,group:'perf-hint'},
-{id:'uses-rel-preload',weight:0,group:'perf-hint'},
-{id:'total-byte-weight',weight:0,group:'perf-info'},
-{id:'uses-long-cache-ttl',weight:0,group:'perf-info'},
-{id:'dom-size',weight:0,group:'perf-info'},
-{id:'critical-request-chains',weight:0,group:'perf-info'},
-{id:'user-timings',weight:0,group:'perf-info'},
-{id:'bootup-time',weight:0,group:'perf-info'},
+title:'Performance',
+auditRefs:[
+{id:'first-contentful-paint',weight:3,group:'metrics'},
+{id:'first-meaningful-paint',weight:1,group:'metrics'},
+{id:'speed-index',weight:4,group:'metrics'},
+{id:'interactive',weight:5,group:'metrics'},
+{id:'first-cpu-idle',weight:2,group:'metrics'},
+{id:'estimated-input-latency',weight:0,group:'metrics'},
+
+{id:'render-blocking-resources',weight:0,group:'load-opportunities'},
+{id:'uses-responsive-images',weight:0,group:'load-opportunities'},
+{id:'offscreen-images',weight:0,group:'load-opportunities'},
+{id:'unminified-css',weight:0,group:'load-opportunities'},
+{id:'unminified-javascript',weight:0,group:'load-opportunities'},
+{id:'unused-css-rules',weight:0,group:'load-opportunities'},
+{id:'uses-optimized-images',weight:0,group:'load-opportunities'},
+{id:'uses-webp-images',weight:0,group:'load-opportunities'},
+{id:'uses-text-compression',weight:0,group:'load-opportunities'},
+{id:'uses-rel-preconnect',weight:0,group:'load-opportunities'},
+{id:'time-to-first-byte',weight:0,group:'load-opportunities'},
+{id:'redirects',weight:0,group:'load-opportunities'},
+{id:'uses-rel-preload',weight:0,group:'load-opportunities'},
+{id:'efficient-animated-content',weight:0,group:'load-opportunities'},
+{id:'total-byte-weight',weight:0,group:'diagnostics'},
+{id:'uses-long-cache-ttl',weight:0,group:'diagnostics'},
+{id:'dom-size',weight:0,group:'diagnostics'},
+{id:'critical-request-chains',weight:0,group:'diagnostics'},
+{id:'network-requests',weight:0},
+{id:'metrics',weight:0},
+{id:'user-timings',weight:0,group:'diagnostics'},
+{id:'bootup-time',weight:0,group:'diagnostics'},
 {id:'screenshot-thumbnails',weight:0},
-{id:'mainthread-work-breakdown',weight:0,group:'perf-info'},
-{id:'font-display',weight:0,group:'perf-info'}]},
+{id:'mainthread-work-breakdown',weight:0,group:'diagnostics'},
+{id:'font-display',weight:0,group:'diagnostics'}]},
 
 
 'pwa':{
-name:'Progressive Web App',
-weight:1,
+title:'Progressive Web App',
 description:'These checks validate the aspects of a Progressive Web App, as specified by the baseline [PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist).',
-audits:[
+manualDescription:'These checks are required by the baseline '+
+'[PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist) but are '+
+'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.',
+auditRefs:[
 {id:'service-worker',weight:1},
 {id:'works-offline',weight:1},
 {id:'without-javascript',weight:1},
@@ -13936,15 +16319,17 @@
 {id:'themed-omnibox',weight:1},
 {id:'viewport',weight:1},
 {id:'content-width',weight:1},
-{id:'pwa-cross-browser',weight:0,group:'manual-pwa-checks'},
-{id:'pwa-page-transitions',weight:0,group:'manual-pwa-checks'},
-{id:'pwa-each-page-has-url',weight:0,group:'manual-pwa-checks'}]},
+
+{id:'pwa-cross-browser',weight:0},
+{id:'pwa-page-transitions',weight:0},
+{id:'pwa-each-page-has-url',weight:0}]},
 
 
 'accessibility':{
-name:'Accessibility',
+title:'Accessibility',
 description:'These checks highlight opportunities to [improve the accessibility of your web app](https://developers.google.com/web/fundamentals/accessibility). Only a subset of accessibility issues can be automatically detected so manual testing is also encouraged.',
-audits:[
+manualDescription:'These items address areas which an automated testing tool cannot cover. Learn more in our guide on [conducting an accessibility review](https://developers.google.com/web/fundamentals/accessibility/how-to-review).',
+auditRefs:[
 {id:'accesskeys',weight:1,group:'a11y-correct-attributes'},
 {id:'aria-allowed-attr',weight:3,group:'a11y-aria'},
 {id:'aria-required-attr',weight:2,group:'a11y-aria'},
@@ -13980,22 +16365,22 @@
 {id:'valid-lang',weight:1,group:'a11y-language'},
 {id:'video-caption',weight:4,group:'a11y-describe-contents'},
 {id:'video-description',weight:3,group:'a11y-describe-contents'},
-{id:'logical-tab-order',weight:0,group:'manual-a11y-checks'},
-{id:'focusable-controls',weight:0,group:'manual-a11y-checks'},
-{id:'managed-focus',weight:0,group:'manual-a11y-checks'},
-{id:'focus-traps',weight:0,group:'manual-a11y-checks'},
-{id:'custom-controls-labels',weight:0,group:'manual-a11y-checks'},
-{id:'custom-controls-roles',weight:0,group:'manual-a11y-checks'},
-{id:'visual-order-follows-dom',weight:0,group:'manual-a11y-checks'},
-{id:'offscreen-content-hidden',weight:0,group:'manual-a11y-checks'},
-{id:'heading-levels',weight:0,group:'manual-a11y-checks'},
-{id:'use-landmarks',weight:0,group:'manual-a11y-checks'}]},
+
+{id:'logical-tab-order',weight:0},
+{id:'focusable-controls',weight:0},
+{id:'managed-focus',weight:0},
+{id:'focus-traps',weight:0},
+{id:'custom-controls-labels',weight:0},
+{id:'custom-controls-roles',weight:0},
+{id:'visual-order-follows-dom',weight:0},
+{id:'offscreen-content-hidden',weight:0},
+{id:'heading-levels',weight:0},
+{id:'use-landmarks',weight:0}]},
 
 
 'best-practices':{
-name:'Best Practices',
-description:'We\'ve compiled some recommendations for modernizing your web app and avoiding performance pitfalls.',
-audits:[
+title:'Best Practices',
+auditRefs:[
 {id:'appcache-manifest',weight:1},
 {id:'no-websql',weight:1},
 {id:'is-on-https',weight:1},
@@ -14015,29 +16400,32 @@
 
 
 'seo':{
-name:'SEO',
+title:'SEO',
 description:'These checks ensure that your page is optimized for search engine results ranking. '+
 'There are additional factors Lighthouse does not check that may affect your search ranking. '+
 '[Learn more](https://support.google.com/webmasters/answer/35769).',
-audits:[
+manualDescription:'Run these additional validators on your site to check additional SEO best practices.',
+auditRefs:[
 {id:'viewport',weight:1,group:'seo-mobile'},
 {id:'document-title',weight:1,group:'seo-content'},
 {id:'meta-description',weight:1,group:'seo-content'},
 {id:'http-status-code',weight:1,group:'seo-crawl'},
 {id:'link-text',weight:1,group:'seo-content'},
 {id:'is-crawlable',weight:1,group:'seo-crawl'},
+{id:'robots-txt',weight:1,group:'seo-crawl'},
 {id:'hreflang',weight:1,group:'seo-content'},
 {id:'canonical',weight:1,group:'seo-content'},
 {id:'font-size',weight:1,group:'seo-mobile'},
 {id:'plugins',weight:1,group:'seo-content'},
-{id:'mobile-friendly',weight:0,group:'manual-seo-checks'},
-{id:'structured-data',weight:0,group:'manual-seo-checks'}]}}};
+
+{id:'mobile-friendly',weight:0},
+{id:'structured-data',weight:0}]}}};
 
 
 
 
 
-},{}],9:[function(require,module,exports){
+},{"./constants":8}],10:[function(require,module,exports){
 
 
 
@@ -14047,58 +16435,7 @@
 
 module.exports={
 extends:'lighthouse:default',
-settings:{
-skipAudits:[
-
-'no-mutation-events',
-'screenshot-thumbnails',
-
-
-'first-meaningful-paint',
-'first-interactive',
-'consistently-interactive',
-'estimated-input-latency',
-'speed-index-metric',
-'offscreen-images',
-'load-fast-enough-for-pwa'],
-
-
-onlyCategories:['performance','pwa','best-practices']},
-
-passes:[
-{
-passName:'defaultPass',
-
-useThrottling:false,
-pauseAfterLoadMs:0,
-networkQuietThresholdMs:500,
-cpuQuietThresholdMs:500,
-
-gatherers:[]}],
-
-
-audits:[
-'predictive-perf'],
-
-categories:{
-performance:{
-audits:[
-{id:'predictive-perf',weight:5,group:'perf-metric'}]}}};
-
-
-
-
-
-},{}],10:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-module.exports={
-extends:'lighthouse:default',
+settings:{},
 passes:[
 {
 passName:'extraPass',
@@ -14112,8 +16449,8 @@
 
 categories:{
 'performance':{
-audits:[
-{id:'unused-javascript',weight:0,group:'perf-hint'}]}}};
+auditRefs:[
+{id:'unused-javascript',weight:0,group:'load-opportunities'}]}}};
 
 
 
@@ -14125,6 +16462,283 @@
 
 
 
+'use strict';
+
+const ArbitraryEqualityMap=require('../../lib/arbitrary-equality-map');
+
+class ComputedArtifact{
+
+
+
+constructor(allComputedArtifacts){
+const cache=new ArbitraryEqualityMap();
+cache.setEqualityFn(ArbitraryEqualityMap.deepEquals);
+
+
+
+this._cache=cache;
+
+
+this._allComputedArtifacts=allComputedArtifacts;
+}
+
+
+
+
+get name(){
+throw new Error('name getter not implemented for computed artifact '+this.constructor.name);
+}
+
+
+
+
+
+
+
+
+
+
+
+async compute_(artifact,allComputedArtifacts){
+throw new Error('compute_() not implemented for computed artifact '+this.name);
+}
+
+
+
+
+
+
+
+
+
+
+async request(requiredArtifacts){
+const computed=this._cache.get(requiredArtifacts);
+if(computed){
+return computed;
+}
+
+
+
+const artifactPromise=
+this.compute_(requiredArtifacts,this._allComputedArtifacts);
+this._cache.set(requiredArtifacts,artifactPromise);
+
+return artifactPromise;
+}}
+
+
+module.exports=ComputedArtifact;
+
+},{"../../lib/arbitrary-equality-map":20}],12:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('../computed-artifact');
+const Node=require('../../../lib/dependency-graph/node');
+const NetworkNode=require('../../../lib/dependency-graph/network-node');
+const Simulator=require('../../../lib/dependency-graph/simulator/simulator');
+const WebInspector=require('../../../lib/web-inspector');
+
+class LanternMetricArtifact extends ComputedArtifact{
+
+
+
+
+
+static getScriptUrls(dependencyGraph,condition){
+const scriptUrls=new Set();
+
+dependencyGraph.traverse(node=>{
+if(node.type===Node.TYPES.CPU)return;
+const asNetworkNode=node;
+if(asNetworkNode.record._resourceType!==WebInspector.resourceTypes.Script)return;
+if(condition&&!condition(asNetworkNode))return;
+scriptUrls.add(asNetworkNode.record.url);
+});
+
+return scriptUrls;
+}
+
+
+
+
+get COEFFICIENTS(){
+throw new Error('COEFFICIENTS unimplemented!');
+}
+
+
+
+
+
+
+getOptimisticGraph(dependencyGraph,traceOfTab){
+throw new Error('Optimistic graph unimplemented!');
+}
+
+
+
+
+
+
+getPessimisticGraph(dependencyGraph,traceOfTab){
+throw new Error('Pessmistic graph unimplemented!');
+}
+
+
+
+
+
+
+getEstimateFromSimulation(simulationResult,extras){
+return simulationResult;
+}
+
+
+
+
+
+
+
+async computeMetricWithGraphs(data,artifacts,extras){
+const{trace,devtoolsLog,settings}=data;
+const graph=await artifacts.requestPageDependencyGraph({trace,devtoolsLog});
+const traceOfTab=await artifacts.requestTraceOfTab(trace);
+
+const simulator=data.simulator||(
+await artifacts.requestLoadSimulator({devtoolsLog,settings}));
+
+const optimisticGraph=this.getOptimisticGraph(graph,traceOfTab);
+const pessimisticGraph=this.getPessimisticGraph(graph,traceOfTab);
+
+const optimisticSimulation=simulator.simulate(optimisticGraph);
+const optimisticFlexSimulation=simulator.simulate(optimisticGraph,{flexibleOrdering:true});
+const pessimisticSimulation=simulator.simulate(pessimisticGraph);
+
+const optimisticEstimate=this.getEstimateFromSimulation(
+optimisticSimulation.timeInMs<optimisticFlexSimulation.timeInMs?
+optimisticSimulation:optimisticFlexSimulation,
+Object.assign({},extras,{optimistic:true}));
+
+
+const pessimisticEstimate=this.getEstimateFromSimulation(
+pessimisticSimulation,
+Object.assign({},extras,{optimistic:false}));
+
+
+
+const interceptMultiplier=this.COEFFICIENTS.intercept>0?
+Math.min(1,optimisticEstimate.timeInMs/1000):1;
+const timing=
+this.COEFFICIENTS.intercept*interceptMultiplier+
+this.COEFFICIENTS.optimistic*optimisticEstimate.timeInMs+
+this.COEFFICIENTS.pessimistic*pessimisticEstimate.timeInMs;
+
+return{
+timing,
+optimisticEstimate,
+pessimisticEstimate,
+optimisticGraph,
+pessimisticGraph};
+
+}
+
+
+
+
+
+
+compute_(data,computedArtifacts){
+return this.computeMetricWithGraphs(data,computedArtifacts);
+}}
+
+
+module.exports=LanternMetricArtifact;
+
+},{"../../../lib/dependency-graph/network-node":24,"../../../lib/dependency-graph/node":25,"../../../lib/dependency-graph/simulator/simulator":28,"../../../lib/web-inspector":47,"../computed-artifact":11}],13:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const ComputedArtifact=require('../computed-artifact');
+
+
+
+
+
+
+
+
+
+
+
+class ComputedMetric extends ComputedArtifact{
+
+get name(){
+throw new Error('Unimplemented');
+}
+
+
+
+
+
+
+computeSimulatedMetric(data,artifacts){
+
+return artifacts[`requestLantern${this.name}`](data);
+}
+
+
+
+
+
+
+computeObservedMetric(data,artifacts){
+throw new Error('Unimplemented');
+}
+
+
+
+
+
+
+async compute_(data,computedArtifacts){
+const{trace,devtoolsLog,settings}=data;
+if(!trace||!devtoolsLog||!settings){
+throw new Error('Did not provide necessary metric computation data');
+}
+
+const augmentedData=Object.assign({
+networkRecords:await computedArtifacts.requestNetworkRecords(devtoolsLog),
+traceOfTab:await computedArtifacts.requestTraceOfTab(trace)},
+data);
+
+switch(settings.throttlingMethod){
+case'simulate':
+return this.computeSimulatedMetric(augmentedData,computedArtifacts);
+case'provided':
+case'devtools':
+return this.computeObservedMetric(augmentedData,computedArtifacts);
+default:
+throw new TypeError(`Unrecognized throttling method: ${settings.throttlingMethod}`);}
+
+}}
+
+
+module.exports=ComputedMetric;
+
+},{"../computed-artifact":11}],14:[function(require,module,exports){
+
+
+
+
 
 'use strict';
 
@@ -14132,11 +16746,19 @@
 const log=require('lighthouse-logger');
 const LHError=require('../../lib/errors');
 
+
+
+
+
+
+
 class Connection{
 constructor(){
 this._lastCommandId=0;
 
 this._callbacks=new Map();
+
+
 this._eventEmitter=new EventEmitter();
 }
 
@@ -14157,7 +16779,6 @@
 
 
 
-
 wsEndpoint(){
 return Promise.reject(new Error('Not implemented'));
 }
@@ -14168,39 +16789,8 @@
 
 
 
-
-
-sendCommand(method,params={},cmdOpts={}){
-log.formatProtocol('method => browser',{method,params},'verbose');
-const id=++this._lastCommandId;
-const message=JSON.stringify({id,method,params});
-this.sendRawMessage(message);
-return new Promise((resolve,reject)=>{
-this._callbacks.set(id,{resolve,reject,method,options:cmdOpts});
-});
-}
-
-
-
-
-
-
-on(eventName,cb){
-if(eventName!=='notification'){
-throw new Error('Only supports "notification" events');
-}
-this._eventEmitter.on(eventName,cb);
-}
-
-
-
-
-
-
-
-
 sendRawMessage(message){
-return Promise.reject(new Error('Not implemented'));
+throw new Error('Not implemented');
 }
 
 
@@ -14214,13 +16804,24 @@
 const object=JSON.parse(message);
 
 
-if(this._callbacks.has(object.id)){
+if(!('id'in object)){
+
+const eventMessage=object;
+log.formatProtocol('<= event',
+{method:eventMessage.method,params:eventMessage.params},'verbose');
+this.emitProtocolEvent(eventMessage);
+return;
+}
+
 const callback=this._callbacks.get(object.id);
+if(callback){
 this._callbacks.delete(object.id);
 
+
+
 return callback.resolve(Promise.resolve().then(_=>{
 if(object.error){
-const logLevel=callback.options&&callback.options.silent?'verbose':'error';
+const logLevel=callback.options.silent?'verbose':'error';
 log.formatProtocol('method <= browser ERR',{method:callback.method},logLevel);
 throw LHError.fromProtocolMessage(callback.method,object.error);
 }
@@ -14229,40 +16830,80 @@
 {method:callback.method,params:object.result},'verbose');
 return object.result;
 }));
-}else if(object.id){
+}else{
 
 
 const error=object.error&&object.error.message;
 log.formatProtocol(`disowned method <= browser ${error?'ERR':'OK'}`,
-{method:object.method,params:error||object.result},'verbose');
-}else{
-log.formatProtocol('<= event',
-{method:object.method,params:object.params},'verbose');
-this.emitNotification(object.method,object.params);
+{method:'UNKNOWN',params:error||object.result},'verbose');
 }
 }
 
 
 
 
+emitProtocolEvent(eventMessage){
+if(!this._eventEmitter){
+throw new Error('Attempted to emit event after connection disposed.');
+}
 
-
-emitNotification(method,params){
-this._eventEmitter.emit('notification',{method,params});
+this._eventEmitter.emit('protocolevent',eventMessage);
 }
 
 
 
 
 dispose(){
+if(this._eventEmitter){
 this._eventEmitter.removeAllListeners();
 this._eventEmitter=null;
+}
 }}
 
 
+
+
+
+
+
+Connection.prototype.on=function on(eventName,cb){
+if(eventName!=='protocolevent'){
+throw new Error('Only supports "protocolevent" events');
+}
+
+if(!this._eventEmitter){
+throw new Error('Attempted to add event listener after connection disposed.');
+}
+this._eventEmitter.on(eventName,cb);
+};
+
+
+
+
+
+
+
+function _sendCommand(method,params={},cmdOpts={}){
+
+log.formatProtocol('method => browser',{method,params},'verbose');
+const id=++this._lastCommandId;
+const message=JSON.stringify({id,method,params});
+this.sendRawMessage(message);
+return new Promise(resolve=>{
+this._callbacks.set(id,{resolve,method,options:cmdOpts});
+});
+
+}
+
+
+
+
+
+Connection.prototype.sendCommand=_sendCommand;
+
 module.exports=Connection;
 
-},{"../../lib/errors":28,"events":56,"lighthouse-logger":137}],12:[function(require,module,exports){
+},{"../../lib/errors":33,"events":62,"lighthouse-logger":143}],15:[function(require,module,exports){
 
 
 
@@ -14295,6 +16936,9 @@
 
 
 class RawConnection extends Connection{
+
+
+
 constructor(port){
 super();
 this._port=port;
@@ -14322,6 +16966,7 @@
 
 
 
+
 sendRawMessage(message){
 this._port.send(message);
 }}
@@ -14329,7 +16974,7 @@
 
 module.exports=RawConnection;
 
-},{"./connection.js":11}],13:[function(require,module,exports){
+},{"./connection.js":14}],16:[function(require,module,exports){
 
 
 
@@ -14386,8 +17031,7 @@
 
 module.exports=DevtoolsLog;
 
-},{}],14:[function(require,module,exports){
-
+},{}],17:[function(require,module,exports){
 
 
 
@@ -14398,13 +17042,21 @@
 const NetworkRecorder=require('../lib/network-recorder');
 const emulation=require('../lib/emulation');
 const Element=require('../lib/element');
+const LHError=require('../lib/errors');
 const EventEmitter=require('events').EventEmitter;
 const URL=require('../lib/url-shim');
 const TraceParser=require('../lib/traces/trace-parser');
+const constants=require('../config/constants');
 
 const log=require('lighthouse-logger');
 const DevtoolsLog=require('./devtools-log');
 
+const pageFunctions=require('../lib/page-functions.js');
+
+
+
+const Connection=require('./connections/connection.js');
+
 
 const DEFAULT_PAUSE_AFTER_LOAD=0;
 
@@ -14412,43 +17064,48 @@
 
 const DEFAULT_CPU_QUIET_THRESHOLD=0;
 
-const _uniq=arr=>Array.from(new Set(arr));
+
+
+
 
 class Driver{
-static get MAX_WAIT_FOR_FULLY_LOADED(){
-return 45*1000;
-}
-
 
 
 
 constructor(connection){
-this._traceEvents=[];
 this._traceCategories=Driver.traceCategories;
+
+
+
+
 this._eventEmitter=new EventEmitter();
 this._connection=connection;
 
 this._devtoolsLog=new DevtoolsLog(/^(Page|Network)\./);
 this.online=true;
+
 this._domainEnabledCounts=new Map();
+
 this._isolatedExecutionContextId=undefined;
 
 
 
 
 
+
 this._networkStatusMonitor=null;
 
 
 
 
 
+
 this._monitoredUrl=null;
 
-connection.on('notification',event=>{
+connection.on('protocolevent',event=>{
 this._devtoolsLog.record(event);
 if(this._networkStatusMonitor){
-this._networkStatusMonitor.dispatch(event.method,event.params);
+this._networkStatusMonitor.dispatch(event);
 }
 this._eventEmitter.emit(event.method,event.params);
 });
@@ -14490,6 +17147,9 @@
 return this._connection.connect();
 }
 
+
+
+
 disconnect(){
 return this._connection.disconnect();
 }
@@ -14508,49 +17168,6 @@
 
 
 
-on(eventName,cb){
-if(this._eventEmitter===null){
-throw new Error('connect() must be called before attempting to listen to events.');
-}
-
-
-log.formatProtocol('listen for event =>',{method:eventName},'verbose');
-this._eventEmitter.on(eventName,cb);
-}
-
-
-
-
-
-
-
-once(eventName,cb){
-if(this._eventEmitter===null){
-throw new Error('connect() must be called before attempting to listen to events.');
-}
-
-log.formatProtocol('listen once for event =>',{method:eventName},'verbose');
-this._eventEmitter.once(eventName,cb);
-}
-
-
-
-
-
-
-off(eventName,cb){
-if(this._eventEmitter===null){
-throw new Error('connect() must be called before attempting to remove an event listener.');
-}
-
-this._eventEmitter.removeListener(eventName,cb);
-}
-
-
-
-
-
-
 
 
 
@@ -14580,25 +17197,6 @@
 
 
 
-
-
-sendCommand(method,params,cmdOpts){
-const domainCommand=/^(\w+)\.(enable|disable)$/.exec(method);
-if(domainCommand){
-const enable=domainCommand[2]==='enable';
-if(!this._shouldToggleDomain(domainCommand[1],enable)){
-return Promise.resolve();
-}
-}
-
-return this._connection.sendCommand(method,params,cmdOpts);
-}
-
-
-
-
-
-
 isDomainEnabled(domain){
 
 return!!this._domainEnabledCounts.get(domain);
@@ -14625,6 +17223,9 @@
 
 
 evaluateAsync(expression,options={}){
+
+
+
 const contextIdPromise=options.useIsolation?
 this._getOrCreateIsolatedContextId():
 Promise.resolve(undefined);
@@ -14657,7 +17258,7 @@
           return new __nativePromise(function (resolve) {
             return __nativePromise.resolve()
               .then(_ => ${expression})
-              .catch(${wrapRuntimeEvalErrorInBrowser.toString()})
+              .catch(${pageFunctions.wrapRuntimeEvalErrorInBrowser.toString()})
               .then(resolve);
           });
         }())`,
@@ -14686,6 +17287,9 @@
 });
 }
 
+
+
+
 getAppManifest(){
 return this.sendCommand('Page.getAppManifest').
 then(response=>{
@@ -14701,19 +17305,14 @@
 });
 }
 
-getSecurityState(){
-return new Promise((resolve,reject)=>{
-this.once('Security.securityStateChanged',data=>{
-this.sendCommand('Security.disable').
-then(_=>resolve(data),reject);
-});
 
-this.sendCommand('Security.enable').catch(reject);
-});
-}
+
 
 getServiceWorkerVersions(){
 return new Promise((resolve,reject)=>{
+
+
+
 const versionUpdatedListener=data=>{
 
 
@@ -14737,6 +17336,9 @@
 });
 }
 
+
+
+
 getServiceWorkerRegistrations(){
 return new Promise((resolve,reject)=>{
 this.once('ServiceWorker.workerRegistrationUpdated',data=>{
@@ -14756,8 +17358,11 @@
 
 
 assertNoSameOriginServiceWorkerClients(pageUrl){
+
 let registrations;
+
 let versions;
+
 return this.getServiceWorkerRegistrations().then(data=>{
 registrations=data.registrations;
 }).then(_=>this.getServiceWorkerVersions()).then(data=>{
@@ -14795,13 +17400,24 @@
 
 
 _waitForNetworkIdle(networkQuietThresholdMs){
+
 let idleTimeout;
-let cancel;
+
+let cancel=()=>{
+throw new Error('_waitForNetworkIdle.cancel() called before it was defined');
+};
+
+
+
+if(!this._networkStatusMonitor){
+throw new Error('Driver._waitForNetworkIdle called with no networkStatusMonitor');
+}
+const networkStatusMonitor=this._networkStatusMonitor;
 
 const promise=new Promise((resolve,reject)=>{
 const onIdle=()=>{
 
-this._networkStatusMonitor.once('network-2-busy',onBusy);
+networkStatusMonitor.once('network-2-busy',onBusy);
 idleTimeout=setTimeout(_=>{
 cancel();
 resolve();
@@ -14809,12 +17425,12 @@
 };
 
 const onBusy=()=>{
-this._networkStatusMonitor.once('network-2-idle',onIdle);
-clearTimeout(idleTimeout);
+networkStatusMonitor.once('network-2-idle',onIdle);
+idleTimeout&&clearTimeout(idleTimeout);
 };
 
 const domContentLoadedListener=()=>{
-if(this._networkStatusMonitor.is2Idle()){
+if(networkStatusMonitor.is2Idle()){
 onIdle();
 }else{
 onBusy();
@@ -14823,10 +17439,10 @@
 
 this.once('Page.domContentEventFired',domContentLoadedListener);
 cancel=()=>{
-clearTimeout(idleTimeout);
+idleTimeout&&clearTimeout(idleTimeout);
 this.off('Page.domContentEventFired',domContentLoadedListener);
-this._networkStatusMonitor.removeListener('network-2-busy',onBusy);
-this._networkStatusMonitor.removeListener('network-2-idle',onIdle);
+networkStatusMonitor.removeListener('network-2-busy',onBusy);
+networkStatusMonitor.removeListener('network-2-idle',onIdle);
 };
 });
 
@@ -14849,10 +17465,15 @@
 
 }
 
+
 let lastTimeout;
 let cancelled=false;
 
-const checkForQuietExpression=`(${checkTimeSinceLastLongTask.toString()})()`;
+const checkForQuietExpression=`(${pageFunctions.checkTimeSinceLastLongTask.toString()})()`;
+
+
+
+
 function checkForQuiet(driver,resolve){
 if(cancelled)return;
 
@@ -14860,7 +17481,8 @@
 then(timeSinceLongTask=>{
 if(cancelled)return;
 
-if(typeof timeSinceLongTask==='number'&&timeSinceLongTask>=waitForCPUQuiet){
+if(typeof timeSinceLongTask==='number'){
+if(timeSinceLongTask>=waitForCPUQuiet){
 log.verbose('Driver',`CPU has been idle for ${timeSinceLongTask} ms`);
 resolve();
 }else{
@@ -14868,10 +17490,14 @@
 const timeToWait=waitForCPUQuiet-timeSinceLongTask;
 lastTimeout=setTimeout(()=>checkForQuiet(driver,resolve),timeToWait);
 }
+}
 });
 }
 
-let cancel;
+
+let cancel=()=>{
+throw new Error('_waitForCPUIdle.cancel() called before it was defined');
+};
 const promise=new Promise((resolve,reject)=>{
 checkForQuiet(this,resolve);
 cancel=()=>{
@@ -14895,19 +17521,24 @@
 
 
 _waitForLoadEvent(pauseAfterLoadMs){
-let loadListener;
-let loadTimeout;
+
+let cancel=()=>{
+throw new Error('_waitForLoadEvent.cancel() called before it was defined');
+};
 
 const promise=new Promise((resolve,reject)=>{
-loadListener=function(){
+
+let loadTimeout;
+const loadListener=function(){
 loadTimeout=setTimeout(resolve,pauseAfterLoadMs);
 };
 this.once('Page.loadEventFired',loadListener);
-});
-const cancel=()=>{
+
+cancel=()=>{
 this.off('Page.loadEventFired',loadListener);
-clearTimeout(loadTimeout);
+loadTimeout&&clearTimeout(loadTimeout);
 };
+});
 
 return{
 promise,
@@ -14931,8 +17562,9 @@
 
 
 
-_waitForFullyLoaded(pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs,
+async _waitForFullyLoaded(pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs,
 maxWaitForLoadedMs){
+
 let maxTimeoutHandle;
 
 
@@ -14940,6 +17572,7 @@
 
 const waitForNetworkIdle=this._waitForNetworkIdle(networkQuietThresholdMs);
 
+
 let waitForCPUIdle=null;
 
 
@@ -14953,7 +17586,7 @@
 }).then(()=>{
 return function(){
 log.verbose('Driver','loadEventFired and network considered idle');
-clearTimeout(maxTimeoutHandle);
+maxTimeoutHandle&&clearTimeout(maxTimeoutHandle);
 };
 });
 
@@ -14971,10 +17604,11 @@
 });
 
 
-return Promise.race([
+const cleanupFn=await Promise.race([
 loadPromise,
-maxTimeoutPromise]).
-then(cleanup=>cleanup());
+maxTimeoutPromise]);
+
+cleanupFn();
 }
 
 
@@ -14990,7 +17624,8 @@
 
 
 this._monitoredUrl=startingUrl;
-this._networkStatusMonitor.on('requestloaded',redirectRequest=>{
+
+const requestLoadedListener=redirectRequest=>{
 
 if(!redirectRequest.redirectSource){
 return;
@@ -14999,7 +17634,8 @@
 if(earlierRequest.url===this._monitoredUrl){
 this._monitoredUrl=redirectRequest.url;
 }
-});
+};
+this._networkStatusMonitor.on('requestloaded',requestLoadedListener);
 
 return this.sendCommand('Network.enable');
 }
@@ -15014,6 +17650,11 @@
 this._networkStatusMonitor=null;
 const finalUrl=this._monitoredUrl;
 this._monitoredUrl=null;
+
+if(!finalUrl){
+throw new Error('Network Status Monitoring ended with an undefined finalUrl');
+}
+
 return finalUrl;
 }
 
@@ -15023,20 +17664,21 @@
 
 
 
-_getOrCreateIsolatedContextId(){
+async _getOrCreateIsolatedContextId(){
 if(typeof this._isolatedExecutionContextId==='number'){
-return Promise.resolve(this._isolatedExecutionContextId);
+return this._isolatedExecutionContextId;
 }
 
-return this.sendCommand('Page.getResourceTree').
-then(data=>{
-const mainFrameId=data.frameTree.frame.id;
-return this.sendCommand('Page.createIsolatedWorld',{
+const resourceTreeResponse=await this.sendCommand('Page.getResourceTree');
+const mainFrameId=resourceTreeResponse.frameTree.frame.id;
+
+const isolatedWorldResponse=await this.sendCommand('Page.createIsolatedWorld',{
 frameId:mainFrameId,
 worldName:'lighthouse_isolated_context'});
 
-}).
-then(data=>this._isolatedExecutionContextId=data.executionContextId);
+
+this._isolatedExecutionContextId=isolatedWorldResponse.executionContextId;
+return isolatedWorldResponse.executionContextId;
 }
 
 _clearIsolatedContextId(){
@@ -15054,35 +17696,38 @@
 
 
 
-gotoURL(url,options={}){
+async gotoURL(url,options={}){
 const waitForLoad=options.waitForLoad||false;
-const disableJS=options.disableJavaScript||false;
+const passContext=options.passContext||{};
+const disableJS=passContext.disableJavaScript||false;
 
-let pauseAfterLoadMs=options.config&&options.config.pauseAfterLoadMs;
-let networkQuietThresholdMs=options.config&&options.config.networkQuietThresholdMs;
-let cpuQuietThresholdMs=options.config&&options.config.cpuQuietThresholdMs;
-let maxWaitMs=options.flags&&options.flags.maxWaitForLoad;
+await this._beginNetworkStatusMonitoring(url);
+await this._clearIsolatedContextId();
 
 
-if(typeof pauseAfterLoadMs!=='number')pauseAfterLoadMs=DEFAULT_PAUSE_AFTER_LOAD;
-if(typeof networkQuietThresholdMs!=='number')networkQuietThresholdMs=DEFAULT_NETWORK_QUIET_THRESHOLD;
-if(typeof cpuQuietThresholdMs!=='number')cpuQuietThresholdMs=DEFAULT_CPU_QUIET_THRESHOLD;
-if(typeof maxWaitMs!=='number')maxWaitMs=Driver.MAX_WAIT_FOR_FULLY_LOADED;
-
-
-return this._beginNetworkStatusMonitoring(url).
-then(_=>this._clearIsolatedContextId()).
-then(_=>{
-
 
 
 this.sendCommand('Page.enable');
 this.sendCommand('Emulation.setScriptExecutionDisabled',{value:disableJS});
 this.sendCommand('Page.navigate',{url});
-}).
-then(_=>waitForLoad&&this._waitForFullyLoaded(pauseAfterLoadMs,
-networkQuietThresholdMs,cpuQuietThresholdMs,maxWaitMs)).
-then(_=>this._endNetworkStatusMonitoring());
+
+if(waitForLoad){
+const passConfig=passContext.passConfig||{};
+let{pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs}=passConfig;
+let maxWaitMs=passContext.settings&&passContext.settings.maxWaitForLoad;
+
+
+if(typeof pauseAfterLoadMs!=='number')pauseAfterLoadMs=DEFAULT_PAUSE_AFTER_LOAD;
+if(typeof networkQuietThresholdMs!=='number')networkQuietThresholdMs=DEFAULT_NETWORK_QUIET_THRESHOLD;
+if(typeof cpuQuietThresholdMs!=='number')cpuQuietThresholdMs=DEFAULT_CPU_QUIET_THRESHOLD;
+if(typeof maxWaitMs!=='number')maxWaitMs=constants.defaultSettings.maxWaitForLoad;
+
+
+await this._waitForFullyLoaded(pauseAfterLoadMs,networkQuietThresholdMs,cpuQuietThresholdMs,
+maxWaitMs);
+}
+
+return this._endNetworkStatusMonitoring();
 }
 
 
@@ -15090,37 +17735,47 @@
 
 
 
-getObjectProperty(objectId,propName){
-return new Promise((resolve,reject)=>{
-this.sendCommand('Runtime.getProperties',{
+async getObjectProperty(objectId,propName){
+const propertiesResponse=await this.sendCommand('Runtime.getProperties',{
 objectId,
 accessorPropertiesOnly:true,
 generatePreview:false,
-ownProperties:false}).
+ownProperties:false});
 
-then(properties=>{
-const propertyForName=properties.result.
+
+const propertyForName=propertiesResponse.result.
 find(property=>property.name===propName);
 
 if(propertyForName&&propertyForName.value){
-resolve(propertyForName.value.value);
+return propertyForName.value.value;
 }else{
-resolve(null);
+return null;
 }
-}).catch(reject);
+}
+
+
+
+
+
+
+
+
+getRequestContent(requestId,timeout=1000){
+return new Promise((resolve,reject)=>{
+
+
+const err=new LHError(LHError.errors.REQUEST_CONTENT_TIMEOUT);
+const asyncTimeout=setTimeout(_=>reject(err),timeout);
+
+this.sendCommand('Network.getResponseBody',{requestId}).then(result=>{
+clearTimeout(asyncTimeout);
+
+resolve(result.body);
+}).catch(e=>{
+clearTimeout(asyncTimeout);
+reject(e);
 });
-}
-
-
-
-
-
-
-getRequestContent(requestId){
-return this.sendCommand('Network.getResponseBody',{
-requestId}).
-
-then(result=>result.body);
+});
 }
 
 
@@ -15142,41 +17797,42 @@
 
 
 
-querySelector(selector){
-return this.sendCommand('DOM.getDocument').
-then(result=>result.root.nodeId).
-then(nodeId=>this.sendCommand('DOM.querySelector',{
-nodeId,
-selector})).
+async querySelector(selector){
+const documentResponse=await this.sendCommand('DOM.getDocument');
+const rootNodeId=documentResponse.root.nodeId;
 
-then(element=>{
-if(element.nodeId===0){
+const targetNode=await this.sendCommand('DOM.querySelector',{
+nodeId:rootNodeId,
+selector});
+
+
+if(targetNode.nodeId===0){
 return null;
 }
-return new Element(element,this);
-});
+return new Element(targetNode,this);
 }
 
 
 
 
 
-querySelectorAll(selector){
-return this.sendCommand('DOM.getDocument').
-then(result=>result.root.nodeId).
-then(nodeId=>this.sendCommand('DOM.querySelectorAll',{
-nodeId,
-selector})).
+async querySelectorAll(selector){
+const documentResponse=await this.sendCommand('DOM.getDocument');
+const rootNodeId=documentResponse.root.nodeId;
 
-then(nodeList=>{
+const targetNodeList=await this.sendCommand('DOM.querySelectorAll',{
+nodeId:rootNodeId,
+selector});
+
+
+
 const elementList=[];
-nodeList.nodeIds.forEach(nodeId=>{
+targetNodeList.nodeIds.forEach(nodeId=>{
 if(nodeId!==0){
 elementList.push(new Element({nodeId},this));
 }
 });
 return elementList;
-});
 }
 
 
@@ -15199,23 +17855,22 @@
 
 
 
-getNodesInDocument(pierce=true){
-return this.sendCommand('DOM.getFlattenedDocument',{depth:-1,pierce}).
-then(result=>result.nodes?result.nodes:[]);
+async getNodesInDocument(pierce=true){
+const flattenedDocument=await this.sendCommand('DOM.getFlattenedDocument',
+{depth:-1,pierce});
+
+return flattenedDocument.nodes?flattenedDocument.nodes:[];
 }
 
 
 
 
-beginTrace(flags){
-const additionalCategories=flags&&flags.additionalTraceCategories&&
-flags.additionalTraceCategories.split(',')||[];
-const traceCategories=this._traceCategories.concat(additionalCategories);
-const tracingOpts={
-categories:_uniq(traceCategories).join(','),
-transferMode:'ReturnAsStream',
-options:'sampling-frequency=10000'};
 
+beginTrace(settings){
+const additionalCategories=settings&&settings.additionalTraceCategories&&
+settings.additionalTraceCategories.split(',')||[];
+const traceCategories=this._traceCategories.concat(additionalCategories);
+const uniqueCategories=Array.from(new Set(traceCategories));
 
 
 if(this.isDomainEnabled('Debugger')){
@@ -15233,9 +17888,16 @@
 
 
 then(_=>this.endTraceIfStarted()).
-then(_=>this.sendCommand('Tracing.start',tracingOpts));
+then(_=>this.sendCommand('Tracing.start',{
+categories:uniqueCategories.join(','),
+transferMode:'ReturnAsStream',
+options:'sampling-frequency=10000'}));
+
 }
 
+
+
+
 endTraceIfStarted(){
 return new Promise(resolve=>{
 const traceCallback=()=>resolve();
@@ -15247,11 +17909,14 @@
 });
 }
 
+
+
+
 endTrace(){
 return new Promise((resolve,reject)=>{
 
-this.once('Tracing.tracingComplete',streamHandle=>{
-this._readTraceFromStream(streamHandle).
+this.once('Tracing.tracingComplete',completeEvent=>{
+this._readTraceFromStream(completeEvent).
 then(traceContents=>resolve(traceContents),reject);
 });
 
@@ -15260,13 +17925,25 @@
 });
 }
 
-_readTraceFromStream(streamHandle){
+
+
+
+
+_readTraceFromStream(traceCompleteEvent){
 return new Promise((resolve,reject)=>{
 let isEOF=false;
 const parser=new TraceParser();
 
+if(!traceCompleteEvent.stream){
+return reject('No streamHandle returned by traceCompleteEvent');
+}
+
 const readArguments={
-handle:streamHandle.stream};
+handle:traceCompleteEvent.stream};
+
+
+
+
 
 
 const onChunkRead=response=>{
@@ -15305,37 +17982,53 @@
 return this._devtoolsLog.messages;
 }
 
+
+
+
 enableRuntimeEvents(){
 return this.sendCommand('Runtime.enable');
 }
 
-beginEmulation(flags){
-return Promise.resolve().then(_=>{
-if(!flags.disableDeviceEmulation)return emulation.enableNexus5X(this);
-}).then(_=>this.setThrottling(flags,{useThrottling:true}));
+
+
+
+
+async beginEmulation(settings){
+if(!settings.disableDeviceEmulation){
+await emulation.enableNexus5X(this);
 }
 
-setThrottling(flags,passConfig){
-const throttleCpu=passConfig.useThrottling&&!flags.disableCpuThrottling;
-const throttleNetwork=passConfig.useThrottling&&!flags.disableNetworkThrottling;
-const cpuPromise=throttleCpu?
-emulation.enableCPUThrottling(this):
+await this.setThrottling(settings,{useThrottling:true});
+}
+
+
+
+
+
+
+async setThrottling(settings,passConfig){
+if(settings.throttlingMethod!=='devtools'){
+return emulation.clearAllNetworkEmulation(this);
+}
+
+const cpuPromise=passConfig.useThrottling?
+emulation.enableCPUThrottling(this,settings.throttling):
 emulation.disableCPUThrottling(this);
-const networkPromise=throttleNetwork?
-emulation.enableNetworkThrottling(this):
-emulation.disableNetworkThrottling(this);
+const networkPromise=passConfig.useThrottling?
+emulation.enableNetworkThrottling(this,settings.throttling):
+emulation.clearAllNetworkEmulation(this);
 
-return Promise.all([cpuPromise,networkPromise]);
+await Promise.all([cpuPromise,networkPromise]);
 }
 
 
 
 
 
-goOffline(){
-return this.sendCommand('Network.enable').
-then(_=>emulation.goOffline(this)).
-then(_=>this.online=false);
+async goOffline(){
+await this.sendCommand('Network.enable');
+await emulation.goOffline(this);
+this.online=false;
 }
 
 
@@ -15343,12 +18036,15 @@
 
 
 
-
-goOnline(options){
-return this.setThrottling(options.flags,options.config).
-then(_=>this.online=true);
+async goOnline(options){
+await this.setThrottling(options.settings,options.passConfig);
+this.online=true;
 }
 
+
+
+
+
 cleanBrowserCaches(){
 
 return this.sendCommand('Network.clearBrowserCache').
@@ -15361,16 +18057,18 @@
 
 
 
-setExtraHTTPHeaders(headers){
-if(headers){
-return this.sendCommand('Network.setExtraHTTPHeaders',{
-headers});
-
+async setExtraHTTPHeaders(headers){
+if(!headers){
+return;
 }
 
-return Promise.resolve({});
+return this.sendCommand('Network.setExtraHTTPHeaders',{headers});
 }
 
+
+
+
+
 clearDataForOrigin(url){
 const origin=new URL(url).origin;
 
@@ -15399,8 +18097,8 @@
 
 
 
-cacheNatives(){
-return this.evaluteScriptOnNewDocument(`window.__nativePromise = Promise;
+async cacheNatives(){
+await this.evaluteScriptOnNewDocument(`window.__nativePromise = Promise;
         window.__nativeError = Error;`);
 }
 
@@ -15408,8 +18106,9 @@
 
 
 
-registerPerformanceObserver(){
-return this.evaluteScriptOnNewDocument(`(${registerPerformanceObserverInPage.toString()})()`);
+async registerPerformanceObserver(){
+const scriptStr=`(${pageFunctions.registerPerformanceObserverInPage.toString()})()`;
+await this.evaluteScriptOnNewDocument(scriptStr);
 }
 
 
@@ -15435,7 +18134,7 @@
 });
 };
 
-const funcBody=captureJSCallUsage.toString();
+const funcBody=pageFunctions.captureJSCallUsage.toString();
 
 this.evaluteScriptOnNewDocument(`
         ${globalVarToPopulate} = new Set();
@@ -15463,8 +18162,9 @@
 
 
 
-dismissJavaScriptDialogs(){
-return this.sendCommand('Page.enable').then(_=>{
+async dismissJavaScriptDialogs(){
+await this.sendCommand('Page.enable');
+
 this.on('Page.javascriptDialogOpening',data=>{
 log.warn('Driver',`${data.type} dialog opened by the page automatically suppressed.`);
 
@@ -15474,10 +18174,3922 @@
 promptText:'Lighthouse prompt response'});
 
 });
+}}
+
+
+
+
+
+
+
+Driver.prototype.on=function on(eventName,cb){
+if(this._eventEmitter===null){
+throw new Error('connect() must be called before attempting to listen to events.');
+}
+
+
+log.formatProtocol('listen for event =>',{method:eventName},'verbose');
+this._eventEmitter.on(eventName,cb);
+};
+
+
+
+
+
+
+Driver.prototype.once=function once(eventName,cb){
+if(this._eventEmitter===null){
+throw new Error('connect() must be called before attempting to listen to events.');
+}
+
+log.formatProtocol('listen once for event =>',{method:eventName},'verbose');
+this._eventEmitter.once(eventName,cb);
+};
+
+
+
+
+
+Driver.prototype.off=function off(eventName,cb){
+if(this._eventEmitter===null){
+throw new Error('connect() must be called before attempting to remove an event listener.');
+}
+
+this._eventEmitter.removeListener(eventName,cb);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+function _sendCommand(method,params={},cmdOpts={}){
+const domainCommand=/^(\w+)\.(enable|disable)$/.exec(method);
+if(domainCommand){
+const enable=domainCommand[2]==='enable';
+
+if(!this._shouldToggleDomain(domainCommand[1],enable)){
+return Promise.resolve();
+}
+}
+
+
+return this._connection.sendCommand(method,params,cmdOpts);
+}
+
+
+
+
+
+Driver.prototype.sendCommand=_sendCommand;
+
+module.exports=Driver;
+
+},{"../config/constants":8,"../lib/element":31,"../lib/emulation":32,"../lib/errors":33,"../lib/network-recorder":37,"../lib/page-functions.js":38,"../lib/traces/trace-parser":45,"../lib/url-shim":"url","./connections/connection.js":14,"./devtools-log":16,"events":62,"lighthouse-logger":143}],18:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const log=require('lighthouse-logger');
+const LHError=require('../lib/errors');
+const URL=require('../lib/url-shim');
+const NetworkRecorder=require('../lib/network-recorder.js');
+const constants=require('../config/constants');
+
+const Driver=require('../gather/driver.js');
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class GatherRunner{
+
+
+
+
+
+
+
+
+
+
+static loadBlank(
+driver,
+url=constants.defaultPassConfig.blankPage,
+duration=constants.defaultPassConfig.blankDuration)
+{
+return driver.gotoURL(url).then(_=>new Promise(resolve=>setTimeout(resolve,duration)));
+}
+
+
+
+
+
+
+
+
+
+
+static loadPage(driver,passContext){
+return driver.gotoURL(passContext.url,{
+waitForLoad:true,
+passContext}).
+then(finalUrl=>{
+passContext.url=finalUrl;
+});
+}
+
+
+
+
+
+
+
+static setupDriver(driver,gathererResults,options){
+log.log('status','Initializing…');
+const resetStorage=!options.settings.disableStorageReset;
+
+return driver.assertNoSameOriginServiceWorkerClients(options.requestedUrl).
+then(_=>driver.getUserAgent()).
+then(userAgent=>{
+gathererResults.UserAgent=[userAgent];
+GatherRunner.warnOnHeadless(userAgent,gathererResults);
+}).
+then(_=>driver.beginEmulation(options.settings)).
+then(_=>driver.enableRuntimeEvents()).
+then(_=>driver.cacheNatives()).
+then(_=>driver.registerPerformanceObserver()).
+then(_=>driver.dismissJavaScriptDialogs()).
+then(_=>{
+if(resetStorage)return driver.clearDataForOrigin(options.requestedUrl);
+});
+}
+
+
+
+
+
+static disposeDriver(driver){
+log.log('status','Disconnecting from browser...');
+return driver.disconnect().catch(err=>{
+
+
+if(!/close\/.*status: 500$/.test(err.message)){
+log.error('GatherRunner disconnect',err.message);
+}
+});
+}
+
+
+
+
+
+
+
+static recoverOrThrow(promise){
+return promise.catch(err=>{
+if(err.fatal){
+throw err;
+}
+});
+}
+
+
+
+
+
+
+
+static getPageLoadError(url,networkRecords){
+const mainRecord=networkRecords.find(record=>{
+
+return URL.equalWithExcludedFragments(record.url,url);
+});
+
+let errorCode;
+let errorReason;
+if(!mainRecord){
+errorCode=LHError.errors.NO_DOCUMENT_REQUEST;
+}else if(mainRecord.failed){
+errorCode=LHError.errors.FAILED_DOCUMENT_REQUEST;
+errorReason=mainRecord.localizedFailDescription;
+}
+
+if(errorCode){
+const error=new LHError(errorCode,{reason:errorReason});
+log.error('GatherRunner',error.message,url);
+return error;
+}
+}
+
+
+
+
+
+
+static warnOnHeadless(userAgent,gathererResults){
+const chromeVersion=userAgent.split(/HeadlessChrome\/(.*) /)[1];
+
+
+const minVersion='63.0.3239.0';
+if(chromeVersion&&chromeVersion<minVersion){
+gathererResults.LighthouseRunWarnings.push('Your site\'s mobile performance may be '+
+'worse than the numbers presented in this report. Lighthouse could not test on a '+
+'mobile connection because Headless Chrome does not support network throttling '+
+'prior to version '+minVersion+'. The version used was '+chromeVersion);
+}
+}
+
+
+
+
+
+
+
+
+static beforePass(passContext,gathererResults){
+const blockedUrls=(passContext.passConfig.blockedUrlPatterns||[]).
+concat(passContext.settings.blockedUrlPatterns||[]);
+const blankPage=passContext.passConfig.blankPage;
+const blankDuration=passContext.passConfig.blankDuration;
+const pass=GatherRunner.loadBlank(passContext.driver,blankPage,blankDuration).
+
+
+
+then(()=>passContext.driver.blockUrlPatterns(blockedUrls)).
+then(()=>passContext.driver.setExtraHTTPHeaders(passContext.settings.extraHeaders));
+
+return passContext.passConfig.gatherers.reduce((chain,gathererDefn)=>{
+return chain.then(_=>{
+const gatherer=gathererDefn.instance;
+
+passContext.options=gathererDefn.options||{};
+const artifactPromise=Promise.resolve().then(_=>gatherer.beforePass(passContext));
+gathererResults[gatherer.name]=[artifactPromise];
+return GatherRunner.recoverOrThrow(artifactPromise);
+});
+},pass);
+}
+
+
+
+
+
+
+
+
+static pass(passContext,gathererResults){
+const driver=passContext.driver;
+const config=passContext.passConfig;
+const settings=passContext.settings;
+const gatherers=config.gatherers;
+
+const recordTrace=config.recordTrace;
+const isPerfRun=!settings.disableStorageReset&&recordTrace&&config.useThrottling;
+
+const gatherernames=gatherers.map(g=>g.instance.name).join(', ');
+const status='Loading page & waiting for onload';
+log.log('status',status,gatherernames);
+
+const pass=Promise.resolve().
+
+then(_=>{
+if(isPerfRun)driver.cleanBrowserCaches();
+}).
+
+then(_=>driver.beginDevtoolsLog()).
+
+then(_=>{
+if(recordTrace)driver.beginTrace(settings);
+}).
+
+then(_=>GatherRunner.loadPage(driver,passContext)).
+then(_=>log.log('statusEnd',status));
+
+return gatherers.reduce((chain,gathererDefn)=>{
+return chain.then(_=>{
+const gatherer=gathererDefn.instance;
+
+passContext.options=gathererDefn.options||{};
+const artifactPromise=Promise.resolve().then(_=>gatherer.pass(passContext));
+gathererResults[gatherer.name].push(artifactPromise);
+return GatherRunner.recoverOrThrow(artifactPromise);
+});
+},pass);
+}
+
+
+
+
+
+
+
+
+
+static async afterPass(passContext,gathererResults){
+const driver=passContext.driver;
+const config=passContext.passConfig;
+const gatherers=config.gatherers;
+
+let trace;
+if(config.recordTrace){
+log.log('status','Retrieving trace');
+trace=await driver.endTrace();
+log.verbose('statusEnd','Retrieving trace');
+}
+
+const status='Retrieving devtoolsLog and network records';
+log.log('status',status);
+const devtoolsLog=driver.endDevtoolsLog();
+const networkRecords=NetworkRecorder.recordsFromLogs(devtoolsLog);
+log.verbose('statusEnd',status);
+
+let pageLoadError=GatherRunner.getPageLoadError(passContext.url,networkRecords);
+
+if(!driver.online)pageLoadError=undefined;
+
+if(pageLoadError){
+gathererResults.LighthouseRunWarnings.push('Lighthouse was unable to reliably load the '+
+'page you requested. Make sure you are testing the correct URL and that the server is '+
+'properly responding to all requests.');
+}
+
+
+
+const passData={
+networkRecords,
+devtoolsLog,
+trace};
+
+
+
+await driver.setThrottling(passContext.settings,{useThrottling:false});
+
+for(const gathererDefn of gatherers){
+const gatherer=gathererDefn.instance;
+const status=`Retrieving: ${gatherer.name}`;
+log.log('status',status);
+
+
+passContext.options=gathererDefn.options||{};
+
+
+const artifactPromise=pageLoadError?
+Promise.reject(pageLoadError):
+
+Promise.resolve().then(_=>gatherer.afterPass(passContext,passData));
+gathererResults[gatherer.name].push(artifactPromise);
+await GatherRunner.recoverOrThrow(artifactPromise);
+log.verbose('statusEnd',status);
+}
+
+
+return passData;
+}
+
+
+
+
+
+
+
+
+
+
+
+static async collectArtifacts(gathererResults,tracingData,settings){
+
+
+
+const artifacts={
+traces:tracingData.traces,
+devtoolsLogs:tracingData.devtoolsLogs,
+settings,
+
+LighthouseRunWarnings:Array.from(new Set(gathererResults.LighthouseRunWarnings))};
+
+
+const pageLoadFailures=[];
+for(const[gathererName,phaseResultsPromises]of Object.entries(gathererResults)){
+if(artifacts[gathererName]!==undefined)continue;
+
+try{
+const phaseResults=await Promise.all(phaseResultsPromises);
+
+const definedResults=phaseResults.filter(element=>element!==undefined);
+const artifact=definedResults[definedResults.length-1];
+artifacts[gathererName]=artifact;
+}catch(err){
+
+
+artifacts[gathererName]=err;
+
+if(LHError.isPageLoadError(err))pageLoadFailures.push(err);
+}
+
+if(artifacts[gathererName]===undefined){
+throw new Error(`${gathererName} failed to provide an artifact.`);
+}
+
+
+if(pageLoadFailures.length>Object.keys(artifacts).length*0.5){
+throw pageLoadFailures[0];
+}
+}
+
+return artifacts;
+}
+
+
+
+
+
+
+static run(passes,options){
+const driver=options.driver;
+
+const tracingData={
+traces:{},
+devtoolsLogs:{}};
+
+
+
+const gathererResults={
+LighthouseRunWarnings:[],
+fetchTime:[new Date().toJSON()],
+URL:[{requestedUrl:options.requestedUrl,finalUrl:''}]};
+
+
+return driver.connect().
+then(_=>GatherRunner.loadBlank(driver)).
+then(_=>GatherRunner.setupDriver(driver,gathererResults,options)).
+
+
+then(_=>{
+return passes.reduce((chain,passConfig,passIndex)=>{
+const passContext={
+driver:options.driver,
+
+url:options.requestedUrl,
+settings:options.settings,
+passConfig};
+
+
+return chain.
+then(_=>driver.setThrottling(options.settings,passConfig)).
+then(_=>GatherRunner.beforePass(passContext,gathererResults)).
+then(_=>GatherRunner.pass(passContext,gathererResults)).
+then(_=>GatherRunner.afterPass(passContext,gathererResults)).
+then(passData=>{
+
+tracingData.devtoolsLogs[passConfig.passName]=passData.devtoolsLog;
+
+
+if(passData.trace){
+tracingData.traces[passConfig.passName]=passData.trace;
+}
+
+if(passIndex===0){
+
+gathererResults.URL[0].finalUrl=passContext.url;
+}
+});
+},Promise.resolve());
+}).
+then(_=>GatherRunner.disposeDriver(driver)).
+then(_=>GatherRunner.collectArtifacts(gathererResults,tracingData,options.settings)).
+
+catch(err=>{
+GatherRunner.disposeDriver(driver);
+
+throw err;
 });
 }}
 
 
+module.exports=GatherRunner;
+
+},{"../config/constants":8,"../gather/driver.js":17,"../lib/errors":33,"../lib/network-recorder.js":37,"../lib/url-shim":"url","lighthouse-logger":143}],19:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+class Gatherer{
+
+
+
+get name(){
+return this.constructor.name;
+}
+
+
+
+
+
+
+
+
+beforePass(passContext){}
+
+
+
+
+
+
+
+pass(passContext){}
+
+
+
+
+
+
+
+
+
+afterPass(passContext,loadData){}}
+
+
+
+
+module.exports=Gatherer;
+
+},{}],20:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+const isEqual=require('lodash.isequal');
+
+
+
+
+
+
+module.exports=class ArbitraryEqualityMap{
+constructor(){
+this._equalsFn=(a,b)=>a===b;
+
+this._entries=[];
+}
+
+
+
+
+setEqualityFn(equalsFn){
+this._equalsFn=equalsFn;
+}
+
+
+
+
+
+has(key){
+return this._findIndexOf(key)!==-1;
+}
+
+
+
+
+
+get(key){
+const entry=this._entries[this._findIndexOf(key)];
+return entry&&entry.value;
+}
+
+
+
+
+
+set(key,value){
+let index=this._findIndexOf(key);
+if(index===-1)index=this._entries.length;
+this._entries[index]={key,value};
+}
+
+
+
+
+
+_findIndexOf(key){
+for(let i=0;i<this._entries.length;i++){
+if(this._equalsFn(key,this._entries[i].key))return i;
+}
+
+return-1;
+}
+
+
+
+
+
+
+
+
+
+static deepEquals(objA,objB){
+return isEqual(objA,objB);
+}};
+
+
+},{"lodash.isequal":144}],21:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+const path=require('path');
+const log=require('lighthouse-logger');
+const stream=require('stream');
+const Metrics=require('./traces/pwmetrics-events');
+const TraceParser=require('./traces/trace-parser');
+const rimraf=require('rimraf');
+const mkdirp=require('mkdirp');
+
+const artifactsFilename='artifacts.json';
+const traceSuffix='.trace.json';
+const devtoolsLogSuffix='.devtoolslog.json';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function screenshotDump(screenshots){
+return`
+  <!doctype html>
+  <meta charset="utf-8">
+  <title>screenshots</title>
+  <style>
+html {
+    overflow-x: scroll;
+    overflow-y: hidden;
+    height: 100%;
+    background-image: linear-gradient(to left, #4ca1af , #c4e0e5);
+    background-attachment: fixed;
+    padding: 10px;
+}
+body {
+    white-space: nowrap;
+    background-image: linear-gradient(to left, #4ca1af , #c4e0e5);
+    width: 100%;
+    margin: 0;
+}
+img {
+    margin: 4px;
+}
+</style>
+  <body>
+    <script>
+      var shots = ${JSON.stringify(screenshots)};
+
+  shots.forEach(s => {
+    var i = document.createElement('img');
+    i.src = s.datauri;
+    i.title = s.timestamp;
+    document.body.appendChild(i);
+  });
+  </script>
+  `;
+}
+
+
+
+
+
+
+
+async function loadArtifacts(basePath){
+log.log('Reading artifacts from disk:',basePath);
+
+if(!fs.existsSync(basePath)){
+throw new Error('No saved artifacts found at '+basePath);
+}
+
+
+
+const artifacts=JSON.parse(fs.readFileSync(path.join(basePath,artifactsFilename),'utf8'));
+
+const filenames=fs.readdirSync(basePath);
+
+
+artifacts.devtoolsLogs={};
+filenames.filter(f=>f.endsWith(devtoolsLogSuffix)).map(filename=>{
+const passName=filename.replace(devtoolsLogSuffix,'');
+const devtoolsLog=JSON.parse(fs.readFileSync(path.join(basePath,filename),'utf8'));
+artifacts.devtoolsLogs[passName]=devtoolsLog;
+});
+
+
+artifacts.traces={};
+const promises=filenames.filter(f=>f.endsWith(traceSuffix)).map(filename=>{
+return new Promise(resolve=>{
+const passName=filename.replace(traceSuffix,'');
+const readStream=fs.createReadStream(path.join(basePath,filename),{
+encoding:'utf-8',
+highWaterMark:4*1024*1024});
+
+const parser=new TraceParser();
+readStream.on('data',chunk=>parser.parseChunk(chunk));
+readStream.on('end',_=>{
+artifacts.traces[passName]=parser.getTrace();
+resolve();
+});
+});
+});
+await Promise.all(promises);
+
+return artifacts;
+}
+
+
+
+
+
+
+
+
+async function saveArtifacts(artifacts,basePath){
+mkdirp.sync(basePath);
+rimraf.sync(`${basePath}/*${traceSuffix}`);
+rimraf.sync(`${basePath}/${artifactsFilename}`);
+
+const{traces,devtoolsLogs,...restArtifacts}=artifacts;
+
+
+for(const[passName,trace]of Object.entries(traces)){
+await saveTrace(trace,`${basePath}/${passName}${traceSuffix}`);
+}
+
+
+for(const[passName,devtoolsLog]of Object.entries(devtoolsLogs)){
+const log=JSON.stringify(devtoolsLog);
+fs.writeFileSync(`${basePath}/${passName}${devtoolsLogSuffix}`,log,'utf8');
+}
+
+
+const restArtifactsString=JSON.stringify(restArtifacts,null,2);
+fs.writeFileSync(`${basePath}/${artifactsFilename}`,restArtifactsString,'utf8');
+log.log('Artifacts saved to disk in folder:',basePath);
+}
+
+
+
+
+
+
+
+async function prepareAssets(artifacts,audits){
+const passNames=Object.keys(artifacts.traces);
+
+const assets=[];
+
+for(const passName of passNames){
+const trace=artifacts.traces[passName];
+const devtoolsLog=artifacts.devtoolsLogs[passName];
+
+
+const Runner=require('../runner.js');
+const computedArtifacts=Runner.instantiateComputedArtifacts();
+
+
+const screenshots=await computedArtifacts.requestScreenshots(trace);
+
+const traceData=Object.assign({},trace);
+const screenshotsHTML=screenshotDump(screenshots);
+
+if(audits){
+const evts=new Metrics(traceData.traceEvents,audits).generateFakeEvents();
+traceData.traceEvents=traceData.traceEvents.concat(evts);
+}
+
+assets.push({
+passName,
+traceData,
+devtoolsLog,
+screenshotsHTML,
+screenshots});
+
+}
+
+return assets;
+}
+
+
+
+
+
+
+
+function*traceJsonGenerator(traceData){
+const keys=Object.keys(traceData);
+
+yield'{\n';
+
+
+yield'"traceEvents": [\n';
+if(traceData.traceEvents.length>0){
+const eventsIterator=traceData.traceEvents[Symbol.iterator]();
+
+const firstEvent=eventsIterator.next().value;
+yield`  ${JSON.stringify(firstEvent)}`;
+for(const event of eventsIterator){
+yield`,\n  ${JSON.stringify(event)}`;
+}
+}
+yield'\n]';
+
+
+if(keys.length>1){
+for(const key of keys){
+if(key==='traceEvents')continue;
+
+yield`,\n"${key}": ${JSON.stringify(traceData[key],null,2)}`;
+}
+}
+
+yield'}\n';
+}
+
+
+
+
+
+
+
+function saveTrace(traceData,traceFilename){
+return new Promise((resolve,reject)=>{
+const traceIter=traceJsonGenerator(traceData);
+
+
+const traceStream=new stream.Readable({
+read(){
+const next=traceIter.next();
+this.push(next.done?null:next.value);
+}});
+
+
+const writeStream=fs.createWriteStream(traceFilename);
+writeStream.on('finish',resolve);
+writeStream.on('error',reject);
+
+traceStream.pipe(writeStream);
+});
+}
+
+
+
+
+
+
+
+
+async function saveAssets(artifacts,audits,pathWithBasename){
+const allAssets=await prepareAssets(artifacts,audits);
+const saveAll=allAssets.map(async(passAssets,index)=>{
+const devtoolsLogFilename=`${pathWithBasename}-${index}${devtoolsLogSuffix}`;
+fs.writeFileSync(devtoolsLogFilename,JSON.stringify(passAssets.devtoolsLog,null,2));
+log.log('saveAssets','devtools log saved to disk: '+devtoolsLogFilename);
+
+const screenshotsHTMLFilename=`${pathWithBasename}-${index}.screenshots.html`;
+fs.writeFileSync(screenshotsHTMLFilename,passAssets.screenshotsHTML);
+log.log('saveAssets','screenshots saved to disk: '+screenshotsHTMLFilename);
+
+const screenshotsJSONFilename=`${pathWithBasename}-${index}.screenshots.json`;
+fs.writeFileSync(screenshotsJSONFilename,JSON.stringify(passAssets.screenshots,null,2));
+log.log('saveAssets','screenshots saved to disk: '+screenshotsJSONFilename);
+
+const streamTraceFilename=`${pathWithBasename}-${index}${traceSuffix}`;
+log.log('saveAssets','streaming trace file to disk: '+streamTraceFilename);
+await saveTrace(passAssets.traceData,streamTraceFilename);
+log.log('saveAssets','trace file streamed to disk: '+streamTraceFilename);
+});
+
+await Promise.all(saveAll);
+}
+
+
+
+
+
+
+
+async function logAssets(artifacts,audits){
+const allAssets=await prepareAssets(artifacts,audits);
+allAssets.map(passAssets=>{
+log.log(`devtoolslog-${passAssets.passName}.json`,JSON.stringify(passAssets.devtoolsLog));
+const traceIter=traceJsonGenerator(passAssets.traceData);
+let traceJson='';
+for(const trace of traceIter){
+traceJson+=trace;
+}
+log.log(`trace-${passAssets.passName}.json`,traceJson);
+});
+}
+
+module.exports={
+saveArtifacts,
+loadArtifacts,
+saveAssets,
+prepareAssets,
+saveTrace,
+logAssets};
+
+
+},{"../runner.js":50,"./traces/pwmetrics-events":44,"./traces/trace-parser":45,"lighthouse-logger":143,"mkdirp":58,"path":75,"rimraf":58,"stream":92}],22:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+const log=require('lighthouse-logger');
+
+
+let _logs=[];
+
+class ConsoleQuieter{
+
+static mute(opts){
+_logs=_logs||[];
+
+
+console.log=function(...args){
+_logs.push({type:'log',args,prefix:opts.prefix});
+};
+
+console.warn=function(...args){
+_logs.push({type:'warn',args,prefix:opts.prefix});
+};
+
+console.error=function(...args){
+_logs.push({type:'error',args,prefix:opts.prefix});
+};
+}
+
+static unmuteAndFlush(){
+console.log=ConsoleQuieter._consolelog;
+console.warn=ConsoleQuieter._consolewarn;
+console.error=ConsoleQuieter._consoleerror;
+
+_logs.forEach(entry=>{
+log.verbose(`${entry.prefix}-${entry.type}`,...entry.args);
+});
+_logs=[];
+}}
+
+
+ConsoleQuieter._consolelog=console.log.bind(console);
+ConsoleQuieter._consolewarn=console.warn.bind(console);
+ConsoleQuieter._consoleerror=console.error.bind(console);
+
+module.exports=ConsoleQuieter;
+
+},{"lighthouse-logger":143}],23:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Node=require('./node');
+
+class CPUNode extends Node{
+
+
+
+
+constructor(parentEvent,childEvents=[]){
+const nodeId=`${parentEvent.tid}.${parentEvent.ts}`;
+super(nodeId);
+
+this._event=parentEvent;
+this._childEvents=childEvents;
+}
+
+
+
+
+get type(){
+return Node.TYPES.CPU;
+}
+
+
+
+
+get startTime(){
+return this._event.ts;
+}
+
+
+
+
+get endTime(){
+return this._event.ts+this._event.dur;
+}
+
+
+
+
+get event(){
+return this._event;
+}
+
+
+
+
+get childEvents(){
+return this._childEvents;
+}
+
+
+
+
+
+didPerformLayout(){
+return this._childEvents.some(evt=>evt.name==='Layout');
+}
+
+
+
+
+
+
+isEvaluateScriptFor(urls){
+return this._childEvents.some(evt=>{
+return evt.name==='EvaluateScript'&&
+!!evt.args.data&&!!evt.args.data.url&&
+urls.has(evt.args.data.url);
+});
+}
+
+
+
+
+cloneWithoutRelationships(){
+return new CPUNode(this._event,this._childEvents);
+}}
+
+
+module.exports=CPUNode;
+
+},{"./node":25}],24:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Node=require('./node');
+const WebInspector=require('../web-inspector');
+
+class NetworkNode extends Node{
+
+
+
+constructor(networkRecord){
+super(networkRecord.requestId);
+this._record=networkRecord;
+}
+
+
+
+
+get type(){
+return Node.TYPES.NETWORK;
+}
+
+
+
+
+get startTime(){
+return this._record.startTime*1000*1000;
+}
+
+
+
+
+get endTime(){
+return this._record.endTime*1000*1000;
+}
+
+
+
+
+get record(){
+return this._record;
+}
+
+
+
+
+get initiatorType(){
+return this._record._initiator&&this._record._initiator.type;
+}
+
+
+
+
+get fromDiskCache(){
+return!!this._record._fromDiskCache;
+}
+
+
+
+
+hasRenderBlockingPriority(){
+const priority=this._record.priority();
+const isScript=this._record._resourceType===WebInspector.resourceTypes.Script;
+const isDocument=this._record._resourceType===WebInspector.resourceTypes.Document;
+const isBlockingScript=priority==='High'&&isScript;
+const isBlockingHtmlImport=priority==='High'&&isDocument;
+return priority==='VeryHigh'||isBlockingScript||isBlockingHtmlImport;
+}
+
+
+
+
+cloneWithoutRelationships(){
+const node=new NetworkNode(this._record);
+node.setIsMainDocument(this._isMainDocument);
+return node;
+}}
+
+
+module.exports=NetworkNode;
+
+},{"../web-inspector":47,"./node":25}],25:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+class Node{
+
+
+
+constructor(id){
+this._id=id;
+this._isMainDocument=false;
+
+this._dependents=[];
+
+this._dependencies=[];
+}
+
+
+
+
+get id(){
+return this._id;
+}
+
+
+
+
+get type(){
+throw new Error('Unimplemented');
+}
+
+
+
+
+get startTime(){
+throw new Error('Unimplemented');
+}
+
+
+
+
+get endTime(){
+throw new Error('Unimplemented');
+}
+
+
+
+
+setIsMainDocument(value){
+this._isMainDocument=value;
+}
+
+
+
+
+isMainDocument(){
+return this._isMainDocument;
+}
+
+
+
+
+getDependents(){
+return this._dependents.slice();
+}
+
+
+
+
+getDependencies(){
+return this._dependencies.slice();
+}
+
+
+
+
+getNumberOfDependencies(){
+return this._dependencies.length;
+}
+
+
+
+
+getRootNode(){
+
+let rootNode=this;
+while(rootNode._dependencies.length){
+rootNode=rootNode._dependencies[0];
+}
+
+return rootNode;
+}
+
+
+
+
+addDependent(node){
+node.addDependency(this);
+}
+
+
+
+
+addDependency(node){
+if(this._dependencies.includes(node)){
+return;
+}
+
+node._dependents.push(this);
+this._dependencies.push(node);
+}
+
+
+
+
+removeDependent(node){
+node.removeDependency(this);
+}
+
+
+
+
+removeDependency(node){
+if(!this._dependencies.includes(node)){
+return;
+}
+
+node._dependents.splice(node._dependents.indexOf(this),1);
+this._dependencies.splice(this._dependencies.indexOf(node),1);
+}
+
+removeAllDependencies(){
+for(const node of this._dependencies.slice()){
+this.removeDependency(node);
+}
+}
+
+
+
+
+
+cloneWithoutRelationships(){
+const node=new Node(this.id);
+node.setIsMainDocument(this._isMainDocument);
+return node;
+}
+
+
+
+
+
+
+
+
+cloneWithRelationships(predicate){
+const rootNode=this.getRootNode();
+
+
+let shouldIncludeNode=()=>true;
+if(predicate){
+const idsToInclude=new Set();
+rootNode.traverse(node=>{
+if(predicate(node)){
+node.traverse(
+node=>idsToInclude.add(node.id),
+node=>node._dependencies.filter(parent=>!idsToInclude.has(parent)));
+
+}
+});
+
+shouldIncludeNode=node=>idsToInclude.has(node.id);
+}
+
+const idToNodeMap=new Map();
+rootNode.traverse(originalNode=>{
+if(!shouldIncludeNode(originalNode))return;
+const clonedNode=originalNode.cloneWithoutRelationships();
+idToNodeMap.set(clonedNode.id,clonedNode);
+});
+
+rootNode.traverse(originalNode=>{
+if(!shouldIncludeNode(originalNode))return;
+const clonedNode=idToNodeMap.get(originalNode.id);
+
+for(const dependency of originalNode._dependencies){
+const clonedDependency=idToNodeMap.get(dependency.id);
+clonedNode.addDependency(clonedDependency);
+}
+});
+
+if(!idToNodeMap.has(this.id))throw new Error(`Cloned graph missing node ${this.id}`);
+return idToNodeMap.get(this.id);
+}
+
+
+
+
+
+
+
+_traversePaths(iterator,getNext){
+
+const stack=[[this]];
+while(stack.length){
+
+
+const path=stack.shift();
+const node=path[0];
+iterator(node,path);
+
+const nodesToAdd=getNext(node);
+for(const nextNode of nodesToAdd){
+stack.push([nextNode].concat(path));
+}
+}
+}
+
+
+
+
+
+
+
+traverse(iterator,getNext){
+if(!getNext){
+getNext=node=>node.getDependents();
+}
+
+const visited=new Set();
+const originalGetNext=getNext;
+
+getNext=node=>{
+visited.add(node.id);
+const allNodesToVisit=originalGetNext(node);
+const nodesToVisit=allNodesToVisit.filter(nextNode=>!visited.has(nextNode.id));
+nodesToVisit.forEach(nextNode=>visited.add(nextNode.id));
+return nodesToVisit;
+};
+
+this._traversePaths(iterator,getNext);
+}
+
+
+
+
+
+
+
+static hasCycle(node,direction='both'){
+
+if(direction==='both'){
+return Node.hasCycle(node,'dependents')||Node.hasCycle(node,'dependencies');
+}
+
+const visited=new Set();
+
+const currentPath=[];
+const toVisit=[node];
+const depthAdded=new Map([[node,0]]);
+
+
+while(toVisit.length){
+
+
+
+const currentNode=toVisit.pop();
+
+
+if(currentPath.includes(currentNode))return true;
+
+if(visited.has(currentNode))continue;
+
+
+
+while(currentPath.length>depthAdded.get(currentNode))currentPath.pop();
+
+
+visited.add(currentNode);
+currentPath.push(currentNode);
+
+
+const nodesToExplore=direction==='dependents'?
+currentNode._dependents:
+currentNode._dependencies;
+for(const nextNode of nodesToExplore){
+if(toVisit.includes(nextNode))continue;
+toVisit.push(nextNode);
+depthAdded.set(nextNode,currentPath.length);
+}
+}
+
+return false;
+}}
+
+
+Node.TYPES={
+NETWORK:'network',
+CPU:'cpu'};
+
+
+module.exports=Node;
+
+},{}],26:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const NetworkAnalyzer=require('./network-analyzer');
+const TcpConnection=require('./tcp-connection');
+
+const DEFAULT_SERVER_RESPONSE_TIME=30;
+const TLS_SCHEMES=['https','wss'];
+
+
+
+const CONNECTIONS_PER_ORIGIN=6;
+
+module.exports=class ConnectionPool{
+
+
+
+
+constructor(records,options){
+this._options=Object.assign(
+{
+rtt:undefined,
+throughput:undefined,
+additionalRttByOrigin:new Map(),
+serverResponseTimeByOrigin:new Map()},
+
+options);
+
+
+if(!this._options.rtt||!this._options.throughput){
+throw new Error('Cannot create pool with no rtt or throughput');
+}
+
+this._records=records;
+
+this._connectionsByOrigin=new Map();
+
+this._connectionsByRecord=new Map();
+this._connectionsInUse=new Set();
+this._connectionReusedByRequestId=NetworkAnalyzer.estimateIfConnectionWasReused(records,{
+forceCoarseEstimates:true});
+
+
+this._initializeConnections();
+}
+
+
+
+
+connectionsInUse(){
+return Array.from(this._connectionsInUse);
+}
+
+_initializeConnections(){
+const connectionReused=this._connectionReusedByRequestId;
+const additionalRttByOrigin=this._options.additionalRttByOrigin;
+const serverResponseTimeByOrigin=this._options.serverResponseTimeByOrigin;
+
+const recordsByOrigin=NetworkAnalyzer.groupByOrigin(this._records);
+for(const[origin,records]of recordsByOrigin.entries()){
+const connections=[];
+const additionalRtt=additionalRttByOrigin.get(origin)||0;
+const responseTime=serverResponseTimeByOrigin.get(origin)||DEFAULT_SERVER_RESPONSE_TIME;
+
+for(const record of records){
+if(connectionReused.get(record.requestId))continue;
+
+const isTLS=TLS_SCHEMES.includes(record.parsedURL.scheme);
+const isH2=record.protocol==='h2';
+const connection=new TcpConnection(
+this._options.rtt+additionalRtt,
+this._options.throughput,
+responseTime,
+isTLS,
+isH2);
+
+
+connections.push(connection);
+}
+
+if(!connections.length){
+throw new Error(`Could not find a connection for origin: ${origin}`);
+}
+
+
+while(connections.length<CONNECTIONS_PER_ORIGIN)connections.push(connections[0].clone());
+
+this._connectionsByOrigin.set(origin,connections);
+}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+acquire(record,options={}){
+if(this._connectionsByRecord.has(record)){
+
+return this._connectionsByRecord.get(record);
+}
+
+const origin=String(record.parsedURL.securityOrigin());
+
+const connections=this._connectionsByOrigin.get(origin)||[];
+
+const availableConnections=connections.
+filter(connection=>!this._connectionsInUse.has(connection)).
+sort((a,b)=>b.congestionWindow-a.congestionWindow);
+
+const observedConnectionWasReused=!!this._connectionReusedByRequestId.get(record.requestId);
+
+
+let connectionToUse=availableConnections[0];
+if(!options.ignoreConnectionReused){
+connectionToUse=availableConnections.find(
+connection=>connection.isWarm()===observedConnectionWasReused);
+
+}
+
+if(!connectionToUse)return null;
+
+this._connectionsInUse.add(connectionToUse);
+this._connectionsByRecord.set(record,connectionToUse);
+return connectionToUse;
+}
+
+
+
+
+release(record){
+const connection=this._connectionsByRecord.get(record);
+this._connectionsByRecord.delete(record);
+this._connectionsInUse.delete(connection);
+}};
+
+
+},{"./network-analyzer":27,"./tcp-connection":29}],27:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const INITIAL_CWD=14*1024;
+const WebInspector=require('../../web-inspector');
+
+class NetworkAnalyzer{
+
+
+
+static get SUMMARY(){
+return'__SUMMARY__';
+}
+
+
+
+
+
+static groupByOrigin(records){
+const grouped=new Map();
+records.forEach(item=>{
+const key=item.parsedURL.securityOrigin();
+const group=grouped.get(key)||[];
+group.push(item);
+grouped.set(key,group);
+});
+return grouped;
+}
+
+
+
+
+
+static getSummary(values){
+values.sort((a,b)=>a-b);
+
+return{
+min:values[0],
+max:values[values.length-1],
+avg:values.reduce((a,b)=>a+b,0)/values.length,
+median:values[Math.floor((values.length-1)/2)]};
+
+}
+
+
+
+
+
+static summarize(values){
+const summaryByKey=new Map();
+const allEstimates=[];
+for(const[key,estimates]of values){
+summaryByKey.set(key,NetworkAnalyzer.getSummary(estimates));
+allEstimates.push(...estimates);
+}
+
+summaryByKey.set(NetworkAnalyzer.SUMMARY,NetworkAnalyzer.getSummary(allEstimates));
+return summaryByKey;
+}
+
+
+
+
+
+
+static _estimateValueByOrigin(records,iteratee){
+const connectionWasReused=NetworkAnalyzer.estimateIfConnectionWasReused(records);
+const groupedByOrigin=NetworkAnalyzer.groupByOrigin(records);
+
+const estimates=new Map();
+for(const[origin,originRecords]of groupedByOrigin.entries()){
+
+let originEstimates=[];
+
+for(const record of originRecords){
+const timing=record._timing;
+if(!timing)continue;
+
+const value=iteratee({
+record,
+timing,
+connectionReused:connectionWasReused.get(record.requestId)});
+
+if(typeof value!=='undefined'){
+originEstimates=originEstimates.concat(value);
+}
+}
+
+if(!originEstimates.length)continue;
+estimates.set(origin,originEstimates);
+}
+
+return estimates;
+}
+
+
+
+
+
+
+
+
+static _estimateRTTByOriginViaTCPTiming(records){
+return NetworkAnalyzer._estimateValueByOrigin(records,({timing,connectionReused})=>{
+if(connectionReused)return;
+
+
+
+if(timing.sslStart>0&&timing.sslEnd>0){
+return[timing.connectEnd-timing.sslStart,timing.sslStart-timing.connectStart];
+}else if(timing.connectStart>0&&timing.connectEnd>0){
+return timing.connectEnd-timing.connectStart;
+}
+});
+}
+
+
+
+
+
+
+
+
+
+static _estimateRTTByOriginViaDownloadTiming(records){
+return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing,connectionReused})=>{
+if(connectionReused)return;
+
+if(record.transferSize<=INITIAL_CWD)return;
+if(!Number.isFinite(timing.receiveHeadersEnd)||timing.receiveHeadersEnd<0)return;
+
+
+const totalTime=(record.endTime-record.startTime)*1000;
+const downloadTimeAfterFirstByte=totalTime-timing.receiveHeadersEnd;
+const numberOfRoundTrips=Math.log2(record.transferSize/INITIAL_CWD);
+
+
+
+if(numberOfRoundTrips>5)return;
+return downloadTimeAfterFirstByte/numberOfRoundTrips;
+});
+}
+
+
+
+
+
+
+
+
+
+
+static _estimateRTTByOriginViaSendStartTiming(records){
+return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing,connectionReused})=>{
+if(connectionReused)return;
+if(!Number.isFinite(timing.sendStart)||timing.sendStart<0)return;
+
+
+
+let roundTrips=1;
+if(record.parsedURL.scheme==='https')roundTrips+=1;
+return timing.sendStart/roundTrips;
+});
+}
+
+
+
+
+
+
+
+
+static _estimateResponseTimeByOrigin(records,rttByOrigin){
+return NetworkAnalyzer._estimateValueByOrigin(records,({record,timing})=>{
+if(!Number.isFinite(timing.receiveHeadersEnd)||timing.receiveHeadersEnd<0)return;
+if(!Number.isFinite(timing.sendEnd)||timing.sendEnd<0)return;
+
+const ttfb=timing.receiveHeadersEnd-timing.sendEnd;
+const origin=record.parsedURL.securityOrigin();
+const rtt=rttByOrigin.get(origin)||rttByOrigin.get(NetworkAnalyzer.SUMMARY)||0;
+return Math.max(ttfb-rtt,0);
+});
+}
+
+
+
+
+
+static canTrustConnectionInformation(records){
+const connectionIdWasStarted=new Map();
+for(const record of records){
+const started=connectionIdWasStarted.get(record.connectionId)||!record.connectionReused;
+connectionIdWasStarted.set(record.connectionId,started);
+}
+
+
+if(connectionIdWasStarted.size<=1)return false;
+
+return Array.from(connectionIdWasStarted.values()).every(started=>started);
+}
+
+
+
+
+
+
+
+
+
+static estimateIfConnectionWasReused(records,options){
+options=Object.assign({forceCoarseEstimates:false},options);
+
+
+if(!options.forceCoarseEstimates&&NetworkAnalyzer.canTrustConnectionInformation(records)){
+
+return new Map(records.map(record=>[record.requestId,!!record.connectionReused]));
+}
+
+
+
+
+
+const connectionWasReused=new Map();
+const groupedByOrigin=NetworkAnalyzer.groupByOrigin(records);
+for(const[_,originRecords]of groupedByOrigin.entries()){
+const earliestReusePossible=originRecords.
+map(record=>record.endTime).
+reduce((a,b)=>Math.min(a,b),Infinity);
+
+for(const record of originRecords){
+connectionWasReused.set(
+record.requestId,
+record.startTime>=earliestReusePossible||record.protocol==='h2');
+
+}
+
+
+
+const firstRecord=originRecords.reduce((a,b)=>a.startTime>b.startTime?b:a);
+connectionWasReused.set(firstRecord.requestId,false);
+}
+
+return connectionWasReused;
+}
+
+
+
+
+
+
+
+
+
+
+static estimateRTTByOrigin(records,options){
+options=Object.assign(
+{
+
+
+forceCoarseEstimates:false,
+
+
+coarseEstimateMultiplier:0.5},
+
+options);
+
+
+let estimatesByOrigin=NetworkAnalyzer._estimateRTTByOriginViaTCPTiming(records);
+if(!estimatesByOrigin.size||options.forceCoarseEstimates){
+estimatesByOrigin=new Map();
+const estimatesViaDownload=NetworkAnalyzer._estimateRTTByOriginViaDownloadTiming(records);
+const estimatesViaSendStart=NetworkAnalyzer._estimateRTTByOriginViaSendStartTiming(records);
+
+for(const[origin,estimates]of estimatesViaDownload.entries()){
+estimatesByOrigin.set(origin,estimates);
+}
+
+for(const[origin,estimates]of estimatesViaSendStart.entries()){
+const existing=estimatesByOrigin.get(origin)||[];
+estimatesByOrigin.set(origin,existing.concat(estimates));
+}
+
+for(const estimates of estimatesByOrigin.values()){
+estimates.forEach((x,i)=>estimates[i]=x*options.coarseEstimateMultiplier);
+}
+}
+
+if(!estimatesByOrigin.size)throw new Error('No timing information available');
+return NetworkAnalyzer.summarize(estimatesByOrigin);
+}
+
+
+
+
+
+
+
+
+
+static estimateServerResponseTimeByOrigin(records,options){
+options=Object.assign(
+{
+rttByOrigin:null},
+
+options);
+
+
+let rttByOrigin=options.rttByOrigin;
+if(!rttByOrigin){
+rttByOrigin=NetworkAnalyzer.estimateRTTByOrigin(records,options);
+for(const[origin,summary]of rttByOrigin.entries()){
+rttByOrigin.set(origin,summary.min);
+}
+}
+
+const estimatesByOrigin=NetworkAnalyzer._estimateResponseTimeByOrigin(records,rttByOrigin);
+return NetworkAnalyzer.summarize(estimatesByOrigin);
+}
+
+
+
+
+
+static findMainDocument(records){
+
+const documentRequests=records.filter(record=>record._resourceType===
+WebInspector.resourceTypes.Document);
+return documentRequests.sort((a,b)=>a.startTime-b.startTime)[0];
+}}
+
+
+module.exports=NetworkAnalyzer;
+
+
+
+
+
+
+
+
+
+},{"../../web-inspector":47}],28:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Node=require('../node');
+const NetworkNode=require('../network-node');
+const CpuNode=require('../cpu-node');
+const TcpConnection=require('./tcp-connection');
+const ConnectionPool=require('./connection-pool');
+const mobile3G=require('../../../config/constants').throttling.mobile3G;
+
+
+const DEFAULT_MAXIMUM_CONCURRENT_REQUESTS=10;
+
+const DEFAULT_LAYOUT_TASK_MULTIPLIER=0.5;
+
+const DEFAULT_MAXIMUM_CPU_TASK_DURATION=10000;
+
+const NodeState={
+NotReadyToStart:0,
+ReadyToStart:1,
+InProgress:2,
+Complete:3};
+
+
+class Simulator{
+
+
+
+constructor(options){
+
+this._options=Object.assign(
+{
+rtt:mobile3G.rttMs,
+throughput:mobile3G.throughputKbps*1024,
+maximumConcurrentRequests:DEFAULT_MAXIMUM_CONCURRENT_REQUESTS,
+cpuSlowdownMultiplier:mobile3G.cpuSlowdownMultiplier,
+layoutTaskMultiplier:DEFAULT_LAYOUT_TASK_MULTIPLIER,
+additionalRttByOrigin:new Map(),
+serverResponseTimeByOrigin:new Map()},
+
+options);
+
+
+this._rtt=this._options.rtt;
+this._throughput=this._options.throughput;
+this._maximumConcurrentRequests=Math.max(Math.min(
+TcpConnection.maximumSaturatedConnections(this._rtt,this._throughput),
+this._options.maximumConcurrentRequests),
+1);
+this._cpuSlowdownMultiplier=this._options.cpuSlowdownMultiplier;
+this._layoutTaskMultiplier=this._cpuSlowdownMultiplier*this._options.layoutTaskMultiplier;
+
+
+this._flexibleOrdering=false;
+this._nodeTimings=new Map();
+this._numberInProgressByType=new Map();
+this._nodes={};
+
+this._connectionPool=null;
+}
+
+
+
+
+_initializeConnectionPool(graph){
+
+const records=[];
+graph.getRootNode().traverse(node=>{
+if(node.type===Node.TYPES.NETWORK){
+records.push(node.record);
+}
+});
+
+this._connectionPool=new ConnectionPool(records,this._options);
+}
+
+
+
+
+_initializeAuxiliaryData(){
+this._nodeTimings=new Map();
+this._numberInProgressByType=new Map();
+
+this._nodes={};
+for(const key of Object.keys(NodeState)){
+this._nodes[NodeState[key]]=new Set();
+}
+}
+
+
+
+
+
+_numberInProgress(type){
+return this._numberInProgressByType.get(type)||0;
+}
+
+
+
+
+
+_setTimingData(node,values){
+const timingData=this._nodeTimings.get(node)||{};
+Object.assign(timingData,values);
+this._nodeTimings.set(node,timingData);
+}
+
+
+
+
+
+_markNodeAsReadyToStart(node,queuedTime){
+this._nodes[NodeState.ReadyToStart].add(node);
+this._nodes[NodeState.NotReadyToStart].delete(node);
+this._setTimingData(node,{queuedTime});
+}
+
+
+
+
+
+_markNodeAsInProgress(node,startTime){
+this._nodes[NodeState.InProgress].add(node);
+this._nodes[NodeState.ReadyToStart].delete(node);
+this._numberInProgressByType.set(node.type,this._numberInProgress(node.type)+1);
+this._setTimingData(node,{startTime});
+}
+
+
+
+
+
+_markNodeAsComplete(node,endTime){
+this._nodes[NodeState.Complete].add(node);
+this._nodes[NodeState.InProgress].delete(node);
+this._numberInProgressByType.set(node.type,this._numberInProgress(node.type)-1);
+this._setTimingData(node,{endTime});
+
+
+for(const dependent of node.getDependents()){
+
+const dependencies=dependent.getDependencies();
+if(dependencies.some(dep=>!this._nodes[NodeState.Complete].has(dep)))continue;
+
+
+this._markNodeAsReadyToStart(dependent,endTime);
+}
+}
+
+
+
+
+
+_acquireConnection(record){
+return this._connectionPool.acquire(record,{
+ignoreConnectionReused:this._flexibleOrdering});
+
+}
+
+
+
+
+
+_startNodeIfPossible(node,totalElapsedTime){
+if(node.type===Node.TYPES.CPU){
+
+if(this._numberInProgress(node.type)===0){
+this._markNodeAsInProgress(node,totalElapsedTime);
+this._setTimingData(node,{timeElapsed:0});
+}
+
+return;
+}
+
+if(node.type!==Node.TYPES.NETWORK)throw new Error('Unsupported');
+
+const networkNode=node;
+
+if(!networkNode.fromDiskCache){
+
+const numberOfActiveRequests=this._numberInProgress(node.type);
+if(numberOfActiveRequests>=this._maximumConcurrentRequests)return;
+const connection=this._acquireConnection(networkNode.record);
+if(!connection)return;
+}
+
+this._markNodeAsInProgress(node,totalElapsedTime);
+this._setTimingData(node,{
+timeElapsed:0,
+timeElapsedOvershoot:0,
+bytesDownloaded:0});
+
+}
+
+
+
+
+
+_updateNetworkCapacity(){
+for(const connection of this._connectionPool.connectionsInUse()){
+connection.setThroughput(this._throughput/this._nodes[NodeState.InProgress].size);
+}
+}
+
+
+
+
+
+
+_estimateTimeRemaining(node){
+if(node.type===Node.TYPES.CPU){
+return this._estimateCPUTimeRemaining(node);
+}else if(node.type===Node.TYPES.NETWORK){
+return this._estimateNetworkTimeRemaining(node);
+}else{
+throw new Error('Unsupported');
+}
+}
+
+
+
+
+
+_estimateCPUTimeRemaining(cpuNode){
+const timingData=this._nodeTimings.get(cpuNode);
+const multiplier=cpuNode.didPerformLayout()?
+this._layoutTaskMultiplier:
+this._cpuSlowdownMultiplier;
+const totalDuration=Math.min(
+Math.round(cpuNode.event.dur/1000*multiplier),
+DEFAULT_MAXIMUM_CPU_TASK_DURATION);
+
+const estimatedTimeElapsed=totalDuration-timingData.timeElapsed;
+this._setTimingData(cpuNode,{estimatedTimeElapsed});
+return estimatedTimeElapsed;
+}
+
+
+
+
+
+_estimateNetworkTimeRemaining(networkNode){
+const timingData=this._nodeTimings.get(networkNode);
+
+let timeElapsed=0;
+if(networkNode.fromDiskCache){
+
+
+const sizeInMb=(networkNode.record._resourceSize||0)/1024/1024;
+timeElapsed=8+20*sizeInMb-timingData.timeElapsed;
+}else{
+
+const connection=this._acquireConnection(networkNode.record);
+const calculation=connection.simulateDownloadUntil(
+networkNode.record.transferSize-timingData.bytesDownloaded,
+{timeAlreadyElapsed:timingData.timeElapsed,maximumTimeToElapse:Infinity});
+
+
+timeElapsed=calculation.timeElapsed;
+}
+
+const estimatedTimeElapsed=timeElapsed+timingData.timeElapsedOvershoot;
+this._setTimingData(networkNode,{estimatedTimeElapsed});
+return estimatedTimeElapsed;
+}
+
+
+
+
+
+_findNextNodeCompletionTime(){
+let minimumTime=Infinity;
+for(const node of this._nodes[NodeState.InProgress]){
+minimumTime=Math.min(minimumTime,this._estimateTimeRemaining(node));
+}
+
+return minimumTime;
+}
+
+
+
+
+
+
+
+_updateProgressMadeInTimePeriod(node,timePeriodLength,totalElapsedTime){
+const timingData=this._nodeTimings.get(node);
+const isFinished=timingData.estimatedTimeElapsed===timePeriodLength;
+
+const networkNode=node;
+
+if(node.type===Node.TYPES.CPU||networkNode.fromDiskCache){
+return isFinished?
+this._markNodeAsComplete(node,totalElapsedTime):
+timingData.timeElapsed+=timePeriodLength;
+}
+
+if(node.type!==Node.TYPES.NETWORK)throw new Error('Unsupported');
+
+const record=networkNode.record;
+
+const connection=this._acquireConnection(record);
+const calculation=connection.simulateDownloadUntil(
+record.transferSize-timingData.bytesDownloaded,
+{
+timeAlreadyElapsed:timingData.timeElapsed,
+maximumTimeToElapse:timePeriodLength-timingData.timeElapsedOvershoot});
+
+
+
+connection.setCongestionWindow(calculation.congestionWindow);
+connection.setH2OverflowBytesDownloaded(calculation.extraBytesDownloaded);
+
+if(isFinished){
+connection.setWarmed(true);
+this._connectionPool.release(record);
+this._markNodeAsComplete(node,totalElapsedTime);
+}else{
+timingData.timeElapsed+=calculation.timeElapsed;
+timingData.timeElapsedOvershoot+=calculation.timeElapsed-timePeriodLength;
+timingData.bytesDownloaded+=calculation.bytesDownloaded;
+}
+}
+
+
+
+
+getOptions(){
+return this._options;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+simulate(graph,options){
+if(Node.hasCycle(graph)){
+throw new Error('Cannot simulate graph with cycle');
+}
+
+options=Object.assign({flexibleOrdering:false},options);
+
+this._flexibleOrdering=!!options.flexibleOrdering;
+this._initializeConnectionPool(graph);
+this._initializeAuxiliaryData();
+
+const nodesNotReadyToStart=this._nodes[NodeState.NotReadyToStart];
+const nodesReadyToStart=this._nodes[NodeState.ReadyToStart];
+const nodesInProgress=this._nodes[NodeState.InProgress];
+
+const rootNode=graph.getRootNode();
+rootNode.traverse(node=>nodesNotReadyToStart.add(node));
+let totalElapsedTime=0;
+let iteration=0;
+
+
+this._markNodeAsReadyToStart(rootNode,totalElapsedTime);
+
+
+while(nodesReadyToStart.size||nodesInProgress.size){
+
+for(const node of nodesReadyToStart){
+this._startNodeIfPossible(node,totalElapsedTime);
+}
+
+if(!nodesInProgress.size){
+
+
+if(this._flexibleOrdering)throw new Error('Failed to start a node');
+this._flexibleOrdering=true;
+continue;
+}
+
+
+this._updateNetworkCapacity();
+
+
+const minimumTime=this._findNextNodeCompletionTime();
+totalElapsedTime+=minimumTime;
+
+
+if(!Number.isFinite(minimumTime)||iteration>100000){
+throw new Error('Graph creation failed, depth exceeded');
+}
+
+iteration++;
+
+for(const node of nodesInProgress){
+this._updateProgressMadeInTimePeriod(node,minimumTime,totalElapsedTime);
+}
+}
+
+return{
+timeInMs:totalElapsedTime,
+nodeTimings:this._nodeTimings};
+
+}}
+
+
+module.exports=Simulator;
+
+},{"../../../config/constants":8,"../cpu-node":23,"../network-node":24,"../node":25,"./connection-pool":26,"./tcp-connection":29}],29:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const INITIAL_CONGESTION_WINDOW=10;
+const TCP_SEGMENT_SIZE=1460;
+
+class TcpConnection{
+
+
+
+
+
+
+
+constructor(rtt,throughput,serverLatency=0,ssl=true,h2=false){
+this._warmed=false;
+this._ssl=ssl;
+this._h2=h2;
+this._rtt=rtt;
+this._throughput=throughput;
+this._serverLatency=serverLatency;
+this._congestionWindow=INITIAL_CONGESTION_WINDOW;
+this._h2OverflowBytesDownloaded=0;
+}
+
+
+
+
+
+
+static maximumSaturatedConnections(rtt,availableThroughput){
+const roundTripsPerSecond=1000/rtt;
+const bytesPerRoundTrip=TCP_SEGMENT_SIZE;
+const bytesPerSecond=roundTripsPerSecond*bytesPerRoundTrip;
+const minimumThroughputRequiredPerRequest=bytesPerSecond*8;
+return Math.floor(availableThroughput/minimumThroughputRequiredPerRequest);
+}
+
+
+
+
+_computeMaximumCongestionWindowInSegments(){
+const bytesPerSecond=this._throughput/8;
+const secondsPerRoundTrip=this._rtt/1000;
+const bytesPerRoundTrip=bytesPerSecond*secondsPerRoundTrip;
+return Math.floor(bytesPerRoundTrip/TCP_SEGMENT_SIZE);
+}
+
+
+
+
+setThroughput(throughput){
+this._throughput=throughput;
+}
+
+
+
+
+setCongestionWindow(congestion){
+this._congestionWindow=congestion;
+}
+
+
+
+
+setWarmed(warmed){
+this._warmed=warmed;
+}
+
+
+
+
+isWarm(){
+return this._warmed;
+}
+
+
+
+
+isH2(){
+return this._h2;
+}
+
+
+
+
+get congestionWindow(){
+return this._congestionWindow;
+}
+
+
+
+
+
+
+setH2OverflowBytesDownloaded(bytes){
+if(!this._h2)return;
+this._h2OverflowBytesDownloaded=bytes;
+}
+
+
+
+
+clone(){
+return Object.assign(new TcpConnection(this._rtt,this._throughput),this);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+simulateDownloadUntil(bytesToDownload,options){
+const{timeAlreadyElapsed=0,maximumTimeToElapse=Infinity}=options||{};
+
+if(this._warmed&&this._h2){
+bytesToDownload-=this._h2OverflowBytesDownloaded;
+}
+const twoWayLatency=this._rtt;
+const oneWayLatency=twoWayLatency/2;
+const maximumCongestionWindow=this._computeMaximumCongestionWindowInSegments();
+
+let handshakeAndRequest=oneWayLatency;
+if(!this._warmed){
+handshakeAndRequest=
+
+oneWayLatency+
+
+oneWayLatency+
+
+oneWayLatency+(
+
+this._ssl?twoWayLatency:0);
+}
+
+let roundTrips=Math.ceil(handshakeAndRequest/twoWayLatency);
+let timeToFirstByte=handshakeAndRequest+this._serverLatency+oneWayLatency;
+if(this._warmed&&this._h2)timeToFirstByte=0;
+
+const timeElapsedForTTFB=Math.max(timeToFirstByte-timeAlreadyElapsed,0);
+const maximumDownloadTimeToElapse=maximumTimeToElapse-timeElapsedForTTFB;
+
+let congestionWindow=Math.min(this._congestionWindow,maximumCongestionWindow);
+let totalBytesDownloaded=0;
+if(timeElapsedForTTFB>0){
+totalBytesDownloaded=congestionWindow*TCP_SEGMENT_SIZE;
+}else{
+roundTrips=0;
+}
+
+let downloadTimeElapsed=0;
+let bytesRemaining=bytesToDownload-totalBytesDownloaded;
+while(bytesRemaining>0&&downloadTimeElapsed<=maximumDownloadTimeToElapse){
+roundTrips++;
+downloadTimeElapsed+=twoWayLatency;
+congestionWindow=Math.max(Math.min(maximumCongestionWindow,congestionWindow*2),1);
+
+const bytesDownloadedInWindow=congestionWindow*TCP_SEGMENT_SIZE;
+totalBytesDownloaded+=bytesDownloadedInWindow;
+bytesRemaining-=bytesDownloadedInWindow;
+}
+
+const timeElapsed=timeElapsedForTTFB+downloadTimeElapsed;
+const extraBytesDownloaded=this._h2?Math.max(totalBytesDownloaded-bytesToDownload,0):0;
+const bytesDownloaded=Math.max(Math.min(totalBytesDownloaded,bytesToDownload),0);
+
+return{
+roundTrips,
+timeElapsed,
+bytesDownloaded,
+extraBytesDownloaded,
+congestionWindow};
+
+}}
+
+
+module.exports=TcpConnection;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+},{}],30:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function getElementsInDocument(selector){
+
+const results=[];
+
+
+const _findAllElements=nodes=>{
+for(let i=0,el;el=nodes[i];++i){
+if(!selector||el.matches(selector)){
+results.push(el);
+}
+
+if(el.shadowRoot){
+_findAllElements(el.shadowRoot.querySelectorAll('*'));
+}
+}
+};
+_findAllElements(document.querySelectorAll('*'));
+
+return results;
+}
+
+module.exports={
+getElementsInDocumentFnString:getElementsInDocument.toString()};
+
+
+},{}],31:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Driver=require('../gather/driver.js');
+
+class Element{
+
+
+
+
+constructor(element,driver){
+if(!element||!driver){
+throw Error('Driver and element required to create Element');
+}
+this.driver=driver;
+this.element=element;
+}
+
+
+
+
+
+getAttribute(name){
+return this.driver.
+sendCommand('DOM.getAttributes',{
+nodeId:this.element.nodeId}).
+
+
+
+
+then(resp=>{
+const attrIndex=resp.attributes.indexOf(name);
+if(attrIndex===-1){
+return null;
+}
+
+return resp.attributes[attrIndex+1];
+});
+}
+
+
+
+
+getNodeId(){
+return this.element.nodeId;
+}
+
+
+
+
+
+getProperty(propName){
+return this.driver.
+sendCommand('DOM.resolveNode',{
+nodeId:this.element.nodeId}).
+
+then(resp=>{
+if(!resp.object.objectId){
+return null;
+}
+return this.driver.getObjectProperty(resp.object.objectId,propName);
+});
+}}
+
+
+module.exports=Element;
+
+},{"../gather/driver.js":17}],32:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const Driver=require('../gather/driver');
+const mobile3G=require('../config/constants').throttling.mobile3G;
+
+
+
+
+
+const NEXUS5X_EMULATION_METRICS={
+mobile:true,
+screenWidth:412,
+screenHeight:732,
+width:412,
+height:732,
+positionX:0,
+positionY:0,
+scale:1,
+deviceScaleFactor:2.625,
+screenOrientation:{
+angle:0,
+type:'portraitPrimary'}};
+
+
+
+const NEXUS5X_USERAGENT={
+userAgent:'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36'+
+'(KHTML, like Gecko) Chrome/66.0.3359.30 Mobile Safari/537.36'};
+
+
+const OFFLINE_METRICS={
+offline:true,
+
+latency:0,
+downloadThroughput:0,
+uploadThroughput:0};
+
+
+const NO_THROTTLING_METRICS={
+latency:0,
+downloadThroughput:0,
+uploadThroughput:0,
+offline:false};
+
+
+const NO_CPU_THROTTLE_METRICS={
+rate:1};
+
+const CPU_THROTTLE_METRICS={
+rate:4};
+
+
+
+
+
+function enableNexus5X(driver){
+return Promise.all([
+driver.sendCommand('Emulation.setDeviceMetricsOverride',NEXUS5X_EMULATION_METRICS),
+
+driver.sendCommand('Network.enable'),
+driver.sendCommand('Network.setUserAgentOverride',NEXUS5X_USERAGENT),
+driver.sendCommand('Emulation.setEmitTouchEventsForMouse',{
+enabled:true,
+configuration:'mobile'})]);
+
+
+}
+
+
+
+
+
+
+function enableNetworkThrottling(driver,throttlingSettings=mobile3G){
+
+const conditions={
+offline:false,
+latency:throttlingSettings.requestLatencyMs||0,
+downloadThroughput:throttlingSettings.downloadThroughputKbps||0,
+uploadThroughput:throttlingSettings.uploadThroughputKbps||0};
+
+
+
+conditions.downloadThroughput=Math.floor(conditions.downloadThroughput*1024/8);
+conditions.uploadThroughput=Math.floor(conditions.uploadThroughput*1024/8);
+return driver.sendCommand('Network.emulateNetworkConditions',conditions);
+}
+
+
+
+
+
+function clearAllNetworkEmulation(driver){
+return driver.sendCommand('Network.emulateNetworkConditions',NO_THROTTLING_METRICS);
+}
+
+
+
+
+
+function goOffline(driver){
+return driver.sendCommand('Network.emulateNetworkConditions',OFFLINE_METRICS);
+}
+
+
+
+
+
+
+function enableCPUThrottling(driver,throttlingSettings){
+
+const rate=throttlingSettings&&throttlingSettings.cpuSlowdownMultiplier!==undefined?
+throttlingSettings.cpuSlowdownMultiplier:
+CPU_THROTTLE_METRICS.rate;
+return driver.sendCommand('Emulation.setCPUThrottlingRate',{rate});
+}
+
+
+
+
+
+function disableCPUThrottling(driver){
+return driver.sendCommand('Emulation.setCPUThrottlingRate',NO_CPU_THROTTLE_METRICS);
+}
+
+module.exports={
+enableNexus5X,
+enableNetworkThrottling,
+clearAllNetworkEmulation,
+enableCPUThrottling,
+disableCPUThrottling,
+goOffline};
+
+
+},{"../config/constants":8,"../gather/driver":17}],33:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const strings=require('./strings');
+
+
+
+
+
+
+
+
+class LighthouseError extends Error{
+
+
+
+
+constructor(errorDefinition,properties){
+super(errorDefinition.code);
+this.name='LHError';
+this.code=errorDefinition.code;
+this.friendlyMessage=errorDefinition.message;
+if(properties)Object.assign(this,properties);
+
+Error.captureStackTrace(this,LighthouseError);
+}
+
+
+
+
+static isPageLoadError(err){
+return err.code===ERRORS.NO_DOCUMENT_REQUEST.code||
+err.code===ERRORS.FAILED_DOCUMENT_REQUEST.code;
+}
+
+
+
+
+
+
+static fromProtocolMessage(method,protocolError){
+
+const protocolErrors=Object.keys(ERRORS).filter(k=>ERRORS[k].pattern).map(k=>ERRORS[k]);
+
+const matchedErrorDefinition=protocolErrors.find(e=>e.pattern.test(protocolError.message));
+if(matchedErrorDefinition){
+return new LighthouseError(matchedErrorDefinition,{
+protocolMethod:method,
+protocolError:protocolError.message});
+
+}
+
+
+let errMsg=`(${method}): ${protocolError.message}`;
+if(protocolError.data)errMsg+=` (${protocolError.data})`;
+const error=new Error(`Protocol error ${errMsg}`);
+return Object.assign(error,{protocolMethod:method,protocolError:protocolError.message});
+}}
+
+
+const ERRORS={
+
+NO_SPEEDLINE_FRAMES:{message:strings.didntCollectScreenshots},
+SPEEDINDEX_OF_ZERO:{message:strings.didntCollectScreenshots},
+NO_SCREENSHOTS:{message:strings.didntCollectScreenshots},
+INVALID_SPEEDLINE:{message:strings.didntCollectScreenshots},
+
+
+NO_TRACING_STARTED:{message:strings.badTraceRecording},
+NO_NAVSTART:{message:strings.badTraceRecording},
+NO_FCP:{message:strings.badTraceRecording},
+NO_FMP:{message:strings.badTraceRecording},
+NO_DCL:{message:strings.badTraceRecording},
+
+
+FMP_TOO_LATE_FOR_FCPUI:{message:strings.pageLoadTookTooLong},
+NO_FCPUI_IDLE_PERIOD:{message:strings.pageLoadTookTooLong},
+NO_TTI_CPU_IDLE_PERIOD:{message:strings.pageLoadTookTooLong},
+NO_TTI_NETWORK_IDLE_PERIOD:{message:strings.pageLoadTookTooLong},
+
+
+NO_DOCUMENT_REQUEST:{message:strings.pageLoadFailed},
+FAILED_DOCUMENT_REQUEST:{message:strings.pageLoadFailed},
+
+
+TRACING_ALREADY_STARTED:{message:strings.internalChromeError,pattern:/Tracing.*started/},
+PARSING_PROBLEM:{message:strings.internalChromeError,pattern:/Parsing problem/},
+READ_FAILED:{message:strings.internalChromeError,pattern:/Read failed/},
+
+
+REQUEST_CONTENT_TIMEOUT:{message:strings.requestContentTimeout}};
+
+
+Object.keys(ERRORS).forEach(code=>ERRORS[code].code=code);
+
+
+LighthouseError.errors=ERRORS;
+module.exports=LighthouseError;
+
+
+},{"./strings":41}],34:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function addFormattedCodeSnippet(listener){
+const handler=listener.handler?listener.handler.description:'...';
+const objectName=listener.objectName.toLowerCase().replace('#document','document');
+return Object.assign({
+pre:`${objectName}.addEventListener('${listener.type}', ${handler})`},
+listener);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function groupCodeSnippetsByLocation(listeners){
+
+const locToListenerMap=new Map();
+
+
+listeners.forEach(loc=>{
+const accPre=loc.pre.trim()+'\n\n';
+const simplifiedLoc={line:loc.line,col:loc.col,url:loc.url,type:loc.type,pre:''};
+
+const key=JSON.stringify(simplifiedLoc);
+const accListener=locToListenerMap.get(key)||simplifiedLoc;
+accListener.pre+=accPre;
+locToListenerMap.set(key,accListener);
+});
+
+return[...locToListenerMap.values()];
+}
+
+module.exports={
+addFormattedCodeSnippet,
+groupCodeSnippetsByLocation};
+
+
+},{}],35:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+function doExist(manifest){
+if(!manifest||!manifest.icons){
+return false;
+}
+if(manifest.icons.value.length===0){
+return false;
+}
+return true;
+}
+
+
+
+
+
+
+function sizeAtLeast(sizeRequirement,manifest){
+
+
+const iconValues=manifest.icons.value;
+
+const flattenedSizes=[];
+iconValues.forEach(icon=>{
+if(icon.value.sizes.value){
+flattenedSizes.push(...icon.value.sizes.value);
+}
+});
+
+return flattenedSizes.
+
+filter(size=>/\d+x\d+/.test(size)).
+filter(size=>{
+
+const sizeStrs=size.split(/x/i);
+
+const sizeNums=[parseFloat(sizeStrs[0]),parseFloat(sizeStrs[1])];
+
+const areIconsBigEnough=sizeNums[0]>=sizeRequirement&&sizeNums[1]>=sizeRequirement;
+
+const areIconsSquare=sizeNums[0]===sizeNums[1];
+return areIconsBigEnough&&areIconsSquare;
+});
+}
+
+module.exports={
+doExist,
+sizeAtLeast};
+
+
+},{}],36:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const URL=require('./url-shim');
+const validateColor=require('./web-inspector').Color.parse;
+
+const ALLOWED_DISPLAY_VALUES=[
+'fullscreen',
+'standalone',
+'minimal-ui',
+'browser'];
+
+
+
+
+
+const DEFAULT_DISPLAY_MODE='browser';
+
+const ALLOWED_ORIENTATION_VALUES=[
+'any',
+'natural',
+'landscape',
+'portrait',
+'portrait-primary',
+'portrait-secondary',
+'landscape-primary',
+'landscape-secondary'];
+
+
+
+
+
+
+function parseString(raw,trim){
+let value;
+let debugString;
+
+if(typeof raw==='string'){
+value=trim?raw.trim():raw;
+}else{
+if(raw!==undefined){
+debugString='ERROR: expected a string.';
+}
+value=undefined;
+}
+
+return{
+raw,
+value,
+debugString};
+
+}
+
+
+
+
+function parseColor(raw){
+const color=parseString(raw);
+
+
+if(color.value===undefined){
+return color;
+}
+
+
+const validatedColor=validateColor(color.raw);
+if(!validatedColor){
+color.value=undefined;
+color.debugString='ERROR: color parsing failed.';
+}
+
+return color;
+}
+
+
+
+
+function parseName(jsonInput){
+return parseString(jsonInput.name,true);
+}
+
+
+
+
+function parseShortName(jsonInput){
+return parseString(jsonInput.short_name,true);
+}
+
+
+
+
+
+
+
+function checkSameOrigin(url1,url2){
+const parsed1=new URL(url1);
+const parsed2=new URL(url2);
+
+return parsed1.origin===parsed2.origin;
+}
+
+
+
+
+
+
+
+function parseStartUrl(jsonInput,manifestUrl,documentUrl){
+const raw=jsonInput.start_url;
+
+
+if(raw===''){
+return{
+raw,
+value:documentUrl,
+debugString:'ERROR: start_url string empty'};
+
+}
+const parsedAsString=parseString(raw);
+if(!parsedAsString.value){
+parsedAsString.value=documentUrl;
+return parsedAsString;
+}
+
+
+let startUrl;
+try{
+startUrl=new URL(raw,manifestUrl).href;
+}catch(e){
+
+return{
+raw,
+value:documentUrl,
+debugString:'ERROR: invalid start_url relative to ${manifestUrl}'};
+
+}
+
+
+if(!checkSameOrigin(startUrl,documentUrl)){
+return{
+raw,
+value:documentUrl,
+debugString:'ERROR: start_url must be same-origin as document'};
+
+}
+
+return{
+raw,
+value:startUrl};
+
+}
+
+
+
+
+function parseDisplay(jsonInput){
+const parsedString=parseString(jsonInput.display,true);
+const stringValue=parsedString.value;
+
+if(!stringValue){
+return{
+raw:jsonInput,
+value:DEFAULT_DISPLAY_MODE,
+debugString:parsedString.debugString};
+
+}
+
+const displayValue=stringValue.toLowerCase();
+if(!ALLOWED_DISPLAY_VALUES.includes(displayValue)){
+return{
+raw:jsonInput,
+value:DEFAULT_DISPLAY_MODE,
+debugString:'ERROR: \'display\' has invalid value '+displayValue+
+`. will fall back to ${DEFAULT_DISPLAY_MODE}.`};
+
+}
+
+return{
+raw:jsonInput,
+value:displayValue,
+debugString:undefined};
+
+}
+
+
+
+
+function parseOrientation(jsonInput){
+const orientation=parseString(jsonInput.orientation,true);
+
+if(orientation.value&&
+!ALLOWED_ORIENTATION_VALUES.includes(orientation.value.toLowerCase())){
+orientation.value=undefined;
+orientation.debugString='ERROR: \'orientation\' has an invalid value, will be ignored.';
+}
+
+return orientation;
+}
+
+
+
+
+
+function parseIcon(raw,manifestUrl){
+
+const src=parseString(raw.src,true);
+
+if(src.value===''){
+src.value=undefined;
+}
+if(src.value){
+
+src.value=new URL(src.value,manifestUrl).href;
+}
+
+const type=parseString(raw.type,true);
+
+const density={
+raw:raw.density,
+value:1,
+
+debugString:undefined};
+
+if(density.raw!==undefined){
+density.value=parseFloat(density.raw);
+if(isNaN(density.value)||!isFinite(density.value)||density.value<=0){
+density.value=1;
+density.debugString='ERROR: icon density cannot be NaN, +∞, or less than or equal to +0.';
+}
+}
+
+let sizes;
+const parsedSizes=parseString(raw.sizes);
+if(parsedSizes.value!==undefined){
+
+const set=new Set();
+parsedSizes.value.trim().split(/\s+/).forEach(size=>set.add(size.toLowerCase()));
+sizes={
+raw:raw.sizes,
+value:set.size>0?Array.from(set):undefined,
+debugString:undefined};
+
+}else{
+sizes={...parsedSizes,value:undefined};
+}
+
+return{
+raw,
+value:{
+src,
+type,
+density,
+sizes},
+
+debugString:undefined};
+
+}
+
+
+
+
+
+function parseIcons(jsonInput,manifestUrl){
+const raw=jsonInput.icons;
+
+if(raw===undefined){
+return{
+raw,
+
+value:[],
+debugString:undefined};
+
+}
+
+if(!Array.isArray(raw)){
+return{
+raw,
+
+value:[],
+debugString:'ERROR: \'icons\' expected to be an array but is not.'};
+
+}
+
+
+
+const value=raw.
+
+filter(icon=>icon.src!==undefined).
+
+map(icon=>parseIcon(icon,manifestUrl)).
+
+filter(parsedIcon=>parsedIcon.value.src.value!==undefined);
+
+return{
+raw,
+value,
+debugString:undefined};
+
+}
+
+
+
+
+function parseApplication(raw){
+const platform=parseString(raw.platform,true);
+const id=parseString(raw.id,true);
+
+
+const appUrl=parseString(raw.url,true);
+if(appUrl.value){
+try{
+
+appUrl.value=new URL(appUrl.value).href;
+}catch(e){
+appUrl.value=undefined;
+appUrl.debugString='ERROR: invalid application URL ${raw.url}';
+}
+}
+
+return{
+raw,
+value:{
+platform,
+id,
+url:appUrl},
+
+debugString:undefined};
+
+}
+
+
+
+
+function parseRelatedApplications(jsonInput){
+const raw=jsonInput.related_applications;
+
+if(raw===undefined){
+return{
+raw,
+value:undefined,
+debugString:undefined};
+
+}
+
+if(!Array.isArray(raw)){
+return{
+raw,
+value:undefined,
+debugString:'ERROR: \'related_applications\' expected to be an array but is not.'};
+
+}
+
+
+
+const value=raw.
+filter(application=>!!application.platform).
+map(parseApplication).
+filter(parsedApp=>!!parsedApp.value.id.value||!!parsedApp.value.url.value);
+
+return{
+raw,
+value,
+debugString:undefined};
+
+}
+
+
+
+
+function parsePreferRelatedApplications(jsonInput){
+const raw=jsonInput.prefer_related_applications;
+let value;
+let debugString;
+
+if(typeof raw==='boolean'){
+value=raw;
+}else{
+if(raw!==undefined){
+debugString='ERROR: \'prefer_related_applications\' expected to be a boolean.';
+}
+value=undefined;
+}
+
+return{
+raw,
+value,
+debugString};
+
+}
+
+
+
+
+function parseThemeColor(jsonInput){
+return parseColor(jsonInput.theme_color);
+}
+
+
+
+
+function parseBackgroundColor(jsonInput){
+return parseColor(jsonInput.background_color);
+}
+
+
+
+
+
+
+
+function parse(string,manifestUrl,documentUrl){
+if(manifestUrl===undefined||documentUrl===undefined){
+throw new Error('Manifest and document URLs required for manifest parsing.');
+}
+
+let jsonInput;
+
+try{
+jsonInput=JSON.parse(string);
+}catch(e){
+return{
+raw:string,
+value:undefined,
+debugString:'ERROR: file isn\'t valid JSON: '+e};
+
+}
+
+
+const manifest={
+name:parseName(jsonInput),
+short_name:parseShortName(jsonInput),
+start_url:parseStartUrl(jsonInput,manifestUrl,documentUrl),
+display:parseDisplay(jsonInput),
+orientation:parseOrientation(jsonInput),
+icons:parseIcons(jsonInput,manifestUrl),
+related_applications:parseRelatedApplications(jsonInput),
+prefer_related_applications:parsePreferRelatedApplications(jsonInput),
+theme_color:parseThemeColor(jsonInput),
+background_color:parseBackgroundColor(jsonInput)};
+
+
+
+return{
+raw:string,
+value:manifest,
+debugString:undefined};
+
+}
+
+module.exports=parse;
+
+},{"./url-shim":"url","./web-inspector":47}],37:[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+const NetworkManager=require('./web-inspector').NetworkManager;
+const EventEmitter=require('events').EventEmitter;
+const log=require('lighthouse-logger');
+
+const IGNORED_NETWORK_SCHEMES=['data','ws'];
+
+
+
+class NetworkRecorder extends EventEmitter{
+
+
+
+
+constructor(recordArray){
+super();
+
+this._records=recordArray;
+this.networkManager=NetworkManager.createWithFakeTarget();
+
+this.networkManager.addEventListener(
+this.EventTypes.RequestStarted,
+this.onRequestStarted.bind(this));
+
+this.networkManager.addEventListener(
+this.EventTypes.RequestFinished,
+this.onRequestFinished.bind(this));
+
+}
+
+
+
+
+
+on(event,listener){
+return super.on(event,listener);
+}
+
+
+
+
+
+once(event,listener){
+return super.once(event,listener);
+}
+
+get EventTypes(){
+return NetworkManager.Events;
+}
+
+isIdle(){
+return!!this._getActiveIdlePeriod(0);
+}
+
+is2Idle(){
+return!!this._getActiveIdlePeriod(2);
+}
+
+
+
+
+_getActiveIdlePeriod(allowedRequests){
+const quietPeriods=NetworkRecorder.findNetworkQuietPeriods(this._records,allowedRequests);
+return quietPeriods.find(period=>!Number.isFinite(period.end));
+}
+
+_emitNetworkStatus(){
+const zeroQuiet=this._getActiveIdlePeriod(0);
+const twoQuiet=this._getActiveIdlePeriod(2);
+
+if(twoQuiet&&zeroQuiet){
+log.verbose('NetworkRecorder','network fully-quiet');
+this.emit('network-2-idle');
+this.emit('networkidle');
+}else if(twoQuiet&&!zeroQuiet){
+log.verbose('NetworkRecorder','network semi-quiet');
+this.emit('network-2-idle');
+this.emit('networkbusy');
+}else{
+log.verbose('NetworkRecorder','network busy');
+this.emit('network-2-busy');
+this.emit('networkbusy');
+}
+}
+
+
+
+
+
+
+
+static _isQUICAndFinished(record){
+const isQUIC=record._responseHeaders&&record._responseHeaders.
+some(header=>header.name.toLowerCase()==='alt-svc'&&/quic/.test(header.value));
+const receivedHeaders=record._timing&&record._timing.receiveHeadersEnd>0;
+return!!(isQUIC&&receivedHeaders&&record.endTime);
+}
+
+
+
+
+
+
+
+
+
+static findNetworkQuietPeriods(networkRecords,allowedConcurrentRequests,endTime=Infinity){
+
+
+let timeBoundaries=[];
+networkRecords.forEach(record=>{
+const scheme=record.parsedURL&&record.parsedURL.scheme;
+if(IGNORED_NETWORK_SCHEMES.includes(scheme)){
+return;
+}
+
+
+timeBoundaries.push({time:record.startTime*1000,isStart:true});
+if(record.finished||NetworkRecorder._isQUICAndFinished(record)){
+timeBoundaries.push({time:record.endTime*1000,isStart:false});
+}
+});
+
+timeBoundaries=timeBoundaries.
+filter(boundary=>boundary.time<=endTime).
+sort((a,b)=>a.time-b.time);
+
+let numInflightRequests=0;
+let quietPeriodStart=0;
+
+const quietPeriods=[];
+timeBoundaries.forEach(boundary=>{
+if(boundary.isStart){
+
+if(numInflightRequests===allowedConcurrentRequests){
+quietPeriods.push({start:quietPeriodStart,end:boundary.time});
+}
+numInflightRequests++;
+}else{
+numInflightRequests--;
+
+if(numInflightRequests===allowedConcurrentRequests){
+quietPeriodStart=boundary.time;
+}
+}
+});
+
+
+if(numInflightRequests<=allowedConcurrentRequests){
+quietPeriods.push({start:quietPeriodStart,end:endTime});
+}
+
+return quietPeriods.filter(period=>period.start!==period.end);
+}
+
+
+
+
+
+
+
+onRequestStarted(request){
+this._records.push(request.data);
+this._emitNetworkStatus();
+}
+
+
+
+
+
+
+
+onRequestFinished(request){
+this.emit('requestloaded',request.data);
+this._emitNetworkStatus();
+}
+
+
+
+
+
+
+
+
+onRequestWillBeSent(data){
+
+this.networkManager._dispatcher.requestWillBeSent(data.requestId,
+data.frameId,data.loaderId,data.documentURL,data.request,
+data.timestamp,data.wallTime,data.initiator,data.redirectResponse,
+data.type);
+}
+
+
+
+
+onRequestServedFromCache(data){
+this.networkManager._dispatcher.requestServedFromCache(data.requestId);
+}
+
+
+
+
+onResponseReceived(data){
+
+this.networkManager._dispatcher.responseReceived(data.requestId,
+data.frameId,data.loaderId,data.timestamp,data.type,data.response);
+}
+
+
+
+
+onDataReceived(data){
+
+this.networkManager._dispatcher.dataReceived(data.requestId,data.timestamp,
+data.dataLength,data.encodedDataLength);
+}
+
+
+
+
+onLoadingFinished(data){
+
+this.networkManager._dispatcher.loadingFinished(data.requestId,
+data.timestamp,data.encodedDataLength);
+}
+
+
+
+
+onLoadingFailed(data){
+
+
+this.networkManager._dispatcher.loadingFailed(data.requestId,
+data.timestamp,data.type,data.errorText,data.canceled,
+data.blockedReason);
+}
+
+
+
+
+onResourceChangedPriority(data){
+this.networkManager._dispatcher.resourceChangedPriority(data.requestId,
+data.newPriority,data.timestamp);
+}
+
+
+
+
+
+dispatch(event){
+if(!event.method.startsWith('Network.')){
+return;
+}
+
+switch(event.method){
+case'Network.requestWillBeSent':return this.onRequestWillBeSent(event.params);
+case'Network.requestServedFromCache':return this.onRequestServedFromCache(event.params);
+case'Network.responseReceived':return this.onResponseReceived(event.params);
+case'Network.dataReceived':return this.onDataReceived(event.params);
+case'Network.loadingFinished':return this.onLoadingFinished(event.params);
+case'Network.loadingFailed':return this.onLoadingFailed(event.params);
+case'Network.resourceChangedPriority':return this.onResourceChangedPriority(event.params);
+default:return;}
+
+}
+
+
+
+
+
+
+static recordsFromLogs(devtoolsLog){
+
+const records=[];
+const nr=new NetworkRecorder(records);
+devtoolsLog.forEach(message=>{
+nr.dispatch(message);
+});
+return records;
+}}
+
+
+module.exports=NetworkRecorder;
+
+},{"./web-inspector":47,"events":62,"lighthouse-logger":143}],38:[function(require,module,exports){
+
+
+
+
+
+
+'use strict';
+
+
+
+
+
 
 
 
@@ -15609,3114 +22221,14 @@
 });
 }
 
-module.exports=Driver;
-
-},{"../lib/element":26,"../lib/emulation":27,"../lib/network-recorder":32,"../lib/traces/trace-parser":39,"../lib/url-shim":41,"./devtools-log":13,"events":56,"lighthouse-logger":137}],15:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const log=require('lighthouse-logger');
-const Audit=require('../audits/audit');
-const LHError=require('../lib/errors');
-const URL=require('../lib/url-shim');
-const NetworkRecorder=require('../lib/network-recorder.js');
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class GatherRunner{
-
-
-
-
-
-
-
-
-
-
-static loadBlank(driver,url='about:blank',duration=300){
-return driver.gotoURL(url).then(_=>new Promise(resolve=>setTimeout(resolve,duration)));
-}
-
-
-
-
-
-
-
-
-
-
-static loadPage(driver,options){
-return driver.gotoURL(options.url,{
-waitForLoad:true,
-disableJavaScript:!!options.disableJavaScript,
-flags:options.flags,
-config:options.config}).
-then(finalUrl=>{
-options.url=finalUrl;
-});
-}
-
-
-
-
-
-
-
-static setupDriver(driver,gathererResults,options){
-log.log('status','Initializing…');
-const resetStorage=!options.flags.disableStorageReset;
-
-return driver.assertNoSameOriginServiceWorkerClients(options.url).
-then(_=>driver.getUserAgent()).
-then(userAgent=>{
-gathererResults.UserAgent=[userAgent];
-GatherRunner.warnOnHeadless(userAgent,gathererResults);
-}).
-then(_=>driver.beginEmulation(options.flags)).
-then(_=>driver.enableRuntimeEvents()).
-then(_=>driver.cacheNatives()).
-then(_=>driver.registerPerformanceObserver()).
-then(_=>driver.dismissJavaScriptDialogs()).
-then(_=>resetStorage&&driver.clearDataForOrigin(options.url));
-}
-
-static disposeDriver(driver){
-log.log('status','Disconnecting from browser...');
-return driver.disconnect().catch(err=>{
-
-
-if(!/close\/.*status: 500$/.test(err.message)){
-log.error('GatherRunner disconnect',err.message);
-}
-});
-}
-
-
-
-
-
-
-
-static recoverOrThrow(promise){
-return promise.catch(err=>{
-if(err.fatal){
-throw err;
-}
-});
-}
-
-
-
-
-
-
-
-static getPageLoadError(url,networkRecords){
-const mainRecord=networkRecords.find(record=>{
-
-return URL.equalWithExcludedFragments(record.url,url);
-});
-
-let errorCode;
-let errorReason;
-if(!mainRecord){
-errorCode=LHError.errors.NO_DOCUMENT_REQUEST;
-}else if(mainRecord.failed){
-errorCode=LHError.errors.FAILED_DOCUMENT_REQUEST;
-errorReason=mainRecord.localizedFailDescription;
-}
-
-if(errorCode){
-const error=new LHError(errorCode,{reason:errorReason});
-log.error('GatherRunner',error.message,url);
-return error;
-}
-}
-
-
-
-
-
-
-static warnOnHeadless(userAgent,gathererResults){
-const chromeVersion=userAgent.split(/HeadlessChrome\/(.*) /)[1];
-
-
-const minVersion='63.0.3239.0';
-if(chromeVersion&&chromeVersion<minVersion){
-gathererResults.LighthouseRunWarnings.push('Your site\'s mobile performance may be '+
-'worse than the numbers presented in this report. Lighthouse could not test on a '+
-'mobile connection because Headless Chrome does not support network throttling '+
-'prior to version '+minVersion+'. The version used was '+chromeVersion);
-}
-}
-
-
-
-
-
-
-
-
-static beforePass(options,gathererResults){
-const blockedUrls=(options.config.blockedUrlPatterns||[]).
-concat(options.flags.blockedUrlPatterns||[]);
-const blankPage=options.config.blankPage;
-const blankDuration=options.config.blankDuration;
-const pass=GatherRunner.loadBlank(options.driver,blankPage,blankDuration).
-
-
-
-then(()=>options.driver.blockUrlPatterns(blockedUrls)).
-then(()=>options.driver.setExtraHTTPHeaders(options.flags.extraHeaders));
-
-return options.config.gatherers.reduce((chain,gatherer)=>{
-return chain.then(_=>{
-const artifactPromise=Promise.resolve().then(_=>gatherer.beforePass(options));
-gathererResults[gatherer.name]=[artifactPromise];
-return GatherRunner.recoverOrThrow(artifactPromise);
-});
-},pass);
-}
-
-
-
-
-
-
-
-
-static pass(options,gathererResults){
-const driver=options.driver;
-const config=options.config;
-const gatherers=config.gatherers;
-
-const recordTrace=config.recordTrace;
-const isPerfRun=!options.flags.disableStorageReset&&recordTrace&&config.useThrottling;
-
-const gatherernames=gatherers.map(g=>g.name).join(', ');
-const status='Loading page & waiting for onload';
-log.log('status',status,gatherernames);
-
-const pass=Promise.resolve().
-
-then(_=>isPerfRun&&driver.cleanBrowserCaches()).
-
-then(_=>driver.beginDevtoolsLog()).
-
-then(_=>recordTrace&&driver.beginTrace(options.flags)).
-
-then(_=>GatherRunner.loadPage(driver,options)).
-then(_=>log.log('statusEnd',status));
-
-return gatherers.reduce((chain,gatherer)=>{
-return chain.then(_=>{
-const artifactPromise=Promise.resolve().then(_=>gatherer.pass(options));
-gathererResults[gatherer.name].push(artifactPromise);
-return GatherRunner.recoverOrThrow(artifactPromise);
-});
-},pass);
-}
-
-
-
-
-
-
-
-
-
-static afterPass(options,gathererResults){
-const driver=options.driver;
-const config=options.config;
-const gatherers=config.gatherers;
-const passData={};
-
-let pass=Promise.resolve();
-let pageLoadError;
-
-if(config.recordTrace){
-pass=pass.then(_=>{
-log.log('status','Retrieving trace');
-return driver.endTrace();
-}).then(traceContents=>{
-
-
-
-passData.trace=Array.isArray(traceContents)?
-{traceEvents:traceContents}:traceContents;
-log.verbose('statusEnd','Retrieving trace');
-});
-}
-
-pass=pass.then(_=>{
-const status='Retrieving devtoolsLog and network records';
-log.log('status',status);
-const devtoolsLog=driver.endDevtoolsLog();
-const networkRecords=NetworkRecorder.recordsFromLogs(devtoolsLog);
-log.verbose('statusEnd',status);
-
-pageLoadError=GatherRunner.getPageLoadError(options.url,networkRecords);
-
-if(!driver.online)pageLoadError=null;
-
-if(pageLoadError){
-gathererResults.LighthouseRunWarnings.push('Lighthouse was unable to reliably load the '+
-'page you requested. Make sure you are testing the correct URL and that the server is '+
-'properly responding to all requests.');
-}
-
-
-passData.devtoolsLog=devtoolsLog;
-passData.networkRecords=networkRecords;
-});
-
-
-pass=pass.then(_=>driver.setThrottling(options.flags,{useThrottling:false}));
-
-pass=gatherers.reduce((chain,gatherer)=>{
-const status=`Retrieving: ${gatherer.name}`;
-return chain.then(_=>{
-log.log('status',status);
-const artifactPromise=pageLoadError?
-Promise.reject(pageLoadError):
-Promise.resolve().then(_=>gatherer.afterPass(options,passData));
-gathererResults[gatherer.name].push(artifactPromise);
-return GatherRunner.recoverOrThrow(artifactPromise);
-}).then(_=>{
-log.verbose('statusEnd',status);
-});
-},pass);
-
-
-return pass.then(_=>passData);
-}
-
-
-
-
-
-
-
-
-
-static collectArtifacts(gathererResults){
-const artifacts={};
-
-
-const uniqueWarnings=Array.from(new Set(gathererResults.LighthouseRunWarnings));
-gathererResults.LighthouseRunWarnings=[uniqueWarnings];
-
-const pageLoadFailures=[];
-return Object.keys(gathererResults).reduce((chain,gathererName)=>{
-return chain.then(_=>{
-const phaseResultsPromises=gathererResults[gathererName];
-return Promise.all(phaseResultsPromises).then(phaseResults=>{
-
-const definedResults=phaseResults.filter(element=>element!==undefined);
-const artifact=definedResults[definedResults.length-1];
-if(artifact===undefined){
-throw new Error(`${gathererName} failed to provide an artifact.`);
-}
-artifacts[gathererName]=artifact;
-},err=>{
-
-
-artifacts[gathererName]=err;
-
-if(LHError.isPageLoadError(err))pageLoadFailures.push(err);
-});
-});
-},Promise.resolve()).then(_=>{
-
-if(pageLoadFailures.length>Object.keys(artifacts).length*.5){
-throw pageLoadFailures[0];
-}
-
-return artifacts;
-});
-}
-
-static run(passes,options){
-const driver=options.driver;
-const tracingData={
-traces:{},
-devtoolsLogs:{}};
-
-
-if(typeof options.url!=='string'||options.url.length===0){
-return Promise.reject(new Error('You must provide a url to the gather-runner'));
-}
-
-if(typeof options.flags==='undefined'){
-options.flags={};
-}
-
-if(typeof options.config==='undefined'){
-return Promise.reject(new Error('You must provide a config'));
-}
-
-if(typeof options.flags.disableCpuThrottling==='undefined'){
-options.flags.disableCpuThrottling=false;
-}
-
-passes=this.instantiateGatherers(passes,options.config.configDir);
-
-const gathererResults={
-LighthouseRunWarnings:[]};
-
-
-return driver.connect().
-then(_=>GatherRunner.loadBlank(driver)).
-then(_=>GatherRunner.setupDriver(driver,gathererResults,options)).
-
-
-then(_=>{
-
-let urlAfterRedirects;
-return passes.reduce((chain,config,passIndex)=>{
-const runOptions=Object.assign({},options,{config});
-return chain.
-then(_=>driver.setThrottling(options.flags,config)).
-then(_=>GatherRunner.beforePass(runOptions,gathererResults)).
-then(_=>GatherRunner.pass(runOptions,gathererResults)).
-then(_=>GatherRunner.afterPass(runOptions,gathererResults)).
-then(passData=>{
-const passName=config.passName||Audit.DEFAULT_PASS;
-
-
-tracingData.devtoolsLogs[passName]=passData.devtoolsLog;
-
-
-if(config.recordTrace){
-tracingData.traces[passName]=passData.trace;
-}
-
-if(passIndex===0){
-urlAfterRedirects=runOptions.url;
-}
-});
-},Promise.resolve()).then(_=>{
-options.url=urlAfterRedirects;
-});
-}).
-then(_=>GatherRunner.disposeDriver(driver)).
-then(_=>GatherRunner.collectArtifacts(gathererResults)).
-then(artifacts=>{
-
-return Object.assign(artifacts,tracingData);
-}).
-
-catch(err=>{
-GatherRunner.disposeDriver(driver);
-
-throw err;
-});
-}
-
-static getGathererClass(nameOrGathererClass,configPath){
-const Runner=require('../runner');
-const coreList=Runner.getGathererList();
-
-let GathererClass;
-if(typeof nameOrGathererClass==='string'){
-const name=nameOrGathererClass;
-
-
-const coreGatherer=coreList.find(a=>a===`${name}.js`);
-let requirePath=`./gatherers/${name}`;
-if(!coreGatherer){
-
-requirePath=Runner.resolvePlugin(name,configPath,'gatherer');
-}
-
-GathererClass=require(requirePath);
-
-this.assertValidGatherer(GathererClass,name);
-}else{
-GathererClass=nameOrGathererClass;
-this.assertValidGatherer(GathererClass);
-}
-
-return GathererClass;
-}
-
-static assertValidGatherer(GathererDefinition,gathererName){
-const gathererInstance=new GathererDefinition();
-gathererName=gathererName||gathererInstance.name||'gatherer';
-
-if(typeof gathererInstance.beforePass!=='function'){
-throw new Error(`${gathererName} has no beforePass() method.`);
-}
-
-if(typeof gathererInstance.pass!=='function'){
-throw new Error(`${gathererName} has no pass() method.`);
-}
-
-if(typeof gathererInstance.afterPass!=='function'){
-throw new Error(`${gathererName} has no afterPass() method.`);
-}
-}
-
-static instantiateGatherers(passes,rootPath){
-return passes.map(pass=>{
-pass.gatherers=pass.gatherers.map(gatherer=>{
-
-if(typeof gatherer!=='string'){
-return gatherer;
-}
-
-const GathererClass=GatherRunner.getGathererClass(gatherer,rootPath);
-return new GathererClass();
-});
-
-return pass;
-});
-}}
-
-
-module.exports=GatherRunner;
-
-},{"../audits/audit":2,"../lib/errors":28,"../lib/network-recorder.js":32,"../lib/url-shim":41,"../runner":44,"lighthouse-logger":137}],16:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-class Gatherer{
-
-
-
-get name(){
-return this.constructor.name;
-}
-
-
-
-
-
-
-
-beforePass(options){}
-
-
-
-
-
-
-pass(options){}
-
-
-
-
-
-
-
-
-
-afterPass(options,loadData){}}
-
-
-
-
-module.exports=Gatherer;
-
-},{}],17:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const isEqual=require('lodash.isequal');
-
-
-
-
-
-
-module.exports=class ArbitraryEqualityMap{
-constructor(){
-this._equalsFn=(a,b)=>a===b;
-this._entries=[];
-}
-
-
-
-
-setEqualityFn(equalsFn){
-this._equalsFn=equalsFn;
-}
-
-has(key){
-return this._findIndexOf(key)!==-1;
-}
-
-get(key){
-const entry=this._entries[this._findIndexOf(key)];
-return entry&&entry.value;
-}
-
-set(key,value){
-let index=this._findIndexOf(key);
-if(index===-1)index=this._entries.length;
-this._entries[index]={key,value};
-}
-
-_findIndexOf(key){
-for(let i=0;i<this._entries.length;i++){
-if(this._equalsFn(key,this._entries[i].key))return i;
-}
-
-return-1;
-}
-
-
-
-
-
-
-
-
-
-static deepEquals(objA,objB){
-return isEqual(objA,objB);
-}};
-
-
-},{"lodash.isequal":138}],18:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-
-const path=require('path');
-const log=require('lighthouse-logger');
-const stream=require('stream');
-const Metrics=require('./traces/pwmetrics-events');
-const TraceParser=require('./traces/trace-parser');
-const rimraf=require('rimraf');
-const mkdirp=require('mkdirp');
-
-
-
-
-
-
-function screenshotDump(screenshots){
-return`
-  <!doctype html>
-  <meta charset="utf-8">
-  <title>screenshots</title>
-  <style>
-html {
-    overflow-x: scroll;
-    overflow-y: hidden;
-    height: 100%;
-    background-image: linear-gradient(to left, #4ca1af , #c4e0e5);
-    background-attachment: fixed;
-    padding: 10px;
-}
-body {
-    white-space: nowrap;
-    background-image: linear-gradient(to left, #4ca1af , #c4e0e5);
-    width: 100%;
-    margin: 0;
-}
-img {
-    margin: 4px;
-}
-</style>
-  <body>
-    <script>
-      var shots = ${JSON.stringify(screenshots)};
-
-  shots.forEach(s => {
-    var i = document.createElement('img');
-    i.src = s.datauri;
-    i.title = s.timestamp;
-    document.body.appendChild(i);
-  });
-  </script>
-  `;
-}
-
-const artifactsFilename='artifacts.json';
-const traceSuffix='.trace.json';
-const devtoolsLogSuffix='.devtoolslog.json';
-
-
-
-
-
-
-
-
-
-function loadArtifacts(basePath){
-log.log('Reading artifacts from disk:',basePath);
-
-if(!fs.existsSync(basePath))return Promise.reject(new Error('No saved artifacts found'));
-
-
-const filenames=fs.readdirSync(basePath);
-const artifacts=JSON.parse(fs.readFileSync(path.join(basePath,artifactsFilename),'utf8'));
-
-
-artifacts.devtoolsLogs={};
-filenames.filter(f=>f.endsWith(devtoolsLogSuffix)).map(filename=>{
-const passName=filename.replace(devtoolsLogSuffix,'');
-const devtoolsLog=JSON.parse(fs.readFileSync(path.join(basePath,filename),'utf8'));
-artifacts.devtoolsLogs[passName]=devtoolsLog;
-});
-
-
-artifacts.traces={};
-const promises=filenames.filter(f=>f.endsWith(traceSuffix)).map(filename=>{
-return new Promise(resolve=>{
-const passName=filename.replace(traceSuffix,'');
-const readStream=fs.createReadStream(path.join(basePath,filename),{
-encoding:'utf-8',
-highWaterMark:4*1024*1024});
-
-const parser=new TraceParser();
-readStream.on('data',chunk=>parser.parseChunk(chunk));
-readStream.on('end',_=>{
-artifacts.traces[passName]=parser.getTrace();
-resolve();
-});
-});
-});
-return Promise.all(promises).then(_=>artifacts);
-}
-
-
-
-
-
-
-
-
-
-function saveArtifacts(artifacts,basePath){
-mkdirp.sync(basePath);
-rimraf.sync(`${basePath}/*${traceSuffix}`);
-rimraf.sync(`${basePath}/${artifactsFilename}`);
-
-
-artifacts=Object.assign({},artifacts);
-
-
-const traces=artifacts.traces;
-let promise=Promise.all(Object.keys(traces).map(passName=>{
-return saveTrace(traces[passName],`${basePath}/${passName}${traceSuffix}`);
-}));
-
-
-const devtoolsLogs=artifacts.devtoolsLogs;
-promise=promise.then(_=>{
-Object.keys(devtoolsLogs).map(passName=>{
-const log=JSON.stringify(devtoolsLogs[passName]);
-fs.writeFileSync(`${basePath}/${passName}${devtoolsLogSuffix}`,log,'utf8');
-});
-delete artifacts.traces;
-delete artifacts.devtoolsLogs;
-});
-
-
-promise=promise.then(_=>{
-fs.writeFileSync(`${basePath}/${artifactsFilename}`,JSON.stringify(artifacts,0,2),'utf8');
-log.log('Artifacts saved to disk in folder:',basePath);
-});
-return promise;
-}
-
-
-
-
-
-
-
-function prepareAssets(artifacts,audits){
-const passNames=Object.keys(artifacts.traces);
-const assets=[];
-
-return passNames.reduce((chain,passName)=>{
-const trace=artifacts.traces[passName];
-const devtoolsLog=artifacts.devtoolsLogs[passName];
-
-return chain.then(_=>artifacts.requestScreenshots(trace)).
-then(screenshots=>{
-const traceData=Object.assign({},trace);
-const screenshotsHTML=screenshotDump(screenshots);
-
-if(audits){
-const evts=new Metrics(traceData.traceEvents,audits).generateFakeEvents();
-traceData.traceEvents=traceData.traceEvents.concat(evts);
-}
-
-assets.push({
-passName,
-traceData,
-devtoolsLog,
-screenshotsHTML,
-screenshots});
-
-});
-},Promise.resolve()).
-then(_=>assets);
-}
-
-
-
-
-
-
-
-function*traceJsonGenerator(traceData){
-const keys=Object.keys(traceData);
-
-yield'{\n';
-
-
-yield'"traceEvents": [\n';
-if(traceData.traceEvents.length>0){
-const eventsIterator=traceData.traceEvents[Symbol.iterator]();
-
-const firstEvent=eventsIterator.next().value;
-yield`  ${JSON.stringify(firstEvent)}`;
-for(const event of eventsIterator){
-yield`,\n  ${JSON.stringify(event)}`;
-}
-}
-yield'\n]';
-
-
-if(keys.length>1){
-for(const key of keys){
-if(key==='traceEvents')continue;
-
-yield`,\n"${key}": ${JSON.stringify(traceData[key],null,2)}`;
-}
-}
-
-yield'}\n';
-}
-
-
-
-
-
-
-
-function saveTrace(traceData,traceFilename){
-return new Promise((resolve,reject)=>{
-const traceIter=traceJsonGenerator(traceData);
-
-
-const traceStream=new stream.Readable({
-read(){
-const next=traceIter.next();
-this.push(next.done?null:next.value);
-}});
-
-
-const writeStream=fs.createWriteStream(traceFilename);
-writeStream.on('finish',resolve);
-writeStream.on('error',reject);
-
-traceStream.pipe(writeStream);
-});
-}
-
-
-
-
-
-
-
-
-function saveAssets(artifacts,audits,pathWithBasename){
-return prepareAssets(artifacts,audits).then(assets=>{
-return Promise.all(assets.map((data,index)=>{
-const devtoolsLogFilename=`${pathWithBasename}-${index}${devtoolsLogSuffix}`;
-fs.writeFileSync(devtoolsLogFilename,JSON.stringify(data.devtoolsLog,null,2));
-log.log('saveAssets','devtools log saved to disk: '+devtoolsLogFilename);
-
-const screenshotsHTMLFilename=`${pathWithBasename}-${index}.screenshots.html`;
-fs.writeFileSync(screenshotsHTMLFilename,data.screenshotsHTML);
-log.log('saveAssets','screenshots saved to disk: '+screenshotsHTMLFilename);
-
-const screenshotsJSONFilename=`${pathWithBasename}-${index}.screenshots.json`;
-fs.writeFileSync(screenshotsJSONFilename,JSON.stringify(data.screenshots,null,2));
-log.log('saveAssets','screenshots saved to disk: '+screenshotsJSONFilename);
-
-const streamTraceFilename=`${pathWithBasename}-${index}${traceSuffix}`;
-log.log('saveAssets','streaming trace file to disk: '+streamTraceFilename);
-return saveTrace(data.traceData,streamTraceFilename).then(_=>{
-log.log('saveAssets','trace file streamed to disk: '+streamTraceFilename);
-});
-}));
-});
-}
-
-
-
-
-
-
-
-function logAssets(artifacts,audits){
-return prepareAssets(artifacts,audits).then(assets=>{
-assets.map(data=>{
-log.log(`devtoolslog-${data.passName}.json`,JSON.stringify(data.devtoolsLog));
-const traceIter=traceJsonGenerator(data.traceData);
-let traceJson='';
-for(const trace of traceIter){
-traceJson+=trace;
-}
-log.log(`trace-${data.passName}.json`,traceJson);
-});
-});
-}
-
 module.exports={
-saveArtifacts,
-loadArtifacts,
-saveAssets,
-prepareAssets,
-saveTrace,
-logAssets};
+captureJSCallUsage,
+wrapRuntimeEvalErrorInBrowser,
+registerPerformanceObserverInPage,
+checkTimeSinceLastLongTask};
 
 
-},{"./traces/pwmetrics-events":38,"./traces/trace-parser":39,"lighthouse-logger":137,"mkdirp":52,"path":69,"rimraf":52,"stream":86}],19:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-const log=require('lighthouse-logger');
-
-class ConsoleQuieter{
-static mute(opts){
-ConsoleQuieter._logs=ConsoleQuieter._logs||[];
-
-console.log=function(...args){
-ConsoleQuieter._logs.push({type:'log',args,prefix:opts.prefix});
-};
-console.warn=function(...args){
-ConsoleQuieter._logs.push({type:'warn',args,prefix:opts.prefix});
-};
-console.error=function(...args){
-ConsoleQuieter._logs.push({type:'error',args,prefix:opts.prefix});
-};
-}
-
-static unmuteAndFlush(){
-console.log=ConsoleQuieter._consolelog;
-console.warn=ConsoleQuieter._consolewarn;
-console.error=ConsoleQuieter._consoleerror;
-
-ConsoleQuieter._logs.forEach(entry=>{
-log.verbose(`${entry.prefix}-${entry.type}`,...entry.args);
-});
-ConsoleQuieter._logs=[];
-}}
-
-
-ConsoleQuieter._consolelog=console.log.bind(console);
-ConsoleQuieter._consolewarn=console.warn.bind(console);
-ConsoleQuieter._consoleerror=console.error.bind(console);
-
-module.exports=ConsoleQuieter;
-
-},{"lighthouse-logger":137}],20:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Node=require('./node');
-
-class CPUNode extends Node{
-
-
-
-
-constructor(parentEvent,childEvents=[]){
-const nodeId=`${parentEvent.tid}.${parentEvent.ts}`;
-super(nodeId);
-
-this._event=parentEvent;
-this._childEvents=childEvents;
-}
-
-
-
-
-get type(){
-return Node.TYPES.CPU;
-}
-
-
-
-
-get startTime(){
-return this._event.ts;
-}
-
-
-
-
-get endTime(){
-return this._event.ts+this._event.dur;
-}
-
-
-
-
-get event(){
-return this._event;
-}
-
-
-
-
-get childEvents(){
-return this._childEvents;
-}
-
-
-
-
-
-didPerformLayout(){
-return this._childEvents.some(evt=>evt.name==='Layout');
-}
-
-
-
-
-
-
-isEvaluateScriptFor(urls){
-return this._childEvents.some(evt=>{
-return evt.name==='EvaluateScript'&&
-evt.args.data&&
-urls.has(evt.args.data.url);
-});
-}
-
-
-
-
-cloneWithoutRelationships(){
-return new CPUNode(this._event,this._childEvents);
-}}
-
-
-module.exports=CPUNode;
-
-},{"./node":22}],21:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Node=require('./node');
-const WebInspector=require('../web-inspector');
-
-class NetworkNode extends Node{
-
-
-
-constructor(networkRecord){
-super(networkRecord.requestId);
-this._record=networkRecord;
-}
-
-
-
-
-get type(){
-return Node.TYPES.NETWORK;
-}
-
-
-
-
-get startTime(){
-return this._record.startTime*1000*1000;
-}
-
-
-
-
-get endTime(){
-return this._record.endTime*1000*1000;
-}
-
-
-
-
-get record(){
-return this._record;
-}
-
-
-
-
-get initiatorType(){
-return this._record._initiator&&this._record._initiator.type;
-}
-
-
-
-
-hasRenderBlockingPriority(){
-const priority=this._record.priority();
-const isScript=this._record._resourceType===WebInspector.resourceTypes.Script;
-return priority==='VeryHigh'||priority==='High'&&isScript;
-}
-
-
-
-
-cloneWithoutRelationships(){
-return new NetworkNode(this._record);
-}}
-
-
-module.exports=NetworkNode;
-
-},{"../web-inspector":42,"./node":22}],22:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-class Node{
-
-
-
-constructor(id){
-this._id=id;
-this._dependents=[];
-this._dependencies=[];
-}
-
-
-
-
-get id(){
-return this._id;
-}
-
-
-
-
-get type(){
-throw new Error('Unimplemented');
-}
-
-
-
-
-get startTime(){
-throw new Error('Unimplemented');
-}
-
-
-
-
-get endTime(){
-throw new Error('Unimplemented');
-}
-
-
-
-
-getDependents(){
-return this._dependents.slice();
-}
-
-
-
-
-getDependencies(){
-return this._dependencies.slice();
-}
-
-
-
-
-getNumberOfDependencies(){
-return this._dependencies.length;
-}
-
-
-
-
-getRootNode(){
-let rootNode=this;
-while(rootNode._dependencies.length){
-rootNode=rootNode._dependencies[0];
-}
-
-return rootNode;
-}
-
-
-
-
-addDependent(node){
-node.addDependency(this);
-}
-
-
-
-
-addDependency(node){
-if(this._dependencies.includes(node)){
-return;
-}
-
-node._dependents.push(this);
-this._dependencies.push(node);
-}
-
-
-
-
-
-cloneWithoutRelationships(){
-return new Node(this.id);
-}
-
-
-
-
-
-
-
-
-
-cloneWithRelationships(predicate){
-const rootNode=this.getRootNode();
-
-let shouldIncludeNode=()=>true;
-if(predicate){
-const idsToInclude=new Set();
-rootNode.traverse(node=>{
-if(predicate(node)){
-node.traverse(
-node=>idsToInclude.add(node.id),
-node=>node._dependencies.filter(parent=>!idsToInclude.has(parent)));
-
-}
-});
-
-shouldIncludeNode=node=>idsToInclude.has(node.id);
-}
-
-const idToNodeMap=new Map();
-rootNode.traverse(originalNode=>{
-if(!shouldIncludeNode(originalNode))return;
-const clonedNode=originalNode.cloneWithoutRelationships();
-idToNodeMap.set(clonedNode.id,clonedNode);
-});
-
-rootNode.traverse(originalNode=>{
-if(!shouldIncludeNode(originalNode))return;
-const clonedNode=idToNodeMap.get(originalNode.id);
-
-for(const dependency of originalNode._dependencies){
-const clonedDependency=idToNodeMap.get(dependency.id);
-clonedNode.addDependency(clonedDependency);
-}
-});
-
-return idToNodeMap.get(this.id);
-}
-
-
-
-
-
-
-
-_traversePaths(iterator,getNext){
-const stack=[[this]];
-while(stack.length){
-const path=stack.shift();
-const node=path[0];
-iterator(node,path);
-
-const nodesToAdd=getNext(node);
-for(const nextNode of nodesToAdd){
-stack.push([nextNode].concat(path));
-}
-}
-}
-
-
-
-
-
-
-
-traverse(iterator,getNext){
-if(!getNext){
-getNext=node=>node.getDependents();
-}
-
-const visited=new Set();
-const originalGetNext=getNext;
-
-getNext=node=>{
-visited.add(node.id);
-const allNodesToVisit=originalGetNext(node);
-const nodesToVisit=allNodesToVisit.filter(nextNode=>!visited.has(nextNode.id));
-nodesToVisit.forEach(nextNode=>visited.add(nextNode.id));
-return nodesToVisit;
-};
-
-this._traversePaths(iterator,getNext);
-}
-
-
-
-
-
-
-static hasCycle(node){
-const visited=new Set();
-const currentPath=[];
-const toVisit=[node];
-const depthAdded=new Map([[node,0]]);
-
-
-while(toVisit.length){
-
-const currentNode=toVisit.pop();
-
-
-if(currentPath.includes(currentNode))return true;
-
-if(visited.has(currentNode))continue;
-
-
-while(currentPath.length>depthAdded.get(currentNode))currentPath.pop();
-
-
-visited.add(currentNode);
-currentPath.push(currentNode);
-
-
-for(const dependent of currentNode._dependents){
-if(toVisit.includes(dependent))continue;
-toVisit.push(dependent);
-depthAdded.set(dependent,currentPath.length);
-}
-}
-
-return false;
-}}
-
-
-Node.TYPES={
-NETWORK:'network',
-CPU:'cpu'};
-
-
-module.exports=Node;
-
-},{}],23:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const Node=require('../node');
-const TcpConnection=require('./tcp-connection');
-const emulation=require('../../emulation').settings;
-
-
-const DEFAULT_MAXIMUM_CONCURRENT_REQUESTS=10;
-
-
-const DEFAULT_FALLBACK_TTFB=30;
-const DEFAULT_RTT=emulation.TYPICAL_MOBILE_THROTTLING_METRICS.targetLatency;
-const DEFAULT_THROUGHPUT=emulation.TYPICAL_MOBILE_THROTTLING_METRICS.targetDownloadThroughput*8;
-
-
-const DEFAULT_CPU_TASK_MULTIPLIER=emulation.CPU_THROTTLE_METRICS.rate;
-
-const DEFAULT_LAYOUT_TASK_MULTIPLIER=DEFAULT_CPU_TASK_MULTIPLIER/2;
-
-const DEFAULT_MAXIMUM_CPU_TASK_DURATION=10000;
-
-const TLS_SCHEMES=['https','wss'];
-
-function groupBy(items,keyFunc){
-const grouped=new Map();
-items.forEach(item=>{
-const key=keyFunc(item);
-const group=grouped.get(key)||[];
-group.push(item);
-grouped.set(key,group);
-});
-
-return grouped;
-}
-
-const NodeState={
-NotReadyToStart:0,
-ReadyToStart:1,
-InProgress:2,
-Complete:3};
-
-
-class Simulator{
-
-
-
-
-
-constructor(graph,options){
-this._graph=graph;
-this._options=Object.assign(
-{
-rtt:DEFAULT_RTT,
-throughput:DEFAULT_THROUGHPUT,
-fallbackTTFB:DEFAULT_FALLBACK_TTFB,
-maximumConcurrentRequests:DEFAULT_MAXIMUM_CONCURRENT_REQUESTS,
-cpuTaskMultiplier:DEFAULT_CPU_TASK_MULTIPLIER,
-layoutTaskMultiplier:DEFAULT_LAYOUT_TASK_MULTIPLIER},
-
-options);
-
-
-this._rtt=this._options.rtt;
-this._throughput=this._options.throughput;
-this._fallbackTTFB=this._options.fallbackTTFB;
-this._maximumConcurrentRequests=Math.min(
-TcpConnection.maximumSaturatedConnections(this._rtt,this._throughput),
-this._options.maximumConcurrentRequests);
-
-this._cpuTaskMultiplier=this._options.cpuTaskMultiplier;
-this._layoutTaskMultiplier=this._options.layoutTaskMultiplier;
-}
-
-
-
-
-
-
-static getTTFB(record){
-const timing=record._timing;
-return timing&&timing.receiveHeadersEnd-timing.sendEnd||Infinity;
-}
-
-
-
-
-_initializeNetworkRecords(){
-this._networkRecords=[];
-
-this._graph.getRootNode().traverse(node=>{
-if(node.type===Node.TYPES.NETWORK){
-this._networkRecords.push(node.record);
-}
-});
-}
-
-
-
-
-_initializeNetworkConnections(){
-const connections=new Map();
-const recordsByConnection=groupBy(this._networkRecords,record=>record.connectionId);
-
-for(const[connectionId,records]of recordsByConnection.entries()){
-const isTLS=TLS_SCHEMES.includes(records[0].parsedURL.scheme);
-const isH2=records[0].protocol==='h2';
-
-
-
-
-
-
-
-let estimatedResponseTime=Math.min(...records.map(Simulator.getTTFB));
-
-
-if(!Number.isFinite(estimatedResponseTime)){
-estimatedResponseTime=this._fallbackTTFB;
-}
-
-const connection=new TcpConnection(
-this._rtt,
-this._throughput,
-estimatedResponseTime,
-isTLS,
-isH2);
-
-
-connections.set(connectionId,connection);
-}
-
-this._connections=connections;
-return connections;
-}
-
-
-
-
-_initializeAuxiliaryData(){
-this._nodeTiming=new Map();
-this._connectionsInUse=new Set();
-this._numberInProgressByType=new Map();
-
-this._nodes=[];
-for(const key of Object.keys(NodeState)){
-this._nodes[NodeState[key]]=new Set();
-}
-}
-
-
-
-
-
-_numberInProgress(type){
-return this._numberInProgressByType.get(type)||0;
-}
-
-
-
-
-
-_setTimingData(node,values){
-const timingData=this._nodeTiming.get(node)||{};
-Object.assign(timingData,values);
-this._nodeTiming.set(node,timingData);
-}
-
-
-
-
-
-_markNodeAsReadyToStart(node,queuedTime){
-this._nodes[NodeState.ReadyToStart].add(node);
-this._nodes[NodeState.NotReadyToStart].delete(node);
-this._setTimingData(node,{queuedTime});
-}
-
-
-
-
-
-_markNodeAsInProgress(node,startTime){
-this._nodes[NodeState.InProgress].add(node);
-this._nodes[NodeState.ReadyToStart].delete(node);
-this._numberInProgressByType.set(node.type,this._numberInProgress(node.type)+1);
-this._setTimingData(node,{startTime});
-}
-
-
-
-
-
-_markNodeAsComplete(node,endTime){
-this._nodes[NodeState.Complete].add(node);
-this._nodes[NodeState.InProgress].delete(node);
-this._numberInProgressByType.set(node.type,this._numberInProgress(node.type)-1);
-this._setTimingData(node,{endTime});
-
-
-for(const dependent of node.getDependents()){
-
-const dependencies=dependent.getDependencies();
-if(dependencies.some(dep=>!this._nodes[NodeState.Complete].has(dep)))continue;
-
-
-this._markNodeAsReadyToStart(dependent,endTime);
-}
-}
-
-
-
-
-
-_startNodeIfPossible(node,totalElapsedTime){
-if(node.type===Node.TYPES.CPU){
-
-if(this._numberInProgress(node.type)===0){
-this._markNodeAsInProgress(node,totalElapsedTime);
-this._setTimingData(node,{timeElapsed:0});
-}
-
-return;
-}
-
-if(node.type!==Node.TYPES.NETWORK)throw new Error('Unsupported');
-
-const connection=this._connections.get(node.record.connectionId);
-const numberOfActiveRequests=this._numberInProgress(node.type);
-
-
-if(
-numberOfActiveRequests>=this._maximumConcurrentRequests||
-this._connectionsInUse.has(connection))
-{
-return;
-}
-
-this._markNodeAsInProgress(node,totalElapsedTime);
-this._setTimingData(node,{
-timeElapsed:0,
-timeElapsedOvershoot:0,
-bytesDownloaded:0});
-
-
-this._connectionsInUse.add(connection);
-}
-
-
-
-
-
-_updateNetworkCapacity(){
-for(const connection of this._connectionsInUse){
-connection.setThroughput(this._throughput/this._nodes[NodeState.InProgress].size);
-}
-}
-
-
-
-
-
-
-_estimateTimeRemaining(node){
-if(node.type===Node.TYPES.CPU){
-const timingData=this._nodeTiming.get(node);
-const multiplier=node.didPerformLayout()?
-this._layoutTaskMultiplier:
-this._cpuTaskMultiplier;
-const totalDuration=Math.min(
-Math.round(node.event.dur/1000*multiplier),
-DEFAULT_MAXIMUM_CPU_TASK_DURATION);
-
-const estimatedTimeElapsed=totalDuration-timingData.timeElapsed;
-this._setTimingData(node,{estimatedTimeElapsed});
-return estimatedTimeElapsed;
-}
-
-if(node.type!==Node.TYPES.NETWORK)throw new Error('Unsupported');
-
-const timingData=this._nodeTiming.get(node);
-const connection=this._connections.get(node.record.connectionId);
-const calculation=connection.simulateDownloadUntil(
-node.record.transferSize-timingData.bytesDownloaded,
-{timeAlreadyElapsed:timingData.timeElapsed});
-
-
-const estimatedTimeElapsed=calculation.timeElapsed+timingData.timeElapsedOvershoot;
-this._setTimingData(node,{estimatedTimeElapsed});
-return estimatedTimeElapsed;
-}
-
-
-
-
-
-_findNextNodeCompletionTime(){
-let minimumTime=Infinity;
-for(const node of this._nodes[NodeState.InProgress]){
-minimumTime=Math.min(minimumTime,this._estimateTimeRemaining(node));
-}
-
-return minimumTime;
-}
-
-
-
-
-
-
-
-_updateProgressMadeInTimePeriod(node,timePeriodLength,totalElapsedTime){
-const timingData=this._nodeTiming.get(node);
-const isFinished=timingData.estimatedTimeElapsed===timePeriodLength;
-
-if(node.type===Node.TYPES.CPU){
-return isFinished?
-this._markNodeAsComplete(node,totalElapsedTime):
-timingData.timeElapsed+=timePeriodLength;
-}
-
-if(node.type!==Node.TYPES.NETWORK)throw new Error('Unsupported');
-
-const connection=this._connections.get(node.record.connectionId);
-const calculation=connection.simulateDownloadUntil(
-node.record.transferSize-timingData.bytesDownloaded,
-{
-timeAlreadyElapsed:timingData.timeElapsed,
-maximumTimeToElapse:timePeriodLength-timingData.timeElapsedOvershoot});
-
-
-
-connection.setCongestionWindow(calculation.congestionWindow);
-connection.setH2OverflowBytesDownloaded(calculation.extraBytesDownloaded);
-
-if(isFinished){
-connection.setWarmed(true);
-this._connectionsInUse.delete(connection);
-this._markNodeAsComplete(node,totalElapsedTime);
-}else{
-timingData.timeElapsed+=calculation.timeElapsed;
-timingData.timeElapsedOvershoot+=calculation.timeElapsed-timePeriodLength;
-timingData.bytesDownloaded+=calculation.bytesDownloaded;
-}
-}
-
-
-
-
-
-simulate(){
-
-this._initializeNetworkRecords();
-this._initializeNetworkConnections();
-this._initializeAuxiliaryData();
-
-const nodesNotReadyToStart=this._nodes[NodeState.NotReadyToStart];
-const nodesReadyToStart=this._nodes[NodeState.ReadyToStart];
-const nodesInProgress=this._nodes[NodeState.InProgress];
-
-const rootNode=this._graph.getRootNode();
-rootNode.traverse(node=>nodesNotReadyToStart.add(node));
-
-let totalElapsedTime=0;
-
-
-this._markNodeAsReadyToStart(rootNode,totalElapsedTime);
-
-
-while(nodesReadyToStart.size||nodesInProgress.size){
-
-for(const node of nodesReadyToStart){
-this._startNodeIfPossible(node,totalElapsedTime);
-}
-
-
-this._updateNetworkCapacity();
-
-
-const minimumTime=this._findNextNodeCompletionTime();
-totalElapsedTime+=minimumTime;
-
-
-for(const node of nodesInProgress){
-this._updateProgressMadeInTimePeriod(node,minimumTime,totalElapsedTime);
-}
-}
-
-return{
-timeInMs:totalElapsedTime,
-nodeTiming:this._nodeTiming};
-
-}}
-
-
-module.exports=Simulator;
-
-
-
-
-
-
-
-
-
-Simulator.NodeTimingData;
-
-},{"../../emulation":27,"../node":22,"./tcp-connection":24}],24:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const INITIAL_CONGESTION_WINDOW=10;
-const TCP_SEGMENT_SIZE=1460;
-
-class TcpConnection{
-
-
-
-
-
-
-
-constructor(rtt,throughput,serverLatency=0,ssl=true,h2=false){
-this._warmed=false;
-this._ssl=ssl;
-this._h2=h2;
-this._rtt=rtt;
-this._throughput=throughput;
-this._serverLatency=serverLatency;
-this._congestionWindow=INITIAL_CONGESTION_WINDOW;
-this._h2OverflowBytesDownloaded=0;
-}
-
-
-
-
-
-
-static maximumSaturatedConnections(rtt,availableThroughput){
-const roundTripsPerSecond=1000/rtt;
-const bytesPerRoundTrip=TCP_SEGMENT_SIZE;
-const bytesPerSecond=roundTripsPerSecond*bytesPerRoundTrip;
-const minimumThroughputRequiredPerRequest=bytesPerSecond*8;
-return Math.floor(availableThroughput/minimumThroughputRequiredPerRequest);
-}
-
-
-
-
-_computeMaximumCongestionWindowInSegments(){
-const bytesPerSecond=this._throughput/8;
-const secondsPerRoundTrip=this._rtt/1000;
-const bytesPerRoundTrip=bytesPerSecond*secondsPerRoundTrip;
-return Math.floor(bytesPerRoundTrip/TCP_SEGMENT_SIZE);
-}
-
-
-
-
-setThroughput(throughput){
-this._throughput=throughput;
-}
-
-
-
-
-setCongestionWindow(congestion){
-this._congestionWindow=congestion;
-}
-
-
-
-
-setWarmed(warmed){
-this._warmed=warmed;
-}
-
-
-
-
-
-
-setH2OverflowBytesDownloaded(bytes){
-if(!this._h2)return;
-this._h2OverflowBytesDownloaded=bytes;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-simulateDownloadUntil(bytesToDownload,options){
-const{timeAlreadyElapsed=0,maximumTimeToElapse=Infinity}=options||{};
-
-if(this._warmed&&this._h2){
-bytesToDownload-=this._h2OverflowBytesDownloaded;
-}
-const twoWayLatency=this._rtt;
-const oneWayLatency=twoWayLatency/2;
-const maximumCongestionWindow=this._computeMaximumCongestionWindowInSegments();
-
-let handshakeAndRequest=oneWayLatency;
-if(!this._warmed){
-handshakeAndRequest=
-
-oneWayLatency+
-
-oneWayLatency+
-
-oneWayLatency+(
-
-this._ssl?twoWayLatency:0);
-}
-
-let roundTrips=Math.ceil(handshakeAndRequest/twoWayLatency);
-let timeToFirstByte=handshakeAndRequest+this._serverLatency+oneWayLatency;
-if(this._warmed&&this._h2)timeToFirstByte=0;
-
-const timeElapsedForTTFB=Math.max(timeToFirstByte-timeAlreadyElapsed,0);
-const maximumDownloadTimeToElapse=maximumTimeToElapse-timeElapsedForTTFB;
-
-let congestionWindow=Math.min(this._congestionWindow,maximumCongestionWindow);
-let totalBytesDownloaded=0;
-if(timeElapsedForTTFB>0){
-totalBytesDownloaded=congestionWindow*TCP_SEGMENT_SIZE;
-}else{
-roundTrips=0;
-}
-
-let downloadTimeElapsed=0;
-let bytesRemaining=bytesToDownload-totalBytesDownloaded;
-while(bytesRemaining>0&&downloadTimeElapsed<=maximumDownloadTimeToElapse){
-roundTrips++;
-downloadTimeElapsed+=twoWayLatency;
-congestionWindow=Math.max(Math.min(maximumCongestionWindow,congestionWindow*2),1);
-
-const bytesDownloadedInWindow=congestionWindow*TCP_SEGMENT_SIZE;
-totalBytesDownloaded+=bytesDownloadedInWindow;
-bytesRemaining-=bytesDownloadedInWindow;
-}
-
-const timeElapsed=timeElapsedForTTFB+downloadTimeElapsed;
-const extraBytesDownloaded=this._h2?Math.max(totalBytesDownloaded-bytesToDownload,0):0;
-const bytesDownloaded=Math.max(Math.min(totalBytesDownloaded,bytesToDownload),0);
-
-return{
-roundTrips,
-timeElapsed,
-bytesDownloaded,
-extraBytesDownloaded,
-congestionWindow};
-
-}}
-
-
-module.exports=TcpConnection;
-
-},{}],25:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-
-
-
-function getElementsInDocument(selector){
-const results=[];
-
-const _findAllElements=nodes=>{
-for(let i=0,el;el=nodes[i];++i){
-if(!selector||el.matches(selector)){
-results.push(el);
-}
-
-if(el.shadowRoot){
-_findAllElements(el.shadowRoot.querySelectorAll('*'));
-}
-}
-};
-_findAllElements(document.querySelectorAll('*'));
-
-return results;
-}
-
-module.exports={
-getElementsInDocumentFnString:getElementsInDocument.toString()};
-
-
-},{}],26:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-class Element{
-constructor(element,driver){
-if(!element||!driver){
-throw Error('Driver and element required to create Element');
-}
-this.driver=driver;
-this.element=element;
-}
-
-
-
-
-
-getAttribute(name){
-return this.driver.
-sendCommand('DOM.getAttributes',{
-nodeId:this.element.nodeId}).
-
-
-
-
-then(resp=>{
-const attrIndex=resp.attributes.indexOf(name);
-if(attrIndex===-1){
-return null;
-}
-
-return resp.attributes[attrIndex+1];
-});
-}
-
-
-
-
-
-getProperty(propName){
-return this.driver.
-sendCommand('DOM.resolveNode',{
-nodeId:this.element.nodeId}).
-
-then(resp=>{
-return this.driver.getObjectProperty(resp.object.objectId,propName);
-});
-}}
-
-
-module.exports=Element;
-
-},{}],27:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-
-
-
-const NEXUS5X_EMULATION_METRICS={
-mobile:true,
-screenWidth:412,
-screenHeight:732,
-width:412,
-height:732,
-positionX:0,
-positionY:0,
-scale:1,
-deviceScaleFactor:2.625,
-fitWindow:false,
-screenOrientation:{
-angle:0,
-type:'portraitPrimary'}};
-
-
-
-const NEXUS5X_USERAGENT={
-userAgent:'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36'+
-'(KHTML, like Gecko) Chrome/61.0.3116.0 Mobile Safari/537.36'};
-
-
-
-
-
-
-
-const LATENCY_FACTOR=3.75;
-const THROUGHPUT_FACTOR=0.9;
-
-const TARGET_LATENCY=150;
-const TARGET_DOWNLOAD_THROUGHPUT=Math.floor(1.6*1024*1024/8);
-const TARGET_UPLOAD_THROUGHPUT=Math.floor(750*1024/8);
-
-const TYPICAL_MOBILE_THROTTLING_METRICS={
-targetLatency:TARGET_LATENCY,
-latency:TARGET_LATENCY*LATENCY_FACTOR,
-targetDownloadThroughput:TARGET_DOWNLOAD_THROUGHPUT,
-downloadThroughput:TARGET_DOWNLOAD_THROUGHPUT*THROUGHPUT_FACTOR,
-targetUploadThroughput:TARGET_UPLOAD_THROUGHPUT,
-uploadThroughput:TARGET_UPLOAD_THROUGHPUT*THROUGHPUT_FACTOR,
-offline:false};
-
-
-const OFFLINE_METRICS={
-offline:true,
-
-latency:0,
-downloadThroughput:0,
-uploadThroughput:0};
-
-
-const NO_THROTTLING_METRICS={
-latency:0,
-downloadThroughput:0,
-uploadThroughput:0,
-offline:false};
-
-
-const NO_CPU_THROTTLE_METRICS={
-rate:1};
-
-const CPU_THROTTLE_METRICS={
-rate:4};
-
-
-function enableNexus5X(driver){
-
-
-
-
-
-
-
-
-
-
-
-
-const injectedTouchEventsFunction=function(){
-const touchEvents=['ontouchstart','ontouchend','ontouchmove','ontouchcancel'];
-const recepients=[window.__proto__,document.__proto__];
-for(let i=0;i<touchEvents.length;++i){
-for(let j=0;j<recepients.length;++j){
-if(!(touchEvents[i]in recepients[j])){
-Object.defineProperty(recepients[j],touchEvents[i],{
-value:null,writable:true,configurable:true,enumerable:true});
-
-}
-}
-}
-};
-
-
-return Promise.all([
-driver.sendCommand('Emulation.setDeviceMetricsOverride',NEXUS5X_EMULATION_METRICS),
-
-driver.sendCommand('Network.enable'),
-driver.sendCommand('Network.setUserAgentOverride',NEXUS5X_USERAGENT),
-driver.sendCommand('Emulation.setTouchEmulationEnabled',{
-enabled:true,
-configuration:'mobile'}),
-
-driver.sendCommand('Page.addScriptToEvaluateOnLoad',{
-scriptSource:'('+injectedTouchEventsFunction.toString()+')()'})]);
-
-
-}
-
-function enableNetworkThrottling(driver){
-return driver.sendCommand('Network.emulateNetworkConditions',TYPICAL_MOBILE_THROTTLING_METRICS);
-}
-
-function disableNetworkThrottling(driver){
-return driver.sendCommand('Network.emulateNetworkConditions',NO_THROTTLING_METRICS);
-}
-
-function goOffline(driver){
-return driver.sendCommand('Network.emulateNetworkConditions',OFFLINE_METRICS);
-}
-
-function enableCPUThrottling(driver){
-return driver.sendCommand('Emulation.setCPUThrottlingRate',CPU_THROTTLE_METRICS);
-}
-
-function disableCPUThrottling(driver){
-return driver.sendCommand('Emulation.setCPUThrottlingRate',NO_CPU_THROTTLE_METRICS);
-}
-
-function getEmulationDesc(){
-const{latency,downloadThroughput,uploadThroughput}=TYPICAL_MOBILE_THROTTLING_METRICS;
-const byteToMbit=bytes=>(bytes/1024/1024*8).toFixed(1);
-return{
-'deviceEmulation':'Nexus 5X',
-'cpuThrottling':`${CPU_THROTTLE_METRICS.rate}x slowdown`,
-'networkThrottling':`${latency}ms RTT, ${byteToMbit(downloadThroughput)}Mbps down, `+
-`${byteToMbit(uploadThroughput)}Mbps up`};
-
-}
-
-module.exports={
-enableNexus5X,
-enableNetworkThrottling,
-disableNetworkThrottling,
-enableCPUThrottling,
-disableCPUThrottling,
-goOffline,
-getEmulationDesc,
-settings:{
-NEXUS5X_EMULATION_METRICS,
-NEXUS5X_USERAGENT,
-TYPICAL_MOBILE_THROTTLING_METRICS,
-OFFLINE_METRICS,
-NO_THROTTLING_METRICS,
-NO_CPU_THROTTLE_METRICS,
-CPU_THROTTLE_METRICS}};
-
-
-
-},{}],28:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const strings=require('./strings');
-
-
-
-
-
-
-
-
-class LighthouseError extends Error{
-
-
-
-
-constructor(errorDefinition,properties){
-super(errorDefinition.code);
-this.name='LHError';
-this.code=errorDefinition.code;
-this.friendlyMessage=errorDefinition.message;
-if(properties)Object.assign(this,properties);
-
-Error.captureStackTrace(this,LighthouseError);
-}
-
-
-
-
-static isPageLoadError(err){
-return err.code===ERRORS.NO_DOCUMENT_REQUEST.code||
-err.code===ERRORS.FAILED_DOCUMENT_REQUEST.code;
-}
-
-
-
-
-
-
-static fromProtocolMessage(method,protocolError){
-
-const protocolErrors=Object.keys(ERRORS).filter(k=>ERRORS[k].pattern).map(k=>ERRORS[k]);
-
-const matchedErrorDefinition=protocolErrors.find(e=>e.pattern.test(protocolError.message));
-if(matchedErrorDefinition){
-return new LighthouseError(matchedErrorDefinition,{
-protocolMethod:method,
-protocolError:protocolError.message});
-
-}
-
-
-let errMsg=`(${method}): ${protocolError.message}`;
-if(protocolError.data)errMsg+=` (${protocolError.data})`;
-const error=new Error(`Protocol error ${errMsg}`);
-return Object.assign(error,{protocolMethod:method,protocolError:protocolError.message});
-}}
-
-
-const ERRORS={
-
-NO_SPEEDLINE_FRAMES:{message:strings.didntCollectScreenshots},
-SPEEDINDEX_OF_ZERO:{message:strings.didntCollectScreenshots},
-NO_SCREENSHOTS:{message:strings.didntCollectScreenshots},
-
-
-NO_TRACING_STARTED:{message:strings.badTraceRecording},
-NO_NAVSTART:{message:strings.badTraceRecording},
-NO_FMP:{message:strings.badTraceRecording},
-NO_DCL:{message:strings.badTraceRecording},
-
-
-FMP_TOO_LATE_FOR_FCPUI:{message:strings.pageLoadTookTooLong},
-NO_FCPUI_IDLE_PERIOD:{message:strings.pageLoadTookTooLong},
-NO_TTI_CPU_IDLE_PERIOD:{message:strings.pageLoadTookTooLong},
-NO_TTI_NETWORK_IDLE_PERIOD:{message:strings.pageLoadTookTooLong},
-
-
-NO_DOCUMENT_REQUEST:{message:strings.pageLoadFailed},
-FAILED_DOCUMENT_REQUEST:{message:strings.pageLoadFailed},
-
-
-TRACING_ALREADY_STARTED:{message:strings.internalChromeError,pattern:/Tracing.*started/},
-PARSING_PROBLEM:{message:strings.internalChromeError,pattern:/Parsing problem/},
-READ_FAILED:{message:strings.internalChromeError,pattern:/Read failed/}};
-
-
-Object.keys(ERRORS).forEach(code=>ERRORS[code].code=code);
-LighthouseError.errors=ERRORS;
-module.exports=LighthouseError;
-
-
-},{"./strings":35}],29:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-
-
-
-function addFormattedCodeSnippet(listener){
-const handler=listener.handler?listener.handler.description:'...';
-const objectName=listener.objectName.toLowerCase().replace('#document','document');
-return Object.assign({
-label:`line: ${listener.line}, col: ${listener.col}`,
-pre:`${objectName}.addEventListener('${listener.type}', ${handler})`},
-listener);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-function groupCodeSnippetsByLocation(listeners){
-const locToListenersMap=new Map();
-listeners.forEach(loc=>{
-const key=JSON.stringify({line:loc.line,col:loc.col,url:loc.url,type:loc.type});
-if(locToListenersMap.has(key)){
-locToListenersMap.get(key).push(loc);
-}else{
-locToListenersMap.set(key,[loc]);
-}
-});
-
-const results=[];
-locToListenersMap.forEach((listenersForLocation,key)=>{
-const lineColUrlObj=JSON.parse(key);
-
-const codeSnippets=listenersForLocation.reduce((prev,loc)=>{
-return prev+loc.pre.trim()+'\n\n';
-},'');
-lineColUrlObj.pre=codeSnippets;
-
-
-lineColUrlObj.label=listenersForLocation[0].label;
-results.push(lineColUrlObj);
-});
-
-return results;
-}
-
-module.exports={
-addFormattedCodeSnippet,
-groupCodeSnippetsByLocation};
-
-
-},{}],30:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-
-
-
-
-function doExist(manifest){
-if(!manifest||!manifest.icons){
-return false;
-}
-if(manifest.icons.value.length===0){
-return false;
-}
-return true;
-}
-
-
-
-
-
-
-function sizeAtLeast(sizeRequirement,manifest){
-
-
-const iconValues=manifest.icons.value;
-const nestedSizes=iconValues.map(icon=>icon.value.sizes.value);
-const flattenedSizes=[].concat(...nestedSizes);
-
-return flattenedSizes.
-
-filter(size=>typeof size==='string').
-
-filter(size=>/\d+x\d+/.test(size)).
-filter(size=>{
-
-const sizeStrs=size.split(/x/i);
-
-const sizeNums=[parseFloat(sizeStrs[0]),parseFloat(sizeStrs[1])];
-
-const areIconsBigEnough=sizeNums[0]>=sizeRequirement&&sizeNums[1]>=sizeRequirement;
-
-const areIconsSquare=sizeNums[0]===sizeNums[1];
-return areIconsBigEnough&&areIconsSquare;
-});
-}
-
-module.exports={
-doExist,
-sizeAtLeast};
-
-
-},{}],31:[function(require,module,exports){
-
-
-
-
-
-'use strict';
-
-const URL=require('./url-shim');
-const validateColor=require('./web-inspector').Color.parse;
-
-const ALLOWED_DISPLAY_VALUES=[
-'fullscreen',
-'standalone',
-'minimal-ui',
-'browser'];
-
-
-
-
-
-const DEFAULT_DISPLAY_MODE='browser';
-
-const ALLOWED_ORIENTATION_VALUES=[
-'any',
-'natural',
-'landscape',
-'portrait',
-'portrait-primary',
-'portrait-secondary',
-'landscape-primary',
-'landscape-secondary'];
-
-
-function parseString(raw,trim){
-let value;
-let debugString;
-
-if(typeof raw==='string'){
-value=trim?raw.trim():raw;
-}else{
-if(raw!==undefined){
-debugString='ERROR: expected a string.';
-}
-value=undefined;
-}
-
-return{
-raw,
-value,
-debugString};
-
-}
-
-function parseColor(raw){
-const color=parseString(raw);
-
-
-if(color.value===undefined){
-return color;
-}
-
-
-const validatedColor=validateColor(color.raw);
-if(!validatedColor){
-color.value=undefined;
-color.debugString='ERROR: color parsing failed.';
-}
-
-return color;
-}
-
-function parseName(jsonInput){
-return parseString(jsonInput.name,true);
-}
-
-function parseShortName(jsonInput){
-return parseString(jsonInput.short_name,true);
-}
-
-
-
-
-
-
-
-function checkSameOrigin(url1,url2){
-const parsed1=new URL(url1);
-const parsed2=new URL(url2);
-
-return parsed1.origin===parsed2.origin;
-}
-
-
-
-
-function parseStartUrl(jsonInput,manifestUrl,documentUrl){
-const raw=jsonInput.start_url;
-
-
-if(raw===''){
-return{
-raw,
-value:documentUrl,
-debugString:'ERROR: start_url string empty'};
-
-}
-const parsedAsString=parseString(raw);
-if(!parsedAsString.value){
-parsedAsString.value=documentUrl;
-return parsedAsString;
-}
-
-
-let startUrl;
-try{
-startUrl=new URL(raw,manifestUrl).href;
-}catch(e){
-
-return{
-raw,
-value:documentUrl,
-debugString:'ERROR: invalid start_url relative to ${manifestUrl}'};
-
-}
-
-
-if(!checkSameOrigin(startUrl,documentUrl)){
-return{
-raw,
-value:documentUrl,
-debugString:'ERROR: start_url must be same-origin as document'};
-
-}
-
-return{
-raw,
-value:startUrl};
-
-}
-
-function parseDisplay(jsonInput){
-const display=parseString(jsonInput.display,true);
-
-if(!display.value){
-display.value=DEFAULT_DISPLAY_MODE;
-return display;
-}
-
-display.value=display.value.toLowerCase();
-if(!ALLOWED_DISPLAY_VALUES.includes(display.value)){
-display.debugString='ERROR: \'display\' has invalid value '+display.value+
-` will fall back to ${DEFAULT_DISPLAY_MODE}.`;
-display.value=DEFAULT_DISPLAY_MODE;
-}
-
-return display;
-}
-
-function parseOrientation(jsonInput){
-const orientation=parseString(jsonInput.orientation,true);
-
-if(orientation.value&&
-!ALLOWED_ORIENTATION_VALUES.includes(orientation.value.toLowerCase())){
-orientation.value=undefined;
-orientation.debugString='ERROR: \'orientation\' has an invalid value, will be ignored.';
-}
-
-return orientation;
-}
-
-function parseIcon(raw,manifestUrl){
-
-const src=parseString(raw.src,true);
-
-if(src.value===''){
-src.value=undefined;
-}
-if(src.value){
-
-src.value=new URL(src.value,manifestUrl).href;
-}
-
-const type=parseString(raw.type,true);
-
-const density={
-raw:raw.density,
-value:1,
-debugString:undefined};
-
-if(density.raw!==undefined){
-density.value=parseFloat(density.raw);
-if(isNaN(density.value)||!isFinite(density.value)||density.value<=0){
-density.value=1;
-density.debugString='ERROR: icon density cannot be NaN, +∞, or less than or equal to +0.';
-}
-}
-
-const sizes=parseString(raw.sizes);
-if(sizes.value!==undefined){
-const set=new Set();
-sizes.value.trim().split(/\s+/).forEach(size=>set.add(size.toLowerCase()));
-sizes.value=set.size>0?Array.from(set):undefined;
-}
-
-return{
-raw,
-value:{
-src,
-type,
-density,
-sizes},
-
-debugString:undefined};
-
-}
-
-function parseIcons(jsonInput,manifestUrl){
-const raw=jsonInput.icons;
-
-if(raw===undefined){
-return{
-raw,
-value:[],
-debugString:undefined};
-
-}
-
-if(!Array.isArray(raw)){
-return{
-raw,
-value:[],
-debugString:'ERROR: \'icons\' expected to be an array but is not.'};
-
-}
-
-
-
-const value=raw.
-
-filter(icon=>icon.src!==undefined).
-
-map(icon=>parseIcon(icon,manifestUrl)).
-
-filter(parsedIcon=>parsedIcon.value.src.value!==undefined);
-
-return{
-raw,
-value,
-debugString:undefined};
-
-}
-
-function parseApplication(raw){
-const platform=parseString(raw.platform,true);
-const id=parseString(raw.id,true);
-
-
-const appUrl=parseString(raw.url,true);
-if(appUrl.value){
-try{
-
-appUrl.value=new URL(appUrl.value).href;
-}catch(e){
-appUrl.value=undefined;
-appUrl.debugString='ERROR: invalid application URL ${raw.url}';
-}
-}
-
-return{
-raw,
-value:{
-platform,
-id,
-url:appUrl},
-
-debugString:undefined};
-
-}
-
-function parseRelatedApplications(jsonInput){
-const raw=jsonInput.related_applications;
-
-if(raw===undefined){
-return{
-raw,
-value:undefined,
-debugString:undefined};
-
-}
-
-if(!Array.isArray(raw)){
-return{
-raw,
-value:undefined,
-debugString:'ERROR: \'related_applications\' expected to be an array but is not.'};
-
-}
-
-
-
-const value=raw.
-filter(application=>!!application.platform).
-map(parseApplication).
-filter(parsedApp=>!!parsedApp.value.id.value||!!parsedApp.value.url.value);
-
-return{
-raw,
-value,
-debugString:undefined};
-
-}
-
-function parsePreferRelatedApplications(jsonInput){
-const raw=jsonInput.prefer_related_applications;
-let value;
-let debugString;
-
-if(typeof raw==='boolean'){
-value=raw;
-}else{
-if(raw!==undefined){
-debugString='ERROR: \'prefer_related_applications\' expected to be a boolean.';
-}
-value=undefined;
-}
-
-return{
-raw,
-value,
-debugString};
-
-}
-
-function parseThemeColor(jsonInput){
-return parseColor(jsonInput.theme_color);
-}
-
-function parseBackgroundColor(jsonInput){
-return parseColor(jsonInput.background_color);
-}
-
-
-
-
-
-
-
-
-function parse(string,manifestUrl,documentUrl){
-if(manifestUrl===undefined||documentUrl===undefined){
-throw new Error('Manifest and document URLs required for manifest parsing.');
-}
-
-let jsonInput;
-
-try{
-jsonInput=JSON.parse(string);
-}catch(e){
-return{
-raw:string,
-value:undefined,
-debugString:'ERROR: file isn\'t valid JSON: '+e};
-
-}
-
-
-const manifest={
-name:parseName(jsonInput),
-short_name:parseShortName(jsonInput),
-start_url:parseStartUrl(jsonInput,manifestUrl,documentUrl),
-display:parseDisplay(jsonInput),
-orientation:parseOrientation(jsonInput),
-icons:parseIcons(jsonInput,manifestUrl),
-related_applications:parseRelatedApplications(jsonInput),
-prefer_related_applications:parsePreferRelatedApplications(jsonInput),
-theme_color:parseThemeColor(jsonInput),
-background_color:parseBackgroundColor(jsonInput)};
-
-
-
-return{
-raw:string,
-value:manifest,
-debugString:undefined};
-
-}
-
-module.exports=parse;
-
-},{"./url-shim":41,"./web-inspector":42}],32:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-const NetworkManager=require('./web-inspector').NetworkManager;
-const EventEmitter=require('events').EventEmitter;
-const log=require('lighthouse-logger');
-
-const IGNORED_NETWORK_SCHEMES=['data','ws'];
-
-class NetworkRecorder extends EventEmitter{
-
-
-
-
-constructor(recordArray){
-super();
-
-this._records=recordArray;
-this.networkManager=NetworkManager.createWithFakeTarget();
-
-this.networkManager.addEventListener(
-this.EventTypes.RequestStarted,
-this.onRequestStarted.bind(this));
-
-this.networkManager.addEventListener(
-this.EventTypes.RequestFinished,
-this.onRequestFinished.bind(this));
-
-}
-
-get EventTypes(){
-return NetworkManager.Events;
-}
-
-isIdle(){
-return!!this._getActiveIdlePeriod(0);
-}
-
-is2Idle(){
-return!!this._getActiveIdlePeriod(2);
-}
-
-_getActiveIdlePeriod(allowedRequests){
-const quietPeriods=NetworkRecorder.findNetworkQuietPeriods(this._records,allowedRequests);
-return quietPeriods.find(period=>!Number.isFinite(period.end));
-}
-
-_emitNetworkStatus(){
-const zeroQuiet=this._getActiveIdlePeriod(0);
-const twoQuiet=this._getActiveIdlePeriod(2);
-
-if(twoQuiet&&zeroQuiet){
-log.verbose('NetworkRecorder','network fully-quiet');
-this.emit('network-2-idle');
-this.emit('networkidle');
-}else if(twoQuiet&&!zeroQuiet){
-log.verbose('NetworkRecorder','network semi-quiet');
-this.emit('network-2-idle');
-this.emit('networkbusy');
-}else{
-log.verbose('NetworkRecorder','network busy');
-this.emit('network-2-busy');
-this.emit('networkbusy');
-}
-}
-
-
-
-
-
-
-
-
-
-static findNetworkQuietPeriods(networkRecords,allowedConcurrentRequests,endTime=Infinity){
-
-let timeBoundaries=[];
-networkRecords.forEach(record=>{
-const scheme=record.parsedURL&&record.parsedURL.scheme;
-if(IGNORED_NETWORK_SCHEMES.includes(scheme)){
-return;
-}
-
-
-timeBoundaries.push({time:record.startTime*1000,isStart:true});
-if(record.finished){
-timeBoundaries.push({time:record.endTime*1000,isStart:false});
-}
-});
-
-timeBoundaries=timeBoundaries.
-filter(boundary=>boundary.time<=endTime).
-sort((a,b)=>a.time-b.time);
-
-let numInflightRequests=0;
-let quietPeriodStart=0;
-const quietPeriods=[];
-timeBoundaries.forEach(boundary=>{
-if(boundary.isStart){
-
-if(numInflightRequests===allowedConcurrentRequests){
-quietPeriods.push({start:quietPeriodStart,end:boundary.time});
-}
-numInflightRequests++;
-}else{
-numInflightRequests--;
-
-if(numInflightRequests===allowedConcurrentRequests){
-quietPeriodStart=boundary.time;
-}
-}
-});
-
-
-if(numInflightRequests<=allowedConcurrentRequests){
-quietPeriods.push({start:quietPeriodStart,end:endTime});
-}
-
-return quietPeriods;
-}
-
-
-
-
-
-
-onRequestStarted(request){
-this._records.push(request.data);
-this._emitNetworkStatus();
-}
-
-
-
-
-
-
-
-onRequestFinished(request){
-this.emit('requestloaded',request.data);
-this._emitNetworkStatus();
-}
-
-
-
-
-
-onRequestWillBeSent(data){
-
-this.networkManager._dispatcher.requestWillBeSent(data.requestId,
-data.frameId,data.loaderId,data.documentURL,data.request,
-data.timestamp,data.wallTime,data.initiator,data.redirectResponse,
-data.type);
-}
-
-onRequestServedFromCache(data){
-this.networkManager._dispatcher.requestServedFromCache(data.requestId);
-}
-
-onResponseReceived(data){
-
-this.networkManager._dispatcher.responseReceived(data.requestId,
-data.frameId,data.loaderId,data.timestamp,data.type,data.response);
-}
-
-onDataReceived(data){
-
-this.networkManager._dispatcher.dataReceived(data.requestId,data.timestamp,
-data.dataLength,data.encodedDataLength);
-}
-
-onLoadingFinished(data){
-
-this.networkManager._dispatcher.loadingFinished(data.requestId,
-data.timestamp,data.encodedDataLength);
-}
-
-onLoadingFailed(data){
-
-
-this.networkManager._dispatcher.loadingFailed(data.requestId,
-data.timestamp,data.type,data.errorText,data.canceled,
-data.blockedReason);
-}
-
-onResourceChangedPriority(data){
-this.networkManager._dispatcher.resourceChangedPriority(data.requestId,
-data.newPriority,data.timestamp);
-}
-
-
-
-
-
-
-dispatch(method,params){
-if(!method.startsWith('Network.')){
-return;
-}
-
-switch(method){
-case'Network.requestWillBeSent':return this.onRequestWillBeSent(params);
-case'Network.requestServedFromCache':return this.onRequestServedFromCache(params);
-case'Network.responseReceived':return this.onResponseReceived(params);
-case'Network.dataReceived':return this.onDataReceived(params);
-case'Network.loadingFinished':return this.onLoadingFinished(params);
-case'Network.loadingFailed':return this.onLoadingFailed(params);
-case'Network.resourceChangedPriority':return this.onResourceChangedPriority(params);
-default:return;}
-
-}
-
-
-
-
-
-
-static recordsFromLogs(devtoolsLog){
-const records=[];
-const nr=new NetworkRecorder(records);
-devtoolsLog.forEach(message=>{
-nr.dispatch(message.method,message.params);
-});
-return records;
-}}
-
-
-module.exports=NetworkRecorder;
-
-},{"./web-inspector":42,"events":56,"lighthouse-logger":137}],33:[function(require,module,exports){
+},{}],39:[function(require,module,exports){
 
 
 
@@ -18801,12 +22313,11 @@
 
 }
 
-const context={
+const context=Object.assign({
 url:opts.url,
 deviceEmulation:!opts.flags.disableDeviceEmulation,
-networkThrottling:!opts.flags.disableNetworkThrottling,
-cpuThrottling:!opts.flags.disableCpuThrottling};
-
+throttlingMethod:opts.flags.throttlingMethod},
+opts.flags.throttling);
 
 sentryDelegate.mergeContext({extra:Object.assign({},environmentData.extra,context)});
 return context;
@@ -18814,7 +22325,7 @@
 
 module.exports=sentryDelegate;
 
-},{"lighthouse-logger":137,"raven":52}],34:[function(require,module,exports){
+},{"lighthouse-logger":143,"raven":58}],40:[function(require,module,exports){
 
 
 
@@ -18880,7 +22391,7 @@
 getLogNormalDistribution};
 
 
-},{}],35:[function(require,module,exports){
+},{}],41:[function(require,module,exports){
 
 
 
@@ -18894,10 +22405,11 @@
 badTraceRecording:`Something went wrong with recording the trace over your page load. Please run Lighthouse again.`,
 pageLoadTookTooLong:`Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse.`,
 pageLoadFailed:`Your page failed to load. Verify that the URL is valid and re-run Lighthouse.`,
-internalChromeError:`An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.`};
+internalChromeError:`An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.`,
+requestContentTimeout:'Fetching resource content has exceeded the allotted time'};
 
 
-},{}],36:[function(require,module,exports){
+},{}],42:[function(require,module,exports){
 
 
 
@@ -18993,7 +22505,7 @@
 taskToGroup};
 
 
-},{}],37:[function(require,module,exports){
+},{}],43:[function(require,module,exports){
 
 
 
@@ -19006,14 +22518,17 @@
 
 
 const TimelineModelTreeView=
+
 require('devtools-timeline-model/lib/timeline-model-treeview.js')(WebInspector);
 
 class TimelineModel{
+
 constructor(events){
 this.init(events);
 }
 
-init(events){
+
+init(trace){
 
 this._tracingModel=
 new WebInspector.TracingModel(new WebInspector.TempFileBackingStorage('tracing'));
@@ -19021,11 +22536,15 @@
 this._timelineModel=
 new WebInspector.TimelineModel(WebInspector.TimelineUIUtils.visibleEventsFilter());
 
-if(typeof events==='string'){
-events=JSON.parse(events);
+let events;
+if(Array.isArray(trace)){
+events=trace;
 }
-if(events.hasOwnProperty('traceEvents')){
-events=events.traceEvents;
+if(typeof trace==='string'){
+events=JSON.parse(trace);
+}
+if(trace.hasOwnProperty('traceEvents')){
+events=trace.traceEvents;
 }
 
 
@@ -19083,7 +22602,6 @@
 
 
 
-
 bottomUpGroupBy(grouping){
 const topDown=this.topDown();
 
@@ -19098,14 +22616,15 @@
 }
 
 frameModel(){
-const frameModel=new WebInspector.TimelineFrameModel(event=>
-WebInspector.TimelineUIUtils.eventStyle(event).category.name);
 
+const mapper=event=>WebInspector.TimelineUIUtils.eventStyle(event).category.name;
+const frameModel=new WebInspector.TimelineFrameModel(mapper);
 frameModel.addTraceEvents({},
 this._timelineModel.inspectedTargetEvents(),this._timelineModel.sessionId()||'');
 return frameModel;
 }
 
+
 filmStripModel(){
 return new WebInspector.FilmStripModel(this._tracingModel);
 }
@@ -19119,7 +22638,7 @@
 
 module.exports=TimelineModel;
 
-},{"../console-quieter":19,"../web-inspector":42,"devtools-timeline-model/lib/timeline-model-treeview.js":129}],38:[function(require,module,exports){
+},{"../console-quieter":22,"../web-inspector":47,"devtools-timeline-model/lib/timeline-model-treeview.js":135}],44:[function(require,module,exports){
 
 
 
@@ -19132,18 +22651,14 @@
 
 
 
+function findValueInMetricsAuditFn(metricName){
+return auditResults=>{
+const metricsAudit=auditResults.metrics;
+if(!metricsAudit||!metricsAudit.details||!metricsAudit.details.items)return;
 
-
-
-function safeGet(object,path){
-const components=path.split('.');
-for(const component of components){
-if(!object){
-return null;
-}
-object=object[component];
-}
-return object;
+const values=metricsAudit.details.items[0];
+return values&&values[metricName];
+};
 }
 
 class Metrics{
@@ -19161,134 +22676,68 @@
 {
 name:'Navigation Start',
 id:'navstart',
-getTs:auditResults=>{
-const fmpExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(fmpExt,'value.timestamps.navStart');
-},
-getTiming:auditResults=>{
-const fmpExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(fmpExt,'value.timings.navStart');
-}},
+getTs:findValueInMetricsAuditFn('observedNavigationStartTs'),
+getTiming:findValueInMetricsAuditFn('observedNavigationStart')},
 
 {
 name:'First Contentful Paint',
 id:'ttfcp',
-getTs:auditResults=>{
-const fmpExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(fmpExt,'value.timestamps.fCP');
-},
-getTiming:auditResults=>{
-const fmpExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(fmpExt,'value.timings.fCP');
-}},
+getTs:findValueInMetricsAuditFn('observedFirstContentfulPaintTs'),
+getTiming:findValueInMetricsAuditFn('observedFirstContentfulPaint')},
 
 {
 name:'First Meaningful Paint',
 id:'ttfmp',
-getTs:auditResults=>{
-const fmpExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(fmpExt,'value.timestamps.fMP');
-},
-getTiming:auditResults=>{
-const fmpExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(fmpExt,'value.timings.fMP');
-}},
+getTs:findValueInMetricsAuditFn('observedFirstMeaningfulPaintTs'),
+getTiming:findValueInMetricsAuditFn('observedFirstMeaningfulPaint')},
 
 {
-name:'Perceptual Speed Index',
-id:'psi',
-getTs:auditResults=>{
-const siExt=auditResults['speed-index-metric'].extendedInfo;
-return safeGet(siExt,'value.timestamps.perceptualSpeedIndex');
-},
-getTiming:auditResults=>{
-const siExt=auditResults['speed-index-metric'].extendedInfo;
-return safeGet(siExt,'value.timings.perceptualSpeedIndex');
-}},
+name:'Speed Index',
+id:'si',
+getTs:findValueInMetricsAuditFn('observedSpeedIndexTs'),
+getTiming:findValueInMetricsAuditFn('observedSpeedIndex')},
 
 {
 name:'First Visual Change',
 id:'fv',
-getTs:auditResults=>{
-const siExt=auditResults['speed-index-metric'].extendedInfo;
-return safeGet(siExt,'value.timestamps.firstVisualChange');
-},
-getTiming:auditResults=>{
-const siExt=auditResults['speed-index-metric'].extendedInfo;
-return safeGet(siExt,'value.timings.firstVisualChange');
-}},
-
-{
-name:'Visually Complete 85%',
-id:'vc85',
-getTs:auditResults=>{
-const siExt=auditResults['speed-index-metric'].extendedInfo;
-return safeGet(siExt,'value.timestamps.visuallyReady');
-},
-getTiming:auditResults=>{
-const siExt=auditResults['speed-index-metric'].extendedInfo;
-return safeGet(siExt,'value.timings.visuallyReady');
-}},
+getTs:findValueInMetricsAuditFn('observedFirstVisualChangeTs'),
+getTiming:findValueInMetricsAuditFn('observedFirstVisualChange')},
 
 {
 name:'Visually Complete 100%',
 id:'vc100',
-getTs:auditResults=>{
-const siExt=auditResults['speed-index-metric'].extendedInfo;
-return safeGet(siExt,'value.timestamps.visuallyComplete');
-},
-getTiming:auditResults=>{
-const siExt=auditResults['speed-index-metric'].extendedInfo;
-return safeGet(siExt,'value.timings.visuallyComplete');
-}},
+getTs:findValueInMetricsAuditFn('observedLastVisualChangeTs'),
+getTiming:findValueInMetricsAuditFn('observedLastVisualChange')},
 
 {
-name:'First Interactive (vBeta)',
+name:'First CPU Idle',
 id:'ttfi',
-getTs:auditResults=>{
-const ttfiExt=auditResults['first-interactive'].extendedInfo;
-return safeGet(ttfiExt,'value.timestamp');
-},
-getTiming:auditResults=>{
-const ttfiExt=auditResults['first-interactive'].extendedInfo;
-return safeGet(ttfiExt,'value.timeInMs');
-}},
+getTs:findValueInMetricsAuditFn('firstCPUIdleTs'),
+getTiming:findValueInMetricsAuditFn('firstCPUIdle')},
 
 {
-name:'Time to Consistently Interactive (vBeta)',
-id:'ttci',
-getTs:auditResults=>{
-const ttiExt=auditResults['consistently-interactive'].extendedInfo;
-return safeGet(ttiExt,'value.timestamp');
-},
-getTiming:auditResults=>{
-const ttiExt=auditResults['consistently-interactive'].extendedInfo;
-return safeGet(ttiExt,'value.timeInMs');
-}},
+name:'Interactive',
+id:'tti',
+getTs:findValueInMetricsAuditFn('interactiveTs'),
+getTiming:findValueInMetricsAuditFn('interactive')},
 
 {
 name:'End of Trace',
 id:'eot',
-getTs:auditResults=>{
-const ttiExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(ttiExt,'value.timestamps.endOfTrace');
-},
-getTiming:auditResults=>{
-const ttiExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(ttiExt,'value.timings.endOfTrace');
-}},
+getTs:findValueInMetricsAuditFn('observedTraceEndTs'),
+getTiming:findValueInMetricsAuditFn('observedTraceEnd')},
 
 {
 name:'On Load',
 id:'onload',
-getTs:auditResults=>{
-const ttiExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(ttiExt,'value.timestamps.onLoad');
-},
-getTiming:auditResults=>{
-const ttiExt=auditResults['first-meaningful-paint'].extendedInfo;
-return safeGet(ttiExt,'value.timings.onLoad');
-}}];
+getTs:findValueInMetricsAuditFn('observedLoadTs'),
+getTiming:findValueInMetricsAuditFn('observedLoad')},
+
+{
+name:'DOM Content Loaded',
+id:'dcl',
+getTs:findValueInMetricsAuditFn('observedDomContentLoadedTs'),
+getTiming:findValueInMetricsAuditFn('observedDomContentLoaded')}];
 
 
 }
@@ -19390,8 +22839,7 @@
 
 module.exports=Metrics;
 
-},{"lighthouse-logger":137}],39:[function(require,module,exports){
-
+},{"lighthouse-logger":143}],45:[function(require,module,exports){
 
 
 
@@ -19411,16 +22859,19 @@
 
 class TraceParser{
 constructor(){
+
 this.traceEvents=[];
 
 this.tracingModel={
-reset:_=>this._reset(),
+reset:()=>this._reset(),
+
 addEvents:evts=>this._addEvents(evts)};
 
 
 const delegateMock={
-loadingProgress:_=>{},
-loadingStarted:_=>{},
+loadingProgress:()=>{},
+loadingStarted:()=>{},
+
 loadingComplete:success=>{
 if(!success)throw new Error('Parsing problem');
 }};
@@ -19464,7 +22915,7 @@
 
 module.exports=TraceParser;
 
-},{"../web-inspector":42}],40:[function(require,module,exports){
+},{"../web-inspector":47}],46:[function(require,module,exports){
 
 
 
@@ -19558,15 +23009,15 @@
 
 
 static getRiskToResponsiveness(
-tabTrace,
-startTime=0,
-endTime=tabTrace.timings.traceEnd,
+events,
+startTime,
+endTime,
 percentiles=[0.5,0.75,0.9,0.99,1])
 {
 const totalTime=endTime-startTime;
 percentiles.sort((a,b)=>a-b);
 
-const ret=TraceProcessor.getMainThreadTopLevelEventDurations(tabTrace,startTime,endTime);
+const ret=TraceProcessor.getMainThreadTopLevelEventDurations(events,startTime,endTime);
 return TraceProcessor._riskPercentiles(ret.durations,totalTime,percentiles,
 ret.clippedLength);
 }
@@ -19578,14 +23029,17 @@
 
 
 
-static getMainThreadTopLevelEventDurations(tabTrace,startTime=0,endTime=Infinity){
-const topLevelEvents=TraceProcessor.getMainThreadTopLevelEvents(tabTrace,startTime,endTime);
+static getMainThreadTopLevelEventDurations(topLevelEvents,startTime=0,endTime=Infinity){
 
 
 const durations=[];
 let clippedLength=0;
 
-topLevelEvents.forEach(event=>{
+for(const event of topLevelEvents){
+if(event.end<startTime||event.start>endTime){
+continue;
+}
+
 let duration=event.duration;
 let eventStart=event.start;
 if(eventStart<startTime){
@@ -19600,7 +23054,7 @@
 }
 
 durations.push(duration);
-});
+}
 durations.sort((a,b)=>a-b);
 
 return{
@@ -19643,153 +23097,25 @@
 return topLevelEvents;
 }
 
+
+
+
+
 static isScheduleableTask(evt){
 return evt.name===SCHEDULABLE_TASK_TITLE||evt.name===SCHEDULABLE_TASK_TITLE_ALT;
 }}
 
 
+
+
+
+
+
+
+
 module.exports=TraceProcessor;
 
-},{}],41:[function(require,module,exports){
-
-
-
-
-
-
-'use strict';
-
-
-
-
-
-
-
-const Util=require('../report/v2/renderer/util.js');
-
-
-
-const URL=typeof self!=='undefined'&&self.URL||require('whatwg-url').URL;
-
-URL.URLSearchParams=typeof self!=='undefined'&&self.URLSearchParams||
-require('whatwg-url').URLSearchParams;
-
-URL.INVALID_URL_DEBUG_STRING=
-'Lighthouse was unable to determine the URL of some script executions. '+
-'It\'s possible a Chrome extension or other eval\'d code is the source.';
-
-
-
-
-
-URL.isValid=function isValid(url){
-try{
-new URL(url);
-return true;
-}catch(e){
-return false;
-}
-};
-
-
-
-
-
-
-URL.hostsMatch=function hostsMatch(urlA,urlB){
-try{
-return new URL(urlA).host===new URL(urlB).host;
-}catch(e){
-return false;
-}
-};
-
-
-
-
-
-
-URL.originsMatch=function originsMatch(urlA,urlB){
-try{
-return new URL(urlA).origin===new URL(urlB).origin;
-}catch(e){
-return false;
-}
-};
-
-
-
-
-
-URL.getOrigin=function getOrigin(url){
-try{
-const urlInfo=new URL(url);
-
-
-return urlInfo.host&&urlInfo.origin||null;
-}catch(e){
-return null;
-}
-};
-
-
-
-
-
-
-URL.getURLDisplayName=function getURLDisplayName(url,options){
-return Util.getURLDisplayName(new URL(url),options);
-};
-
-
-
-
-
-
-URL.elideDataURI=function elideDataURI(url){
-try{
-const parsed=new URL(url);
-return parsed.protocol==='data:'?url.slice(0,100):url;
-}catch(e){
-return url;
-}
-};
-
-
-
-
-function rewriteChromeInternalUrl(url){
-if(!url||!url.startsWith('chrome://'))return url;
-
-
-if(url.endsWith('/'))url=url.replace(/\/$/,'');
-return url.replace(/^chrome:\/\/chrome\//,'chrome://');
-}
-
-
-
-
-
-
-
-URL.equalWithExcludedFragments=function(url1,url2){
-[url1,url2]=[url1,url2].map(rewriteChromeInternalUrl);
-try{
-url1=new URL(url1);
-url1.hash='';
-
-url2=new URL(url2);
-url2.hash='';
-
-return url1.href===url2.href;
-}catch(e){
-return false;
-}
-};
-
-module.exports=URL;
-
-},{"../report/v2/renderer/util.js":43,"whatwg-url":52}],42:[function(require,module,exports){
+},{}],47:[function(require,module,exports){
 (function(global){
 
 
@@ -20114,7 +23440,7 @@
 }();
 
 }).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"chrome-devtools-frontend/front_end/bindings/TempFile.js":93,"chrome-devtools-frontend/front_end/common/Color.js":94,"chrome-devtools-frontend/front_end/common/Object.js":95,"chrome-devtools-frontend/front_end/common/ParsedURL.js":96,"chrome-devtools-frontend/front_end/common/ResourceType.js":97,"chrome-devtools-frontend/front_end/common/SegmentedRange.js":98,"chrome-devtools-frontend/front_end/common/TextRange.js":99,"chrome-devtools-frontend/front_end/common/TextUtils.js":100,"chrome-devtools-frontend/front_end/common/UIString.js":101,"chrome-devtools-frontend/front_end/components_lazy/FilmStripModel.js":102,"chrome-devtools-frontend/front_end/platform/utilities.js":103,"chrome-devtools-frontend/front_end/sdk/CPUProfileDataModel.js":104,"chrome-devtools-frontend/front_end/sdk/CSSMatchedStyles.js":105,"chrome-devtools-frontend/front_end/sdk/CSSMedia.js":106,"chrome-devtools-frontend/front_end/sdk/CSSMetadata.js":107,"chrome-devtools-frontend/front_end/sdk/CSSProperty.js":108,"chrome-devtools-frontend/front_end/sdk/CSSRule.js":109,"chrome-devtools-frontend/front_end/sdk/CSSStyleDeclaration.js":110,"chrome-devtools-frontend/front_end/sdk/NetworkManager.js":111,"chrome-devtools-frontend/front_end/sdk/NetworkRequest.js":112,"chrome-devtools-frontend/front_end/sdk/ProfileTreeModel.js":113,"chrome-devtools-frontend/front_end/sdk/Target.js":114,"chrome-devtools-frontend/front_end/sdk/TargetManager.js":115,"chrome-devtools-frontend/front_end/sdk/TracingModel.js":116,"chrome-devtools-frontend/front_end/timeline/TimelineLoader.js":117,"chrome-devtools-frontend/front_end/timeline/TimelineTreeView.js":118,"chrome-devtools-frontend/front_end/timeline/TimelineUIUtils.js":119,"chrome-devtools-frontend/front_end/timeline_model/LayerTreeModel.js":120,"chrome-devtools-frontend/front_end/timeline_model/TimelineFrameModel.js":121,"chrome-devtools-frontend/front_end/timeline_model/TimelineIRModel.js":122,"chrome-devtools-frontend/front_end/timeline_model/TimelineJSProfile.js":123,"chrome-devtools-frontend/front_end/timeline_model/TimelineModel.js":124,"chrome-devtools-frontend/front_end/timeline_model/TimelineProfileTree.js":125,"chrome-devtools-frontend/front_end/ui_lazy/SortableDataGrid.js":126}],43:[function(require,module,exports){
+},{"chrome-devtools-frontend/front_end/bindings/TempFile.js":99,"chrome-devtools-frontend/front_end/common/Color.js":100,"chrome-devtools-frontend/front_end/common/Object.js":101,"chrome-devtools-frontend/front_end/common/ParsedURL.js":102,"chrome-devtools-frontend/front_end/common/ResourceType.js":103,"chrome-devtools-frontend/front_end/common/SegmentedRange.js":104,"chrome-devtools-frontend/front_end/common/TextRange.js":105,"chrome-devtools-frontend/front_end/common/TextUtils.js":106,"chrome-devtools-frontend/front_end/common/UIString.js":107,"chrome-devtools-frontend/front_end/components_lazy/FilmStripModel.js":108,"chrome-devtools-frontend/front_end/platform/utilities.js":109,"chrome-devtools-frontend/front_end/sdk/CPUProfileDataModel.js":110,"chrome-devtools-frontend/front_end/sdk/CSSMatchedStyles.js":111,"chrome-devtools-frontend/front_end/sdk/CSSMedia.js":112,"chrome-devtools-frontend/front_end/sdk/CSSMetadata.js":113,"chrome-devtools-frontend/front_end/sdk/CSSProperty.js":114,"chrome-devtools-frontend/front_end/sdk/CSSRule.js":115,"chrome-devtools-frontend/front_end/sdk/CSSStyleDeclaration.js":116,"chrome-devtools-frontend/front_end/sdk/NetworkManager.js":117,"chrome-devtools-frontend/front_end/sdk/NetworkRequest.js":118,"chrome-devtools-frontend/front_end/sdk/ProfileTreeModel.js":119,"chrome-devtools-frontend/front_end/sdk/Target.js":120,"chrome-devtools-frontend/front_end/sdk/TargetManager.js":121,"chrome-devtools-frontend/front_end/sdk/TracingModel.js":122,"chrome-devtools-frontend/front_end/timeline/TimelineLoader.js":123,"chrome-devtools-frontend/front_end/timeline/TimelineTreeView.js":124,"chrome-devtools-frontend/front_end/timeline/TimelineUIUtils.js":125,"chrome-devtools-frontend/front_end/timeline_model/LayerTreeModel.js":126,"chrome-devtools-frontend/front_end/timeline_model/TimelineFrameModel.js":127,"chrome-devtools-frontend/front_end/timeline_model/TimelineIRModel.js":128,"chrome-devtools-frontend/front_end/timeline_model/TimelineJSProfile.js":129,"chrome-devtools-frontend/front_end/timeline_model/TimelineModel.js":130,"chrome-devtools-frontend/front_end/timeline_model/TimelineProfileTree.js":131,"chrome-devtools-frontend/front_end/ui_lazy/SortableDataGrid.js":132}],48:[function(require,module,exports){
 
 
 
@@ -20126,20 +23452,106 @@
 
 const ELLIPSIS='\u2026';
 const NBSP='\xa0';
+const PASS_THRESHOLD=0.75;
 
 const RATINGS={
-PASS:{label:'pass',minScore:75},
-AVERAGE:{label:'average',minScore:45},
-FAIL:{label:'fail'}};
+PASS:{label:'pass',minScore:PASS_THRESHOLD},
+AVERAGE:{label:'average',minScore:0.45},
+FAIL:{label:'fail'},
+ERROR:{label:'error'}};
 
 
 class Util{
+static get PASS_THRESHOLD(){
+return PASS_THRESHOLD;
+}
+
+static get MS_DISPLAY_VALUE(){
+return`%10d${NBSP}ms`;
+}
 
 
 
 
 
-static calculateRating(score){
+static formatDisplayValue(displayValue){
+if(typeof displayValue==='string')return displayValue;
+if(!displayValue)return'';
+
+const replacementRegex=/%([0-9]*(\.[0-9]+)?d|s)/;
+const template=displayValue[0];
+if(typeof template!=='string'){
+
+
+return'UNKNOWN';
+}
+
+let output=template;
+for(const replacement of displayValue.slice(1)){
+if(!replacementRegex.test(output)){
+
+console.warn('Too many replacements given');
+break;
+}
+
+output=output.replace(replacementRegex,match=>{
+const granularity=Number(match.match(/[0-9.]+/))||1;
+return match==='%s'?
+replacement.toLocaleString():
+(Math.round(Number(replacement)/granularity)*granularity).toLocaleString();
+});
+}
+
+if(replacementRegex.test(output)){
+
+console.warn('Not enough replacements given');
+}
+
+return output;
+}
+
+
+
+
+
+
+
+
+static showAsPassed(audit){
+switch(audit.scoreDisplayMode){
+case'manual':
+case'not-applicable':
+return true;
+case'error':
+case'informative':
+return false;
+case'numeric':
+case'binary':
+default:
+
+
+
+return Number(audit.score)===1;}
+
+}
+
+
+
+
+
+
+
+static calculateRating(score,scoreDisplayMode){
+
+if(scoreDisplayMode==='manual'||scoreDisplayMode==='not-applicable'){
+return RATINGS.PASS.label;
+}else if(scoreDisplayMode==='error'){
+return RATINGS.ERROR.label;
+}else if(score===null){
+return RATINGS.FAIL.label;
+}
+
+
 let rating=RATINGS.FAIL.label;
 if(score>=RATINGS.PASS.minScore){
 rating=RATINGS.PASS.label;
@@ -20155,8 +23567,9 @@
 
 
 
-static formatNumber(number,decimalPlaces=1){
-return number.toLocaleString(undefined,{maximumFractionDigits:decimalPlaces});
+static formatNumber(number,granularity=0.1){
+const coarseValue=Math.round(number/granularity)*granularity;
+return coarseValue.toLocaleString();
 }
 
 
@@ -20164,8 +23577,8 @@
 
 
 
-static formatBytesToKB(size,decimalPlaces=2){
-const kbs=(size/1024).toLocaleString(undefined,{maximumFractionDigits:decimalPlaces});
+static formatBytesToKB(size,granularity=0.1){
+const kbs=(Math.round(size/1024/granularity)*granularity).toLocaleString();
 return`${kbs}${NBSP}KB`;
 }
 
@@ -20184,6 +23597,16 @@
 
 
 
+static formatSeconds(ms,granularity=0.1){
+const coarseTime=Math.round(ms/1000/granularity)*granularity;
+return`${coarseTime.toLocaleString()}${NBSP}s`;
+}
+
+
+
+
+
+
 static formatDateTime(date){
 const options={
 month:'short',day:'numeric',year:'numeric',
@@ -20205,10 +23628,10 @@
 
 
 
-
-static formatDuration(timeInSeconds,zeroLabel='None'){
-if(timeInSeconds===0){
-return zeroLabel;
+static formatDuration(timeInMilliseconds){
+let timeInSeconds=timeInMilliseconds/1000;
+if(Math.round(timeInSeconds)===0){
+return'None';
 }
 
 
@@ -20238,7 +23661,9 @@
 
 
 static getURLDisplayName(parsedUrl,options){
-options=options||{};
+
+options=options||{numPathParts:undefined,preserveQuery:undefined,
+preserveHost:undefined};
 const numPathParts=options.numPathParts!==undefined?options.numPathParts:2;
 const preserveQuery=options.preserveQuery!==undefined?options.preserveQuery:true;
 const preserveHost=options.preserveHost||false;
@@ -20307,7 +23732,11 @@
 
 static parseURL(url){
 const parsedUrl=new URL(url);
-return{file:Util.getURLDisplayName(parsedUrl),hostname:parsedUrl.hostname};
+return{
+file:Util.getURLDisplayName(parsedUrl),
+hostname:parsedUrl.hostname,
+origin:parsedUrl.origin};
+
 }
 
 
@@ -20317,19 +23746,88 @@
 
 static chainDuration(startTime,endTime){
 return Util.formatNumber((endTime-startTime)*1000);
+}
+
+
+
+
+
+static getEnvironmentDisplayValues(settings){
+const emulationDesc=Util.getEmulationDescriptions(settings);
+
+return[
+{
+name:'Device',
+description:emulationDesc.deviceEmulation},
+
+{
+name:'Network throttling',
+description:emulationDesc.networkThrottling},
+
+{
+name:'CPU throttling',
+description:emulationDesc.cpuThrottling}];
+
+
+}
+
+
+
+
+
+static getEmulationDescriptions(settings){
+let cpuThrottling;
+let networkThrottling;
+let summary;
+
+const throttling=settings.throttling;
+
+switch(settings.throttlingMethod){
+case'provided':
+cpuThrottling='Provided by environment';
+networkThrottling='Provided by environment';
+summary='No throttling applied';
+break;
+case'devtools':{
+const{cpuSlowdownMultiplier,requestLatencyMs}=throttling;
+cpuThrottling=`${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (DevTools)`;
+networkThrottling=`${Util.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, `+
+`${Util.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, `+
+`${Util.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;
+summary='Throttled Fast 3G network';
+break;
+}
+case'simulate':{
+const{cpuSlowdownMultiplier,rttMs,throughputKbps}=throttling;
+cpuThrottling=`${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
+networkThrottling=`${Util.formatNumber(rttMs)}${NBSP}ms TCP RTT, `+
+`${Util.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;
+summary='Simulated Fast 3G network';
+break;
+}
+default:
+cpuThrottling='Unknown';
+networkThrottling='Unknown';
+summary='Unknown';}
+
+
+const deviceEmulation=settings.disableDeviceEmulation?'No emulation':'Emulated Nexus 5X';
+return{
+deviceEmulation,
+cpuThrottling,
+networkThrottling,
+summary:`${deviceEmulation}, ${summary}`};
+
 }}
 
 
 if(typeof module!=='undefined'&&module.exports){
 module.exports=Util;
 }else{
-
 self.Util=Util;
 }
 
-},{}],44:[function(require,module,exports){
-(function(process,__dirname){
-
+},{}],49:[function(require,module,exports){
 
 
 
@@ -20337,46 +23835,179 @@
 
 'use strict';
 
+const htmlReportAssets=require('./html/html-report-assets');
+
+class ReportGenerator{
+
+
+
+
+
+
+static replaceStrings(source,replacements){
+if(replacements.length===0){
+return source;
+}
+
+const firstReplacement=replacements[0];
+const nextReplacements=replacements.slice(1);
+return source.
+split(firstReplacement.search).
+map(part=>ReportGenerator.replaceStrings(part,nextReplacements)).
+join(firstReplacement.replacement);
+}
+
+
+
+
+
+
+static generateReportHtml(lhr){
+const sanitizedJson=JSON.stringify(lhr).
+replace(/</g,'\\u003c').
+replace(/\u2028/g,'\\u2028').
+replace(/\u2029/g,'\\u2029');
+const sanitizedJavascript=htmlReportAssets.REPORT_JAVASCRIPT.replace(/<\//g,'\\u003c/');
+
+return ReportGenerator.replaceStrings(htmlReportAssets.REPORT_TEMPLATE,[
+{search:'%%LIGHTHOUSE_JSON%%',replacement:sanitizedJson},
+{search:'%%LIGHTHOUSE_JAVASCRIPT%%',replacement:sanitizedJavascript},
+{search:'/*%%LIGHTHOUSE_CSS%%*/',replacement:htmlReportAssets.REPORT_CSS},
+{search:'%%LIGHTHOUSE_TEMPLATES%%',replacement:htmlReportAssets.REPORT_TEMPLATES}]);
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+static generateReportCSV(lhr){
+
+
+const CRLF='\r\n';
+const separator=',';
+
+const escape=value=>`"${value.replace(/"/g,'""')}"`;
+
+
+const header=['category','name','title','type','score'];
+const table=Object.values(lhr.categories).map(category=>{
+return category.auditRefs.map(auditRef=>{
+const audit=lhr.audits[auditRef.id];
+
+const numericScore=audit.score===null?-1:audit.score;
+return[category.title,audit.id,audit.title,audit.scoreDisplayMode,numericScore].
+map(value=>value.toString()).
+map(escape);
+});
+});
+
+
+const flattedTable=[].concat(...table);
+return[header,...flattedTable].map(row=>row.join(separator)).join(CRLF);
+}
+
+
+
+
+
+
+
+static generateReport(lhr,outputModes){
+const outputAsArray=Array.isArray(outputModes);
+if(typeof outputModes==='string')outputModes=[outputModes];
+
+const output=outputModes.map(outputMode=>{
+
+if(outputMode==='html'){
+return ReportGenerator.generateReportHtml(lhr);
+}
+
+if(outputMode==='csv'){
+return ReportGenerator.generateReportCSV(lhr);
+}
+
+if(outputMode==='json'){
+return JSON.stringify(lhr,null,2);
+}
+
+throw new Error('Invalid output mode: '+outputMode);
+});
+
+return outputAsArray?output:output[0];
+}}
+
+
+module.exports=ReportGenerator;
+
+},{"./html/html-report-assets":58}],50:[function(require,module,exports){
+(function(process,__dirname){
+
+
+
+
+
+'use strict';
+
+const isDeepEqual=require('lodash.isequal');
 const Driver=require('./gather/driver.js');
 const GatherRunner=require('./gather/gather-runner');
 const ReportScoring=require('./scoring');
 const Audit=require('./audits/audit');
-const emulation=require('./lib/emulation');
 const log=require('lighthouse-logger');
 const assetSaver=require('./lib/asset-saver');
 
 const path=require('path');
 const URL=require('./lib/url-shim');
 const Sentry=require('./lib/sentry');
+const generateReport=require('./report/report-generator').generateReport;
 
-const basePath=path.join(process.cwd(),'latest-run');
+const Connection=require('./gather/connections/connection.js');
 
 class Runner{
-static run(connection,opts){
 
-opts.flags=opts.flags||{};
+
+
+
+
+static async run(connection,opts){
+try{
+const startTime=Date.now();
+const settings=opts.config.settings;
+
+
+
 
 
 const lighthouseRunWarnings=[];
 
 
-opts.initialUrl=opts.url;
-if(typeof opts.initialUrl!=='string'||opts.initialUrl.length===0){
-return Promise.reject(new Error('You must provide a url to the runner'));
+const rawRequestedUrl=opts.url;
+if(typeof rawRequestedUrl!=='string'||rawRequestedUrl.length===0){
+throw new Error(`You must provide a url to the runner. '${rawRequestedUrl}' provided.`);
 }
 
 let parsedURL;
 try{
 parsedURL=new URL(opts.url);
 }catch(e){
-const err=new Error('The url provided should have a proper protocol and hostname.');
-return Promise.reject(err);
+throw new Error('The url provided should have a proper protocol and hostname.');
 }
 
 const sentryContext=Sentry.getContext();
+
 Sentry.captureBreadcrumb({
 message:'Run started',
 category:'lifecycle',
+
 data:sentryContext&&sentryContext.extra});
 
 
@@ -20387,10 +24018,7 @@
 }
 
 
-opts.url=parsedURL.href;
-
-
-let run=Promise.resolve();
+const requestedUrl=parsedURL.href;
 
 
 
@@ -20398,66 +24026,74 @@
 
 
 
-if(opts.flags.auditMode&&!opts.flags.gatherMode){
-run=run.then(_=>Runner._loadArtifactsFromDisk());
-}else if(opts.config.artifacts){
-run=run.then(_=>opts.config.artifacts);
+let artifacts;
+if(settings.auditMode&&!settings.gatherMode){
+
+const path=Runner._getArtifactsPath(settings);
+artifacts=await assetSaver.loadArtifacts(path);
 }else{
-run=run.then(_=>Runner._gatherArtifactsFromBrowser(opts,connection));
+artifacts=await Runner._gatherArtifactsFromBrowser(requestedUrl,opts,connection);
+
+if(settings.gatherMode){
+const path=Runner._getArtifactsPath(settings);
+await assetSaver.saveArtifacts(artifacts,path);
+}
 }
 
 
-if(opts.flags.gatherMode&&!opts.flags.auditMode)return run;
+if(settings.gatherMode&&!settings.auditMode)return;
 
 
-run=run.then(artifacts=>Runner._runAudits(opts,artifacts));
+if(!opts.config.audits){
+throw new Error('No audits to evaluate.');
+}
+const auditResults=await Runner._runAudits(settings,opts.config.audits,artifacts);
 
 
-run=run.then(runResults=>{
 log.log('status','Generating results...');
 
-if(runResults.artifacts.LighthouseRunWarnings){
-lighthouseRunWarnings.push(...runResults.artifacts.LighthouseRunWarnings);
+if(artifacts.LighthouseRunWarnings){
+lighthouseRunWarnings.push(...artifacts.LighthouseRunWarnings);
 }
 
 
+
+const lighthouseVersion=require('../package.json').version;
+
+
 const resultsById={};
-for(const audit of runResults.auditResults)resultsById[audit.name]=audit;
-
-let report;
-if(opts.config.categories){
-report=Runner._scoreAndCategorize(opts,resultsById);
+for(const audit of auditResults){
+resultsById[audit.id]=audit;
 }
 
-return{
-userAgent:runResults.artifacts.UserAgent,
-lighthouseVersion:require('../package').version,
-generatedTime:new Date().toJSON(),
-initialUrl:opts.initialUrl,
-url:opts.url,
+
+let categories={};
+if(opts.config.categories){
+categories=ReportScoring.scoreAllCategories(opts.config.categories,resultsById);
+}
+
+
+const lhr={
+userAgent:artifacts.UserAgent,
+lighthouseVersion,
+fetchTime:artifacts.fetchTime,
+requestedUrl:requestedUrl,
+finalUrl:artifacts.URL.finalUrl,
 runWarnings:lighthouseRunWarnings,
 audits:resultsById,
-artifacts:runResults.artifacts,
-runtimeConfig:Runner.getRuntimeConfig(opts.flags),
-score:report?report.score:0,
-reportCategories:report?report.categories:[],
-reportGroups:opts.config.groups};
+configSettings:settings,
+categories,
+categoryGroups:opts.config.groups,
+timing:{total:Date.now()-startTime}};
 
-}).catch(err=>{
-return Sentry.captureException(err,{level:'fatal'}).then(()=>{
+
+const report=generateReport(lhr,settings.output);
+return{lhr,artifacts,report};
+}catch(err){
+
+await Sentry.captureException(err,{level:'fatal'});
 throw err;
-});
-});
-
-return run;
 }
-
-
-
-
-
-static _loadArtifactsFromDisk(){
-return assetSaver.loadArtifacts(basePath);
 }
 
 
@@ -20466,27 +24102,20 @@
 
 
 
-static _gatherArtifactsFromBrowser(opts,connection){
-if(!opts.config.passes){
-return Promise.reject(new Error('No browser artifacts are either provided or requested.'));
+
+static async _gatherArtifactsFromBrowser(requestedUrl,runnerOpts,connection){
+if(!runnerOpts.config.passes){
+throw new Error('No browser artifacts are either provided or requested.');
 }
 
-opts.driver=opts.driverMock||new Driver(connection);
-return GatherRunner.run(opts.config.passes,opts).then(artifacts=>{
-const flags=opts.flags;
-const shouldSave=flags.gatherMode;
-const p=shouldSave?Runner._saveArtifacts(artifacts):Promise.resolve();
-return p.then(_=>artifacts);
-});
-}
+const driver=runnerOpts.driverMock||new Driver(connection);
+const gatherOpts={
+driver,
+requestedUrl,
+settings:runnerOpts.config.settings};
 
-
-
-
-
-
-static _saveArtifacts(artifacts){
-return assetSaver.saveArtifacts(artifacts,basePath);
+const artifacts=await GatherRunner.run(runnerOpts.config.passes,gatherOpts);
+return artifacts;
 }
 
 
@@ -20495,35 +24124,30 @@
 
 
 
-static _runAudits(opts,artifacts){
-if(!opts.config.audits){
-return Promise.reject(new Error('No audits to evaluate.'));
-}
 
+static async _runAudits(settings,audits,artifacts){
 log.log('status','Analyzing and running audits...');
-artifacts=Object.assign(Runner.instantiateComputedArtifacts(),
-artifacts||opts.config.artifacts);
+artifacts=Object.assign({},Runner.instantiateComputedArtifacts(),artifacts);
+
+if(artifacts.settings){
+const overrides={gatherMode:undefined,auditMode:undefined,output:undefined};
+const normalizedGatherSettings=Object.assign({},artifacts.settings,overrides);
+const normalizedAuditSettings=Object.assign({},settings,overrides);
+
+
+if(!isDeepEqual(normalizedGatherSettings,normalizedAuditSettings)){
+throw new Error('Cannot change settings between gathering and auditing');
+}
+}
 
 
 const auditResults=[];
-let promise=Promise.resolve();
-for(const audit of opts.config.audits){
-promise=promise.then(_=>{
-return Runner._runAudit(audit,artifacts).then(ret=>auditResults.push(ret));
-});
-}
-return promise.then(_=>{
-const runResults={artifacts,auditResults};
-return runResults;
-});
+for(const auditDefn of audits){
+const auditResult=await Runner._runAudit(auditDefn,artifacts,settings);
+auditResults.push(auditResult);
 }
 
-
-
-
-
-static _scoreAndCategorize(opts,resultsById){
-return ReportScoring.scoreAllCategories(opts.config,resultsById);
+return auditResults;
 }
 
 
@@ -20534,15 +24158,17 @@
 
 
 
-static _runAudit(audit,artifacts){
+
+static async _runAudit(auditDefn,artifacts,settings){
+const audit=auditDefn.implementation;
 const status=`Evaluating: ${audit.meta.description}`;
 
-return Promise.resolve().then(_=>{
 log.log('status',status);
-
+let auditResult;
+try{
 
 for(const artifactName of audit.meta.requiredArtifacts){
-const noArtifact=typeof artifacts[artifactName]==='undefined';
+const noArtifact=artifacts[artifactName]===undefined;
 
 
 
@@ -20557,7 +24183,11 @@
 
 
 if(artifacts[artifactName]instanceof Error){
+
+
 const artifactError=artifacts[artifactName];
+
+
 Sentry.captureException(artifactError,{
 tags:{gatherer:artifactName},
 level:'error'});
@@ -20569,30 +24199,33 @@
 
 const error=new Error(
 `Required ${artifactName} gatherer encountered an error: ${artifactError.message}`);
+
 error.expected=true;
 throw error;
 }
 }
 
-return audit.audit(artifacts);
 
-}).then(auditResult=>Audit.generateAuditResult(audit,auditResult)).
-catch(err=>{
+const auditOptions=Object.assign({},audit.defaultOptions,auditDefn.options);
+const product=await audit.audit(artifacts,{options:auditOptions,settings:settings});
+auditResult=Audit.generateAuditResult(audit,product);
+}catch(err){
 log.warn(audit.meta.name,`Caught exception: ${err.message}`);
 if(err.fatal){
 throw err;
 }
 
+
 Sentry.captureException(err,{tags:{audit:audit.meta.name},level:'error'});
 
-const debugString=err.friendlyMessage?
+const errorMessage=err.friendlyMessage?
 `${err.friendlyMessage} (${err.message})`:
 `Audit error: ${err.message}`;
-return Audit.generateErrorAuditResult(audit,debugString);
-}).then(result=>{
+auditResult=Audit.generateErrorAuditResult(audit,errorMessage);
+}
+
 log.verbose('statusEnd',status);
-return result;
-});
+return auditResult;
 }
 
 
@@ -20610,15 +24243,15 @@
 
 
 const fileList=[
-...[".DS_Store","accessibility","audit.js","bootup-time.js","byte-efficiency","cache-start-url.js","consistently-interactive.js","content-width.js","critical-request-chains.js","deprecations.js","dobetterweb","errors-in-console.js","estimated-input-latency.js","first-interactive.js","first-meaningful-paint.js","font-display.js","image-aspect-ratio.js","is-on-https.js","load-fast-enough-for-pwa.js","mainthread-work-breakdown.js","manifest-short-name-length.js","manual","mixed-content.js","multi-check-audit.js","predictive-perf.js","redirects-http.js","redirects.js","screenshot-thumbnails.js","seo","service-worker.js","speed-index-metric.js","splash-screen.js","themed-omnibox.js","time-to-first-byte.js","user-timings.js","uses-rel-preload.js","viewport.js","violation-audit.js","webapp-install-banner.js","without-javascript.js","works-offline.js"],
-...["appcache-manifest.js","dom-size.js","external-anchors-use-rel-noopener.js","geolocation-on-start.js","link-blocking-first-paint.js","no-document-write.js","no-mutation-events.js","no-vulnerable-libraries.js","no-websql.js","notification-on-start.js","password-inputs-can-be-pasted-into.js","script-blocking-first-paint.js","uses-http2.js","uses-passive-event-listeners.js"].map(f=>`dobetterweb/${f}`),
-...["canonical.js","font-size.js","hreflang.js","http-status-code.js","is-crawlable.js","link-text.js","manual","meta-description.js","plugins.js"].map(f=>`seo/${f}`),
+...["accessibility","audit.js","bootup-time.js","byte-efficiency","content-width.js","critical-request-chains.js","deprecations.js","dobetterweb","errors-in-console.js","estimated-input-latency.js","first-contentful-paint.js","first-cpu-idle.js","first-meaningful-paint.js","font-display.js","image-aspect-ratio.js","interactive.js","is-on-https.js","load-fast-enough-for-pwa.js","mainthread-work-breakdown.js","manifest-short-name-length.js","manual","metrics.js","mixed-content.js","multi-check-audit.js","network-requests.js","predictive-perf.js","redirects-http.js","redirects.js","screenshot-thumbnails.js","seo","service-worker.js","speed-index.js","splash-screen.js","themed-omnibox.js","time-to-first-byte.js","user-timings.js","uses-rel-preconnect.js","uses-rel-preload.js","viewport.js","violation-audit.js","webapp-install-banner.js","without-javascript.js","works-offline.js"],
+...["appcache-manifest.js","dom-size.js","external-anchors-use-rel-noopener.js","geolocation-on-start.js","no-document-write.js","no-mutation-events.js","no-vulnerable-libraries.js","no-websql.js","notification-on-start.js","password-inputs-can-be-pasted-into.js","uses-http2.js","uses-passive-event-listeners.js"].map(f=>`dobetterweb/${f}`),
+...["canonical.js","font-size.js","hreflang.js","http-status-code.js","is-crawlable.js","link-text.js","manual","meta-description.js","plugins.js","robots-txt.js"].map(f=>`seo/${f}`),
 ...["mobile-friendly.js","structured-data.js"].map(f=>`seo/manual/${f}`),
 ...["accesskeys.js","aria-allowed-attr.js","aria-required-attr.js","aria-required-children.js","aria-required-parent.js","aria-roles.js","aria-valid-attr-value.js","aria-valid-attr.js","audio-caption.js","axe-audit.js","button-name.js","bypass.js","color-contrast.js","definition-list.js","dlitem.js","document-title.js","duplicate-id.js","frame-title.js","html-has-lang.js","html-lang-valid.js","image-alt.js","input-image-alt.js","label.js","layout-table.js","link-name.js","list.js","listitem.js","manual","meta-refresh.js","meta-viewport.js","object-alt.js","tabindex.js","td-headers-attr.js","th-has-data-cells.js","valid-lang.js","video-caption.js","video-description.js"].
 map(f=>`accessibility/${f}`),
 ...["custom-controls-labels.js","custom-controls-roles.js","focus-traps.js","focusable-controls.js","heading-levels.js","logical-tab-order.js","managed-focus.js","offscreen-content-hidden.js","use-landmarks.js","visual-order-follows-dom.js"].
 map(f=>`accessibility/manual/${f}`),
-...["byte-efficiency-audit.js","offscreen-images.js","total-byte-weight.js","unminified-css.js","unminified-javascript.js","unused-css-rules.js","unused-javascript.js","uses-long-cache-ttl.js","uses-optimized-images.js","uses-request-compression.js","uses-responsive-images.js","uses-webp-images.js"].
+...["byte-efficiency-audit.js","efficient-animated-content.js","offscreen-images.js","render-blocking-resources.js","total-byte-weight.js","unminified-css.js","unminified-javascript.js","unused-css-rules.js","unused-javascript.js","uses-long-cache-ttl.js","uses-optimized-images.js","uses-responsive-images.js","uses-text-compression.js","uses-webp-images.js"].
 map(f=>`byte-efficiency/${f}`),
 ...["manual-audit.js","pwa-cross-browser.js","pwa-each-page-has-url.js","pwa-page-transitions.js"].map(f=>`manual/${f}`)];
 
@@ -20633,8 +24266,8 @@
 
 static getGathererList(){
 const fileList=[
-...["accessibility.js","cache-contents.js","chrome-console-messages.js","css-usage.js","dobetterweb","fonts.js","gatherer.js","html-without-javascript.js","http-redirect.js","image-usage.js","js-usage.js","manifest.js","mixed-content.js","offline.js","runtime-exceptions.js","scripts.js","seo","service-worker.js","start-url.js","theme-color.js","url.js","viewport-dimensions.js","viewport.js"],
-...["canonical.js","crawlable-links.js","embedded-content.js","font-size.js","hreflang.js","meta-description.js","meta-robots.js"].map(f=>`seo/${f}`),
+...["accessibility.js","cache-contents.js","chrome-console-messages.js","css-usage.js","dobetterweb","fonts.js","gatherer.js","html-without-javascript.js","http-redirect.js","image-usage.js","js-usage.js","manifest.js","mixed-content.js","offline.js","runtime-exceptions.js","scripts.js","seo","service-worker.js","start-url.js","theme-color.js","viewport-dimensions.js","viewport.js"],
+...["canonical.js","crawlable-links.js","embedded-content.js","font-size.js","hreflang.js","meta-description.js","meta-robots.js","robots-txt.js"].map(f=>`seo/${f}`),
 ...["all-event-listeners.js","anchors-with-no-rel-noopener.js","appcache.js","domstats.js","js-libraries.js","optimized-images.js","password-inputs-with-prevented-paste.js","response-compression.js","tags-blocking-first-paint.js","websql.js"].
 map(f=>`dobetterweb/${f}`)];
 
@@ -20644,15 +24277,30 @@
 
 
 
+
+static getComputedGathererList(){
+const filenamesToSkip=[
+'computed-artifact.js',
+'metrics',
+'metrics/lantern-metric.js',
+'metrics/metric.js'];
+
+
+const fileList=[
+...["computed-artifact.js","critical-request-chains.js","dtm-model.js","load-simulator.js","main-resource.js","manifest-values.js","metrics","network-analysis.js","network-records.js","network-throughput.js","page-dependency-graph.js","pushed-requests.js","screenshots.js","speedline.js","trace-of-tab.js"],
+...["estimated-input-latency.js","first-contentful-paint.js","first-cpu-idle.js","first-meaningful-paint.js","interactive.js","lantern-estimated-input-latency.js","lantern-first-contentful-paint.js","lantern-first-cpu-idle.js","lantern-first-meaningful-paint.js","lantern-interactive.js","lantern-metric.js","lantern-speed-index.js","metric.js","speed-index.js"].map(f=>`metrics/${f}`)];
+
+
+return fileList.filter(f=>/\.js$/.test(f)&&!filenamesToSkip.includes(f)).sort();
+}
+
+
+
+
+
 static instantiateComputedArtifacts(){
 const computedArtifacts={};
-const filenamesToSkip=[
-'computed-artifact.js'];
-
-
-["computed-artifact.js","critical-request-chains.js","dtm-model.js","first-interactive.js","main-resource.js","manifest-values.js","network-records.js","network-throughput.js","page-dependency-graph.js","pushed-requests.js","screenshots.js","speedline.js","trace-of-tab.js"].forEach(function(filename){
-if(filenamesToSkip.includes(filename))return;
-
+Runner.getComputedGathererList().forEach(function(filename){
 
 filename=filename.replace(/\.js$/,'');
 const ArtifactClass=require('./gather/computed/'+filename);
@@ -20660,6 +24308,7 @@
 
 computedArtifacts['request'+artifact.name]=artifact.request.bind(artifact);
 });
+
 return computedArtifacts;
 }
 
@@ -20714,38 +24363,21 @@
 
 
 
-static getRuntimeConfig(flags){
-const emulationDesc=emulation.getEmulationDesc();
-const environment=[
-{
-name:'Device Emulation',
-enabled:!flags.disableDeviceEmulation,
-description:emulationDesc['deviceEmulation']},
-
-{
-name:'Network Throttling',
-enabled:!flags.disableNetworkThrottling,
-description:emulationDesc['networkThrottling']},
-
-{
-name:'CPU Throttling',
-enabled:!flags.disableCpuThrottling,
-description:emulationDesc['cpuThrottling']}];
+static _getArtifactsPath(settings){
+const{auditMode,gatherMode}=settings;
 
 
+if(typeof auditMode==='string')return path.resolve(process.cwd(),auditMode);
+if(typeof gatherMode==='string')return path.resolve(process.cwd(),gatherMode);
 
-return{
-environment,
-blockedUrlPatterns:flags.blockedUrlPatterns||[],
-extraHeaders:flags.extraHeaders||{}};
-
+return path.join(process.cwd(),'latest-run');
 }}
 
 
 module.exports=Runner;
 
 }).call(this,require('_process'),"/../lighthouse-core");
-},{"../package":146,"./audits/audit":2,"./gather/driver.js":14,"./gather/gather-runner":15,"./lib/asset-saver":18,"./lib/emulation":27,"./lib/sentry":33,"./lib/url-shim":41,"./scoring":45,"_process":71,"lighthouse-logger":137,"path":69}],45:[function(require,module,exports){
+},{"../package.json":154,"./audits/audit":2,"./gather/connections/connection.js":14,"./gather/driver.js":17,"./gather/gather-runner":18,"./lib/asset-saver":21,"./lib/sentry":39,"./lib/url-shim":"url","./report/report-generator":49,"./scoring":51,"_process":77,"lighthouse-logger":143,"lodash.isequal":144,"path":75}],51:[function(require,module,exports){
 
 
 
@@ -20754,6 +24386,15 @@
 
 'use strict';
 
+const Audit=require('./audits/audit');
+
+
+
+
+
+
+const clampTo2Decimals=val=>Math.round(val*100)/100;
+
 class ReportScoring{
 
 
@@ -20761,16 +24402,25 @@
 
 
 static arithmeticMean(items){
-const results=items.reduce((result,item)=>{
-const score=Number(item.score)||0;
-const weight=Number(item.weight)||0;
+
+items=items.filter(item=>item.weight>0);
+
+if(items.some(item=>item.score===null))return null;
+
+const results=items.reduce(
+(result,item)=>{
+const score=item.score;
+const weight=item.weight;
+
 return{
 weight:result.weight+weight,
 sum:result.sum+score*weight};
 
-},{weight:0,sum:0});
+},
+{weight:0,sum:0});
 
-return results.sum/results.weight||0;
+
+return clampTo2Decimals(results.sum/results.weight||0);
 }
 
 
@@ -20779,43 +24429,49 @@
 
 
 
-static scoreAllCategories(config,resultsByAuditId){
-const categories=Object.keys(config.categories).map(categoryId=>{
-const category=config.categories[categoryId];
-category.id=categoryId;
+static scoreAllCategories(configCategories,resultsByAuditId){
+const scoredCategories={};
 
-const audits=category.audits.map(audit=>{
-const result=resultsByAuditId[audit.id];
+for(const[categoryId,configCategory]of Object.entries(configCategories)){
 
-let auditScore=Number(result.score)||0;
-if(typeof result.score==='boolean'){
-auditScore=result.score?100:0;
+const auditRefs=configCategory.auditRefs.map(configMember=>{
+const member={...configMember};
+
+
+
+
+
+const result=resultsByAuditId[member.id];
+if(result.scoreDisplayMode===Audit.SCORING_MODES.NOT_APPLICABLE||
+result.scoreDisplayMode===Audit.SCORING_MODES.INFORMATIVE||
+result.scoreDisplayMode===Audit.SCORING_MODES.MANUAL){
+member.weight=0;
 }
 
-
-
-
-if(result.notApplicable){
-auditScore=100;
-audit.weight=0;
-result.informative=true;
-}
-
-return Object.assign({},audit,{result,score:auditScore});
+return member;
 });
 
-const categoryScore=ReportScoring.arithmeticMean(audits);
-return Object.assign({},category,{audits,score:categoryScore});
-});
+const scores=auditRefs.map(auditRef=>({
+score:resultsByAuditId[auditRef.id].score,
+weight:auditRef.weight}));
 
-const overallScore=ReportScoring.arithmeticMean(categories);
-return{score:overallScore,categories};
+const score=ReportScoring.arithmeticMean(scores);
+
+scoredCategories[categoryId]={
+...configCategory,
+auditRefs,
+id:categoryId,
+score};
+
+}
+
+return scoredCategories;
 }}
 
 
 module.exports=ReportScoring;
 
-},{}],46:[function(require,module,exports){
+},{"./audits/audit":2}],52:[function(require,module,exports){
 
 
 
@@ -20826,8 +24482,7 @@
 const RawProtocol=require('../../../lighthouse-core/gather/connections/raw');
 const Runner=require('../../../lighthouse-core/runner');
 const Config=require('../../../lighthouse-core/config/config');
-const defaultConfig=require('../../../lighthouse-core/config/default.js');
-const fastConfig=require('../../../lighthouse-core/config/fast-config.js');
+const defaultConfig=require('../../../lighthouse-core/config/default-config.js');
 const log=require('lighthouse-logger');
 
 
@@ -20840,10 +24495,10 @@
 window.runLighthouseForConnection=function(
 connection,url,options,categoryIDs,
 updateBadgeFn=function(){}){
-const config=options&&options.fastMode?new Config(fastConfig):new Config({
+const config=new Config({
 extends:'lighthouse:default',
-settings:{onlyCategories:categoryIDs}});
-
+settings:{onlyCategories:categoryIDs}},
+options.flags);
 
 
 const runOptions=Object.assign({},options,{url,config});
@@ -20886,7 +24541,7 @@
 log.events.addListener('status',listenCallback);
 };
 
-},{"../../../lighthouse-core/config/config":7,"../../../lighthouse-core/config/default.js":8,"../../../lighthouse-core/config/fast-config.js":9,"../../../lighthouse-core/gather/connections/raw":12,"../../../lighthouse-core/runner":44,"lighthouse-logger":137}],47:[function(require,module,exports){
+},{"../../../lighthouse-core/config/config":7,"../../../lighthouse-core/config/default-config.js":9,"../../../lighthouse-core/gather/connections/raw":15,"../../../lighthouse-core/runner":50,"lighthouse-logger":143}],53:[function(require,module,exports){
 (function(global){
 'use strict';
 
@@ -21380,7 +25035,7 @@
 };
 
 }).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"util/":91}],48:[function(require,module,exports){
+},{"util/":97}],54:[function(require,module,exports){
 'use strict';
 
 exports.byteLength=byteLength;
@@ -21397,68 +25052,102 @@
 revLookup[code.charCodeAt(i)]=i;
 }
 
+
+
 revLookup['-'.charCodeAt(0)]=62;
 revLookup['_'.charCodeAt(0)]=63;
 
-function placeHoldersCount(b64){
+function getLens(b64){
 var len=b64.length;
+
 if(len%4>0){
 throw new Error('Invalid string. Length must be a multiple of 4');
 }
 
 
 
+var validLen=b64.indexOf('=');
+if(validLen===-1)validLen=len;
 
+var placeHoldersLen=validLen===len?
+0:
+4-validLen%4;
 
-
-return b64[len-2]==='='?2:b64[len-1]==='='?1:0;
+return[validLen,placeHoldersLen];
 }
 
-function byteLength(b64){
 
-return b64.length*3/4-placeHoldersCount(b64);
+function byteLength(b64){
+var lens=getLens(b64);
+var validLen=lens[0];
+var placeHoldersLen=lens[1];
+return(validLen+placeHoldersLen)*3/4-placeHoldersLen;
+}
+
+function _byteLength(b64,validLen,placeHoldersLen){
+return(validLen+placeHoldersLen)*3/4-placeHoldersLen;
 }
 
 function toByteArray(b64){
-var i,j,l,tmp,placeHolders,arr;
-var len=b64.length;
-placeHolders=placeHoldersCount(b64);
+var tmp;
+var lens=getLens(b64);
+var validLen=lens[0];
+var placeHoldersLen=lens[1];
 
-arr=new Arr(len*3/4-placeHolders);
+var arr=new Arr(_byteLength(b64,validLen,placeHoldersLen));
+
+var curByte=0;
 
 
-l=placeHolders>0?len-4:len;
+var len=placeHoldersLen>0?
+validLen-4:
+validLen;
 
-var L=0;
-
-for(i=0,j=0;i<l;i+=4,j+=3){
-tmp=revLookup[b64.charCodeAt(i)]<<18|revLookup[b64.charCodeAt(i+1)]<<12|revLookup[b64.charCodeAt(i+2)]<<6|revLookup[b64.charCodeAt(i+3)];
-arr[L++]=tmp>>16&0xFF;
-arr[L++]=tmp>>8&0xFF;
-arr[L++]=tmp&0xFF;
+for(var i=0;i<len;i+=4){
+tmp=
+revLookup[b64.charCodeAt(i)]<<18|
+revLookup[b64.charCodeAt(i+1)]<<12|
+revLookup[b64.charCodeAt(i+2)]<<6|
+revLookup[b64.charCodeAt(i+3)];
+arr[curByte++]=tmp>>16&0xFF;
+arr[curByte++]=tmp>>8&0xFF;
+arr[curByte++]=tmp&0xFF;
 }
 
-if(placeHolders===2){
-tmp=revLookup[b64.charCodeAt(i)]<<2|revLookup[b64.charCodeAt(i+1)]>>4;
-arr[L++]=tmp&0xFF;
-}else if(placeHolders===1){
-tmp=revLookup[b64.charCodeAt(i)]<<10|revLookup[b64.charCodeAt(i+1)]<<4|revLookup[b64.charCodeAt(i+2)]>>2;
-arr[L++]=tmp>>8&0xFF;
-arr[L++]=tmp&0xFF;
+if(placeHoldersLen===2){
+tmp=
+revLookup[b64.charCodeAt(i)]<<2|
+revLookup[b64.charCodeAt(i+1)]>>4;
+arr[curByte++]=tmp&0xFF;
+}
+
+if(placeHoldersLen===1){
+tmp=
+revLookup[b64.charCodeAt(i)]<<10|
+revLookup[b64.charCodeAt(i+1)]<<4|
+revLookup[b64.charCodeAt(i+2)]>>2;
+arr[curByte++]=tmp>>8&0xFF;
+arr[curByte++]=tmp&0xFF;
 }
 
 return arr;
 }
 
 function tripletToBase64(num){
-return lookup[num>>18&0x3F]+lookup[num>>12&0x3F]+lookup[num>>6&0x3F]+lookup[num&0x3F];
+return lookup[num>>18&0x3F]+
+lookup[num>>12&0x3F]+
+lookup[num>>6&0x3F]+
+lookup[num&0x3F];
 }
 
 function encodeChunk(uint8,start,end){
 var tmp;
 var output=[];
 for(var i=start;i<end;i+=3){
-tmp=(uint8[i]<<16)+(uint8[i+1]<<8)+uint8[i+2];
+tmp=
+(uint8[i]<<16&0xFF0000)+(
+uint8[i+1]<<8&0xFF00)+(
+uint8[i+2]&0xFF);
 output.push(tripletToBase64(tmp));
 }
 return output.join('');
@@ -21468,40 +25157,47 @@
 var tmp;
 var len=uint8.length;
 var extraBytes=len%3;
-var output='';
 var parts=[];
 var maxChunkLength=16383;
 
 
 for(var i=0,len2=len-extraBytes;i<len2;i+=maxChunkLength){
-parts.push(encodeChunk(uint8,i,i+maxChunkLength>len2?len2:i+maxChunkLength));
+parts.push(encodeChunk(
+uint8,i,i+maxChunkLength>len2?len2:i+maxChunkLength));
+
 }
 
 
 if(extraBytes===1){
 tmp=uint8[len-1];
-output+=lookup[tmp>>2];
-output+=lookup[tmp<<4&0x3F];
-output+='==';
+parts.push(
+lookup[tmp>>2]+
+lookup[tmp<<4&0x3F]+
+'==');
+
 }else if(extraBytes===2){
 tmp=(uint8[len-2]<<8)+uint8[len-1];
-output+=lookup[tmp>>10];
-output+=lookup[tmp>>4&0x3F];
-output+=lookup[tmp<<2&0x3F];
-output+='=';
-}
+parts.push(
+lookup[tmp>>10]+
+lookup[tmp>>4&0x3F]+
+lookup[tmp<<2&0x3F]+
+'=');
 
-parts.push(output);
+}
 
 return parts.join('');
 }
 
-},{}],49:[function(require,module,exports){
+},{}],55:[function(require,module,exports){
 
-},{}],50:[function(require,module,exports){
+},{}],56:[function(require,module,exports){
 (function(process,Buffer){
-var msg=require('pako/lib/zlib/messages');
-var zstream=require('pako/lib/zlib/zstream');
+'use strict';
+
+
+var assert=require('assert');
+
+var Zstream=require('pako/lib/zlib/zstream');
 var zlib_deflate=require('pako/lib/zlib/deflate.js');
 var zlib_inflate=require('pako/lib/zlib/inflate.js');
 var constants=require('pako/lib/zlib/constants');
@@ -21520,178 +25216,30 @@
 exports.INFLATERAW=6;
 exports.UNZIP=7;
 
+var GZIP_HEADER_ID1=0x1f;
+var GZIP_HEADER_ID2=0x8b;
+
 
 
 
 function Zlib(mode){
-if(mode<exports.DEFLATE||mode>exports.UNZIP)
-throw new TypeError("Bad argument");
+if(typeof mode!=='number'||mode<exports.DEFLATE||mode>exports.UNZIP){
+throw new TypeError('Bad argument');
+}
 
-this.mode=mode;
+this.dictionary=null;
+this.err=0;
+this.flush=0;
 this.init_done=false;
-this.write_in_progress=false;
-this.pending_close=false;
-this.windowBits=0;
 this.level=0;
 this.memLevel=0;
+this.mode=mode;
 this.strategy=0;
-this.dictionary=null;
-}
-
-Zlib.prototype.init=function(windowBits,level,memLevel,strategy,dictionary){
-this.windowBits=windowBits;
-this.level=level;
-this.memLevel=memLevel;
-this.strategy=strategy;
-
-
-if(this.mode===exports.GZIP||this.mode===exports.GUNZIP)
-this.windowBits+=16;
-
-if(this.mode===exports.UNZIP)
-this.windowBits+=32;
-
-if(this.mode===exports.DEFLATERAW||this.mode===exports.INFLATERAW)
-this.windowBits=-this.windowBits;
-
-this.strm=new zstream();
-
-switch(this.mode){
-case exports.DEFLATE:
-case exports.GZIP:
-case exports.DEFLATERAW:
-var status=zlib_deflate.deflateInit2(
-this.strm,
-this.level,
-exports.Z_DEFLATED,
-this.windowBits,
-this.memLevel,
-this.strategy);
-
-break;
-case exports.INFLATE:
-case exports.GUNZIP:
-case exports.INFLATERAW:
-case exports.UNZIP:
-var status=zlib_inflate.inflateInit2(
-this.strm,
-this.windowBits);
-
-break;
-default:
-throw new Error("Unknown mode "+this.mode);}
-
-
-if(status!==exports.Z_OK){
-this._error(status);
-return;
-}
-
+this.windowBits=0;
 this.write_in_progress=false;
-this.init_done=true;
-};
-
-Zlib.prototype.params=function(){
-throw new Error("deflateParams Not supported");
-};
-
-Zlib.prototype._writeCheck=function(){
-if(!this.init_done)
-throw new Error("write before init");
-
-if(this.mode===exports.NONE)
-throw new Error("already finalized");
-
-if(this.write_in_progress)
-throw new Error("write already in progress");
-
-if(this.pending_close)
-throw new Error("close is pending");
-};
-
-Zlib.prototype.write=function(flush,input,in_off,in_len,out,out_off,out_len){
-this._writeCheck();
-this.write_in_progress=true;
-
-var self=this;
-process.nextTick(function(){
-self.write_in_progress=false;
-var res=self._write(flush,input,in_off,in_len,out,out_off,out_len);
-self.callback(res[0],res[1]);
-
-if(self.pending_close)
-self.close();
-});
-
-return this;
-};
-
-
-function bufferSet(data,offset){
-for(var i=0;i<data.length;i++){
-this[offset+i]=data[i];
+this.pending_close=false;
+this.gzip_id_bytes_read=0;
 }
-}
-
-Zlib.prototype.writeSync=function(flush,input,in_off,in_len,out,out_off,out_len){
-this._writeCheck();
-return this._write(flush,input,in_off,in_len,out,out_off,out_len);
-};
-
-Zlib.prototype._write=function(flush,input,in_off,in_len,out,out_off,out_len){
-this.write_in_progress=true;
-
-if(flush!==exports.Z_NO_FLUSH&&
-flush!==exports.Z_PARTIAL_FLUSH&&
-flush!==exports.Z_SYNC_FLUSH&&
-flush!==exports.Z_FULL_FLUSH&&
-flush!==exports.Z_FINISH&&
-flush!==exports.Z_BLOCK){
-throw new Error("Invalid flush value");
-}
-
-if(input==null){
-input=new Buffer(0);
-in_len=0;
-in_off=0;
-}
-
-if(out._set)
-out.set=out._set;else
-
-out.set=bufferSet;
-
-var strm=this.strm;
-strm.avail_in=in_len;
-strm.input=input;
-strm.next_in=in_off;
-strm.avail_out=out_len;
-strm.output=out;
-strm.next_out=out_off;
-
-switch(this.mode){
-case exports.DEFLATE:
-case exports.GZIP:
-case exports.DEFLATERAW:
-var status=zlib_deflate.deflate(strm,flush);
-break;
-case exports.UNZIP:
-case exports.INFLATE:
-case exports.GUNZIP:
-case exports.INFLATERAW:
-var status=zlib_inflate.inflate(strm,flush);
-break;
-default:
-throw new Error("Unknown mode "+this.mode);}
-
-
-if(status!==exports.Z_STREAM_END&&status!==exports.Z_OK){
-this._error(status);
-}
-
-this.write_in_progress=false;
-return[strm.avail_in,strm.avail_out];
-};
 
 Zlib.prototype.close=function(){
 if(this.write_in_progress){
@@ -21701,71 +25249,370 @@
 
 this.pending_close=false;
 
+assert(this.init_done,'close before init');
+assert(this.mode<=exports.UNZIP);
+
 if(this.mode===exports.DEFLATE||this.mode===exports.GZIP||this.mode===exports.DEFLATERAW){
 zlib_deflate.deflateEnd(this.strm);
-}else{
+}else if(this.mode===exports.INFLATE||this.mode===exports.GUNZIP||this.mode===exports.INFLATERAW||this.mode===exports.UNZIP){
 zlib_inflate.inflateEnd(this.strm);
 }
 
 this.mode=exports.NONE;
+
+this.dictionary=null;
 };
 
-Zlib.prototype.reset=function(){
+Zlib.prototype.write=function(flush,input,in_off,in_len,out,out_off,out_len){
+return this._write(true,flush,input,in_off,in_len,out,out_off,out_len);
+};
+
+Zlib.prototype.writeSync=function(flush,input,in_off,in_len,out,out_off,out_len){
+return this._write(false,flush,input,in_off,in_len,out,out_off,out_len);
+};
+
+Zlib.prototype._write=function(async,flush,input,in_off,in_len,out,out_off,out_len){
+assert.equal(arguments.length,8);
+
+assert(this.init_done,'write before init');
+assert(this.mode!==exports.NONE,'already finalized');
+assert.equal(false,this.write_in_progress,'write already in progress');
+assert.equal(false,this.pending_close,'close is pending');
+
+this.write_in_progress=true;
+
+assert.equal(false,flush===undefined,'must provide flush value');
+
+this.write_in_progress=true;
+
+if(flush!==exports.Z_NO_FLUSH&&flush!==exports.Z_PARTIAL_FLUSH&&flush!==exports.Z_SYNC_FLUSH&&flush!==exports.Z_FULL_FLUSH&&flush!==exports.Z_FINISH&&flush!==exports.Z_BLOCK){
+throw new Error('Invalid flush value');
+}
+
+if(input==null){
+input=Buffer.alloc(0);
+in_len=0;
+in_off=0;
+}
+
+this.strm.avail_in=in_len;
+this.strm.input=input;
+this.strm.next_in=in_off;
+this.strm.avail_out=out_len;
+this.strm.output=out;
+this.strm.next_out=out_off;
+this.flush=flush;
+
+if(!async){
+
+this._process();
+
+if(this._checkError()){
+return this._afterSync();
+}
+return;
+}
+
+
+var self=this;
+process.nextTick(function(){
+self._process();
+self._after();
+});
+
+return this;
+};
+
+Zlib.prototype._afterSync=function(){
+var avail_out=this.strm.avail_out;
+var avail_in=this.strm.avail_in;
+
+this.write_in_progress=false;
+
+return[avail_in,avail_out];
+};
+
+Zlib.prototype._process=function(){
+var next_expected_header_byte=null;
+
+
+
+
 switch(this.mode){
 case exports.DEFLATE:
+case exports.GZIP:
 case exports.DEFLATERAW:
-var status=zlib_deflate.deflateReset(this.strm);
+this.err=zlib_deflate.deflate(this.strm,this.flush);
 break;
+case exports.UNZIP:
+if(this.strm.avail_in>0){
+next_expected_header_byte=this.strm.next_in;
+}
+
+switch(this.gzip_id_bytes_read){
+case 0:
+if(next_expected_header_byte===null){
+break;
+}
+
+if(this.strm.input[next_expected_header_byte]===GZIP_HEADER_ID1){
+this.gzip_id_bytes_read=1;
+next_expected_header_byte++;
+
+if(this.strm.avail_in===1){
+
+break;
+}
+}else{
+this.mode=exports.INFLATE;
+break;
+}
+
+
+case 1:
+if(next_expected_header_byte===null){
+break;
+}
+
+if(this.strm.input[next_expected_header_byte]===GZIP_HEADER_ID2){
+this.gzip_id_bytes_read=2;
+this.mode=exports.GUNZIP;
+}else{
+
+
+this.mode=exports.INFLATE;
+}
+
+break;
+default:
+throw new Error('invalid number of gzip magic number bytes read');}
+
+
+
 case exports.INFLATE:
+case exports.GUNZIP:
 case exports.INFLATERAW:
-var status=zlib_inflate.inflateReset(this.strm);
-break;}
+this.err=zlib_inflate.inflate(this.strm,this.flush);
 
 
-if(status!==exports.Z_OK){
-this._error(status);
+if(this.err===exports.Z_NEED_DICT&&this.dictionary){
+
+this.err=zlib_inflate.inflateSetDictionary(this.strm,this.dictionary);
+if(this.err===exports.Z_OK){
+
+this.err=zlib_inflate.inflate(this.strm,this.flush);
+}else if(this.err===exports.Z_DATA_ERROR){
+
+
+
+this.err=exports.Z_NEED_DICT;
+}
+}
+while(this.strm.avail_in>0&&this.mode===exports.GUNZIP&&this.err===exports.Z_STREAM_END&&this.strm.next_in[0]!==0x00){
+
+
+
+
+
+this.reset();
+this.err=zlib_inflate.inflate(this.strm,this.flush);
+}
+break;
+default:
+throw new Error('Unknown mode '+this.mode);}
+
+};
+
+Zlib.prototype._checkError=function(){
+
+switch(this.err){
+case exports.Z_OK:
+case exports.Z_BUF_ERROR:
+if(this.strm.avail_out!==0&&this.flush===exports.Z_FINISH){
+this._error('unexpected end of file');
+return false;
+}
+break;
+case exports.Z_STREAM_END:
+
+break;
+case exports.Z_NEED_DICT:
+if(this.dictionary==null){
+this._error('Missing dictionary');
+}else{
+this._error('Bad dictionary');
+}
+return false;
+default:
+
+this._error('Zlib error');
+return false;}
+
+
+return true;
+};
+
+Zlib.prototype._after=function(){
+if(!this._checkError()){
+return;
+}
+
+var avail_out=this.strm.avail_out;
+var avail_in=this.strm.avail_in;
+
+this.write_in_progress=false;
+
+
+this.callback(avail_in,avail_out);
+
+if(this.pending_close){
+this.close();
 }
 };
 
-Zlib.prototype._error=function(status){
-this.onerror(msg[status]+': '+this.strm.msg,status);
+Zlib.prototype._error=function(message){
+if(this.strm.msg){
+message=this.strm.msg;
+}
+this.onerror(message,this.err);
+
 
 this.write_in_progress=false;
-if(this.pending_close)
+if(this.pending_close){
 this.close();
+}
+};
+
+Zlib.prototype.init=function(windowBits,level,memLevel,strategy,dictionary){
+assert(arguments.length===4||arguments.length===5,'init(windowBits, level, memLevel, strategy, [dictionary])');
+
+assert(windowBits>=8&&windowBits<=15,'invalid windowBits');
+assert(level>=-1&&level<=9,'invalid compression level');
+
+assert(memLevel>=1&&memLevel<=9,'invalid memlevel');
+
+assert(strategy===exports.Z_FILTERED||strategy===exports.Z_HUFFMAN_ONLY||strategy===exports.Z_RLE||strategy===exports.Z_FIXED||strategy===exports.Z_DEFAULT_STRATEGY,'invalid strategy');
+
+this._init(level,windowBits,memLevel,strategy,dictionary);
+this._setDictionary();
+};
+
+Zlib.prototype.params=function(){
+throw new Error('deflateParams Not supported');
+};
+
+Zlib.prototype.reset=function(){
+this._reset();
+this._setDictionary();
+};
+
+Zlib.prototype._init=function(level,windowBits,memLevel,strategy,dictionary){
+this.level=level;
+this.windowBits=windowBits;
+this.memLevel=memLevel;
+this.strategy=strategy;
+
+this.flush=exports.Z_NO_FLUSH;
+
+this.err=exports.Z_OK;
+
+if(this.mode===exports.GZIP||this.mode===exports.GUNZIP){
+this.windowBits+=16;
+}
+
+if(this.mode===exports.UNZIP){
+this.windowBits+=32;
+}
+
+if(this.mode===exports.DEFLATERAW||this.mode===exports.INFLATERAW){
+this.windowBits=-1*this.windowBits;
+}
+
+this.strm=new Zstream();
+
+switch(this.mode){
+case exports.DEFLATE:
+case exports.GZIP:
+case exports.DEFLATERAW:
+this.err=zlib_deflate.deflateInit2(this.strm,this.level,exports.Z_DEFLATED,this.windowBits,this.memLevel,this.strategy);
+break;
+case exports.INFLATE:
+case exports.GUNZIP:
+case exports.INFLATERAW:
+case exports.UNZIP:
+this.err=zlib_inflate.inflateInit2(this.strm,this.windowBits);
+break;
+default:
+throw new Error('Unknown mode '+this.mode);}
+
+
+if(this.err!==exports.Z_OK){
+this._error('Init error');
+}
+
+this.dictionary=dictionary;
+
+this.write_in_progress=false;
+this.init_done=true;
+};
+
+Zlib.prototype._setDictionary=function(){
+if(this.dictionary==null){
+return;
+}
+
+this.err=exports.Z_OK;
+
+switch(this.mode){
+case exports.DEFLATE:
+case exports.DEFLATERAW:
+this.err=zlib_deflate.deflateSetDictionary(this.strm,this.dictionary);
+break;
+default:
+break;}
+
+
+if(this.err!==exports.Z_OK){
+this._error('Failed to set dictionary');
+}
+};
+
+Zlib.prototype._reset=function(){
+this.err=exports.Z_OK;
+
+switch(this.mode){
+case exports.DEFLATE:
+case exports.DEFLATERAW:
+case exports.GZIP:
+this.err=zlib_deflate.deflateReset(this.strm);
+break;
+case exports.INFLATE:
+case exports.INFLATERAW:
+case exports.GUNZIP:
+this.err=zlib_inflate.inflateReset(this.strm);
+break;
+default:
+break;}
+
+
+if(this.err!==exports.Z_OK){
+this._error('Failed to reset stream');
+}
 };
 
 exports.Zlib=Zlib;
-
 }).call(this,require('_process'),require("buffer").Buffer);
-},{"_process":71,"buffer":54,"pako/lib/zlib/constants":63,"pako/lib/zlib/deflate.js":65,"pako/lib/zlib/inflate.js":52,"pako/lib/zlib/messages":66,"pako/lib/zlib/zstream":68}],51:[function(require,module,exports){
-(function(process,Buffer){
+},{"_process":77,"assert":53,"buffer":60,"pako/lib/zlib/constants":69,"pako/lib/zlib/deflate.js":71,"pako/lib/zlib/inflate.js":58,"pako/lib/zlib/zstream":74}],57:[function(require,module,exports){
+(function(process){
+'use strict';
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var Transform=require('_stream_transform');
-
+var Buffer=require('buffer').Buffer;
+var Transform=require('stream').Transform;
 var binding=require('./binding');
 var util=require('util');
 var assert=require('assert').ok;
+var kMaxLength=require('buffer').kMaxLength;
+var kRangeErrorMessage='Cannot create final Buffer. It would be larger '+'than 0x'+kMaxLength.toString(16)+' bytes';
 
 
 
@@ -21789,12 +25636,18 @@
 binding.Z_DEFAULT_LEVEL=binding.Z_DEFAULT_COMPRESSION;
 
 
-Object.keys(binding).forEach(function(k){
-if(k.match(/^Z/))exports[k]=binding[k];
-});
+var bkeys=Object.keys(binding);
+for(var bk=0;bk<bkeys.length;bk++){
+var bkey=bkeys[bk];
+if(bkey.match(/^Z/)){
+Object.defineProperty(exports,bkey,{
+enumerable:true,value:binding[bkey],writable:false});
+
+}
+}
 
 
-exports.codes={
+var codes={
 Z_OK:binding.Z_OK,
 Z_STREAM_END:binding.Z_STREAM_END,
 Z_NEED_DICT:binding.Z_NEED_DICT,
@@ -21806,9 +25659,15 @@
 Z_VERSION_ERROR:binding.Z_VERSION_ERROR};
 
 
-Object.keys(exports.codes).forEach(function(k){
-exports.codes[exports.codes[k]]=k;
-});
+var ckeys=Object.keys(codes);
+for(var ck=0;ck<ckeys.length;ck++){
+var ckey=ckeys[ck];
+codes[codes[ckey]]=ckey;
+}
+
+Object.defineProperty(exports,'codes',{
+enumerable:true,value:Object.freeze(codes),writable:false});
+
 
 exports.Deflate=Deflate;
 exports.Inflate=Inflate;
@@ -21848,7 +25707,6 @@
 
 
 
-
 exports.deflate=function(buffer,opts,callback){
 if(typeof opts==='function'){
 callback=opts;
@@ -21959,20 +25817,27 @@
 }
 
 function onEnd(){
-var buf=Buffer.concat(buffers,nread);
+var buf;
+var err=null;
+
+if(nread>=kMaxLength){
+err=new RangeError(kRangeErrorMessage);
+}else{
+buf=Buffer.concat(buffers,nread);
+}
+
 buffers=[];
-callback(null,buf);
 engine.close();
+callback(err,buf);
 }
 }
 
 function zlibBufferSync(engine,buffer){
-if(typeof buffer==='string')
-buffer=new Buffer(buffer);
-if(!Buffer.isBuffer(buffer))
-throw new TypeError('Not a string or buffer');
+if(typeof buffer==='string')buffer=Buffer.from(buffer);
 
-var flushFlag=binding.Z_FINISH;
+if(!Buffer.isBuffer(buffer))throw new TypeError('Not a string or buffer');
+
+var flushFlag=engine._finishFlushFlag;
 
 return engine._processChunk(buffer,flushFlag);
 }
@@ -21990,8 +25855,6 @@
 }
 
 
-
-
 function Gzip(opts){
 if(!(this instanceof Gzip))return new Gzip(opts);
 Zlib.call(this,opts,binding.GZIP);
@@ -22003,8 +25866,6 @@
 }
 
 
-
-
 function DeflateRaw(opts){
 if(!(this instanceof DeflateRaw))return new DeflateRaw(opts);
 Zlib.call(this,opts,binding.DEFLATERAW);
@@ -22016,12 +25877,14 @@
 }
 
 
-
 function Unzip(opts){
 if(!(this instanceof Unzip))return new Unzip(opts);
 Zlib.call(this,opts,binding.UNZIP);
 }
 
+function isValidFlushFlag(flag){
+return flag===binding.Z_NO_FLUSH||flag===binding.Z_PARTIAL_FLUSH||flag===binding.Z_SYNC_FLUSH||flag===binding.Z_FULL_FLUSH||flag===binding.Z_FINISH||flag===binding.Z_BLOCK;
+}
 
 
 
@@ -22029,57 +25892,49 @@
 
 
 function Zlib(opts,mode){
+var _this=this;
+
 this._opts=opts=opts||{};
 this._chunkSize=opts.chunkSize||exports.Z_DEFAULT_CHUNK;
 
 Transform.call(this,opts);
 
-if(opts.flush){
-if(opts.flush!==binding.Z_NO_FLUSH&&
-opts.flush!==binding.Z_PARTIAL_FLUSH&&
-opts.flush!==binding.Z_SYNC_FLUSH&&
-opts.flush!==binding.Z_FULL_FLUSH&&
-opts.flush!==binding.Z_FINISH&&
-opts.flush!==binding.Z_BLOCK){
+if(opts.flush&&!isValidFlushFlag(opts.flush)){
 throw new Error('Invalid flush flag: '+opts.flush);
 }
+if(opts.finishFlush&&!isValidFlushFlag(opts.finishFlush)){
+throw new Error('Invalid flush flag: '+opts.finishFlush);
 }
+
 this._flushFlag=opts.flush||binding.Z_NO_FLUSH;
+this._finishFlushFlag=typeof opts.finishFlush!=='undefined'?opts.finishFlush:binding.Z_FINISH;
 
 if(opts.chunkSize){
-if(opts.chunkSize<exports.Z_MIN_CHUNK||
-opts.chunkSize>exports.Z_MAX_CHUNK){
+if(opts.chunkSize<exports.Z_MIN_CHUNK||opts.chunkSize>exports.Z_MAX_CHUNK){
 throw new Error('Invalid chunk size: '+opts.chunkSize);
 }
 }
 
 if(opts.windowBits){
-if(opts.windowBits<exports.Z_MIN_WINDOWBITS||
-opts.windowBits>exports.Z_MAX_WINDOWBITS){
+if(opts.windowBits<exports.Z_MIN_WINDOWBITS||opts.windowBits>exports.Z_MAX_WINDOWBITS){
 throw new Error('Invalid windowBits: '+opts.windowBits);
 }
 }
 
 if(opts.level){
-if(opts.level<exports.Z_MIN_LEVEL||
-opts.level>exports.Z_MAX_LEVEL){
+if(opts.level<exports.Z_MIN_LEVEL||opts.level>exports.Z_MAX_LEVEL){
 throw new Error('Invalid compression level: '+opts.level);
 }
 }
 
 if(opts.memLevel){
-if(opts.memLevel<exports.Z_MIN_MEMLEVEL||
-opts.memLevel>exports.Z_MAX_MEMLEVEL){
+if(opts.memLevel<exports.Z_MIN_MEMLEVEL||opts.memLevel>exports.Z_MAX_MEMLEVEL){
 throw new Error('Invalid memLevel: '+opts.memLevel);
 }
 }
 
 if(opts.strategy){
-if(opts.strategy!=exports.Z_FILTERED&&
-opts.strategy!=exports.Z_HUFFMAN_ONLY&&
-opts.strategy!=exports.Z_RLE&&
-opts.strategy!=exports.Z_FIXED&&
-opts.strategy!=exports.Z_DEFAULT_STRATEGY){
+if(opts.strategy!=exports.Z_FILTERED&&opts.strategy!=exports.Z_HUFFMAN_ONLY&&opts.strategy!=exports.Z_RLE&&opts.strategy!=exports.Z_FIXED&&opts.strategy!=exports.Z_DEFAULT_STRATEGY){
 throw new Error('Invalid strategy: '+opts.strategy);
 }
 }
@@ -22090,14 +25945,14 @@
 }
 }
 
-this._binding=new binding.Zlib(mode);
+this._handle=new binding.Zlib(mode);
 
 var self=this;
 this._hadError=false;
-this._binding.onerror=function(message,errno){
+this._handle.onerror=function(message,errno){
 
 
-self._binding=null;
+_close(self);
 self._hadError=true;
 
 var error=new Error(message);
@@ -22112,40 +25967,39 @@
 var strategy=exports.Z_DEFAULT_STRATEGY;
 if(typeof opts.strategy==='number')strategy=opts.strategy;
 
-this._binding.init(opts.windowBits||exports.Z_DEFAULT_WINDOWBITS,
-level,
-opts.memLevel||exports.Z_DEFAULT_MEMLEVEL,
-strategy,
-opts.dictionary);
+this._handle.init(opts.windowBits||exports.Z_DEFAULT_WINDOWBITS,level,opts.memLevel||exports.Z_DEFAULT_MEMLEVEL,strategy,opts.dictionary);
 
-this._buffer=new Buffer(this._chunkSize);
+this._buffer=Buffer.allocUnsafe(this._chunkSize);
 this._offset=0;
-this._closed=false;
 this._level=level;
 this._strategy=strategy;
 
 this.once('end',this.close);
+
+Object.defineProperty(this,'_closed',{
+get:function(){
+return!_this._handle;
+},
+configurable:true,
+enumerable:true});
+
 }
 
 util.inherits(Zlib,Transform);
 
 Zlib.prototype.params=function(level,strategy,callback){
-if(level<exports.Z_MIN_LEVEL||
-level>exports.Z_MAX_LEVEL){
+if(level<exports.Z_MIN_LEVEL||level>exports.Z_MAX_LEVEL){
 throw new RangeError('Invalid compression level: '+level);
 }
-if(strategy!=exports.Z_FILTERED&&
-strategy!=exports.Z_HUFFMAN_ONLY&&
-strategy!=exports.Z_RLE&&
-strategy!=exports.Z_FIXED&&
-strategy!=exports.Z_DEFAULT_STRATEGY){
+if(strategy!=exports.Z_FILTERED&&strategy!=exports.Z_HUFFMAN_ONLY&&strategy!=exports.Z_RLE&&strategy!=exports.Z_FIXED&&strategy!=exports.Z_DEFAULT_STRATEGY){
 throw new TypeError('Invalid strategy: '+strategy);
 }
 
 if(this._level!==level||this._strategy!==strategy){
 var self=this;
 this.flush(binding.Z_SYNC_FLUSH,function(){
-self._binding.params(level,strategy);
+assert(self._handle,'zlib binding closed');
+self._handle.params(level,strategy);
 if(!self._hadError){
 self._level=level;
 self._strategy=strategy;
@@ -22158,73 +26012,77 @@
 };
 
 Zlib.prototype.reset=function(){
-return this._binding.reset();
+assert(this._handle,'zlib binding closed');
+return this._handle.reset();
 };
 
 
 
 Zlib.prototype._flush=function(callback){
-this._transform(new Buffer(0),'',callback);
+this._transform(Buffer.alloc(0),'',callback);
 };
 
 Zlib.prototype.flush=function(kind,callback){
+var _this2=this;
+
 var ws=this._writableState;
 
-if(typeof kind==='function'||kind===void 0&&!callback){
+if(typeof kind==='function'||kind===undefined&&!callback){
 callback=kind;
 kind=binding.Z_FULL_FLUSH;
 }
 
 if(ws.ended){
-if(callback)
-process.nextTick(callback);
+if(callback)process.nextTick(callback);
 }else if(ws.ending){
-if(callback)
-this.once('end',callback);
+if(callback)this.once('end',callback);
 }else if(ws.needDrain){
-var self=this;
+if(callback){
 this.once('drain',function(){
-self.flush(callback);
+return _this2.flush(kind,callback);
 });
+}
 }else{
 this._flushFlag=kind;
-this.write(new Buffer(0),'',callback);
+this.write(Buffer.alloc(0),'',callback);
 }
 };
 
 Zlib.prototype.close=function(callback){
-if(callback)
-process.nextTick(callback);
-
-if(this._closed)
-return;
-
-this._closed=true;
-
-this._binding.close();
-
-var self=this;
-process.nextTick(function(){
-self.emit('close');
-});
+_close(this,callback);
+process.nextTick(emitCloseNT,this);
 };
 
+function _close(engine,callback){
+if(callback)process.nextTick(callback);
+
+
+if(!engine._handle)return;
+
+engine._handle.close();
+engine._handle=null;
+}
+
+function emitCloseNT(self){
+self.emit('close');
+}
+
 Zlib.prototype._transform=function(chunk,encoding,cb){
 var flushFlag;
 var ws=this._writableState;
 var ending=ws.ending||ws.ended;
 var last=ending&&(!chunk||ws.length===chunk.length);
 
-if(!chunk===null&&!Buffer.isBuffer(chunk))
-return cb(new Error('invalid input'));
+if(chunk!==null&&!Buffer.isBuffer(chunk))return cb(new Error('invalid input'));
+
+if(!this._handle)return cb(new Error('zlib binding closed'));
 
 
 
 
 
-if(last)
-flushFlag=binding.Z_FINISH;else
-{
+
+if(last)flushFlag=this._finishFlushFlag;else{
 flushFlag=this._flushFlag;
 
 
@@ -22233,7 +26091,6 @@
 }
 }
 
-var self=this;
 this._processChunk(chunk,flushFlag,cb);
 };
 
@@ -22255,9 +26112,9 @@
 error=er;
 });
 
+assert(this._handle,'zlib binding closed');
 do{
-var res=this._binding.writeSync(flushFlag,
-chunk,
+var res=this._handle.writeSync(flushFlag,chunk,
 inOff,
 availInBefore,
 this._buffer,
@@ -22269,14 +26126,19 @@
 throw error;
 }
 
+if(nread>=kMaxLength){
+_close(this);
+throw new RangeError(kRangeErrorMessage);
+}
+
 var buf=Buffer.concat(buffers,nread);
-this.close();
+_close(this);
 
 return buf;
 }
 
-var req=this._binding.write(flushFlag,
-chunk,
+assert(this._handle,'zlib binding closed');
+var req=this._handle.write(flushFlag,chunk,
 inOff,
 availInBefore,
 this._buffer,
@@ -22287,8 +26149,17 @@
 req.callback=callback;
 
 function callback(availInAfter,availOutAfter){
-if(self._hadError)
-return;
+
+
+
+
+
+if(this){
+this.buffer=null;
+this.callback=null;
+}
+
+if(self._hadError)return;
 
 var have=availOutBefore-availOutAfter;
 assert(have>=0,'have should not go down');
@@ -22309,7 +26180,7 @@
 if(availOutAfter===0||self._offset>=self._chunkSize){
 availOutBefore=self._chunkSize;
 self._offset=0;
-self._buffer=new Buffer(self._chunkSize);
+self._buffer=Buffer.allocUnsafe(self._chunkSize);
 }
 
 if(availOutAfter===0){
@@ -22320,23 +26191,15 @@
 inOff+=availInBefore-availInAfter;
 availInBefore=availInAfter;
 
-if(!async)
-return true;
+if(!async)return true;
 
-var newReq=self._binding.write(flushFlag,
-chunk,
-inOff,
-availInBefore,
-self._buffer,
-self._offset,
-self._chunkSize);
+var newReq=self._handle.write(flushFlag,chunk,inOff,availInBefore,self._buffer,self._offset,self._chunkSize);
 newReq.callback=callback;
 newReq.buffer=chunk;
 return;
 }
 
-if(!async)
-return false;
+if(!async)return false;
 
 
 cb();
@@ -22350,11 +26213,10 @@
 util.inherits(DeflateRaw,Zlib);
 util.inherits(InflateRaw,Zlib);
 util.inherits(Unzip,Zlib);
-
-}).call(this,require('_process'),require("buffer").Buffer);
-},{"./binding":50,"_process":71,"_stream_transform":84,"assert":47,"buffer":54,"util":91}],52:[function(require,module,exports){
-arguments[4][49][0].apply(exports,arguments);
-},{"dup":49}],53:[function(require,module,exports){
+}).call(this,require('_process'));
+},{"./binding":56,"_process":77,"assert":53,"buffer":60,"stream":92,"util":97}],58:[function(require,module,exports){
+arguments[4][55][0].apply(exports,arguments);
+},{"dup":55}],59:[function(require,module,exports){
 (function(global){
 'use strict';
 
@@ -22466,8 +26328,7 @@
 };
 
 }).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"buffer":54}],54:[function(require,module,exports){
-(function(global){
+},{"buffer":60}],60:[function(require,module,exports){
 
 
 
@@ -22480,12 +26341,13 @@
 
 var base64=require('base64-js');
 var ieee754=require('ieee754');
-var isArray=require('isarray');
 
 exports.Buffer=Buffer;
 exports.SlowBuffer=SlowBuffer;
 exports.INSPECT_MAX_BYTES=50;
 
+var K_MAX_LENGTH=0x7fffffff;
+exports.kMaxLength=K_MAX_LENGTH;
 
 
 
@@ -22501,59 +26363,53 @@
 
 
 
+Buffer.TYPED_ARRAY_SUPPORT=typedArraySupport();
 
+if(!Buffer.TYPED_ARRAY_SUPPORT&&typeof console!=='undefined'&&
+typeof console.error==='function'){
+console.error(
+'This browser lacks typed array (Uint8Array) support which is required by '+
+'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.');
 
-
-
-
-
-
-
-
-Buffer.TYPED_ARRAY_SUPPORT=global.TYPED_ARRAY_SUPPORT!==undefined?
-global.TYPED_ARRAY_SUPPORT:
-typedArraySupport();
-
-
-
-
-exports.kMaxLength=kMaxLength();
+}
 
 function typedArraySupport(){
+
 try{
 var arr=new Uint8Array(1);
 arr.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42;}};
-return arr.foo()===42&&
-typeof arr.subarray==='function'&&
-arr.subarray(1,1).byteLength===0;
+return arr.foo()===42;
 }catch(e){
 return false;
 }
 }
 
-function kMaxLength(){
-return Buffer.TYPED_ARRAY_SUPPORT?
-0x7fffffff:
-0x3fffffff;
+Object.defineProperty(Buffer.prototype,'parent',{
+get:function(){
+if(!(this instanceof Buffer)){
+return undefined;
 }
+return this.buffer;
+}});
 
-function createBuffer(that,length){
-if(kMaxLength()<length){
+
+Object.defineProperty(Buffer.prototype,'offset',{
+get:function(){
+if(!(this instanceof Buffer)){
+return undefined;
+}
+return this.byteOffset;
+}});
+
+
+function createBuffer(length){
+if(length>K_MAX_LENGTH){
 throw new RangeError('Invalid typed array length');
 }
-if(Buffer.TYPED_ARRAY_SUPPORT){
 
-that=new Uint8Array(length);
-that.__proto__=Buffer.prototype;
-}else{
-
-if(that===null){
-that=new Buffer(length);
-}
-that.length=length;
-}
-
-return that;
+var buf=new Uint8Array(length);
+buf.__proto__=Buffer.prototype;
+return buf;
 }
 
 
@@ -22567,10 +26423,6 @@
 
 
 function Buffer(arg,encodingOrOffset,length){
-if(!Buffer.TYPED_ARRAY_SUPPORT&&!(this instanceof Buffer)){
-return new Buffer(arg,encodingOrOffset,length);
-}
-
 
 if(typeof arg==='number'){
 if(typeof encodingOrOffset==='string'){
@@ -22578,33 +26430,38 @@
 'If encoding is specified then the first argument must be a string');
 
 }
-return allocUnsafe(this,arg);
+return allocUnsafe(arg);
 }
-return from(this,arg,encodingOrOffset,length);
+return from(arg,encodingOrOffset,length);
+}
+
+
+if(typeof Symbol!=='undefined'&&Symbol.species&&
+Buffer[Symbol.species]===Buffer){
+Object.defineProperty(Buffer,Symbol.species,{
+value:null,
+configurable:true,
+enumerable:false,
+writable:false});
+
 }
 
 Buffer.poolSize=8192;
 
-
-Buffer._augment=function(arr){
-arr.__proto__=Buffer.prototype;
-return arr;
-};
-
-function from(that,value,encodingOrOffset,length){
+function from(value,encodingOrOffset,length){
 if(typeof value==='number'){
 throw new TypeError('"value" argument must not be a number');
 }
 
-if(typeof ArrayBuffer!=='undefined'&&value instanceof ArrayBuffer){
-return fromArrayBuffer(that,value,encodingOrOffset,length);
+if(isArrayBuffer(value)||value&&isArrayBuffer(value.buffer)){
+return fromArrayBuffer(value,encodingOrOffset,length);
 }
 
 if(typeof value==='string'){
-return fromString(that,value,encodingOrOffset);
+return fromString(value,encodingOrOffset);
 }
 
-return fromObject(that,value);
+return fromObject(value);
 }
 
 
@@ -22616,44 +26473,36 @@
 
 
 Buffer.from=function(value,encodingOrOffset,length){
-return from(null,value,encodingOrOffset,length);
+return from(value,encodingOrOffset,length);
 };
 
-if(Buffer.TYPED_ARRAY_SUPPORT){
+
+
 Buffer.prototype.__proto__=Uint8Array.prototype;
 Buffer.__proto__=Uint8Array;
-if(typeof Symbol!=='undefined'&&Symbol.species&&
-Buffer[Symbol.species]===Buffer){
-
-Object.defineProperty(Buffer,Symbol.species,{
-value:null,
-configurable:true});
-
-}
-}
 
 function assertSize(size){
 if(typeof size!=='number'){
-throw new TypeError('"size" argument must be a number');
+throw new TypeError('"size" argument must be of type number');
 }else if(size<0){
 throw new RangeError('"size" argument must not be negative');
 }
 }
 
-function alloc(that,size,fill,encoding){
+function alloc(size,fill,encoding){
 assertSize(size);
 if(size<=0){
-return createBuffer(that,size);
+return createBuffer(size);
 }
 if(fill!==undefined){
 
 
 
 return typeof encoding==='string'?
-createBuffer(that,size).fill(fill,encoding):
-createBuffer(that,size).fill(fill);
+createBuffer(size).fill(fill,encoding):
+createBuffer(size).fill(fill);
 }
-return createBuffer(that,size);
+return createBuffer(size);
 }
 
 
@@ -22661,132 +26510,118 @@
 
 
 Buffer.alloc=function(size,fill,encoding){
-return alloc(null,size,fill,encoding);
+return alloc(size,fill,encoding);
 };
 
-function allocUnsafe(that,size){
+function allocUnsafe(size){
 assertSize(size);
-that=createBuffer(that,size<0?0:checked(size)|0);
-if(!Buffer.TYPED_ARRAY_SUPPORT){
-for(var i=0;i<size;++i){
-that[i]=0;
-}
-}
-return that;
+return createBuffer(size<0?0:checked(size)|0);
 }
 
 
 
 
 Buffer.allocUnsafe=function(size){
-return allocUnsafe(null,size);
+return allocUnsafe(size);
 };
 
 
 
 Buffer.allocUnsafeSlow=function(size){
-return allocUnsafe(null,size);
+return allocUnsafe(size);
 };
 
-function fromString(that,string,encoding){
+function fromString(string,encoding){
 if(typeof encoding!=='string'||encoding===''){
 encoding='utf8';
 }
 
 if(!Buffer.isEncoding(encoding)){
-throw new TypeError('"encoding" must be a valid string encoding');
+throw new TypeError('Unknown encoding: '+encoding);
 }
 
 var length=byteLength(string,encoding)|0;
-that=createBuffer(that,length);
+var buf=createBuffer(length);
 
-var actual=that.write(string,encoding);
+var actual=buf.write(string,encoding);
 
 if(actual!==length){
 
 
 
-that=that.slice(0,actual);
+buf=buf.slice(0,actual);
 }
 
-return that;
+return buf;
 }
 
-function fromArrayLike(that,array){
+function fromArrayLike(array){
 var length=array.length<0?0:checked(array.length)|0;
-that=createBuffer(that,length);
+var buf=createBuffer(length);
 for(var i=0;i<length;i+=1){
-that[i]=array[i]&255;
+buf[i]=array[i]&255;
 }
-return that;
+return buf;
 }
 
-function fromArrayBuffer(that,array,byteOffset,length){
-array.byteLength;
-
+function fromArrayBuffer(array,byteOffset,length){
 if(byteOffset<0||array.byteLength<byteOffset){
-throw new RangeError('\'offset\' is out of bounds');
+throw new RangeError('"offset" is outside of buffer bounds');
 }
 
 if(array.byteLength<byteOffset+(length||0)){
-throw new RangeError('\'length\' is out of bounds');
+throw new RangeError('"length" is outside of buffer bounds');
 }
 
+var buf;
 if(byteOffset===undefined&&length===undefined){
-array=new Uint8Array(array);
+buf=new Uint8Array(array);
 }else if(length===undefined){
-array=new Uint8Array(array,byteOffset);
+buf=new Uint8Array(array,byteOffset);
 }else{
-array=new Uint8Array(array,byteOffset,length);
+buf=new Uint8Array(array,byteOffset,length);
 }
 
-if(Buffer.TYPED_ARRAY_SUPPORT){
 
-that=array;
-that.__proto__=Buffer.prototype;
-}else{
-
-that=fromArrayLike(that,array);
-}
-return that;
+buf.__proto__=Buffer.prototype;
+return buf;
 }
 
-function fromObject(that,obj){
+function fromObject(obj){
 if(Buffer.isBuffer(obj)){
 var len=checked(obj.length)|0;
-that=createBuffer(that,len);
+var buf=createBuffer(len);
 
-if(that.length===0){
-return that;
+if(buf.length===0){
+return buf;
 }
 
-obj.copy(that,0,0,len);
-return that;
+obj.copy(buf,0,0,len);
+return buf;
 }
 
 if(obj){
-if(typeof ArrayBuffer!=='undefined'&&
-obj.buffer instanceof ArrayBuffer||'length'in obj){
-if(typeof obj.length!=='number'||isnan(obj.length)){
-return createBuffer(that,0);
+if(ArrayBuffer.isView(obj)||'length'in obj){
+if(typeof obj.length!=='number'||numberIsNaN(obj.length)){
+return createBuffer(0);
 }
-return fromArrayLike(that,obj);
+return fromArrayLike(obj);
 }
 
-if(obj.type==='Buffer'&&isArray(obj.data)){
-return fromArrayLike(that,obj.data);
+if(obj.type==='Buffer'&&Array.isArray(obj.data)){
+return fromArrayLike(obj.data);
 }
 }
 
-throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.');
+throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object.');
 }
 
 function checked(length){
 
 
-if(length>=kMaxLength()){
+if(length>=K_MAX_LENGTH){
 throw new RangeError('Attempt to allocate Buffer larger than maximum '+
-'size: 0x'+kMaxLength().toString(16)+' bytes');
+'size: 0x'+K_MAX_LENGTH.toString(16)+' bytes');
 }
 return length|0;
 }
@@ -22799,7 +26634,7 @@
 }
 
 Buffer.isBuffer=function isBuffer(b){
-return!!(b!=null&&b._isBuffer);
+return b!=null&&b._isBuffer===true;
 };
 
 Buffer.compare=function compare(a,b){
@@ -22845,7 +26680,7 @@
 };
 
 Buffer.concat=function concat(list,length){
-if(!isArray(list)){
+if(!Array.isArray(list)){
 throw new TypeError('"list" argument must be an Array of Buffers');
 }
 
@@ -22865,6 +26700,9 @@
 var pos=0;
 for(i=0;i<list.length;++i){
 var buf=list[i];
+if(ArrayBuffer.isView(buf)){
+buf=Buffer.from(buf);
+}
 if(!Buffer.isBuffer(buf)){
 throw new TypeError('"list" argument must be an Array of Buffers');
 }
@@ -22878,8 +26716,7 @@
 if(Buffer.isBuffer(string)){
 return string.length;
 }
-if(typeof ArrayBuffer!=='undefined'&&typeof ArrayBuffer.isView==='function'&&(
-ArrayBuffer.isView(string)||string instanceof ArrayBuffer)){
+if(ArrayBuffer.isView(string)||isArrayBuffer(string)){
 return string.byteLength;
 }
 if(typeof string!=='string'){
@@ -22991,6 +26828,10 @@
 
 
 
+
+
+
+
 Buffer.prototype._isBuffer=true;
 
 function swap(b,n,m){
@@ -23037,12 +26878,14 @@
 };
 
 Buffer.prototype.toString=function toString(){
-var length=this.length|0;
+var length=this.length;
 if(length===0)return'';
 if(arguments.length===0)return utf8Slice(this,0,length);
 return slowToString.apply(this,arguments);
 };
 
+Buffer.prototype.toLocaleString=Buffer.prototype.toString;
+
 Buffer.prototype.equals=function equals(b){
 if(!Buffer.isBuffer(b))throw new TypeError('Argument must be a Buffer');
 if(this===b)return true;
@@ -23141,7 +26984,7 @@
 byteOffset=-0x80000000;
 }
 byteOffset=+byteOffset;
-if(isNaN(byteOffset)){
+if(numberIsNaN(byteOffset)){
 
 byteOffset=dir?0:buffer.length-1;
 }
@@ -23170,8 +27013,7 @@
 return arrayIndexOf(buffer,val,byteOffset,encoding,dir);
 }else if(typeof val==='number'){
 val=val&0xFF;
-if(Buffer.TYPED_ARRAY_SUPPORT&&
-typeof Uint8Array.prototype.indexOf==='function'){
+if(typeof Uint8Array.prototype.indexOf==='function'){
 if(dir){
 return Uint8Array.prototype.indexOf.call(buffer,val,byteOffset);
 }else{
@@ -23264,16 +27106,14 @@
 }
 }
 
-
 var strLen=string.length;
-if(strLen%2!==0)throw new TypeError('Invalid hex string');
 
 if(length>strLen/2){
 length=strLen/2;
 }
 for(var i=0;i<length;++i){
 var parsed=parseInt(string.substr(i*2,2),16);
-if(isNaN(parsed))return i;
+if(numberIsNaN(parsed))return i;
 buf[offset+i]=parsed;
 }
 return i;
@@ -23312,15 +27152,14 @@
 offset=0;
 
 }else if(isFinite(offset)){
-offset=offset|0;
+offset=offset>>>0;
 if(isFinite(length)){
-length=length|0;
+length=length>>>0;
 if(encoding===undefined)encoding='utf8';
 }else{
 encoding=length;
 length=undefined;
 }
-
 }else{
 throw new Error(
 'Buffer.write(string, encoding, offset[, length]) is no longer supported');
@@ -23545,18 +27384,9 @@
 
 if(end<start)end=start;
 
-var newBuf;
-if(Buffer.TYPED_ARRAY_SUPPORT){
-newBuf=this.subarray(start,end);
-newBuf.__proto__=Buffer.prototype;
-}else{
-var sliceLen=end-start;
-newBuf=new Buffer(sliceLen,undefined);
-for(var i=0;i<sliceLen;++i){
-newBuf[i]=this[i+start];
-}
-}
+var newBuf=this.subarray(start,end);
 
+newBuf.__proto__=Buffer.prototype;
 return newBuf;
 };
 
@@ -23569,8 +27399,8 @@
 }
 
 Buffer.prototype.readUIntLE=function readUIntLE(offset,byteLength,noAssert){
-offset=offset|0;
-byteLength=byteLength|0;
+offset=offset>>>0;
+byteLength=byteLength>>>0;
 if(!noAssert)checkOffset(offset,byteLength,this.length);
 
 var val=this[offset];
@@ -23584,8 +27414,8 @@
 };
 
 Buffer.prototype.readUIntBE=function readUIntBE(offset,byteLength,noAssert){
-offset=offset|0;
-byteLength=byteLength|0;
+offset=offset>>>0;
+byteLength=byteLength>>>0;
 if(!noAssert){
 checkOffset(offset,byteLength,this.length);
 }
@@ -23600,21 +27430,25 @@
 };
 
 Buffer.prototype.readUInt8=function readUInt8(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,1,this.length);
 return this[offset];
 };
 
 Buffer.prototype.readUInt16LE=function readUInt16LE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,2,this.length);
 return this[offset]|this[offset+1]<<8;
 };
 
 Buffer.prototype.readUInt16BE=function readUInt16BE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,2,this.length);
 return this[offset]<<8|this[offset+1];
 };
 
 Buffer.prototype.readUInt32LE=function readUInt32LE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,4,this.length);
 
 return(this[offset]|
@@ -23624,6 +27458,7 @@
 };
 
 Buffer.prototype.readUInt32BE=function readUInt32BE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,4,this.length);
 
 return this[offset]*0x1000000+(
@@ -23633,8 +27468,8 @@
 };
 
 Buffer.prototype.readIntLE=function readIntLE(offset,byteLength,noAssert){
-offset=offset|0;
-byteLength=byteLength|0;
+offset=offset>>>0;
+byteLength=byteLength>>>0;
 if(!noAssert)checkOffset(offset,byteLength,this.length);
 
 var val=this[offset];
@@ -23651,8 +27486,8 @@
 };
 
 Buffer.prototype.readIntBE=function readIntBE(offset,byteLength,noAssert){
-offset=offset|0;
-byteLength=byteLength|0;
+offset=offset>>>0;
+byteLength=byteLength>>>0;
 if(!noAssert)checkOffset(offset,byteLength,this.length);
 
 var i=byteLength;
@@ -23669,24 +27504,28 @@
 };
 
 Buffer.prototype.readInt8=function readInt8(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,1,this.length);
 if(!(this[offset]&0x80))return this[offset];
 return(0xff-this[offset]+1)*-1;
 };
 
 Buffer.prototype.readInt16LE=function readInt16LE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,2,this.length);
 var val=this[offset]|this[offset+1]<<8;
 return val&0x8000?val|0xFFFF0000:val;
 };
 
 Buffer.prototype.readInt16BE=function readInt16BE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,2,this.length);
 var val=this[offset+1]|this[offset]<<8;
 return val&0x8000?val|0xFFFF0000:val;
 };
 
 Buffer.prototype.readInt32LE=function readInt32LE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,4,this.length);
 
 return this[offset]|
@@ -23696,6 +27535,7 @@
 };
 
 Buffer.prototype.readInt32BE=function readInt32BE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,4,this.length);
 
 return this[offset]<<24|
@@ -23705,21 +27545,25 @@
 };
 
 Buffer.prototype.readFloatLE=function readFloatLE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,4,this.length);
 return ieee754.read(this,offset,true,23,4);
 };
 
 Buffer.prototype.readFloatBE=function readFloatBE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,4,this.length);
 return ieee754.read(this,offset,false,23,4);
 };
 
 Buffer.prototype.readDoubleLE=function readDoubleLE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,8,this.length);
 return ieee754.read(this,offset,true,52,8);
 };
 
 Buffer.prototype.readDoubleBE=function readDoubleBE(offset,noAssert){
+offset=offset>>>0;
 if(!noAssert)checkOffset(offset,8,this.length);
 return ieee754.read(this,offset,false,52,8);
 };
@@ -23732,8 +27576,8 @@
 
 Buffer.prototype.writeUIntLE=function writeUIntLE(value,offset,byteLength,noAssert){
 value=+value;
-offset=offset|0;
-byteLength=byteLength|0;
+offset=offset>>>0;
+byteLength=byteLength>>>0;
 if(!noAssert){
 var maxBytes=Math.pow(2,8*byteLength)-1;
 checkInt(this,value,offset,byteLength,maxBytes,0);
@@ -23751,8 +27595,8 @@
 
 Buffer.prototype.writeUIntBE=function writeUIntBE(value,offset,byteLength,noAssert){
 value=+value;
-offset=offset|0;
-byteLength=byteLength|0;
+offset=offset>>>0;
+byteLength=byteLength>>>0;
 if(!noAssert){
 var maxBytes=Math.pow(2,8*byteLength)-1;
 checkInt(this,value,offset,byteLength,maxBytes,0);
@@ -23770,87 +27614,55 @@
 
 Buffer.prototype.writeUInt8=function writeUInt8(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,1,0xff,0);
-if(!Buffer.TYPED_ARRAY_SUPPORT)value=Math.floor(value);
 this[offset]=value&0xff;
 return offset+1;
 };
 
-function objectWriteUInt16(buf,value,offset,littleEndian){
-if(value<0)value=0xffff+value+1;
-for(var i=0,j=Math.min(buf.length-offset,2);i<j;++i){
-buf[offset+i]=(value&0xff<<8*(littleEndian?i:1-i))>>>
-(littleEndian?i:1-i)*8;
-}
-}
-
 Buffer.prototype.writeUInt16LE=function writeUInt16LE(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,2,0xffff,0);
-if(Buffer.TYPED_ARRAY_SUPPORT){
 this[offset]=value&0xff;
 this[offset+1]=value>>>8;
-}else{
-objectWriteUInt16(this,value,offset,true);
-}
 return offset+2;
 };
 
 Buffer.prototype.writeUInt16BE=function writeUInt16BE(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,2,0xffff,0);
-if(Buffer.TYPED_ARRAY_SUPPORT){
 this[offset]=value>>>8;
 this[offset+1]=value&0xff;
-}else{
-objectWriteUInt16(this,value,offset,false);
-}
 return offset+2;
 };
 
-function objectWriteUInt32(buf,value,offset,littleEndian){
-if(value<0)value=0xffffffff+value+1;
-for(var i=0,j=Math.min(buf.length-offset,4);i<j;++i){
-buf[offset+i]=value>>>(littleEndian?i:3-i)*8&0xff;
-}
-}
-
 Buffer.prototype.writeUInt32LE=function writeUInt32LE(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,4,0xffffffff,0);
-if(Buffer.TYPED_ARRAY_SUPPORT){
 this[offset+3]=value>>>24;
 this[offset+2]=value>>>16;
 this[offset+1]=value>>>8;
 this[offset]=value&0xff;
-}else{
-objectWriteUInt32(this,value,offset,true);
-}
 return offset+4;
 };
 
 Buffer.prototype.writeUInt32BE=function writeUInt32BE(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,4,0xffffffff,0);
-if(Buffer.TYPED_ARRAY_SUPPORT){
 this[offset]=value>>>24;
 this[offset+1]=value>>>16;
 this[offset+2]=value>>>8;
 this[offset+3]=value&0xff;
-}else{
-objectWriteUInt32(this,value,offset,false);
-}
 return offset+4;
 };
 
 Buffer.prototype.writeIntLE=function writeIntLE(value,offset,byteLength,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert){
 var limit=Math.pow(2,8*byteLength-1);
 
@@ -23873,7 +27685,7 @@
 
 Buffer.prototype.writeIntBE=function writeIntBE(value,offset,byteLength,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert){
 var limit=Math.pow(2,8*byteLength-1);
 
@@ -23896,9 +27708,8 @@
 
 Buffer.prototype.writeInt8=function writeInt8(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,1,0x7f,-0x80);
-if(!Buffer.TYPED_ARRAY_SUPPORT)value=Math.floor(value);
 if(value<0)value=0xff+value+1;
 this[offset]=value&0xff;
 return offset+1;
@@ -23906,58 +27717,42 @@
 
 Buffer.prototype.writeInt16LE=function writeInt16LE(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,2,0x7fff,-0x8000);
-if(Buffer.TYPED_ARRAY_SUPPORT){
 this[offset]=value&0xff;
 this[offset+1]=value>>>8;
-}else{
-objectWriteUInt16(this,value,offset,true);
-}
 return offset+2;
 };
 
 Buffer.prototype.writeInt16BE=function writeInt16BE(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,2,0x7fff,-0x8000);
-if(Buffer.TYPED_ARRAY_SUPPORT){
 this[offset]=value>>>8;
 this[offset+1]=value&0xff;
-}else{
-objectWriteUInt16(this,value,offset,false);
-}
 return offset+2;
 };
 
 Buffer.prototype.writeInt32LE=function writeInt32LE(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,4,0x7fffffff,-0x80000000);
-if(Buffer.TYPED_ARRAY_SUPPORT){
 this[offset]=value&0xff;
 this[offset+1]=value>>>8;
 this[offset+2]=value>>>16;
 this[offset+3]=value>>>24;
-}else{
-objectWriteUInt32(this,value,offset,true);
-}
 return offset+4;
 };
 
 Buffer.prototype.writeInt32BE=function writeInt32BE(value,offset,noAssert){
 value=+value;
-offset=offset|0;
+offset=offset>>>0;
 if(!noAssert)checkInt(this,value,offset,4,0x7fffffff,-0x80000000);
 if(value<0)value=0xffffffff+value+1;
-if(Buffer.TYPED_ARRAY_SUPPORT){
 this[offset]=value>>>24;
 this[offset+1]=value>>>16;
 this[offset+2]=value>>>8;
 this[offset+3]=value&0xff;
-}else{
-objectWriteUInt32(this,value,offset,false);
-}
 return offset+4;
 };
 
@@ -23967,6 +27762,8 @@
 }
 
 function writeFloat(buf,value,offset,littleEndian,noAssert){
+value=+value;
+offset=offset>>>0;
 if(!noAssert){
 checkIEEE754(buf,value,offset,4,3.4028234663852886e+38,-3.4028234663852886e+38);
 }
@@ -23983,6 +27780,8 @@
 };
 
 function writeDouble(buf,value,offset,littleEndian,noAssert){
+value=+value;
+offset=offset>>>0;
 if(!noAssert){
 checkIEEE754(buf,value,offset,8,1.7976931348623157E+308,-1.7976931348623157E+308);
 }
@@ -24000,6 +27799,7 @@
 
 
 Buffer.prototype.copy=function copy(target,targetStart,start,end){
+if(!Buffer.isBuffer(target))throw new TypeError('argument should be a Buffer');
 if(!start)start=0;
 if(!end&&end!==0)end=this.length;
 if(targetStart>=target.length)targetStart=target.length;
@@ -24014,7 +27814,7 @@
 if(targetStart<0){
 throw new RangeError('targetStart out of bounds');
 }
-if(start<0||start>=this.length)throw new RangeError('sourceStart out of bounds');
+if(start<0||start>=this.length)throw new RangeError('Index out of range');
 if(end<0)throw new RangeError('sourceEnd out of bounds');
 
 
@@ -24024,22 +27824,19 @@
 }
 
 var len=end-start;
-var i;
 
-if(this===target&&start<targetStart&&targetStart<end){
+if(this===target&&typeof Uint8Array.prototype.copyWithin==='function'){
 
-for(i=len-1;i>=0;--i){
-target[i+targetStart]=this[i+start];
-}
-}else if(len<1000||!Buffer.TYPED_ARRAY_SUPPORT){
+this.copyWithin(targetStart,start,end);
+}else if(this===target&&start<targetStart&&targetStart<end){
 
-for(i=0;i<len;++i){
+for(var i=len-1;i>=0;--i){
 target[i+targetStart]=this[i+start];
 }
 }else{
 Uint8Array.prototype.set.call(
 target,
-this.subarray(start,start+len),
+this.subarray(start,end),
 targetStart);
 
 }
@@ -24062,18 +27859,20 @@
 encoding=end;
 end=this.length;
 }
-if(val.length===1){
-var code=val.charCodeAt(0);
-if(code<256){
-val=code;
-}
-}
 if(encoding!==undefined&&typeof encoding!=='string'){
 throw new TypeError('encoding must be a string');
 }
 if(typeof encoding==='string'&&!Buffer.isEncoding(encoding)){
 throw new TypeError('Unknown encoding: '+encoding);
 }
+if(val.length===1){
+var code=val.charCodeAt(0);
+if(encoding==='utf8'&&code<128||
+encoding==='latin1'){
+
+val=code;
+}
+}
 }else if(typeof val==='number'){
 val=val&255;
 }
@@ -24100,8 +27899,12 @@
 }else{
 var bytes=Buffer.isBuffer(val)?
 val:
-utf8ToBytes(new Buffer(val,encoding).toString());
+new Buffer(val,encoding);
 var len=bytes.length;
+if(len===0){
+throw new TypeError('The value "'+val+
+'" is invalid for argument "value"');
+}
 for(i=0;i<end-start;++i){
 this[i+start]=bytes[i%len];
 }
@@ -24113,11 +27916,13 @@
 
 
 
-var INVALID_BASE64_RE=/[^+\/0-9A-Za-z-_]/g;
+var INVALID_BASE64_RE=/[^+/0-9A-Za-z-_]/g;
 
 function base64clean(str){
 
-str=stringtrim(str).replace(INVALID_BASE64_RE,'');
+str=str.split('=')[0];
+
+str=str.trim().replace(INVALID_BASE64_RE,'');
 
 if(str.length<2)return'';
 
@@ -24127,11 +27932,6 @@
 return str;
 }
 
-function stringtrim(str){
-if(str.trim)return str.trim();
-return str.replace(/^\s+|\s+$/g,'');
-}
-
 function toHex(n){
 if(n<16)return'0'+n.toString(16);
 return n.toString(16);
@@ -24254,12 +28054,19 @@
 return i;
 }
 
-function isnan(val){
-return val!==val;
+
+
+function isArrayBuffer(obj){
+return obj instanceof ArrayBuffer||
+obj!=null&&obj.constructor!=null&&obj.constructor.name==='ArrayBuffer'&&
+typeof obj.byteLength==='number';
 }
 
-}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"base64-js":48,"ieee754":57,"isarray":60}],55:[function(require,module,exports){
+function numberIsNaN(obj){
+return obj!==obj;
+}
+
+},{"base64-js":54,"ieee754":63}],61:[function(require,module,exports){
 (function(Buffer){
 
 
@@ -24370,7 +28177,7 @@
 }
 
 }).call(this,{"isBuffer":require("../../is-buffer/index.js")});
-},{"../../is-buffer/index.js":59}],56:[function(require,module,exports){
+},{"../../is-buffer/index.js":65}],62:[function(require,module,exports){
 
 
 
@@ -24392,8 +28199,16 @@
 
 
 
+var objectCreate=Object.create||objectCreatePolyfill;
+var objectKeys=Object.keys||objectKeysPolyfill;
+var bind=Function.prototype.bind||functionBindPolyfill;
+
 function EventEmitter(){
-this._events=this._events||{};
+if(!this._events||!Object.prototype.hasOwnProperty.call(this,'_events')){
+this._events=objectCreate(null);
+this._eventsCount=0;
+}
+
 this._maxListeners=this._maxListeners||undefined;
 }
 module.exports=EventEmitter;
@@ -24406,169 +28221,319 @@
 
 
 
-EventEmitter.defaultMaxListeners=10;
+var defaultMaxListeners=10;
+
+var hasDefineProperty;
+try{
+var o={};
+if(Object.defineProperty)Object.defineProperty(o,'x',{value:0});
+hasDefineProperty=o.x===0;
+}catch(err){hasDefineProperty=false;}
+if(hasDefineProperty){
+Object.defineProperty(EventEmitter,'defaultMaxListeners',{
+enumerable:true,
+get:function(){
+return defaultMaxListeners;
+},
+set:function(arg){
+
+
+if(typeof arg!=='number'||arg<0||arg!==arg)
+throw new TypeError('"defaultMaxListeners" must be a positive number');
+defaultMaxListeners=arg;
+}});
+
+}else{
+EventEmitter.defaultMaxListeners=defaultMaxListeners;
+}
 
 
 
-EventEmitter.prototype.setMaxListeners=function(n){
-if(!isNumber(n)||n<0||isNaN(n))
-throw TypeError('n must be a positive number');
+EventEmitter.prototype.setMaxListeners=function setMaxListeners(n){
+if(typeof n!=='number'||n<0||isNaN(n))
+throw new TypeError('"n" argument must be a positive number');
 this._maxListeners=n;
 return this;
 };
 
-EventEmitter.prototype.emit=function(type){
-var er,handler,len,args,i,listeners;
+function $getMaxListeners(that){
+if(that._maxListeners===undefined)
+return EventEmitter.defaultMaxListeners;
+return that._maxListeners;
+}
 
-if(!this._events)
-this._events={};
+EventEmitter.prototype.getMaxListeners=function getMaxListeners(){
+return $getMaxListeners(this);
+};
 
 
-if(type==='error'){
-if(!this._events.error||
-isObject(this._events.error)&&!this._events.error.length){
+
+
+
+
+function emitNone(handler,isFn,self){
+if(isFn)
+handler.call(self);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].call(self);
+}
+}
+function emitOne(handler,isFn,self,arg1){
+if(isFn)
+handler.call(self,arg1);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].call(self,arg1);
+}
+}
+function emitTwo(handler,isFn,self,arg1,arg2){
+if(isFn)
+handler.call(self,arg1,arg2);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].call(self,arg1,arg2);
+}
+}
+function emitThree(handler,isFn,self,arg1,arg2,arg3){
+if(isFn)
+handler.call(self,arg1,arg2,arg3);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].call(self,arg1,arg2,arg3);
+}
+}
+
+function emitMany(handler,isFn,self,args){
+if(isFn)
+handler.apply(self,args);else
+{
+var len=handler.length;
+var listeners=arrayClone(handler,len);
+for(var i=0;i<len;++i)
+listeners[i].apply(self,args);
+}
+}
+
+EventEmitter.prototype.emit=function emit(type){
+var er,handler,len,args,i,events;
+var doError=type==='error';
+
+events=this._events;
+if(events)
+doError=doError&&events.error==null;else
+if(!doError)
+return false;
+
+
+if(doError){
+if(arguments.length>1)
 er=arguments[1];
 if(er instanceof Error){
 throw er;
 }else{
 
-var err=new Error('Uncaught, unspecified "error" event. ('+er+')');
+var err=new Error('Unhandled "error" event. ('+er+')');
 err.context=er;
 throw err;
 }
-}
+return false;
 }
 
-handler=this._events[type];
+handler=events[type];
 
-if(isUndefined(handler))
+if(!handler)
 return false;
 
-if(isFunction(handler)){
-switch(arguments.length){
+var isFn=typeof handler==='function';
+len=arguments.length;
+switch(len){
 
 case 1:
-handler.call(this);
+emitNone(handler,isFn,this);
 break;
 case 2:
-handler.call(this,arguments[1]);
+emitOne(handler,isFn,this,arguments[1]);
 break;
 case 3:
-handler.call(this,arguments[1],arguments[2]);
+emitTwo(handler,isFn,this,arguments[1],arguments[2]);
+break;
+case 4:
+emitThree(handler,isFn,this,arguments[1],arguments[2],arguments[3]);
 break;
 
 default:
-args=Array.prototype.slice.call(arguments,1);
-handler.apply(this,args);}
+args=new Array(len-1);
+for(i=1;i<len;i++)
+args[i-1]=arguments[i];
+emitMany(handler,isFn,this,args);}
 
-}else if(isObject(handler)){
-args=Array.prototype.slice.call(arguments,1);
-listeners=handler.slice();
-len=listeners.length;
-for(i=0;i<len;i++)
-listeners[i].apply(this,args);
-}
 
 return true;
 };
 
-EventEmitter.prototype.addListener=function(type,listener){
+function _addListener(target,type,listener,prepend){
 var m;
+var events;
+var existing;
 
-if(!isFunction(listener))
-throw TypeError('listener must be a function');
+if(typeof listener!=='function')
+throw new TypeError('"listener" argument must be a function');
 
-if(!this._events)
-this._events={};
-
-
-
-if(this._events.newListener)
-this.emit('newListener',type,
-isFunction(listener.listener)?
-listener.listener:listener);
-
-if(!this._events[type])
-
-this._events[type]=listener;else
-if(isObject(this._events[type]))
-
-this._events[type].push(listener);else
-
-
-this._events[type]=[this._events[type],listener];
-
-
-if(isObject(this._events[type])&&!this._events[type].warned){
-if(!isUndefined(this._maxListeners)){
-m=this._maxListeners;
+events=target._events;
+if(!events){
+events=target._events=objectCreate(null);
+target._eventsCount=0;
 }else{
-m=EventEmitter.defaultMaxListeners;
+
+
+if(events.newListener){
+target.emit('newListener',type,
+listener.listener?listener.listener:listener);
+
+
+
+events=target._events;
+}
+existing=events[type];
 }
 
-if(m&&m>0&&this._events[type].length>m){
-this._events[type].warned=true;
-console.error('(node) warning: possible EventEmitter memory '+
-'leak detected. %d listeners added. '+
-'Use emitter.setMaxListeners() to increase limit.',
-this._events[type].length);
-if(typeof console.trace==='function'){
+if(!existing){
 
-console.trace();
+existing=events[type]=listener;
+++target._eventsCount;
+}else{
+if(typeof existing==='function'){
+
+existing=events[type]=
+prepend?[listener,existing]:[existing,listener];
+}else{
+
+if(prepend){
+existing.unshift(listener);
+}else{
+existing.push(listener);
+}
+}
+
+
+if(!existing.warned){
+m=$getMaxListeners(target);
+if(m&&m>0&&existing.length>m){
+existing.warned=true;
+var w=new Error('Possible EventEmitter memory leak detected. '+
+existing.length+' "'+String(type)+'" listeners '+
+'added. Use emitter.setMaxListeners() to '+
+'increase limit.');
+w.name='MaxListenersExceededWarning';
+w.emitter=target;
+w.type=type;
+w.count=existing.length;
+if(typeof console==='object'&&console.warn){
+console.warn('%s: %s',w.name,w.message);
+}
 }
 }
 }
 
-return this;
+return target;
+}
+
+EventEmitter.prototype.addListener=function addListener(type,listener){
+return _addListener(this,type,listener,false);
 };
 
 EventEmitter.prototype.on=EventEmitter.prototype.addListener;
 
-EventEmitter.prototype.once=function(type,listener){
-if(!isFunction(listener))
-throw TypeError('listener must be a function');
+EventEmitter.prototype.prependListener=
+function prependListener(type,listener){
+return _addListener(this,type,listener,true);
+};
 
-var fired=false;
+function onceWrapper(){
+if(!this.fired){
+this.target.removeListener(this.type,this.wrapFn);
+this.fired=true;
+switch(arguments.length){
+case 0:
+return this.listener.call(this.target);
+case 1:
+return this.listener.call(this.target,arguments[0]);
+case 2:
+return this.listener.call(this.target,arguments[0],arguments[1]);
+case 3:
+return this.listener.call(this.target,arguments[0],arguments[1],
+arguments[2]);
+default:
+var args=new Array(arguments.length);
+for(var i=0;i<args.length;++i)
+args[i]=arguments[i];
+this.listener.apply(this.target,args);}
 
-function g(){
-this.removeListener(type,g);
-
-if(!fired){
-fired=true;
-listener.apply(this,arguments);
 }
 }
 
-g.listener=listener;
-this.on(type,g);
+function _onceWrap(target,type,listener){
+var state={fired:false,wrapFn:undefined,target:target,type:type,listener:listener};
+var wrapped=bind.call(onceWrapper,state);
+wrapped.listener=listener;
+state.wrapFn=wrapped;
+return wrapped;
+}
 
+EventEmitter.prototype.once=function once(type,listener){
+if(typeof listener!=='function')
+throw new TypeError('"listener" argument must be a function');
+this.on(type,_onceWrap(this,type,listener));
+return this;
+};
+
+EventEmitter.prototype.prependOnceListener=
+function prependOnceListener(type,listener){
+if(typeof listener!=='function')
+throw new TypeError('"listener" argument must be a function');
+this.prependListener(type,_onceWrap(this,type,listener));
 return this;
 };
 
 
-EventEmitter.prototype.removeListener=function(type,listener){
-var list,position,length,i;
+EventEmitter.prototype.removeListener=
+function removeListener(type,listener){
+var list,events,position,i,originalListener;
 
-if(!isFunction(listener))
-throw TypeError('listener must be a function');
+if(typeof listener!=='function')
+throw new TypeError('"listener" argument must be a function');
 
-if(!this._events||!this._events[type])
+events=this._events;
+if(!events)
 return this;
 
-list=this._events[type];
-length=list.length;
+list=events[type];
+if(!list)
+return this;
+
+if(list===listener||list.listener===listener){
+if(--this._eventsCount===0)
+this._events=objectCreate(null);else
+{
+delete events[type];
+if(events.removeListener)
+this.emit('removeListener',type,list.listener||listener);
+}
+}else if(typeof list!=='function'){
 position=-1;
 
-if(list===listener||
-isFunction(list.listener)&&list.listener===listener){
-delete this._events[type];
-if(this._events.removeListener)
-this.emit('removeListener',type,listener);
-
-}else if(isObject(list)){
-for(i=length;i-->0;){
-if(list[i]===listener||
-list[i].listener&&list[i].listener===listener){
+for(i=list.length-1;i>=0;i--){
+if(list[i]===listener||list[i].listener===listener){
+originalListener=list[i].listener;
 position=i;
 break;
 }
@@ -24577,104 +28542,163 @@
 if(position<0)
 return this;
 
-if(list.length===1){
-list.length=0;
-delete this._events[type];
-}else{
-list.splice(position,1);
-}
+if(position===0)
+list.shift();else
 
-if(this._events.removeListener)
-this.emit('removeListener',type,listener);
+spliceOne(list,position);
+
+if(list.length===1)
+events[type]=list[0];
+
+if(events.removeListener)
+this.emit('removeListener',type,originalListener||listener);
 }
 
 return this;
 };
 
-EventEmitter.prototype.removeAllListeners=function(type){
-var key,listeners;
+EventEmitter.prototype.removeAllListeners=
+function removeAllListeners(type){
+var listeners,events,i;
 
-if(!this._events)
+events=this._events;
+if(!events)
 return this;
 
 
-if(!this._events.removeListener){
-if(arguments.length===0)
-this._events={};else
-if(this._events[type])
-delete this._events[type];
+if(!events.removeListener){
+if(arguments.length===0){
+this._events=objectCreate(null);
+this._eventsCount=0;
+}else if(events[type]){
+if(--this._eventsCount===0)
+this._events=objectCreate(null);else
+
+delete events[type];
+}
 return this;
 }
 
 
 if(arguments.length===0){
-for(key in this._events){
+var keys=objectKeys(events);
+var key;
+for(i=0;i<keys.length;++i){
+key=keys[i];
 if(key==='removeListener')continue;
 this.removeAllListeners(key);
 }
 this.removeAllListeners('removeListener');
-this._events={};
+this._events=objectCreate(null);
+this._eventsCount=0;
 return this;
 }
 
-listeners=this._events[type];
+listeners=events[type];
 
-if(isFunction(listeners)){
+if(typeof listeners==='function'){
 this.removeListener(type,listeners);
 }else if(listeners){
 
-while(listeners.length)
-this.removeListener(type,listeners[listeners.length-1]);
+for(i=listeners.length-1;i>=0;i--){
+this.removeListener(type,listeners[i]);
 }
-delete this._events[type];
+}
 
 return this;
 };
 
-EventEmitter.prototype.listeners=function(type){
+EventEmitter.prototype.listeners=function listeners(type){
+var evlistener;
 var ret;
-if(!this._events||!this._events[type])
-ret=[];else
-if(isFunction(this._events[type]))
-ret=[this._events[type]];else
+var events=this._events;
 
-ret=this._events[type].slice();
+if(!events)
+ret=[];else
+{
+evlistener=events[type];
+if(!evlistener)
+ret=[];else
+if(typeof evlistener==='function')
+ret=[evlistener.listener||evlistener];else
+
+ret=unwrapListeners(evlistener);
+}
+
 return ret;
 };
 
-EventEmitter.prototype.listenerCount=function(type){
-if(this._events){
-var evlistener=this._events[type];
+EventEmitter.listenerCount=function(emitter,type){
+if(typeof emitter.listenerCount==='function'){
+return emitter.listenerCount(type);
+}else{
+return listenerCount.call(emitter,type);
+}
+};
 
-if(isFunction(evlistener))
-return 1;else
-if(evlistener)
+EventEmitter.prototype.listenerCount=listenerCount;
+function listenerCount(type){
+var events=this._events;
+
+if(events){
+var evlistener=events[type];
+
+if(typeof evlistener==='function'){
+return 1;
+}else if(evlistener){
 return evlistener.length;
 }
+}
+
 return 0;
+}
+
+EventEmitter.prototype.eventNames=function eventNames(){
+return this._eventsCount>0?Reflect.ownKeys(this._events):[];
 };
 
-EventEmitter.listenerCount=function(emitter,type){
-return emitter.listenerCount(type);
+
+function spliceOne(list,index){
+for(var i=index,k=i+1,n=list.length;k<n;i+=1,k+=1)
+list[i]=list[k];
+list.pop();
+}
+
+function arrayClone(arr,n){
+var copy=new Array(n);
+for(var i=0;i<n;++i)
+copy[i]=arr[i];
+return copy;
+}
+
+function unwrapListeners(arr){
+var ret=new Array(arr.length);
+for(var i=0;i<ret.length;++i){
+ret[i]=arr[i].listener||arr[i];
+}
+return ret;
+}
+
+function objectCreatePolyfill(proto){
+var F=function(){};
+F.prototype=proto;
+return new F();
+}
+function objectKeysPolyfill(obj){
+var keys=[];
+for(var k in obj)if(Object.prototype.hasOwnProperty.call(obj,k)){
+keys.push(k);
+}
+return k;
+}
+function functionBindPolyfill(context){
+var fn=this;
+return function(){
+return fn.apply(context,arguments);
 };
-
-function isFunction(arg){
-return typeof arg==='function';
 }
 
-function isNumber(arg){
-return typeof arg==='number';
-}
-
-function isObject(arg){
-return typeof arg==='object'&&arg!==null;
-}
-
-function isUndefined(arg){
-return arg===void 0;
-}
-
-},{}],57:[function(require,module,exports){
+},{}],63:[function(require,module,exports){
 exports.read=function(buffer,offset,isLE,mLen,nBytes){
 var e,m;
 var eLen=nBytes*8-mLen-1;
@@ -24760,7 +28784,7 @@
 buffer[offset+i-d]|=s*128;
 };
 
-},{}],58:[function(require,module,exports){
+},{}],64:[function(require,module,exports){
 if(typeof Object.create==='function'){
 
 module.exports=function inherits(ctor,superCtor){
@@ -24785,7 +28809,7 @@
 };
 }
 
-},{}],59:[function(require,module,exports){
+},{}],65:[function(require,module,exports){
 
 
 
@@ -24808,14 +28832,14 @@
 return typeof obj.readFloatLE==='function'&&typeof obj.slice==='function'&&isBuffer(obj.slice(0,0));
 }
 
-},{}],60:[function(require,module,exports){
+},{}],66:[function(require,module,exports){
 var toString={}.toString;
 
 module.exports=Array.isArray||function(arr){
 return toString.call(arr)=='[object Array]';
 };
 
-},{}],61:[function(require,module,exports){
+},{}],67:[function(require,module,exports){
 'use strict';
 
 
@@ -24823,6 +28847,9 @@
 typeof Uint16Array!=='undefined'&&
 typeof Int32Array!=='undefined';
 
+function _has(obj,key){
+return Object.prototype.hasOwnProperty.call(obj,key);
+}
 
 exports.assign=function(obj){
 var sources=Array.prototype.slice.call(arguments,1);
@@ -24835,7 +28862,7 @@
 }
 
 for(var p in source){
-if(source.hasOwnProperty(p)){
+if(_has(source,p)){
 obj[p]=source[p];
 }
 }
@@ -24919,13 +28946,32 @@
 
 exports.setTyped(TYPED_OK);
 
-},{}],62:[function(require,module,exports){
+},{}],68:[function(require,module,exports){
 'use strict';
 
 
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 function adler32(adler,buf,len,pos){
 var s1=adler&0xffff|0,
 s2=adler>>>16&0xffff|0,
@@ -24953,10 +28999,28 @@
 
 module.exports=adler32;
 
-},{}],63:[function(require,module,exports){
+},{}],69:[function(require,module,exports){
 'use strict';
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 module.exports={
 
 
@@ -25005,7 +29069,7 @@
 
 
 
-},{}],64:[function(require,module,exports){
+},{}],70:[function(require,module,exports){
 'use strict';
 
 
@@ -25014,6 +29078,24 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 function makeTable(){
 var c,table=[];
 
@@ -25048,9 +29130,28 @@
 
 module.exports=crc32;
 
-},{}],65:[function(require,module,exports){
+},{}],71:[function(require,module,exports){
 'use strict';
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 var utils=require('../utils/common');
 var trees=require('./trees');
 var adler32=require('./adler32');
@@ -26905,9 +31006,28 @@
 
 
 
-},{"../utils/common":61,"./adler32":62,"./crc32":64,"./messages":66,"./trees":67}],66:[function(require,module,exports){
+},{"../utils/common":67,"./adler32":68,"./crc32":70,"./messages":72,"./trees":73}],72:[function(require,module,exports){
 'use strict';
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 module.exports={
 2:'need dictionary',
 1:'stream end',
@@ -26920,10 +31040,28 @@
 '-6':'incompatible version'};
 
 
-},{}],67:[function(require,module,exports){
+},{}],73:[function(require,module,exports){
 'use strict';
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 var utils=require('../utils/common');
 
 
@@ -28124,10 +32262,28 @@
 exports._tr_tally=_tr_tally;
 exports._tr_align=_tr_align;
 
-},{"../utils/common":61}],68:[function(require,module,exports){
+},{"../utils/common":67}],74:[function(require,module,exports){
 'use strict';
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 function ZStream(){
 
 this.input=null;
@@ -28155,7 +32311,7 @@
 
 module.exports=ZStream;
 
-},{}],69:[function(require,module,exports){
+},{}],75:[function(require,module,exports){
 (function(process){
 
 
@@ -28383,7 +32539,7 @@
 
 
 }).call(this,require('_process'));
-},{"_process":71}],70:[function(require,module,exports){
+},{"_process":77}],76:[function(require,module,exports){
 (function(process){
 'use strict';
 
@@ -28430,7 +32586,7 @@
 }
 
 }).call(this,require('_process'));
-},{"_process":71}],71:[function(require,module,exports){
+},{"_process":77}],77:[function(require,module,exports){
 
 var process=module.exports={};
 
@@ -28601,6 +32757,10 @@
 process.removeListener=noop;
 process.removeAllListeners=noop;
 process.emit=noop;
+process.prependListener=noop;
+process.prependOnceListener=noop;
+
+process.listeners=function(name){return[];};
 
 process.binding=function(name){
 throw new Error('process.binding is not supported');
@@ -28612,7 +32772,7 @@
 };
 process.umask=function(){return 0;};
 
-},{}],72:[function(require,module,exports){
+},{}],78:[function(require,module,exports){
 
 
 
@@ -28698,7 +32858,7 @@
 return Object.prototype.toString.call(xs)==='[object Array]';
 };
 
-},{}],73:[function(require,module,exports){
+},{}],79:[function(require,module,exports){
 
 
 
@@ -28785,16 +32945,16 @@
 return res;
 };
 
-},{}],74:[function(require,module,exports){
+},{}],80:[function(require,module,exports){
 'use strict';
 
 exports.decode=exports.parse=require('./decode');
 exports.encode=exports.stringify=require('./encode');
 
-},{"./decode":72,"./encode":73}],75:[function(require,module,exports){
+},{"./decode":78,"./encode":79}],81:[function(require,module,exports){
 module.exports=require("./lib/_stream_duplex.js");
 
-},{"./lib/_stream_duplex.js":76}],76:[function(require,module,exports){
+},{"./lib/_stream_duplex.js":82}],82:[function(require,module,exports){
 
 
 
@@ -28870,7 +33030,7 @@
 f(xs[i],i);
 }
 }
-},{"./_stream_readable":78,"./_stream_writable":80,"core-util-is":55,"inherits":58,"process-nextick-args":70}],77:[function(require,module,exports){
+},{"./_stream_readable":84,"./_stream_writable":86,"core-util-is":61,"inherits":64,"process-nextick-args":76}],83:[function(require,module,exports){
 
 
 
@@ -28897,7 +33057,7 @@
 PassThrough.prototype._transform=function(chunk,encoding,cb){
 cb(null,chunk);
 };
-},{"./_stream_transform":79,"core-util-is":55,"inherits":58}],78:[function(require,module,exports){
+},{"./_stream_transform":85,"core-util-is":61,"inherits":64}],84:[function(require,module,exports){
 (function(process){
 'use strict';
 
@@ -29841,7 +34001,7 @@
 return-1;
 }
 }).call(this,require('_process'));
-},{"./_stream_duplex":76,"./internal/streams/BufferList":81,"_process":71,"buffer":54,"buffer-shims":53,"core-util-is":55,"events":56,"inherits":58,"isarray":60,"process-nextick-args":70,"string_decoder/":87,"util":49}],79:[function(require,module,exports){
+},{"./_stream_duplex":82,"./internal/streams/BufferList":87,"_process":77,"buffer":60,"buffer-shims":59,"core-util-is":61,"events":62,"inherits":64,"isarray":66,"process-nextick-args":76,"string_decoder/":93,"util":55}],85:[function(require,module,exports){
 
 
 
@@ -30024,7 +34184,7 @@
 
 return stream.push(null);
 }
-},{"./_stream_duplex":76,"core-util-is":55,"inherits":58}],80:[function(require,module,exports){
+},{"./_stream_duplex":82,"core-util-is":61,"inherits":64}],86:[function(require,module,exports){
 (function(process){
 
 
@@ -30581,7 +34741,7 @@
 };
 }
 }).call(this,require('_process'));
-},{"./_stream_duplex":76,"_process":71,"buffer":54,"buffer-shims":53,"core-util-is":55,"events":56,"inherits":58,"process-nextick-args":70,"util-deprecate":88}],81:[function(require,module,exports){
+},{"./_stream_duplex":82,"_process":77,"buffer":60,"buffer-shims":59,"core-util-is":61,"events":62,"inherits":64,"process-nextick-args":76,"util-deprecate":94}],87:[function(require,module,exports){
 'use strict';
 
 var Buffer=require('buffer').Buffer;
@@ -30646,10 +34806,10 @@
 }
 return ret;
 };
-},{"buffer":54,"buffer-shims":53}],82:[function(require,module,exports){
+},{"buffer":60,"buffer-shims":59}],88:[function(require,module,exports){
 module.exports=require("./lib/_stream_passthrough.js");
 
-},{"./lib/_stream_passthrough.js":77}],83:[function(require,module,exports){
+},{"./lib/_stream_passthrough.js":83}],89:[function(require,module,exports){
 (function(process){
 var Stream=function(){
 try{
@@ -30669,13 +34829,13 @@
 }
 
 }).call(this,require('_process'));
-},{"./lib/_stream_duplex.js":76,"./lib/_stream_passthrough.js":77,"./lib/_stream_readable.js":78,"./lib/_stream_transform.js":79,"./lib/_stream_writable.js":80,"_process":71}],84:[function(require,module,exports){
+},{"./lib/_stream_duplex.js":82,"./lib/_stream_passthrough.js":83,"./lib/_stream_readable.js":84,"./lib/_stream_transform.js":85,"./lib/_stream_writable.js":86,"_process":77}],90:[function(require,module,exports){
 module.exports=require("./lib/_stream_transform.js");
 
-},{"./lib/_stream_transform.js":79}],85:[function(require,module,exports){
+},{"./lib/_stream_transform.js":85}],91:[function(require,module,exports){
 module.exports=require("./lib/_stream_writable.js");
 
-},{"./lib/_stream_writable.js":80}],86:[function(require,module,exports){
+},{"./lib/_stream_writable.js":86}],92:[function(require,module,exports){
 
 
 
@@ -30804,7 +34964,7 @@
 return dest;
 };
 
-},{"events":56,"inherits":58,"readable-stream/duplex.js":75,"readable-stream/passthrough.js":82,"readable-stream/readable.js":83,"readable-stream/transform.js":84,"readable-stream/writable.js":85}],87:[function(require,module,exports){
+},{"events":62,"inherits":64,"readable-stream/duplex.js":81,"readable-stream/passthrough.js":88,"readable-stream/readable.js":89,"readable-stream/transform.js":90,"readable-stream/writable.js":91}],93:[function(require,module,exports){
 
 
 
@@ -31027,7 +35187,7 @@
 this.charLength=this.charReceived?3:0;
 }
 
-},{"buffer":54}],88:[function(require,module,exports){
+},{"buffer":60}],94:[function(require,module,exports){
 (function(global){
 
 
@@ -31098,16 +35258,16 @@
 }
 
 }).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{}],89:[function(require,module,exports){
-arguments[4][58][0].apply(exports,arguments);
-},{"dup":58}],90:[function(require,module,exports){
+},{}],95:[function(require,module,exports){
+arguments[4][64][0].apply(exports,arguments);
+},{"dup":64}],96:[function(require,module,exports){
 module.exports=function isBuffer(arg){
 return arg&&typeof arg==='object'&&
 typeof arg.copy==='function'&&
 typeof arg.fill==='function'&&
 typeof arg.readUInt8==='function';
 };
-},{}],91:[function(require,module,exports){
+},{}],97:[function(require,module,exports){
 (function(process,global){
 
 
@@ -31697,7 +35857,7 @@
 }
 
 }).call(this,require('_process'),typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{"./support/isBuffer":90,"_process":71,"inherits":89}],92:[function(require,module,exports){
+},{"./support/isBuffer":96,"_process":77,"inherits":95}],98:[function(require,module,exports){
 
 
 var langs=[
@@ -39841,7 +44001,7 @@
 return langs;
 };
 
-},{}],93:[function(require,module,exports){
+},{}],99:[function(require,module,exports){
 
 
 
@@ -40435,7 +44595,7 @@
 }};
 
 
-},{}],94:[function(require,module,exports){
+},{}],100:[function(require,module,exports){
 
 
 
@@ -41262,7 +45422,7 @@
 return format;
 };
 
-},{}],95:[function(require,module,exports){
+},{}],101:[function(require,module,exports){
 
 
 
@@ -41483,7 +45643,7 @@
 this.method=method;
 };
 
-},{}],96:[function(require,module,exports){
+},{}],102:[function(require,module,exports){
 
 
 
@@ -41846,7 +46006,7 @@
 return null;
 };
 
-},{}],97:[function(require,module,exports){
+},{}],103:[function(require,module,exports){
 
 
 
@@ -42156,7 +46316,7 @@
 ["woff","application/font-woff"]]);
 
 
-},{}],98:[function(require,module,exports){
+},{}],104:[function(require,module,exports){
 
 
 
@@ -42270,7 +46430,7 @@
 }};
 
 
-},{}],99:[function(require,module,exports){
+},{}],105:[function(require,module,exports){
 
 
 
@@ -42617,7 +46777,7 @@
 return WebInspector.TextRange.comparator(edit1.oldRange,edit2.oldRange);
 };
 
-},{}],100:[function(require,module,exports){
+},{}],106:[function(require,module,exports){
 
 
 
@@ -42927,7 +47087,7 @@
 createTokenizer:function(mimeType){}};
 
 
-},{}],101:[function(require,module,exports){
+},{}],107:[function(require,module,exports){
 
 
 
@@ -43039,7 +47199,7 @@
 }};
 
 
-},{}],102:[function(require,module,exports){
+},{}],108:[function(require,module,exports){
 
 
 
@@ -43195,7 +47355,7 @@
 }};
 
 
-},{}],103:[function(require,module,exports){
+},{}],109:[function(require,module,exports){
 
 
 
@@ -44737,7 +48897,7 @@
 
 };
 
-},{}],104:[function(require,module,exports){
+},{}],110:[function(require,module,exports){
 
 
 
@@ -45116,7 +49276,7 @@
 __proto__:WebInspector.ProfileTreeModel.prototype};
 
 
-},{}],105:[function(require,module,exports){
+},{}],111:[function(require,module,exports){
 
 
 
@@ -45562,7 +49722,7 @@
 Overloaded:"Overloaded"};
 
 
-},{}],106:[function(require,module,exports){
+},{}],112:[function(require,module,exports){
 
 
 
@@ -45816,7 +49976,7 @@
 }};
 
 
-},{}],107:[function(require,module,exports){
+},{}],113:[function(require,module,exports){
 
 
 
@@ -46787,7 +50947,7 @@
 "zoom":200};
 
 
-},{}],108:[function(require,module,exports){
+},{}],114:[function(require,module,exports){
 
 
 
@@ -47089,7 +51249,7 @@
 }};
 
 
-},{}],109:[function(require,module,exports){
+},{}],115:[function(require,module,exports){
 
 
 
@@ -47415,7 +51575,7 @@
 __proto__:WebInspector.CSSRule.prototype};
 
 
-},{}],110:[function(require,module,exports){
+},{}],116:[function(require,module,exports){
 
 
 
@@ -47730,7 +51890,7 @@
 }};
 
 
-},{}],111:[function(require,module,exports){
+},{}],117:[function(require,module,exports){
 
 
 
@@ -48668,7 +52828,7 @@
 
 WebInspector.multitargetNetworkManager;
 
-},{}],112:[function(require,module,exports){
+},{}],118:[function(require,module,exports){
 
 
 
@@ -49933,7 +54093,7 @@
 __proto__:WebInspector.SDKObject.prototype};
 
 
-},{}],113:[function(require,module,exports){
+},{}],119:[function(require,module,exports){
 
 
 
@@ -50060,7 +54220,7 @@
 }};
 
 
-},{}],114:[function(require,module,exports){
+},{}],120:[function(require,module,exports){
 
 
 
@@ -50353,7 +54513,7 @@
 __proto__:WebInspector.SDKObject.prototype};
 
 
-},{}],115:[function(require,module,exports){
+},{}],121:[function(require,module,exports){
 
 
 
@@ -50744,7 +54904,7 @@
 
 WebInspector.targetManager=new WebInspector.TargetManager();
 
-},{}],116:[function(require,module,exports){
+},{}],122:[function(require,module,exports){
 
 
 
@@ -51731,7 +55891,7 @@
 __proto__:WebInspector.TracingModel.NamedObject.prototype};
 
 
-},{}],117:[function(require,module,exports){
+},{}],123:[function(require,module,exports){
 
 
 
@@ -52012,7 +56172,7 @@
 }};
 
 
-},{}],118:[function(require,module,exports){
+},{}],124:[function(require,module,exports){
 
 
 
@@ -52902,7 +57062,7 @@
 __proto__:WebInspector.VBox.prototype};
 
 
-},{}],119:[function(require,module,exports){
+},{}],125:[function(require,module,exports){
 
 
 
@@ -55058,7 +59218,7 @@
 return span;
 };
 
-},{}],120:[function(require,module,exports){
+},{}],126:[function(require,module,exports){
 
 
 
@@ -56370,7 +60530,7 @@
 return model;
 };
 
-},{}],121:[function(require,module,exports){
+},{}],127:[function(require,module,exports){
 
 
 
@@ -57031,7 +61191,7 @@
 this.triggerTime=triggerTime;
 };
 
-},{}],122:[function(require,module,exports){
+},{}],128:[function(require,module,exports){
 
 
 
@@ -57366,7 +61526,7 @@
 
 
 
-},{}],123:[function(require,module,exports){
+},{}],129:[function(require,module,exports){
 
 
 
@@ -57866,7 +62026,7 @@
 return samples;
 };
 
-},{}],124:[function(require,module,exports){
+},{}],130:[function(require,module,exports){
 
 
 
@@ -59665,7 +63825,7 @@
 }};
 
 
-},{}],125:[function(require,module,exports){
+},{}],131:[function(require,module,exports){
 
 
 
@@ -60046,7 +64206,7 @@
 }};
 
 
-},{}],126:[function(require,module,exports){
+},{}],132:[function(require,module,exports){
 
 
 
@@ -60235,7 +64395,7 @@
 __proto__:WebInspector.ViewportDataGridNode.prototype};
 
 
-},{}],127:[function(require,module,exports){
+},{}],133:[function(require,module,exports){
 (function(process){
 
 
@@ -60424,7 +64584,7 @@
 }
 
 }).call(this,require('_process'));
-},{"./debug":128,"_process":71}],128:[function(require,module,exports){
+},{"./debug":134,"_process":77}],134:[function(require,module,exports){
 
 
 
@@ -60628,7 +64788,7 @@
 return val;
 }
 
-},{"ms":140}],129:[function(require,module,exports){
+},{"ms":146}],135:[function(require,module,exports){
 
 
 
@@ -60725,7 +64885,7 @@
 
 };
 
-},{}],130:[function(require,module,exports){
+},{}],136:[function(require,module,exports){
 (function webpackUniversalModuleDefinition(root,factory){
 
 if(typeof exports==='object'&&typeof module==='object')
@@ -67426,7 +71586,7 @@
 
 });
 ;
-},{}],131:[function(require,module,exports){
+},{}],137:[function(require,module,exports){
 (function(Buffer){
 var querystring=require('querystring');
 var trim=require('./trim');
@@ -67733,12 +71893,12 @@
 module.exports=Link;
 
 }).call(this,{"isBuffer":require("../../../lighthouse-extension/node_modules/is-buffer/index.js")});
-},{"../../../lighthouse-extension/node_modules/is-buffer/index.js":59,"./trim":132,"querystring":74}],132:[function(require,module,exports){
+},{"../../../lighthouse-extension/node_modules/is-buffer/index.js":65,"./trim":138,"querystring":80}],138:[function(require,module,exports){
 module.exports=function trim(value){
 return value.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,'');
 };
 
-},{}],133:[function(require,module,exports){
+},{}],139:[function(require,module,exports){
 
 
 
@@ -67883,7 +72043,7 @@
 })(ImageSSIM||(ImageSSIM={}));
 module.exports=ImageSSIM;
 
-},{}],134:[function(require,module,exports){
+},{}],140:[function(require,module,exports){
 var encode=require('./lib/encoder'),
 decode=require('./lib/decoder');
 
@@ -67892,7 +72052,7 @@
 decode:decode};
 
 
-},{"./lib/decoder":135,"./lib/encoder":136}],135:[function(require,module,exports){
+},{"./lib/decoder":141,"./lib/encoder":142}],141:[function(require,module,exports){
 (function(Buffer){
 
 
@@ -68882,7 +73042,7 @@
 }
 
 }).call(this,require("buffer").Buffer);
-},{"buffer":54}],136:[function(require,module,exports){
+},{"buffer":60}],142:[function(require,module,exports){
 (function(Buffer){
 
 
@@ -69652,7 +73812,7 @@
 }
 
 }).call(this,require("buffer").Buffer);
-},{"buffer":54}],137:[function(require,module,exports){
+},{"buffer":60}],143:[function(require,module,exports){
 (function(process){
 
 
@@ -69868,7 +74028,7 @@
 module.exports=Log;
 
 }).call(this,require('_process'));
-},{"_process":71,"debug":127,"events":56}],138:[function(require,module,exports){
+},{"_process":77,"debug":133,"events":62}],144:[function(require,module,exports){
 (function(global){
 
 
@@ -71720,7 +75880,7 @@
 module.exports=isEqual;
 
 }).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{});
-},{}],139:[function(require,module,exports){
+},{}],145:[function(require,module,exports){
 exports.getRenderingDataFromViewport=function(viewportProperties,uaDeviceWidth,uaDeviceHeight,uaMaxZoom,uaMinZoom){
 
 var vw=uaDeviceWidth/100;
@@ -72063,7 +76223,7 @@
 "viewport-fit":["auto","cover"]};
 
 
-},{}],140:[function(require,module,exports){
+},{}],146:[function(require,module,exports){
 
 
 
@@ -72217,7 +76377,7 @@
 return Math.ceil(ms/n)+' '+name+'s';
 }
 
-},{}],141:[function(require,module,exports){
+},{}],147:[function(require,module,exports){
 module.exports=function parseCacheControl(field){
 
 if(typeof field!=='string'){
@@ -72256,7 +76416,436 @@
 return err?null:header;
 };
 
-},{}],142:[function(require,module,exports){
+},{}],148:[function(require,module,exports){
+var URL=require('url').URL;
+
+
+
+
+
+
+
+
+
+
+
+function trimLine(line){
+if(!line){
+return null;
+}
+
+if(Array.isArray(line)){
+return line.map(trimLine);
+}
+
+return String(line).trim();
+}
+
+
+
+
+
+
+
+
+function removeComments(line){
+var commentStartIndex=line.indexOf('#');
+if(commentStartIndex>-1){
+return line.substr(0,commentStartIndex);
+}
+
+return line;
+}
+
+
+
+
+
+
+
+
+function splitLine(line){
+var idx=String(line).indexOf(':');
+
+if(!line||idx<0){
+return null;
+}
+
+return[line.slice(0,idx),line.slice(idx+1)];
+}
+
+
+
+
+
+
+
+
+
+function formatUserAgent(userAgent){
+var formattedUserAgent=userAgent.toLowerCase();
+
+
+var idx=formattedUserAgent.indexOf('/');
+if(idx>-1){
+formattedUserAgent=formattedUserAgent.substr(0,idx);
+}
+
+return formattedUserAgent.trim();
+}
+
+
+
+
+
+
+
+
+
+function normaliseEncoding(path){
+try{
+return urlEncodeToUpper(encodeURI(path).replace(/%25/g,'%'));
+}catch(e){
+return path;
+}
+}
+
+
+
+
+
+
+
+
+
+
+function urlEncodeToUpper(path){
+return path.replace(/%[0-9a-fA-F]{2}/g,function(match){
+return match.toUpperCase();
+});
+}
+
+
+
+
+
+
+
+
+
+
+
+function parsePattern(pattern){
+var regexSpecialChars=/[\-\[\]\/\{\}\(\)\+\?\.\\\^\$\|]/g;
+var wildCardPattern=/\*/g;
+var endOfLinePattern=/\\\$$/;
+
+pattern=normaliseEncoding(pattern);
+
+if(pattern.indexOf('*')<0&&pattern.indexOf('$')<0){
+return pattern;
+}
+
+pattern=pattern.
+replace(regexSpecialChars,'\\$&').
+replace(wildCardPattern,'(?:.*)').
+replace(endOfLinePattern,'$');
+
+return new RegExp(pattern);
+}
+
+function parseRobots(contents,robots){
+var newlineRegex=/\r\n|\r|\n/;
+var lines=contents.
+split(newlineRegex).
+map(removeComments).
+map(splitLine).
+map(trimLine);
+
+var currentUserAgents=[];
+var isNoneUserAgentState=true;
+for(var i=0;i<lines.length;i++){
+var line=lines[i];
+
+if(!line||!line[0]){
+continue;
+}
+
+switch(line[0].toLowerCase()){
+case'user-agent':
+if(isNoneUserAgentState){
+currentUserAgents.length=0;
+}
+
+if(line[1]){
+currentUserAgents.push(formatUserAgent(line[1]));
+}
+break;
+case'disallow':
+robots.addRule(currentUserAgents,line[1],false,i+1);
+break;
+case'allow':
+robots.addRule(currentUserAgents,line[1],true,i+1);
+break;
+case'crawl-delay':
+robots.setCrawlDelay(currentUserAgents,line[1]);
+break;
+case'sitemap':
+if(line[1]){
+robots.addSitemap(line[1]);
+}
+break;
+case'host':
+if(line[1]){
+robots.setPreferredHost(line[1].toLowerCase());
+}
+break;}
+
+
+isNoneUserAgentState=line[0].toLowerCase()!=='user-agent';
+}
+}
+
+
+
+
+
+
+
+
+
+function findRule(path,rules){
+var matchingRule=null;
+
+for(var i=0;i<rules.length;i++){
+var rule=rules[i];
+
+if(typeof rule.pattern==='string'){
+if(path.indexOf(rule.pattern)!==0){
+continue;
+}
+
+
+if(!matchingRule||rule.pattern.length>matchingRule.pattern.length){
+matchingRule=rule;
+}
+
+
+}else if(rule.pattern.test(path)){
+return rule;
+}
+}
+
+return matchingRule;
+}
+
+
+
+
+
+
+
+
+
+
+function parseUrl(url){
+try{
+return new URL(url);
+}catch(e){
+return null;
+}
+}
+
+
+function Robots(url,contents){
+this._url=parseUrl(url)||{};
+this._url.port=this._url.port||80;
+
+this._rules={};
+this._sitemaps=[];
+this._preferedHost=null;
+
+parseRobots(contents||'',this);
+}
+
+
+
+
+
+
+
+
+
+
+Robots.prototype.addRule=function(userAgents,pattern,allow,lineNumber){
+var rules=this._rules;
+
+userAgents.forEach(function(userAgent){
+rules[userAgent]=rules[userAgent]||[];
+
+if(!pattern){
+return;
+}
+
+rules[userAgent].push({
+pattern:parsePattern(pattern),
+allow:allow,
+lineNumber:lineNumber});
+
+});
+};
+
+
+
+
+
+
+
+Robots.prototype.setCrawlDelay=function(userAgents,delayStr){
+var rules=this._rules;
+var delay=Number(delayStr);
+
+userAgents.forEach(function(userAgent){
+rules[userAgent]=rules[userAgent]||[];
+
+if(isNaN(delay)){
+return;
+}
+
+rules[userAgent].crawlDelay=delay;
+});
+};
+
+
+
+
+
+
+Robots.prototype.addSitemap=function(url){
+this._sitemaps.push(url);
+};
+
+
+
+
+
+
+Robots.prototype.setPreferredHost=function(url){
+this._preferedHost=url;
+};
+
+Robots.prototype._getRule=function(url,ua){
+var parsedUrl=parseUrl(url)||{};
+var userAgent=formatUserAgent(ua||'*');
+
+parsedUrl.port=parsedUrl.port||'80';
+
+
+if(parsedUrl.protocol!==this._url.protocol||
+parsedUrl.hostname!==this._url.hostname||
+parsedUrl.port!==this._url.port){
+return;
+}
+
+var rules=this._rules[userAgent]||this._rules['*']||[];
+var path=urlEncodeToUpper(parsedUrl.pathname+parsedUrl.search);
+var rule=findRule(path,rules);
+
+return rule;
+};
+
+
+
+
+
+
+
+
+
+
+
+Robots.prototype.isAllowed=function(url,ua){
+var rule=this._getRule(url,ua);
+
+if(typeof rule==='undefined'){
+return;
+}
+
+return!rule||rule.allow;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Robots.prototype.getMatchingLineNumber=function(url,ua){
+var rule=this._getRule(url,ua);
+
+return rule?rule.lineNumber:-1;
+};
+
+
+
+
+
+
+
+
+Robots.prototype.isDisallowed=function(url,ua){
+return!this.isAllowed(url,ua);
+};
+
+
+
+
+
+
+
+
+
+Robots.prototype.getCrawlDelay=function(ua){
+var userAgent=formatUserAgent(ua||'*');
+
+return(this._rules[userAgent]||this._rules['*']||{}).crawlDelay;
+};
+
+
+
+
+
+
+Robots.prototype.getPreferredHost=function(){
+return this._preferedHost;
+};
+
+
+
+
+
+
+Robots.prototype.getSitemaps=function(){
+return this._sitemaps.slice(0);
+};
+
+module.exports=Robots;
+
+},{"url":"url"}],149:[function(require,module,exports){
+var Robots=require('./Robots');
+
+module.exports=function(url,contents){
+return new Robots(url,contents);
+};
+},{"./Robots":148}],150:[function(require,module,exports){
 (function(process){
 exports=module.exports=SemVer;
 
@@ -73463,7 +78052,7 @@
 }
 
 }).call(this,require('_process'));
-},{"_process":71}],143:[function(require,module,exports){
+},{"_process":77}],151:[function(require,module,exports){
 (function(Buffer){
 'use strict';
 
@@ -73651,7 +78240,7 @@
 
 
 }).call(this,require("buffer").Buffer);
-},{"buffer":54,"jpeg-js":134}],144:[function(require,module,exports){
+},{"buffer":60,"jpeg-js":140}],152:[function(require,module,exports){
 'use strict';
 
 const frame=require('./frame');
@@ -73709,7 +78298,7 @@
 });
 };
 
-},{"./frame":143,"./speed-index":145}],145:[function(require,module,exports){
+},{"./frame":151,"./speed-index":153}],153:[function(require,module,exports){
 'use strict';
 
 const imageSSIM=require('image-ssim');
@@ -73932,11 +78521,260 @@
 calculateSpeedIndexes};
 
 
-},{"image-ssim":133}],146:[function(require,module,exports){
+},{"image-ssim":139}],154:[function(require,module,exports){
 module.exports={
-"version":"2.9.1"};
+"version":"3.0.0-beta.0"};
 
-},{}],147:[function(require,module,exports){
-module.exports={"npm":{"angular":[{"title":"Cross-site Scripting (XSS)","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-78"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10170"]},"severity":"medium","semver":{"unaffected":[">=1.2.0"],"vulnerable":["<=1.1.5"]},"credit":["Chirayu Krishnappa"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N","disclosureTime":"2013-06-20T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T10:00:00.000Z","modificationTime":"2016-11-01T14:08:59.890Z","creationTime":"2016-11-01T14:08:59.890Z","id":"npm:angular:20130621","packageName":"angular","cvssScore":6.8,"alternativeIds":["SNYK-JS-ANGULAR-10170"]},{"title":"Cross-site Scripting (XSS)","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10179"]},"severity":"medium","semver":{"unaffected":[">=1.2.0"],"vulnerable":["<1.2.0 >=1.0.0"]},"credit":["Chirayu Krishnappa"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2013-06-21T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T10:10:00.000Z","modificationTime":"2016-11-01T15:35:22.355Z","creationTime":"2016-11-01T15:35:22.355Z","id":"npm:angular:20130622","packageName":"angular","cvssScore":5.4,"alternativeIds":["SNYK-JS-ANGULAR-10179"]},{"title":"Arbitrary Script Injection","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-78"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10140"]},"severity":"high","semver":{"unaffected":[">=1.1.5"],"vulnerable":["<1.1.5"]},"credit":["Chirayu Krishnappa","Igor Minar"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","disclosureTime":"2013-06-24T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T10:20:00.000Z","modificationTime":"2016-11-01T12:48:50.251Z","creationTime":"2016-11-01T12:48:50.251Z","id":"npm:angular:20130625","packageName":"angular","cvssScore":8.1,"alternativeIds":["SNYK-JS-ANGULAR-10140"]},{"title":"Protection Bypass","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":[],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10200"]},"severity":"high","semver":{"unaffected":[">=1.2.2"],"vulnerable":["<1.2.2"]},"credit":["Chirayu Krishnappa"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","disclosureTime":"2013-11-12T22:00:00.000Z","patches":[],"publicationTime":"2017-01-23T10:30:00.000Z","modificationTime":"2016-11-09T12:07:09.956Z","creationTime":"2016-11-09T12:07:09.956Z","id":"npm:angular:20131113","packageName":"angular","cvssScore":7.4,"alternativeIds":["SNYK-JS-ANGULAR-10200"]},{"title":"Arbitrary Code Execution","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":[],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10201"]},"severity":"low","semver":{"unaffected":[">=1.3.0"],"vulnerable":["<1.3.0"]},"credit":["Jann Horn"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N","disclosureTime":"2014-06-07T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T10:40:00.000Z","modificationTime":"2016-11-09T12:23:07.035Z","creationTime":"2016-11-09T12:23:07.035Z","id":"npm:angular:20140608","packageName":"angular","cvssScore":3.7,"alternativeIds":["SNYK-JS-ANGULAR-10201"]},{"title":"Cross-site Scripting (XSS)","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10191"]},"severity":"medium","semver":{"unaffected":[">=1.3.0-rc.4"],"vulnerable":["<1.3.0-rc.4"]},"credit":["Laurent Trillaud"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N","disclosureTime":"2014-09-07T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T10:50:00.000Z","modificationTime":"2016-11-07T09:46:43.092Z","creationTime":"2016-11-07T09:46:43.092Z","id":"npm:angular:20140908","packageName":"angular","cvssScore":5.3,"alternativeIds":["SNYK-JS-ANGULAR-10191"]},{"title":"Unsafe Object Deserialization","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":[],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10141"]},"severity":"high","semver":{"unaffected":[">=1.2.24"],"vulnerable":["<1.2.24 >=1.2.19"]},"credit":["Chirayu Krishnappa"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","disclosureTime":"2014-09-08T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T11:00:00.000Z","modificationTime":"2016-11-01T13:57:31.962Z","creationTime":"2016-11-01T13:57:31.962Z","id":"npm:angular:20140909","packageName":"angular","cvssScore":7.4,"alternativeIds":["SNYK-JS-ANGULAR-10141"]},{"title":"Arbitrary Command Execution","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-78"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10173"]},"severity":"medium","semver":{"unaffected":[">=1.3.2"],"vulnerable":["<1.3.2"]},"credit":["Sebastian Lekies","Jann Horn","Gábor Molnár"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:L","disclosureTime":"2014-11-03T22:00:00.000Z","patches":[],"publicationTime":"2017-01-23T11:10:00.000Z","modificationTime":"2016-11-01T12:33:38.496Z","creationTime":"2016-11-01T12:33:38.496Z","id":"npm:angular:20141104","packageName":"angular","cvssScore":6.5,"alternativeIds":["SNYK-JS-ANGULAR-10173"]},{"title":"Arbitrary Code Execution","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-78"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10174"]},"severity":"high","semver":{"unaffected":[">=1.5.0-beta.2"],"vulnerable":["<1.5.0-beta.2"]},"credit":["Rodric Haddad"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","disclosureTime":"2015-03-09T22:00:00.000Z","patches":[],"publicationTime":"2017-01-23T11:20:00.000Z","modificationTime":"2017-02-13T14:24:12.988Z","creationTime":"2016-11-01T14:24:12.988Z","id":"npm:angular:20150310","packageName":"angular","cvssScore":7.4,"alternativeIds":["SNYK-JS-ANGULAR-10174"]},{"title":"JSONP Callback Attack","credit":["Pete Bacon Darwin"],"moduleName":"angular","packageName":"angular","language":"js","packageManager":"npm","id":"npm:angular:20150315","identifiers":{"CWE":[],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10175"]},"semver":{"vulnerable":["<1.6.1"],"unaffected":[">=1.6.1"]},"patches":[],"cvssScore":6.5,"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","disclosureTime":"2015-03-14T22:00:00.000Z","publicationTime":"2017-02-13T18:30:00.000Z","modificationTime":"2017-02-13T14:36:18.735Z","creationTime":"2016-11-01T14:36:18.735Z","alternativeIds":["SNYK-JS-ANGULAR-10175"]},{"title":"Cross-site Scripting (XSS)","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-78"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10176"]},"severity":"high","semver":{"unaffected":[">=1.5.0-beta.0"],"vulnerable":["<1.5.0-beta.0 >=1.0.0"]},"credit":["Igor Minar"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N","disclosureTime":"2015-08-06T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T11:40:00.000Z","modificationTime":"2016-11-01T13:30:14.967Z","creationTime":"2016-11-01T13:30:14.967Z","id":"npm:angular:20150807","packageName":"angular","cvssScore":7.1,"alternativeIds":["SNYK-JS-ANGULAR-10176"]},{"title":"Clickjacking","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-693"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10177"]},"severity":"medium","semver":{"unaffected":[">=1.5.0-beta.0"],"vulnerable":["<1.5.0-beta.0 >=1.3.1"]},"credit":["Igor Minar"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N","disclosureTime":"2015-08-06T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T11:50:00.000Z","modificationTime":"2016-11-01T13:30:14.967Z","creationTime":"2016-11-01T13:30:14.967Z","id":"npm:angular:20150807-1","packageName":"angular","cvssScore":6.8,"alternativeIds":["SNYK-JS-ANGULAR-10177"]},{"title":"Cross-site Scripting (XSS)","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":[],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10182"]},"severity":"high","semver":{"unaffected":[">=1.5.0-beta.2"],"vulnerable":["<1.5.0-beta.2"]},"credit":["Igor Minar"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N","disclosureTime":"2015-09-08T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T12:00:00.000Z","modificationTime":"2016-11-02T08:40:11.750Z","creationTime":"2016-11-02T08:40:11.750Z","id":"npm:angular:20150909","packageName":"angular","cvssScore":7.1,"alternativeIds":["SNYK-JS-ANGULAR-10182"]},{"title":"Cross-site Scripting (XSS)","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10180"]},"severity":"medium","semver":{"unaffected":[">=1.4.10"],"vulnerable":["<1.4.10"]},"credit":["Lucas Mirelmann"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2015-11-29T22:00:00.000Z","patches":[],"publicationTime":"2017-01-23T12:10:00.000Z","modificationTime":"2016-11-02T08:16:55.157Z","creationTime":"2016-11-02T08:16:55.157Z","id":"npm:angular:20151130","packageName":"angular","cvssScore":5.4,"alternativeIds":["SNYK-JS-ANGULAR-10180"]},{"title":"Cross-site Scripting (XSS)","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10181"]},"severity":"medium","semver":{"unaffected":[">=1.5.0-rc.0"],"vulnerable":["<1.5.0-rc.0"]},"credit":["Pete Bacon Darwin"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","disclosureTime":"2015-12-04T22:00:00.000Z","patches":[],"publicationTime":"2017-01-23T12:20:00.000Z","modificationTime":"2016-11-02T08:26:38.753Z","creationTime":"2016-11-02T08:26:38.753Z","id":"npm:angular:20151205","packageName":"angular","cvssScore":4.3,"alternativeIds":["SNYK-JS-ANGULAR-10181"]},{"title":"Cross-site Scripting (XSS)","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10202"]},"severity":"medium","semver":{"unaffected":[">=1.5.0-rc.2"],"vulnerable":["<1.5.0-rc.2 >=1.3.0"]},"credit":["Lucas Mirelmann"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","disclosureTime":"2016-01-21T22:00:00.000Z","patches":[],"publicationTime":"2017-01-23T12:30:00.000Z","modificationTime":"2016-11-09T12:45:57.682Z","creationTime":"2016-11-09T12:45:57.682Z","id":"npm:angular:20160122","packageName":"angular","cvssScore":4.3,"alternativeIds":["SNYK-JS-ANGULAR-10202"]},{"title":"Arbitrary Script Injection","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":[],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10203"]},"severity":"medium","semver":{"unaffected":[">=1.2.30"],"vulnerable":["<1.2.30 >=1.0.0"]},"credit":["Raphaël Jamet"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N","disclosureTime":"2016-05-26T21:00:00.000Z","patches":[],"publicationTime":"2017-01-23T12:40:00.000Z","modificationTime":"2016-11-09T13:00:18.135Z","creationTime":"2016-11-09T13:00:18.135Z","id":"npm:angular:20160527","packageName":"angular","cvssScore":4.8,"alternativeIds":["SNYK-JS-ANGULAR-10203"]},{"title":"Content Security Policy (CSP) Bypass","moduleName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":[],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-10190"]},"severity":"medium","semver":{"unaffected":[">=1.5.9"],"vulnerable":["<1.5.9 >=1.5.0"]},"credit":["Martin Probst"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N","disclosureTime":"2016-10-31T22:00:00.000Z","patches":[],"publicationTime":"2017-01-23T12:50:00.000Z","modificationTime":"2017-01-24T09:16:32.893Z","creationTime":"2016-11-07T09:16:32.893Z","id":"npm:angular:20161101","packageName":"angular","cvssScore":6.5,"alternativeIds":["SNYK-JS-ANGULAR-10190"]},{"title":"Cross-site Scripting (XSS)","credit":["Unknown"],"moduleName":"angular","packageName":"angular","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-ANGULAR-12026"]},"semver":{"unaffected":[">=1.6.7"],"vulnerable":["<1.6.7"]},"patches":[],"cvssScore":6.5,"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","disclosureTime":"2017-10-17T21:00:00.000Z","publicationTime":"2017-12-25T14:45:01.473Z","modificationTime":"2017-12-19T11:18:55.007Z","creationTime":"2017-12-19T11:18:55.007Z","id":"npm:angular:20171018","alternativeIds":["SNYK-JS-ANGULAR-12026"]}],"backbone":[{"title":"Cross-site Scripting (XSS)","credit":[],"language":"js","packageManager":"npm","packageName":"backbone","moduleName":"backbone","semver":{"vulnerable":["<0.5.0"],"unaffected":[">=0.5.0"]},"identifiers":{"CWE":[],"CVE":[],"ALTERNATIVE":["SNYK-JS-BACKBONE-10054"]},"patches":[{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/backbone/20110701/backbone_20110701_0_0_0cdc525961d3fa98e810ffae6bcc8e3838e36d93.patch"],"version":"<0.5.0 >=0.3.3","modificationTime":"2015-11-06T02:09:36.180Z","comments":["https://github.com/jashkenas/backbone/commit/0cdc525961d3fa98e810ffae6bcc8e3838e36d93.patch"],"id":"patch:npm:backbone:20110701:0"}],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","creationTime":"2015-11-06T02:09:36.180Z","publicationTime":"2015-11-06T02:09:36.180Z","modificationTime":"2015-11-06T02:09:36.180Z","disclosureTime":"2015-11-06T02:09:36.180Z","id":"npm:backbone:20110701","cvssScore":6.5,"alternativeIds":["SNYK-JS-BACKBONE-10054"]},{"title":"Cross-site Scripting (XSS)","credit":["Unknown"],"creationTime":"2016-05-24T06:45:20.086Z","modificationTime":"2016-05-24T06:45:20.086Z","publicationTime":"2016-06-22T17:50:20.000Z","disclosureTime":"2016-05-23T17:50:20.000Z","semver":{"vulnerable":["<= 0.3.3"],"unaffected":[">= 0.5.0"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","severity":"medium","identifiers":{"CWE":["CWE-79"],"CVE":[],"NSP":108,"ALTERNATIVE":["SNYK-JS-BACKBONE-10110"]},"patches":[],"moduleName":"backbone","language":"js","packageManager":"npm","id":"npm:backbone:20160523","packageName":"backbone","cvssScore":6.5,"alternativeIds":["SNYK-JS-BACKBONE-10110"]}],"bootstrap":[{"title":"Cross-site Scripting (XSS)","credit":["Peter Corsaro"],"packageName":"bootstrap","moduleName":"bootstrap","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-BOOTSTRAP-10433"]},"semver":{"unaffected":[">=2.1.0"],"vulnerable":["<2.1.0"]},"patches":[],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","disclosureTime":"2012-05-09T21:00:00.000Z","publicationTime":"2017-04-10T09:39:59.975Z","modificationTime":"2017-02-27T10:05:00.075Z","creationTime":"2017-02-27T10:05:00.075Z","id":"npm:bootstrap:20120510","cvssScore":6.5,"alternativeIds":["SNYK-JS-BOOTSTRAP-10433"]},{"title":"Cross-Site Scripting (XSS)","credit":["Unknown"],"moduleName":"bootstrap","packageName":"bootstrap","language":"js","packageManager":"npm","identifiers":{"CVE":[],"CWE":["CWE-79"],"ALTERNATIVE":["SNYK-JS-BOOTSTRAP-10860"]},"semver":{"unaffected":[">=3.4.0 <4.0.0-alpha || >4.0.0-beta.2"],"vulnerable":["<3.4.0 || >=4.0.0-alpha <4.0.0-beta.2"]},"severity":"medium","cvssScore":6.5,"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","patches":[],"creationTime":"2017-11-25T17:23:26.518Z","modificationTime":"2017-11-25T17:23:26.518Z","publicationTime":"2018-01-19T09:37:48.056Z","disclosureTime":"2016-06-27T17:23:26.518Z","id":"npm:bootstrap:20160627","alternativeIds":["SNYK-JS-BOOTSTRAP-10860"]}],"dojo":[{"title":"Cross-site Scripting (XSS)","credit":[],"semver":{"vulnerable":["<1.1"],"unaffected":[">=1.1"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","severity":"medium","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2008-6681"],"ALTERNATIVE":["SNYK-JS-DOJO-10051"]},"patches":[],"moduleName":"dojo","creationTime":"2015-11-06T02:09:36.180Z","publicationTime":"2015-11-06T02:09:36.180Z","modificationTime":"2015-11-06T02:09:36.180Z","disclosureTime":"2015-11-06T02:09:36.180Z","language":"js","packageManager":"npm","id":"npm:dojo:20090409","packageName":"dojo","cvssScore":6.5,"alternativeIds":["SNYK-JS-DOJO-10051"]},{"title":"Cross-site Scripting (XSS)","credit":[],"semver":{"vulnerable":[">=0.4 <0.4.4 || >=1.0 <1.0.3 || >=1.1 <1.1.2 || >=1.2 <1.2.4 || >=1.3 <1.3.3 || >=1.4 <1.4.2"],"unaffected":["<0.4 >=0.4.4 || <1.0 >=1.0.3 || <1.1 >=1.1.2 || <1.2 >=1.2.4 || <1.3 >=1.3.3 || <1.4 >=1.4.2"]},"CVSSv2":"CVSS:2.0/AV:N/AC:L/Au:N/C:C/I:C/A:C","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H","severity":"high","identifiers":{"CWE":["CWE-16"],"CVE":["CVE-2010-2276","CVE-2010-2272"],"ALTERNATIVE":["npm:dojo:20100614-1","npm:dojo:20100614-2","npm:dojo:20100614-3","npm:dojo:20100614-4","npm:dojo:20100614-5","SNYK-JS-DOJO-10052"]},"patches":[],"moduleName":"dojo","creationTime":"2015-11-06T02:09:36.180Z","publicationTime":"2015-11-06T02:09:36.180Z","modificationTime":"2015-11-06T02:09:36.180Z","disclosureTime":"2015-11-06T02:09:36.180Z","language":"js","packageManager":"npm","id":"npm:dojo:20100614","packageName":"dojo","cvssScore":10,"alternativeIds":["npm:dojo:20100614-1","npm:dojo:20100614-2","npm:dojo:20100614-3","npm:dojo:20100614-4","npm:dojo:20100614-5","SNYK-JS-DOJO-10052"]},{"title":"Cross-site Scripting (XSS)","credit":[],"semver":{"vulnerable":["<1.4.2"],"unaffected":[">=1.4.2"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","severity":"medium","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2010-2275"],"ALTERNATIVE":["SNYK-JS-DOJO-10053"]},"patches":[],"moduleName":"dojo","creationTime":"2015-11-06T02:09:36.180Z","publicationTime":"2015-11-06T02:09:36.180Z","modificationTime":"2015-11-06T02:09:36.180Z","disclosureTime":"2015-11-06T02:09:36.180Z","language":"js","packageManager":"npm","id":"npm:dojo:20100614-6","packageName":"dojo","cvssScore":6.5,"alternativeIds":["SNYK-JS-DOJO-10053"]},{"title":"Cross Site Scripting","credit":["Unknown"],"creationTime":"2016-05-24T06:45:20.086Z","modificationTime":"2016-05-24T06:45:20.086Z","publicationTime":"2016-06-22T00:00:00.000Z","disclosureTime":"2016-05-23T16:48:27.000Z","semver":{"vulnerable":["<= 1.0.0"],"unaffected":[">= 1.1.0"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N","severity":"medium","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2008-6681"],"NSP":107,"ALTERNATIVE":["SNYK-JS-DOJO-10108"]},"patches":[],"moduleName":"dojo","language":"js","packageManager":"npm","id":"npm:dojo:20160523","packageName":"dojo","cvssScore":4.3,"alternativeIds":["SNYK-JS-DOJO-10108"]}],"foundation-sites":[{"title":"Cross-site Scripting (XSS)","credit":["Mathieu Amiot"],"moduleName":"foundation-sites","packageName":"foundation-sites","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-FOUNDATIONSITES-10413"]},"semver":{"unaffected":[">=3.0.6"],"vulnerable":["<3.0.6 >=3.0.0"]},"patches":[],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","cvssScore":6.5,"disclosureTime":"2012-07-16T21:00:00.000Z","publicationTime":"2017-03-13T08:00:22.155Z","modificationTime":"2017-03-06T12:29:55.952Z","creationTime":"2017-03-06T12:29:55.952Z","id":"npm:foundation-sites:20120717","alternativeIds":["SNYK-JS-FOUNDATIONSITES-10413"]},{"title":"Cross-site Scripting (XSS)","credit":["Maya Kokits"],"moduleName":"foundation-sites","packageName":"foundation-sites","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-FOUNDATIONSITES-10414"]},"semver":{"unaffected":[">=5.5.3"],"vulnerable":["<5.5.3"]},"patches":[],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","disclosureTime":"2015-06-18T21:00:00.000Z","publicationTime":"2017-03-13T08:00:22.227Z","modificationTime":"2017-03-06T12:57:37.670Z","creationTime":"2017-03-06T12:57:37.670Z","id":"npm:foundation-sites:20150619","cvssScore":6.5,"alternativeIds":["SNYK-JS-FOUNDATIONSITES-10414"]},{"title":"Cross-site Scripting (XSS)","credit":["Nathaniel Paulus"],"moduleName":"foundation-sites","packageName":"foundation-sites","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-FOUNDATIONSITES-10743"]},"semver":{"vulnerable":["<6.0.0"],"unaffected":[">=6.0.0"]},"patches":[],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","cvssScore":6.5,"disclosureTime":"2017-08-01T21:00:00.000Z","publicationTime":"2017-08-02T13:09:44.451Z","modificationTime":"2017-08-02T10:42:11.945Z","creationTime":"2017-08-02T10:42:11.945Z","id":"npm:foundation-sites:20170802","alternativeIds":["SNYK-JS-FOUNDATIONSITES-10743"]}],"handlebars":[{"title":"Cross-site Scripting (XSS)","credit":[],"semver":{"vulnerable":["<=1.0.0-beta.3"],"unaffected":[">1.0.0-beta.3"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","severity":"medium","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-HANDLEBARS-10047"]},"patches":[{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/handlebars/20110425/handlebars_20110425_0_0_b291a1ad8c9a33f834d126450635f0b6ca546a0c.patch"],"version":"<=1.0.0-beta.3","modificationTime":"2015-11-06T02:09:36.180Z","comments":["https://github.com/rgrove/handlebars.js/commit/b291a1ad8c9a33f834d126450635f0b6ca546a0c.patch"],"id":"patch:npm:handlebars:20110425:0"}],"moduleName":"handlebars","creationTime":"2015-11-06T02:09:36.180Z","publicationTime":"2015-11-06T02:09:36.180Z","modificationTime":"2015-11-06T02:09:36.180Z","disclosureTime":"2015-11-06T02:09:36.180Z","language":"js","packageManager":"npm","id":"npm:handlebars:20110425","packageName":"handlebars","cvssScore":5.3,"alternativeIds":["SNYK-JS-HANDLEBARS-10047"]},{"title":"Content Injection (XSS)","credit":["Matias P. Brutti"],"semver":{"vulnerable":["<4.0.0"],"unaffected":[">=4.0.0"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","severity":"medium","identifiers":{"CWE":["CWE-79"],"CVE":[],"NSP":61,"ALTERNATIVE":["SNYK-JS-HANDLEBARS-10068"]},"patches":[{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/handlebars/20151207/handlebars_0.patch"],"version":"<4.0.0 >=3.0.2","modificationTime":"2015-12-14T23:52:16.811Z","comments":["https://github.com/wycats/handlebars.js/commit/83b8e846a3569bd366cf0b6bdc1e4604d1a2077e"],"id":"patch:npm:handlebars:20151207:0"}],"moduleName":"handlebars","creationTime":"2015-12-14T23:52:16.811Z","modificationTime":"2015-12-14T23:52:16.811Z","publicationTime":"2015-12-14T23:52:16.811Z","disclosureTime":"2015-12-07T16:52:07.962Z","language":"js","packageManager":"npm","id":"npm:handlebars:20151207","packageName":"handlebars","cvssScore":5.3,"alternativeIds":["SNYK-JS-HANDLEBARS-10068"]}],"jquery":[{"title":"Cross-site Scripting (XSS)","moduleName":"jquery","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2011-4969"],"ALTERNATIVE":["SNYK-JS-JQUERY-10183"]},"severity":"medium","semver":{"unaffected":[">=1.6.3"],"vulnerable":["<1.6.3"]},"credit":["Dave Methvin"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2011-06-05T21:00:00.000Z","patches":[],"publicationTime":"2016-10-20T14:16:53.138Z","modificationTime":"2016-11-06T15:25:26.117Z","creationTime":"2016-11-06T15:25:26.117Z","id":"npm:jquery:20110606","packageName":"jquery","cvssScore":5.4,"alternativeIds":["SNYK-JS-JQUERY-10183"]},{"title":"Cross-site Scripting (XSS)","moduleName":"jquery","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2012-6708"],"NSP":329,"ALTERNATIVE":["SNYK-JS-JQUERY-10184"]},"severity":"medium","semver":{"unaffected":[">=1.9.0"],"vulnerable":["<1.9.0 >=1.7.1"]},"credit":["Richard Gibson"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2012-06-19T21:00:00.000Z","patches":[],"publicationTime":"2016-10-20T14:16:53.138Z","modificationTime":"2017-03-12T14:17:57.686Z","creationTime":"2016-11-06T13:53:57.686Z","id":"npm:jquery:20120206","packageName":"jquery","cvssScore":5.4,"alternativeIds":["SNYK-JS-JQUERY-10184"]},{"title":"DOM Based Cross-site Scripting (XSS)","moduleName":"jquery","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2014-6071"],"ALTERNATIVE":["SNYK-JS-JQUERY-10185"]},"severity":"medium","semver":{"unaffected":[">=1.6.2"],"vulnerable":["<=1.5.1 >=1.4.2"]},"credit":["Mauro Risonho de Paula Assumpção"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2014-09-01T21:00:00.000Z","patches":[],"publicationTime":"2016-10-20T14:16:53.138Z","modificationTime":"2016-10-06T14:16:53.138Z","creationTime":"2016-11-06T14:16:53.138Z","id":"npm:jquery:20140902","packageName":"jquery","cvssScore":5.4,"alternativeIds":["SNYK-JS-JQUERY-10185"]},{"title":"Cross-site Scripting (XSS)","moduleName":"jquery","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2015-9251"],"NSP":328,"ALTERNATIVE":["SNYK-JS-JQUERY-10186"]},"severity":"medium","semver":{"unaffected":[">=3.0.0-beta1 || >=1.12.0 <1.12.3"],"vulnerable":["<3.0.0-beta1 >1.12.3 || <1.12.0 >=1.4.0"]},"credit":["Egor Homakov"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2015-06-26T21:00:00.000Z","patches":[],"publicationTime":"2016-11-27T00:00:00.000Z","modificationTime":"2017-03-27T15:12:44.538Z","creationTime":"2016-11-06T15:12:44.538Z","id":"npm:jquery:20150627","packageName":"jquery","cvssScore":5.4,"alternativeIds":["SNYK-JS-JQUERY-10186"]},{"title":"Denial of Service (DoS)","moduleName":"jquery","language":"js","packageManager":"npm","identifiers":{"CWE":[],"CVE":["CVE-2016-10707"],"NSP":330,"ALTERNATIVE":["SNYK-JS-JQUERY-10187"]},"severity":"low","semver":{"unaffected":[">=3.0.0"],"vulnerable":["<3.0.0 >=2.1.0-beta1"]},"credit":["Michał Gołębiowski"],"CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L","disclosureTime":"2016-05-28T21:00:00.000Z","patches":[],"publicationTime":"2016-12-26T15:37:35.224Z","modificationTime":"2016-12-26T15:37:35.224Z","creationTime":"2016-11-06T15:37:35.224Z","id":"npm:jquery:20160529","packageName":"jquery","cvssScore":3.7,"alternativeIds":["SNYK-JS-JQUERY-10187"]}],"jquery-mobile":[{"title":"Cross-site Scripting (XSS)","moduleName":"jquery-mobile","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-JQUERYMOBILE-10199"]},"severity":"medium","semver":{"unaffected":[">=1.2.0"],"vulnerable":["<1.2.0"]},"credit":["Masato Kinugawa"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N","disclosureTime":"2012-08-01T21:00:00.000Z","patches":[],"publicationTime":"2016-12-26T11:28:34.624Z","modificationTime":"2016-12-26T11:28:34.624Z","creationTime":"2016-11-09T11:28:34.624Z","id":"npm:jquery-mobile:20120802","packageName":"jquery-mobile","cvssScore":6.5,"alternativeIds":["SNYK-JS-JQUERYMOBILE-10199"]}],"jquery-ui":[{"title":"Cross-site Scripting (XSS)","moduleName":"jquery-ui","packageName":"jquery-ui","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2010-5312"],"ALTERNATIVE":["SNYK-JS-JQUERYUI-10188"]},"severity":"medium","semver":{"unaffected":[">=1.10.0"],"vulnerable":["<1.10.0"]},"credit":["shadowman131"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","disclosureTime":"2010-09-02T21:00:00.000Z","patches":[],"publicationTime":"2017-02-13T14:37:13.516Z","modificationTime":"2017-02-13T14:37:13.516Z","creationTime":"2016-12-26T14:37:13.516Z","id":"npm:jquery-ui:20100903","cvssScore":4.3,"alternativeIds":["SNYK-JS-JQUERYUI-10188"]},{"title":"Cross-site Scripting (XSS) via Tooltip","moduleName":"jquery-ui","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2012-6662"],"ALTERNATIVE":["SNYK-JS-JQUERYUI-10189"]},"severity":"medium","semver":{"unaffected":[">=1.10.0"],"vulnerable":["<1.10.0"]},"credit":["Scott González"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","disclosureTime":"2012-11-26T22:00:00.000Z","patches":[],"publicationTime":"2016-12-26T15:04:27.065Z","modificationTime":"2016-12-26T15:04:27.065Z","creationTime":"2016-11-06T15:04:27.065Z","id":"npm:jquery-ui:20121127","packageName":"jquery-ui","cvssScore":4.3,"alternativeIds":["SNYK-JS-JQUERYUI-10189"]},{"title":"XSS in dialog closeText","credit":["Phat Ly"],"creationTime":"2016-07-22T00:00:02.715Z","modificationTime":"2016-07-22T00:00:02.715Z","publicationTime":"2016-07-21T22:21:41.000Z","disclosureTime":"2016-07-21T22:21:41.000Z","semver":{"vulnerable":["<=1.11.4"],"unaffected":[">=1.12.0"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N","severity":"high","identifiers":{"CWE":["CWE-79"],"CVE":[],"NSP":127,"ALTERNATIVE":["SNYK-JS-JQUERYUI-10118"]},"patches":[],"moduleName":"jquery-ui","language":"js","packageManager":"npm","id":"npm:jquery-ui:20160721","packageName":"jquery-ui","cvssScore":7.3,"alternativeIds":["SNYK-JS-JQUERYUI-10118"]}],"knockout":[{"title":"Cross-site Scripting (XSS)","credit":["Steven Sanderson"],"moduleName":"knockout","packageName":"knockout","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-KNOCKOUT-10415"]},"semver":{"unaffected":[">=3.0.0"],"vulnerable":["<3.0.0 >=2.1.0-pre"]},"patches":[],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2013-06-30T21:00:00.000Z","publicationTime":"2017-03-13T08:00:22.295Z","modificationTime":"2017-03-01T12:39:34.669Z","creationTime":"2017-03-01T12:39:34.669Z","id":"npm:knockout:20130701","cvssScore":5.4,"alternativeIds":["SNYK-JS-KNOCKOUT-10415"]}],"moment":[{"title":"Regular Expression Denial of Service (ReDoS)","credit":["Adam Baldwin"],"language":"js","packageManager":"npm","moduleName":"moment","packageName":"moment","id":"npm:moment:20160126","semver":{"vulnerable":["<=2.11.1"],"unaffected":[">2.11.1"]},"identifiers":{"CWE":["CWE-400"],"CVE":[],"NSP":55,"ALTERNATIVE":["SNYK-JS-MOMENT-10084"]},"patches":[{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/moment/20160126/moment_20160126_0_0_34af63b8b21208a949dfaf42d228502c73d20ec0.patch"],"version":"<=2.11.1 >2.10.6","modificationTime":"2016-01-26T20:04:21.225Z","comments":[],"id":"patch:npm:moment:20160126:0"},{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/moment/20160126/moment_20160126_0_1_34af63b8b21208a949dfaf42d228502c73d20ec0.patch"],"version":"<=2.10.6 >2.9.0","modificationTime":"2016-01-26T20:04:21.225Z","comments":[],"id":"patch:npm:moment:20160126:1"},{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/moment/20160126/moment_20160126_0_2_34af63b8b21208a949dfaf42d228502c73d20ec0.patch"],"version":"<=2.9.0 >2.2.1","modificationTime":"2016-01-26T20:04:21.225Z","comments":[],"id":"patch:npm:moment:20160126:2"},{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/moment/20160126/moment_20160126_0_3_34af63b8b21208a949dfaf42d228502c73d20ec0.patch"],"version":"=2.2.1","modificationTime":"2016-01-26T20:04:21.225Z","comments":[],"id":"patch:npm:moment:20160126:3"},{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/moment/20160126/moment_20160126_0_4_34af63b8b21208a949dfaf42d228502c73d20ec0.patch"],"version":"<2.2.1 >2.0.0","modificationTime":"2016-01-26T20:04:21.225Z","comments":[],"id":"patch:npm:moment:20160126:4"}],"cvssScore":5.3,"severity":"low","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","disclosureTime":"2016-01-26T20:04:21.225Z","creationTime":"2016-02-01T19:00:03.862Z","modificationTime":"2016-09-28T19:00:03.862Z","publicationTime":"2016-02-01T19:00:03.862Z","alternativeIds":["SNYK-JS-MOMENT-10084"]},{"title":"Regular Expression Denial of Service (ReDoS)","credit":["Snyk Security Research Team"],"language":"js","packageManager":"npm","moduleName":"moment","packageName":"moment","id":"npm:moment:20161019","identifiers":{"CWE":["CWE-400"],"CVE":[],"ALTERNATIVE":["SNYK-JS-MOMENT-10164"]},"semver":{"vulnerable":["<2.15.2"],"unaffected":[">=2.15.2"]},"patches":[{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/moment/20161019/moment_20161019_0_1.patch"],"version":"<2.15.2 >=2.14.0","modificationTime":"2016-10-24T00:00:00.000Z","comments":[],"id":"patch:npm:moment:20161019:0"},{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/moment/20161019/moment_20161019_0_0.patch"],"version":"<2.14.0 >=2.12.0","modificationTime":"2016-10-24T00:00:00.000Z","comments":[],"id":"patch:npm:moment:20161019:1"}],"cvssScore":5.9,"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","disclosureTime":"2016-10-18T21:00:00.000Z","publicationTime":"2016-10-24T06:57:59.675Z","modificationTime":"2016-10-23T06:57:59.675Z","creationTime":"2016-10-23T06:57:59.675Z","alternativeIds":["SNYK-JS-MOMENT-10164"]},{"title":"Regular Expression Denial of Service (ReDoS)","credit":["Cristian-Alexandru Staicu"],"moduleName":"moment","packageName":"moment","language":"js","packageManager":"npm","identifiers":{"NSP":532,"CWE":["CWE-400"],"CVE":[],"ALTERNATIVE":["SNYK-JS-MOMENT-10841"]},"semver":{"unaffected":[">=2.19.3"],"vulnerable":["<2.19.3"]},"patches":[{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/moment/20170905/moment_0_0_69ed9d44957fa6ab12b73d2ae29d286a857b80eb.patch"],"version":"<2.19.3 >=2.16.0","modificationTime":"2017-11-30T14:47:22.471Z","comments":[],"id":"patch:npm:moment:20170905:0"}],"cvssScore":3.7,"severity":"low","CVSSv3":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L","disclosureTime":"2017-09-05T21:00:00.000Z","publicationTime":"2017-11-28T14:47:22.471Z","modificationTime":"2017-11-28T06:55:05.106Z","creationTime":"2017-09-13T07:55:05.106Z","id":"npm:moment:20170905","alternativeIds":["SNYK-JS-MOMENT-10841"]}],"mustache":[{"title":"Cross-site Scripting (XSS)","credit":[],"semver":{"vulnerable":["< 0.3.1"],"unaffected":[">= 0.3.1"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","severity":"medium","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-MUSTACHE-10046"]},"patches":[],"moduleName":"mustache","creationTime":"2015-11-06T02:09:36.180Z","publicationTime":"2015-11-06T02:09:36.180Z","modificationTime":"2015-11-06T02:09:36.180Z","disclosureTime":"2015-11-06T02:09:36.180Z","language":"js","packageManager":"npm","id":"npm:mustache:20110814","packageName":"mustache","cvssScore":5.4,"alternativeIds":["SNYK-JS-MUSTACHE-10046"]},{"title":"Content Injection due to quoteless attributes","credit":["Matias P. Brutti"],"semver":{"vulnerable":["<2.2.1"],"unaffected":[">=2.2.1"]},"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","severity":"medium","identifiers":{"CWE":["CWE-79"],"CVE":[],"NSP":62,"ALTERNATIVE":["SNYK-JS-MUSTACHE-10067"]},"patches":[{"urls":["https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/master/patches/npm/mustache/20151207/mustache_0.patch"],"version":"<2.2.1 >=2.1.0","modificationTime":"2015-12-14T23:52:16.806Z","comments":["https://github.com/janl/mustache.js/commit/378bcca8a5cfe4058f294a3dbb78e8755e8e0da5"],"id":"patch:npm:mustache:20151207:0"}],"moduleName":"mustache","creationTime":"2015-12-14T23:52:16.806Z","modificationTime":"2015-12-14T23:52:16.806Z","publicationTime":"2015-12-14T23:52:16.806Z","disclosureTime":"2015-12-07T17:13:57.565Z","language":"js","packageManager":"npm","id":"npm:mustache:20151207","packageName":"mustache","cvssScore":5.3,"alternativeIds":["SNYK-JS-MUSTACHE-10067"]}],"react":[{"title":"Cross-site Scripting (XSS)","moduleName":"react","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2013-7035"],"ALTERNATIVE":["SNYK-JS-REACT-10192"]},"severity":"medium","semver":{"unaffected":[">=0.5.2 || <=0.3.x || =0.4.2"],"vulnerable":[">=0.5.0 <0.5.2 || >=0.4.0 <0.4.2"]},"credit":["Paul O’Shannessy","Thomas Aylott"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N","disclosureTime":"2013-12-16T22:00:00.000Z","patches":[],"publicationTime":"2017-01-18T14:00:21.094Z","modificationTime":"2016-11-08T08:23:21.094Z","creationTime":"2016-11-08T08:23:21.094Z","id":"npm:react:20131217","packageName":"react","cvssScore":6.5,"alternativeIds":["SNYK-JS-REACT-10192"]},{"title":"Cross-site Scripting (XSS)","moduleName":"react","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-REACT-10193"]},"severity":"high","semver":{"unaffected":[">=0.14.0"],"vulnerable":["<0.14.0"]},"credit":["Daniel LeCheminant"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N","disclosureTime":"2015-03-17T22:00:00.000Z","patches":[],"publicationTime":"2017-01-18T14:00:38.403Z","modificationTime":"2016-11-08T09:59:38.403Z","creationTime":"2016-11-08T09:59:38.403Z","id":"npm:react:20150318","packageName":"react","cvssScore":7.1,"alternativeIds":["SNYK-JS-REACT-10193"]}],"riot":[{"title":"Cross-site Scripting (XSS)","credit":["crazy2be"],"moduleName":"riot","packageName":"riot","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-RIOT-10447"]},"semver":{"unaffected":[">=0.9.6"],"vulnerable":["<0.9.6"]},"patches":[],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","disclosureTime":"2013-11-13T22:00:00.000Z","publicationTime":"2017-05-08T12:34:46.386Z","modificationTime":"2017-03-20T14:44:23.092Z","creationTime":"2017-03-20T14:44:23.092Z","id":"npm:riot:20131114","cvssScore":6.5,"alternativeIds":["SNYK-JS-RIOT-10447"]}],"socket.io":[{"title":"Insecure Randomness","credit":["Martin Thomson"],"moduleName":"socket.io","packageName":"socket.io","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-330"],"CVE":[],"NSP":321,"ALTERNATIVE":["SNYK-JS-SOCKETIO-10397"]},"semver":{"unaffected":[">=0.9.7"],"vulnerable":["<0.9.7"]},"patches":[],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N","disclosureTime":"2012-03-22T22:00:00.000Z","publicationTime":"2017-02-13T13:46:59.513Z","modificationTime":"2017-02-13T13:46:59.513Z","creationTime":"2017-02-01T13:46:59.513Z","id":"npm:socket.io:20120323","cvssScore":5.3,"alternativeIds":["SNYK-JS-SOCKETIO-10397"]},{"title":"Cross-site Scripting (XSS)","credit":["Almog Melamed"],"moduleName":"socket.io","packageName":"socket.io","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-SOCKETIO-10398"]},"semver":{"unaffected":[">=0.9.6"],"vulnerable":["<0.9.6"]},"patches":[],"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2012-04-16T21:00:00.000Z","publicationTime":"2017-02-13T13:28:52.754Z","modificationTime":"2017-02-13T13:28:52.754Z","creationTime":"2017-02-01T13:28:52.754Z","id":"npm:socket.io:20120417","cvssScore":5.4,"alternativeIds":["SNYK-JS-SOCKETIO-10398"]}],"vue":[{"title":"Cross-site Scripting (XSS)","credit":["Unknown"],"moduleName":"vue","packageName":"vue","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-VUE-12035"]},"semver":{"unaffected":[">=2.3.0-beta.1"],"vulnerable":["<2.3.0-beta.1"]},"patches":[],"cvssScore":6.5,"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","disclosureTime":"2017-03-31T21:00:00.000Z","publicationTime":"2017-12-25T14:45:02.463Z","modificationTime":"2017-12-19T11:55:30.354Z","creationTime":"2017-12-19T11:55:30.354Z","id":"npm:vue:20170401","alternativeIds":["SNYK-JS-VUE-12035"]},{"title":"Cross-site Scripting (XSS)","credit":["Unknown"],"moduleName":"vue","packageName":"vue","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-VUE-12036"]},"semver":{"unaffected":[">=2.4.3"],"vulnerable":["<2.4.3"]},"patches":[],"cvssScore":6.5,"severity":"medium","CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N","disclosureTime":"2017-08-28T21:00:00.000Z","publicationTime":"2017-12-25T14:45:02.568Z","modificationTime":"2017-12-19T11:56:17.017Z","creationTime":"2017-12-19T11:56:17.017Z","id":"npm:vue:20170829","alternativeIds":["SNYK-JS-VUE-12036"]}],"yui":[{"title":"Cross-site Scripting (XSS)","moduleName":"yui","packageName":"yui","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2010-4207"],"ALTERNATIVE":["SNYK-JS-YUI-10383"]},"severity":"medium","semver":{"unaffected":[">=2.8.2 || <2.4.0"],"vulnerable":["<2.8.2 >=2.4.0"]},"credit":["Unknown"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2010-10-24T22:00:00.000Z","patches":[],"publicationTime":"2017-02-13T09:24:55.944Z","modificationTime":"2017-01-22T09:24:55.944Z","creationTime":"2017-01-22T09:24:55.944Z","id":"npm:yui:20101025","cvssScore":5.4,"alternativeIds":["SNYK-JS-YUI-10383"]},{"title":"Cross-site Scripting (XSS)","moduleName":"yui","packageName":"yui","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":[],"ALTERNATIVE":["SNYK-JS-YUI-10384"]},"severity":"medium","semver":{"unaffected":[">=3.5.1 || <3.5.0-PR1"],"vulnerable":["<3.5.1 >=3.5.0-PR1"]},"credit":["Ryan Grove"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2012-04-27T21:00:00.000Z","patches":[],"publicationTime":"2017-02-13T09:12:40.841Z","modificationTime":"2017-02-13T09:12:40.841Z","creationTime":"2017-01-22T09:12:40.841Z","id":"npm:yui:20120428","cvssScore":5.4,"alternativeIds":["SNYK-JS-YUI-10384"]},{"title":"Cross-site Scripting (XSS)","moduleName":"yui","packageName":"yui","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2012-5881","CVE-2012-5882","CVE-2012-5883"],"ALTERNATIVE":["SNYK-JS-YUI-10385"]},"severity":"medium","semver":{"unaffected":[">=3.0.0 || <2.4.0"],"vulnerable":["<3.0.0 >=2.4.0"]},"credit":["Unknwon"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2012-10-29T22:00:00.000Z","patches":[],"publicationTime":"2017-02-13T09:20:03.679Z","modificationTime":"2017-02-13T09:20:03.679Z","creationTime":"2017-01-22T09:20:03.679Z","id":"npm:yui:20121030","cvssScore":5.4,"alternativeIds":["SNYK-JS-YUI-10385"]},{"title":"Cross-site Scripting (XSS)","moduleName":"yui","packageName":"yui","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2013-4941"],"NSP":332,"ALTERNATIVE":["SNYK-JS-YUI-10386"]},"severity":"medium","semver":{"unaffected":[">=3.10.0 || <3.0.0"],"vulnerable":["<3.10.0 >=3.0.0"]},"credit":["Aleksandr Dobkin"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2013-05-14T21:00:00.000Z","patches":[],"publicationTime":"2017-02-13T08:54:05.822Z","modificationTime":"2017-02-13T08:54:05.822Z","creationTime":"2017-01-22T08:54:05.822Z","id":"npm:yui:20130515","cvssScore":5.4,"alternativeIds":["SNYK-JS-YUI-10386"]},{"title":"Cross-site Scripting (XSS)","moduleName":"yui","packageName":"yui","language":"js","packageManager":"npm","identifiers":{"CWE":["CWE-79"],"CVE":["CVE-2013-4940"],"ALTERNATIVE":["SNYK-JS-YUI-10387"]},"severity":"medium","semver":{"unaffected":[">=3.10.3 <3.10.2"],"vulnerable":["=3.10.2"]},"credit":["Unknown"],"CVSSv3":"CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","disclosureTime":"2013-06-03T21:00:00.000Z","patches":[],"publicationTime":"2017-02-13T09:01:24.863Z","modificationTime":"2017-02-13T09:01:24.863Z","creationTime":"2017-01-22T09:01:24.863Z","id":"npm:yui:20130604","cvssScore":5.4,"alternativeIds":["SNYK-JS-YUI-10387"]}]}};
+},{}],155:[function(require,module,exports){
+module.exports={
+"npm":{
+"angular":[
+{"id":"npm:angular:20130621","severity":"medium","semver":{"vulnerable":["<=1.1.5"]}},
+{"id":"npm:angular:20130622","severity":"medium","semver":{"vulnerable":["<1.2.0 >=1.0.0"]}},
+{"id":"npm:angular:20130625","severity":"high","semver":{"vulnerable":["<1.1.5"]}},
+{"id":"npm:angular:20131113","severity":"high","semver":{"vulnerable":["<1.2.2"]}},
+{"id":"npm:angular:20140608","severity":"low","semver":{"vulnerable":["<1.3.0"]}},
+{"id":"npm:angular:20140908","severity":"medium","semver":{"vulnerable":["<1.3.0-rc.4"]}},
+{"id":"npm:angular:20140909","severity":"high","semver":{"vulnerable":["<1.2.24 >=1.2.19"]}},
+{"id":"npm:angular:20141104","severity":"medium","semver":{"vulnerable":["<1.3.2"]}},
+{"id":"npm:angular:20150310","severity":"high","semver":{"vulnerable":["<1.5.0-beta.2"]}},
+{"id":"npm:angular:20150315","severity":"medium","semver":{"vulnerable":["<1.6.1"]}},
+{"id":"npm:angular:20150807","severity":"high","semver":{"vulnerable":["<1.5.0-beta.0 >=1.0.0"]}},
+{"id":"npm:angular:20150807-1","severity":"medium","semver":{"vulnerable":["<1.5.0-beta.0 >=1.3.1"]}},
+{"id":"npm:angular:20150909","severity":"high","semver":{"vulnerable":["<1.5.0-beta.2"]}},
+{"id":"npm:angular:20151130","severity":"medium","semver":{"vulnerable":["<1.4.10"]}},
+{"id":"npm:angular:20151205","severity":"medium","semver":{"vulnerable":["<1.5.0-rc.0"]}},
+{"id":"npm:angular:20160122","severity":"medium","semver":{"vulnerable":["<1.5.0-rc.2 >=1.3.0"]}},
+{"id":"npm:angular:20160527","severity":"medium","semver":{"vulnerable":["<1.2.30 >=1.0.0"]}},
+{"id":"npm:angular:20161101","severity":"medium","semver":{"vulnerable":["<1.5.9 >=1.5.0"]}},
+{"id":"npm:angular:20171018","severity":"medium","semver":{"vulnerable":["<1.6.7"]}},
+{"id":"npm:angular:20180202","severity":"medium","semver":{"vulnerable":["<1.6.9"]}}],
 
-},{}]},{},[46]);
\ No newline at end of file
+"backbone":[
+{"id":"npm:backbone:20110701","severity":"medium","semver":{"vulnerable":["<0.5.0"]}},
+{"id":"npm:backbone:20160523","severity":"medium","semver":{"vulnerable":["<= 0.3.3"]}}],
+
+"bootstrap":[
+{"id":"npm:bootstrap:20120510","severity":"medium","semver":{"vulnerable":["<2.1.0"]}},
+{"id":"npm:bootstrap:20160627","severity":"medium","semver":{"vulnerable":["<3.4.0 || >=4.0.0-alpha <4.0.0-beta.2"]}}],
+
+"dojo":[
+{"id":"npm:dojo:20090409","severity":"medium","semver":{"vulnerable":["<1.1"]}},
+{"id":"npm:dojo:20100614","severity":"high","semver":{"vulnerable":[">=0.4 <0.4.4 || >=1.0 <1.0.3 || >=1.1 <1.1.2 || >=1.2 <1.2.4 || >=1.3 <1.3.3 || >=1.4 <1.4.2"]}},
+{"id":"npm:dojo:20100614-6","severity":"medium","semver":{"vulnerable":["<1.4.2"]}},
+{"id":"npm:dojo:20160523","severity":"medium","semver":{"vulnerable":["<= 1.0.0"]}}],
+
+"foundation-sites":[
+{"id":"npm:foundation-sites:20120717","severity":"medium","semver":{"vulnerable":["<3.0.6 >=3.0.0"]}},
+{"id":"npm:foundation-sites:20150619","severity":"medium","semver":{"vulnerable":["<5.5.3"]}},
+{"id":"npm:foundation-sites:20170802","severity":"medium","semver":{"vulnerable":["<6.0.0"]}}],
+
+"handlebars":[
+{"id":"npm:handlebars:20110425","severity":"medium","semver":{"vulnerable":["<=1.0.0-beta.3"]}},
+{"id":"npm:handlebars:20151207","severity":"medium","semver":{"vulnerable":["<4.0.0"]}}],
+
+"highcharts":[
+{"id":"npm:highcharts:20180225","severity":"low","semver":{"vulnerable":["<=6.0.7"]}}],
+
+"jquery":[
+{"id":"npm:jquery:20110606","severity":"medium","semver":{"vulnerable":["<1.6.3"]}},
+{"id":"npm:jquery:20120206","severity":"medium","semver":{"vulnerable":["<1.9.0 >=1.7.1"]}},
+{"id":"npm:jquery:20140902","severity":"medium","semver":{"vulnerable":["<=1.5.1 >=1.4.2"]}},
+{"id":"npm:jquery:20150627","severity":"medium","semver":{"vulnerable":["<3.0.0-beta1 >1.12.3 || <1.12.0 >=1.4.0"]}},
+{"id":"npm:jquery:20160529","severity":"low","semver":{"vulnerable":["=3.0.0-rc.1"]}}],
+
+"jquery-mobile":[
+{"id":"npm:jquery-mobile:20120802","severity":"medium","semver":{"vulnerable":["<1.2.0"]}}],
+
+"jquery-ui":[
+{"id":"npm:jquery-ui:20100903","severity":"medium","semver":{"vulnerable":["<1.10.0"]}},
+{"id":"npm:jquery-ui:20121127","severity":"medium","semver":{"vulnerable":["<1.10.0"]}},
+{"id":"npm:jquery-ui:20160721","severity":"high","semver":{"vulnerable":["<=1.11.4"]}}],
+
+"knockout":[
+{"id":"npm:knockout:20130701","severity":"medium","semver":{"vulnerable":["<3.0.0 >=2.1.0-pre"]}},
+{"id":"npm:knockout:20180213","severity":"medium","semver":{"vulnerable":["<3.5.0-beta"]}}],
+
+"lodash":[
+{"id":"npm:lodash:20180130","severity":"low","semver":{"vulnerable":["<4.17.5"]}}],
+
+"moment":[
+{"id":"npm:moment:20160126","severity":"low","semver":{"vulnerable":["<=2.11.1"]}},
+{"id":"npm:moment:20161019","severity":"medium","semver":{"vulnerable":["<2.15.2"]}},
+{"id":"npm:moment:20170905","severity":"low","semver":{"vulnerable":["<2.19.3"]}}],
+
+"mustache":[
+{"id":"npm:mustache:20110814","severity":"medium","semver":{"vulnerable":["< 0.3.1"]}},
+{"id":"npm:mustache:20151207","severity":"medium","semver":{"vulnerable":["<2.2.1"]}}],
+
+"react":[
+{"id":"npm:react:20131217","severity":"medium","semver":{"vulnerable":[">=0.5.0 <0.5.2 || >=0.4.0 <0.4.2"]}},
+{"id":"npm:react:20150318","severity":"high","semver":{"vulnerable":["<0.14.0"]}}],
+
+"riot":[
+{"id":"npm:riot:20131114","severity":"medium","semver":{"vulnerable":["<0.9.6"]}}],
+
+"socket.io":[
+{"id":"npm:socket.io:20120323","severity":"medium","semver":{"vulnerable":["<0.9.7"]}},
+{"id":"npm:socket.io:20120417","severity":"medium","semver":{"vulnerable":["<0.9.6"]}}],
+
+"vue":[
+{"id":"npm:vue:20170401","severity":"medium","semver":{"vulnerable":["<2.3.0-beta.1"]}},
+{"id":"npm:vue:20170829","severity":"medium","semver":{"vulnerable":["<2.4.3"]}},
+{"id":"npm:vue:20180222","severity":"low","semver":{"vulnerable":["<=2.5.14"]}}],
+
+"yui":[
+{"id":"npm:yui:20101025","severity":"medium","semver":{"vulnerable":["<2.8.2 >=2.4.0"]}},
+{"id":"npm:yui:20120428","severity":"medium","semver":{"vulnerable":["<3.5.1 >=3.5.0-PR1"]}},
+{"id":"npm:yui:20121030","severity":"medium","semver":{"vulnerable":["<3.0.0 >=2.4.0"]}},
+{"id":"npm:yui:20130515","severity":"medium","semver":{"vulnerable":["<3.10.0 >=3.0.0"]}},
+{"id":"npm:yui:20130604","severity":"medium","semver":{"vulnerable":[">=3.0.0 <3.10.1 || =3.10.2"]}}]}};
+
+
+
+},{}],"url":[function(require,module,exports){
+
+
+
+
+
+'use strict';
+
+
+
+
+
+
+
+const Util=require('../report/html/renderer/util.js');
+
+
+const URL=typeof self!=='undefined'&&self.URL||
+require('url').URL;
+
+
+
+
+
+
+
+
+function rewriteChromeInternalUrl(url){
+if(!url||!url.startsWith('chrome://'))return url;
+
+
+if(url.endsWith('/'))url=url.replace(/\/$/,'');
+return url.replace(/^chrome:\/\/chrome\//,'chrome://');
+}
+
+class URLShim extends URL{
+
+
+
+
+static isValid(url){
+try{
+new URL(url);
+return true;
+}catch(e){
+return false;
+}
+}
+
+
+
+
+
+
+static hostsMatch(urlA,urlB){
+try{
+return new URL(urlA).host===new URL(urlB).host;
+}catch(e){
+return false;
+}
+}
+
+
+
+
+
+
+static originsMatch(urlA,urlB){
+try{
+return new URL(urlA).origin===new URL(urlB).origin;
+}catch(e){
+return false;
+}
+}
+
+
+
+
+
+static getOrigin(url){
+try{
+const urlInfo=new URL(url);
+
+
+return urlInfo.host&&urlInfo.origin||null;
+}catch(e){
+return null;
+}
+}
+
+
+
+
+
+
+static getURLDisplayName(url,options){
+return Util.getURLDisplayName(new URL(url),options);
+}
+
+
+
+
+
+
+static elideDataURI(url){
+try{
+const parsed=new URL(url);
+return parsed.protocol==='data:'?url.slice(0,100):url;
+}catch(e){
+return url;
+}
+}
+
+
+
+
+
+
+
+static equalWithExcludedFragments(url1,url2){
+[url1,url2]=[url1,url2].map(rewriteChromeInternalUrl);
+try{
+const urla=new URL(url1);
+urla.hash='';
+
+const urlb=new URL(url2);
+urlb.hash='';
+
+return urla.href===urlb.href;
+}catch(e){
+return false;
+}
+}}
+
+
+URLShim.URL=URL;
+URLShim.URLSearchParams=typeof self!=='undefined'&&self.URLSearchParams||
+require('url').URLSearchParams;
+
+URLShim.INVALID_URL_DEBUG_STRING=
+'Lighthouse was unable to determine the URL of some script executions. '+
+'It\'s possible a Chrome extension or other eval\'d code is the source.';
+
+module.exports=URLShim;
+
+},{"../report/html/renderer/util.js":48,"url":"url"}]},{},[52]);
\ No newline at end of file
diff --git a/front_end/bindings/FileUtils.js b/front_end/bindings/FileUtils.js
index 0afebe5..2128eca 100644
--- a/front_end/bindings/FileUtils.js
+++ b/front_end/bindings/FileUtils.js
@@ -143,7 +143,7 @@
     if (event.target.readyState !== FileReader.DONE)
       return;
 
-    const buffer = event.target.result;
+    const buffer = this._reader.result;
     this._loadedSize += buffer.byteLength;
     const endOfFile = this._loadedSize === this._fileSize;
     const decodedString = this._decoder.decode(buffer, {stream: !endOfFile});
diff --git a/front_end/externs.js b/front_end/externs.js
index 2993f2c..7f815d3 100644
--- a/front_end/externs.js
+++ b/front_end/externs.js
@@ -836,3 +836,164 @@
  * @param {function(!Array<*>)} callback
  */
 const ResizeObserver = function(callback) {};
+
+
+// Lighthouse Report Renderer
+
+/**
+ * @constructor
+ * @param {!Document} document
+ */
+const DOM = function(document) {};
+
+/**
+ * @constructor
+ * @param {!DOM} dom
+ */
+const ReportRenderer = function(dom) {};
+
+ReportRenderer.prototype = {
+  /**
+   * @param {!ReportRenderer.ReportJSON} report
+   * @param {!Element} container Parent element to render the report into.
+   */
+  renderReport: function(report, container) {},
+
+  /**
+   * @param {!Document|!Element} context
+   */
+  setTemplateContext: function(context) {},
+
+};
+
+/**
+ * @typedef {{
+ *     rawValue: (number|boolean|undefined),
+ *     id: string,
+ *     title: string,
+ *     description: string,
+ *     explanation: (string|undefined),
+ *     errorMessage: (string|undefined),
+ *     displayValue: (string|Array<string|number>|undefined),
+ *     scoreDisplayMode: string,
+ *     error: boolean,
+ *     score: (number|null),
+ *     details: (!DetailsRenderer.DetailsJSON|undefined),
+ * }}
+ */
+ReportRenderer.AuditResultJSON;
+
+/**
+ * @typedef {{
+ *     id: string,
+ *     score: (number|null),
+ *     weight: number,
+ *     group: (string|undefined),
+ *     result: ReportRenderer.AuditResultJSON
+ * }}
+ */
+ReportRenderer.AuditJSON;
+
+/**
+ * @typedef {{
+ *     title: string,
+ *     id: string,
+ *     score: (number|null),
+ *     description: (string|undefined),
+ *     manualDescription: string,
+ *     auditRefs: !Array<!ReportRenderer.AuditJSON>
+ * }}
+ */
+ReportRenderer.CategoryJSON;
+
+/**
+ * @typedef {{
+ *     title: string,
+ *     description: (string|undefined),
+ * }}
+ */
+ReportRenderer.GroupJSON;
+
+/**
+ * @typedef {{
+ *     lighthouseVersion: string,
+ *     userAgent: string,
+ *     fetchTime: string,
+ *     timing: {total: number},
+ *     requestedUrl: string,
+ *     finalUrl: string,
+ *     runWarnings: (!Array<string>|undefined),
+ *     artifacts: {traces: {defaultPass: {traceEvents: !Array}}},
+ *     audits: !Object<string, !ReportRenderer.AuditResultJSON>,
+ *     categories: !Object<string, !ReportRenderer.CategoryJSON>,
+ *     categoryGroups: !Object<string, !ReportRenderer.GroupJSON>,
+ * }}
+ */
+ReportRenderer.ReportJSON;
+
+/**
+ * @typedef {{
+ *     traces: {defaultPass: {traceEvents: !Array}},
+ * }}
+ */
+ReportRenderer.RunnerResultArtifacts;
+
+/**
+ * @typedef {{
+ *     lhr: !ReportRenderer.ReportJSON,
+ *     artifacts: ReportRenderer.RunnerResultArtifacts,
+ *     report: string
+ * }}
+ */
+ReportRenderer.RunnerResult;
+
+
+/**
+ * @constructor
+ * @param {!DOM} dom
+ * @param {!DetailsRenderer} detailsRenderer
+ */
+const CategoryRenderer = function(dom, detailsRenderer) {};
+
+
+/**
+ * @constructor
+ * @param {!DOM} dom
+ */
+const DetailsRenderer = function(dom) {};
+
+DetailsRenderer.prototype = {
+  /**
+   * @param {!DetailsRenderer.NodeDetailsJSON} item
+   * @return {!Element}
+   */
+  renderNode: function(item) {},
+};
+
+/**
+ * @typedef {{
+ *     type: string,
+ *     value: (string|number|undefined),
+ *     summary: (DetailsRenderer.OpportunitySummary|undefined),
+ *     granularity: (number|undefined),
+ *     displayUnit: (string|undefined)
+ * }}
+ */
+DetailsRenderer.DetailsJSON;
+
+/**
+ * @typedef {{
+ *     type: string,
+ *     path: (string|undefined),
+ *     selector: (string|undefined),
+ *     snippet:(string|undefined)
+ * }}
+ */
+DetailsRenderer.NodeDetailsJSON;
+
+/** @typedef {{
+ *     wastedMs: (number|undefined),
+ *     wastedBytes: (number|undefined),
+ * }}
+ */
+DetailsRenderer.OpportunitySummary;