%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /snap/firefox/current/usr/lib/firefox/browser/features/
Upload File :
Create Path :
Current File : //snap/firefox/current/usr/lib/firefox/browser/features/webcompat@mozilla.org.xpi

�[PK
!<M'�W�����3about-compat/aboutPage.jsPK
!<�ȌBB���8experiment-apis/appConstants.jsPK
!<$�(++#��<experiment-apis/aboutConfigPrefs.jsPK
!<�EO%��nCexperiment-apis/trackingProtection.jsPK
!<�9ה�� ���[about-compat/AboutCompat.sys.mjsPK
!<�� "
"
���`about-compat/aboutCompat.cssPK
!<�D�HRR��nabout-compat/aboutCompat.htmlPK
!<�ib�����tabout-compat/aboutCompat.jsPK
!<u!o�__����about-compat/aboutPage.jsonPK
!<�T�&���about-compat/aboutPageProcessScript.jsPK
!<<N7�n�n��s�data/injections.jsPK
!<'�U]^]^
���data/shims.jsPK
!<�M�@����
edata/ua_overrides.jsPK
!<�l��C	C	%��+�experiment-apis/aboutConfigPrefs.jsonPK
!<Ա�oBB(���experiment-apis/aboutConfigPrefsChild.jsPK
!<��Mf%%!��9experiment-apis/appConstants.jsonPK
!<u�q��� ���
experiment-apis/matchPatterns.jsPK
!<u�#r��"���experiment-apis/matchPatterns.jsonPK
!<�N'LL%���experiment-apis/systemManufacturer.jsPK
!<(��		'��+experiment-apis/systemManufacturer.jsonPK
!<y�ڋ�
�
'��yexperiment-apis/trackingProtection.jsonPK
!<�s����3���#injections/css/bug0000000-testbed-css-injection.cssPK
!<�	�7��F���$injections/css/bug1575000-apply.lloydsbank.co.uk-radio-buttons-fix.cssPK
!<����E���'injections/css/bug1610344-directv.com.co-hide-unsupported-message.cssPK
!<轤��I��+injections/css/bug1644830-missingmail.usps.com-checkboxes-not-visible.cssPK
!<������B��+.injections/css/bug1651917-teletrader.com.body-transform-origin.cssPK
!<�3��=��z1injections/css/bug1653075-livescience.com-scrollbar-width.cssPK
!<��l���:��b4injections/css/bug1654907-reactine.ca-hide-unsupported.cssPK
!<��=��>7injections/css/bug1694470-myvidster.com-content-not-shown.cssPK
!<��J*��A���9injections/css/bug1707795-office365-sheets-overscroll-disable.cssPK
!<�0ZZ��=���;injections/css/bug1741234-patient.alphalabs.ca-height-fix.cssPK
!<�p\��9���=injections/css/bug1765947-veniceincoming.com-left-fix.cssPK
!<�R%%%B���?injections/css/bug1770962-coldwellbankerhomes.com-image-height.cssPK
!<����4��lBinjections/css/bug1774490-rainews.it-gallery-fix.cssPK
!<БF�vv?���Dinjections/css/bug1784141-aveeno.com-acuvue.com-unsupported.cssPK
!<,��:��TGinjections/css/bug1784199-entrata-platform-unsupported.cssPK
!<ic����B���Iinjections/css/bug1819678-nppes.cms.hhs.gov-unsupported-banner.cssPK
!<�t���>���Kinjections/css/bug1829949-tomshardware.com-scrollbar-width.cssPK
!<��ģ��=��6Oinjections/css/bug1830752-afisha.ru-slider-pointer-events.cssPK
!<��i��:��RSinjections/css/bug1830761-91mobiles.com-content-height.cssPK
!<�_���<��jVinjections/css/bug1830796-copyleaks.com-hide-unsupported.cssPK
!<3�	|��?���Xinjections/css/bug1830810-interceramic.com-hide-unsupported.cssPK
!<.�33?���Zinjections/css/bug1830813-page.onstove.com-hide-unsupported.cssPK
!<��C���B��4]injections/css/bug1836103-autostar-novoross.ru-make-map-taller.cssPK
!<)�|}}C��]_injections/css/bug1836105-cnn.com-fix-blank-pages-when-printing.cssPK
!<�A'OO1��;binjections/css/bug1848711-vio.com-page-height.cssPK
!<
��3���dinjections/css/bug1848713-cleanrider.com-slider.cssPK
!<�q���9�� hinjections/css/bug1848849-theaa.com-printing-mode-fix.cssPK
!<ڶL��<��kinjections/css/bug1849388-kucharkaprodceru.cz-scroll-fix.cssPK
!<�ʹ��3���minjections/css/bug1868345-tvmovie.de-scroll-fix.cssPK
!<��:3223��
qinjections/css/bug1884842-foodora.cz-height-fix.cssPK
!<^�x77;���tinjections/css/bug1895994-softtrans.ro-unlock-scrolling.cssPK
!<_��/aa;�� winjections/css/bug1896571-gracobaby.ca-unlock-scrolling.cssPK
!<�|����N���yinjections/css/bug1905278-personalizedplates.revenue.tn.gov-pointer-events.cssPK
!<����0���|injections/js/bug0000000-testbed-js-injection.jsPK
!<��P���*���~injections/js/bug1448747-fastclick-shim.jsPK
!<��T�ooA��3�injections/js/bug1452707-window.controllers-shim-ib.absa.co.za.jsPK
!<�i�
��4���injections/js/bug1457335-histography.io-ua-change.jsPK
!<g��227���injections/js/bug1472075-bankofamerica.com-ua-change.jsPK
!<��%���=��v�injections/js/bug1579159-m.tailieu.vn-pdfjs-worker-disable.jsPK
!<��p��5��v�injections/js/bug1722955-frontgate.com-ua-override.jsPK
!<���AA8����injections/js/bug1724868-news.yahoo.co.jp-ua-override.jsPK
!<q/��1�injections/js/bug1739489-draftjs-beforeinput.jsPK
!<�?#���3���injections/js/bug1769762-tiktok.com-plugins-shim.jsPK
!<�M��/����injections/js/bug1774005-installtrigger-shim.jsPK
!<���**@����injections/js/bug1799968-www.samsung.com-appVersion-linux-fix.jsPK
!<��(���8��#�injections/js/bug1799980-healow.com-infinite-loop-fix.jsPK
!<�PR���:���injections/js/bug1815733-outlook365-clipboard-read-noop.jsPK
!<�
����1���injections/js/bug1818818-fastclick-legacy-shim.jsPK
!<0�pp2���injections/js/bug1819450-cmbchina.com-ua-change.jsPK
!<�w@�YYE����injections/js/bug1819476-axisbank.com-webkitSpeechRecognition-shim.jsPK
!<��7��<��|�injections/js/bug1819678-free4talk.com-window-chrome-shim.jsPK
!<�B�d{{8����injections/js/bug1830776-blueshieldca.com-unsupported.jsPK
!<j{���@��d�injections/js/bug1831007-nintendo-window-OnetrustActiveGroups.jsPK
!<[�ff<��v�injections/js/bug1836157-thai-masszazs-niceScroll-disable.jsPK
!<S�7E��6�injections/js/bug1842437-www.youtube.com-performance-now-precision.jsPK
!<+<��hhB����injections/js/bug1849058-nicochannel.jp-picture-in-picture-shim.jsPK
!<���*��}�injections/js/bug1855014-eksiseyler.com.jsPK
!<�,u4��*����injections/js/bug1855071-www.meteoam.it.jsPK
!<�b�++7��#�injections/js/bug1859617-installtrigger-removal-shim.jsPK
!<$q����5����injections/js/bug1864564-esri-transfrom-names-shim.jsPK
!<y'���:���injections/js/bug1881922-disable-legacy-mutation-events.jsPK
!<[�齲�D��(injections/js/bug1889326-office365-email-handling-prompt-autohide.jsPK
!<vꅖbb8��<injections/js/bug1896383-error-capturestacktrace-shim.jsPK
!<(�4�		+���	injections/js/bug1897120-turnjs-zoom-fix.jsPK
!<�����/��Rinjections/js/bug1898952-digits.t-mobile.com.jsPK
!<uD~ccB��Iinjections/js/bug1899937-plus.nhk.jp-request-picture-in-picture.jsPK
!<�$d`����lib/about_compat_broker.jsPK
!<�|K����./lib/custom_functions.jsPK
!<0G�� ! !��	<lib/injections.jsPK
!<*܍�UU��X]lib/intervention_helpers.jsPK
!<K�$i�����hlib/messaging_helper.jsPK
!<r������mlib/module_shim.jsPK
!<6AA"���rlib/requestStorageAccess_helper.jsPK
!<�'Ŕ���-wlib/shim_messaging_helper.jsPK
!<1#h�|�|���}lib/shims.jsPK
!<�S�Q�����lib/ua_helpers.jsPK
!<�`a>���
lib/ua_overrides.jsPK
!<���666
��$manifest.jsonPK
!<�������5run.jsPK
!<�����2:shims/addthis-angular.jsPK
!<KHm#��t<shims/adform.jsPK
!<!hv(���?shims/adnexus-ast.jsPK
!<���99��Rshims/adnexus-prebid.jsPK
!<�v���pXshims/adsafeprotected-ima.jsPK
!<LJ�22���Zshims/apstag.jsPK
!<�Ɩo����ashims/blogger.jsPK
!<�������ishims/bloggerAccount.jsPK
!<��	����qshims/bmauth.jsPK
!<� ����tshims/branch.jsPK
!<�	���J{shims/chartbeat.jsPK
!<�e'�LL���}shims/crave-ca.jsPK
!<���	�����shims/criteo.jsPK
!<��QAQA���shims/cxense.jsPK
!<yaYT))����shims/doubleverify.jsPK
!<��iW
W
����shims/eluminate.jsPK
!<�4������shims/empty-script.jsPK
!<����shims/empty-shim.txtPK
!<�	��������shims/everest.jsPK
!<H�!D!D����shims/facebook-sdk.jsPK
!<{�Q����	1shims/facebook.svgPK
!<�G������3shims/fastclick.jsPK
!<�Y�'	'	��5:shims/firebase.jsPK
!<<���pp���Cshims/google-ads.jsPK
!<�f��UU)��,Jshims/google-analytics-and-tag-manager.jsPK
!<����RR*���\shims/google-analytics-ecommerce-plugin.jsPK
!<*�pU"
"
 ��b^shims/google-analytics-legacy.jsPK
!<�A�s�5�5���kshims/google-ima.jsPK
!<G]�p''��ԡshims/google-page-ad.jsPK
!<�?��4343��0�shims/google-publisher-tags.jsPK
!<wA0�II����shims/google-safeframe.htmlPK
!<�L//��"�shims/history.jsPK
!<��kH�����shims/iam.jsPK
!<�\�����+�shims/iaspet.jsPK
!<5�e����shims/instagram.jsPK
!<�d.z����O�shims/kinja.jsPK
!<n��[����G�shims/live-test-shim.jsPK
!<
`�&&��@�shims/maxmind-geoip.jsPK
!<
o�33���shims/microsoftLogin.jsPK
!<oi0��"��
shims/microsoftVirtualAssistant.jsPK
!<�v�GG
��shims/moat.jsPK
!<FEhƸ	�	��yshims/mochitest-shim-1.jsPK
!<�܎�P	P	��hshims/mochitest-shim-2.jsPK
!<�$K*���(shims/mochitest-shim-3.jsPK
!<��S
		��)*shims/nielsen.jsPK
!<�������n3shims/optimizely.jsPK
!<�Vii���Cshims/play.svgPK
!<AIEI����Fshims/rambler-authenticator.jsPK
!<g("W����Rshims/rich-relevance.jsPK
!<8�f����kshims/salesforce.jsPK
!<��A����,qshims/spotify-embed.jsPK
!<IJ�FF��
�shims/tracking-pixel.pngPK
!<����CC����shims/tsn-ca.jsPK
!<�d+�������shims/vast2.xmlPK
!<L��U�����shims/vast3.xmlPK
!<OCr+1+1���shims/vidible.jsPK
!<􅤒����d�shims/vmad.xmlPK
!<��)�����n�shims/webtrends.jsPK���3PK
!<M'�W��about-compat/aboutPage.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* global ExtensionAPI, XPCOMUtils, Services */

XPCOMUtils.defineLazyServiceGetter(
  this,
  "resProto",
  "@mozilla.org/network/protocol;1?name=resource",
  "nsISubstitutingProtocolHandler"
);

const ResourceSubstitution = "webcompat";
const ProcessScriptURL = "resource://webcompat/aboutPageProcessScript.js";
const ContractID = "@mozilla.org/network/protocol/about;1?what=compat";

this.aboutPage = class extends ExtensionAPI {
  onStartup() {
    const { rootURI } = this.extension;

    resProto.setSubstitution(
      ResourceSubstitution,
      Services.io.newURI("about-compat/", null, rootURI)
    );

    if (!(ContractID in Cc)) {
      Services.ppmm.loadProcessScript(ProcessScriptURL, true);
      this.processScriptRegistered = true;
    }
  }

  onShutdown() {
    resProto.setSubstitution(ResourceSubstitution, null);

    if (this.processScriptRegistered) {
      Services.ppmm.removeDelayedProcessScript(ProcessScriptURL);
    }
  }
};
PK
!<�ȌBBexperiment-apis/appConstants.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* global AppConstants, ExtensionAPI, XPCOMUtils */

this.appConstants = class extends ExtensionAPI {
  getAPI() {
    return {
      appConstants: {
        getReleaseBranch: () => {
          if (AppConstants.NIGHTLY_BUILD) {
            return "nightly";
          } else if (AppConstants.MOZ_DEV_EDITION) {
            return "dev_edition";
          } else if (AppConstants.EARLY_BETA_OR_EARLIER) {
            return "early_beta_or_earlier";
          } else if (AppConstants.RELEASE_OR_BETA) {
            return "release_or_beta";
          }
          return "unknown";
        },
      },
    };
  }
};
PK
!<$�(++#experiment-apis/aboutConfigPrefs.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* global ExtensionAPI, ExtensionCommon, Services */

this.aboutConfigPrefs = class extends ExtensionAPI {
  getAPI(context) {
    const EventManager = ExtensionCommon.EventManager;
    const extensionIDBase = context.extension.id.split("@")[0];
    const extensionPrefNameBase = `extensions.${extensionIDBase}.`;

    return {
      aboutConfigPrefs: {
        onPrefChange: new EventManager({
          context,
          name: "aboutConfigPrefs.onUAOverridesPrefChange",
          register: (fire, name) => {
            const prefName = `${extensionPrefNameBase}${name}`;
            const callback = () => {
              fire.async(name).catch(() => {}); // ignore Message Manager disconnects
            };
            Services.prefs.addObserver(prefName, callback);
            return () => {
              Services.prefs.removeObserver(prefName, callback);
            };
          },
        }).api(),
        async getBranch(branchName) {
          const branch = `${extensionPrefNameBase}${branchName}.`;
          return Services.prefs.getChildList(branch).map(pref => {
            const name = pref.replace(branch, "");
            return { name, value: Services.prefs.getBoolPref(pref) };
          });
        },
        async getPref(name) {
          try {
            return Services.prefs.getBoolPref(
              `${extensionPrefNameBase}${name}`
            );
          } catch (_) {
            return undefined;
          }
        },
        async setPref(name, value) {
          Services.prefs.setBoolPref(`${extensionPrefNameBase}${name}`, value);
        },
      },
    };
  }
};
PK
!<�EO%experiment-apis/trackingProtection.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* global ExtensionAPI, ExtensionCommon, ExtensionParent, Services, XPCOMUtils */

// eslint-disable-next-line mozilla/reject-importGlobalProperties
XPCOMUtils.defineLazyGlobalGetters(this, ["URL", "ChannelWrapper"]);

class AllowList {
  constructor(id) {
    this._id = id;
  }

  setShims(patterns, notHosts) {
    this._shimPatterns = patterns;
    this._shimMatcher = new MatchPatternSet(patterns || []);
    this._shimNotHosts = notHosts || [];
    return this;
  }

  setAllows(patterns, hosts) {
    this._allowPatterns = patterns;
    this._allowMatcher = new MatchPatternSet(patterns || []);
    this._allowHosts = hosts || [];
    return this;
  }

  shims(url, topHost) {
    return (
      this._shimMatcher?.matches(url) && !this._shimNotHosts?.includes(topHost)
    );
  }

  allows(url, topHost) {
    return (
      this._allowMatcher?.matches(url) && this._allowHosts?.includes(topHost)
    );
  }
}

class Manager {
  constructor() {
    this._allowLists = new Map();
  }

  _getAllowList(id) {
    if (!this._allowLists.has(id)) {
      this._allowLists.set(id, new AllowList(id));
    }
    return this._allowLists.get(id);
  }

  _ensureStarted() {
    if (this._classifierObserver) {
      return;
    }

    this._unblockedChannelIds = new Set();
    this._channelClassifier = Cc[
      "@mozilla.org/url-classifier/channel-classifier-service;1"
    ].getService(Ci.nsIChannelClassifierService);
    this._classifierObserver = {};
    this._classifierObserver.observe = (subject, topic) => {
      switch (topic) {
        case "http-on-stop-request": {
          const { channelId } = subject.QueryInterface(Ci.nsIIdentChannel);
          this._unblockedChannelIds.delete(channelId);
          break;
        }
        case "urlclassifier-before-block-channel": {
          const channel = subject.QueryInterface(
            Ci.nsIUrlClassifierBlockedChannel
          );
          const { channelId, url } = channel;
          let topHost;
          try {
            topHost = new URL(channel.topLevelUrl).hostname;
          } catch (_) {
            return;
          }
          // If anti-tracking webcompat is disabled, we only permit replacing
          // channels, not fully unblocking them.
          if (Manager.ENABLE_WEBCOMPAT) {
            // if any allowlist unblocks the request entirely, we allow it
            for (const allowList of this._allowLists.values()) {
              if (allowList.allows(url, topHost)) {
                this._unblockedChannelIds.add(channelId);
                channel.allow();
                return;
              }
            }
          }
          // otherwise, if any allowlist shims the request we say it's replaced
          for (const allowList of this._allowLists.values()) {
            if (allowList.shims(url, topHost)) {
              this._unblockedChannelIds.add(channelId);
              channel.replace();
              return;
            }
          }
          break;
        }
      }
    };
    Services.obs.addObserver(this._classifierObserver, "http-on-stop-request");
    this._channelClassifier.addListener(this._classifierObserver);
  }

  stop() {
    if (!this._classifierObserver) {
      return;
    }

    Services.obs.removeObserver(
      this._classifierObserver,
      "http-on-stop-request"
    );
    this._channelClassifier.removeListener(this._classifierObserver);
    delete this._channelClassifier;
    delete this._classifierObserver;
  }

  wasChannelIdUnblocked(channelId) {
    return this._unblockedChannelIds?.has(channelId);
  }

  allow(allowListId, patterns, hosts) {
    this._ensureStarted();
    this._getAllowList(allowListId).setAllows(patterns, hosts);
  }

  shim(allowListId, patterns, notHosts) {
    this._ensureStarted();
    this._getAllowList(allowListId).setShims(patterns, notHosts);
  }

  revoke(allowListId) {
    this._allowLists.delete(allowListId);
  }
}
var manager = new Manager();

function getChannelId(context, requestId) {
  const wrapper = ChannelWrapper.getRegisteredChannel(
    requestId,
    context.extension.policy,
    context.xulBrowser.frameLoader.remoteTab
  );
  return wrapper?.channel?.QueryInterface(Ci.nsIIdentChannel)?.channelId;
}

var dFPIPrefName = "network.cookie.cookieBehavior";
var dFPIPbPrefName = "network.cookie.cookieBehavior.pbmode";
var dFPIStatus;
function updateDFPIStatus() {
  dFPIStatus = {
    nonPbMode: 5 == Services.prefs.getIntPref(dFPIPrefName),
    pbMode: 5 == Services.prefs.getIntPref(dFPIPbPrefName),
  };
}

this.trackingProtection = class extends ExtensionAPI {
  onShutdown() {
    if (manager) {
      manager.stop();
    }
    Services.prefs.removeObserver(dFPIPrefName, updateDFPIStatus);
    Services.prefs.removeObserver(dFPIPbPrefName, updateDFPIStatus);
  }

  getAPI(context) {
    Services.prefs.addObserver(dFPIPrefName, updateDFPIStatus);
    Services.prefs.addObserver(dFPIPbPrefName, updateDFPIStatus);
    updateDFPIStatus();

    return {
      trackingProtection: {
        async shim(allowListId, patterns, notHosts) {
          manager.shim(allowListId, patterns, notHosts);
        },
        async allow(allowListId, patterns, hosts) {
          manager.allow(allowListId, patterns, hosts);
        },
        async revoke(allowListId) {
          manager.revoke(allowListId);
        },
        async wasRequestUnblocked(requestId) {
          if (!manager) {
            return false;
          }
          const channelId = getChannelId(context, requestId);
          if (!channelId) {
            return false;
          }
          return manager.wasChannelIdUnblocked(channelId);
        },
        async isDFPIActive(isPrivate) {
          if (isPrivate) {
            return dFPIStatus.pbMode;
          }
          return dFPIStatus.nonPbMode;
        },
      },
    };
  }
};

XPCOMUtils.defineLazyPreferenceGetter(
  Manager,
  "ENABLE_WEBCOMPAT",
  "privacy.antitracking.enableWebcompat",
  false
);
PK
!<�9ה�� about-compat/AboutCompat.sys.mjs/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const addonID = "webcompat@mozilla.org";
const addonPageRelativeURL = "/about-compat/aboutCompat.html";

export function AboutCompat() {
  this.chromeURL =
    WebExtensionPolicy.getByID(addonID).getURL(addonPageRelativeURL);
}

AboutCompat.prototype = {
  QueryInterface: ChromeUtils.generateQI(["nsIAboutModule"]),
  getURIFlags() {
    return (
      Ci.nsIAboutModule.URI_MUST_LOAD_IN_EXTENSION_PROCESS |
      Ci.nsIAboutModule.IS_SECURE_CHROME_UI
    );
  },

  newChannel(aURI, aLoadInfo) {
    const uri = Services.io.newURI(this.chromeURL);
    const channel = Services.io.newChannelFromURIWithLoadInfo(uri, aLoadInfo);
    channel.originalURI = aURI;

    channel.owner = (
      Services.scriptSecurityManager.createContentPrincipal ||
      // Handles fallback to earlier versions.
      // eslint-disable-next-line mozilla/valid-services-property
      Services.scriptSecurityManager.createCodebasePrincipal
    )(uri, aLoadInfo.originAttributes);
    return channel;
  },
};
PK
!<�� "
"
about-compat/aboutCompat.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

@media (any-pointer: fine) {
  :root {
    font-family: sans-serif;
    margin: 40px auto;
    min-width: 30em;
    max-width: 60em;
  }

  table {
    width: 100%;
    padding-bottom: 2em;
    border-spacing: 0;
  }

  td {
    border-bottom: 1px solid var(--in-content-border-color);
  }

  td:last-child > button {
    float: inline-end;
  }
}

/* Mobile UI where common.css is not loaded */

@media (any-pointer: coarse), (any-pointer: none) {
  * {
    margin: 0;
    padding: 0;
  }

  :root {
    --background-color: #fff;
    --text-color: #0c0c0d;
    --border-color: #e1e1e2;
    --button-background-color: #f5f5f5;
    --selected-tab-text-color: #0061e0;
  }

  @media (prefers-color-scheme: dark) {
    :root {
      --background-color: #292833;
      --text-color: #f9f9fa;
      --border-color: rgba(255, 255, 255, 0.15);
      --button-background-color: rgba(0, 0, 0, 0.15);
      --selected-tab-text-color: #00ddff;
    }
  }

  body {
    background-color: var(--background-color);
    color: var(--text-color);
    font: message-box;
    font-size: 14px;
    -moz-text-size-adjust: none;
    display: grid;
    grid-template-areas: "a b c" "d d d";
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: fit-content(100%) 1fr;
  }

  .tab[data-l10n-id="label-overrides"] {
    grid-area: a;
  }

  .tab[data-l10n-id="label-interventions"] {
    grid-area: b;
  }

  .tab[data-l10n-id="label-smartblock"] {
    grid-area: c;
  }

  table {
    grid-area: d;
  }

  table,
  tr,
  p {
    display: block;
  }

  table {
    border-top: 2px solid var(--border-color);
    margin-top: -2px;
    width: 100%;
    z-index: 1;
    display: none;
  }

  tr {
    border-bottom: 1px solid var(--border-color);
    padding: 0;
  }

  a {
    color: inherit;
    font-size: 94%;
  }

  .tab {
    cursor: pointer;
    z-index: 2;
    display: inline-block;
    text-align: left;
    border-block: 2px solid transparent;
    font-size: 1em;
    font-weight: bold;
    padding: 1em;
  }

  .tab.active {
    color: var(--selected-tab-text-color);
    border-bottom-color: currentColor;
    margin-bottom: 0;
    padding-bottom: calc(1em + 2px);
  }

  .tab.active + table {
    display: block;
  }

  td {
    grid-area: b;
    padding-left: 1em;
  }

  td:first-child {
    grid-area: a;
    padding-top: 1em;
  }

  td:last-child {
    grid-area: c;
    padding-bottom: 1em;
  }

  tr {
    display: grid;
    grid-template-areas: "a c" "b c";
    grid-template-columns: 1fr 6.5em;
  }

  td[colspan="4"] {
    padding: 1em;
    font-style: italic;
    text-align: center;
  }

  td:not([colspan]):nth-child(1) {
    font-weight: bold;
    padding-bottom: 0.25em;
  }

  td:nth-child(2) {
    padding-bottom: 1em;
  }

  td:nth-child(3) {
    display: flex;
    padding: 0;
  }

  button {
    cursor: pointer;
    width: 100%;
    height: 100%;
    background: var(--button-background-color);
    color: inherit;
    inset-inline-end: 0;
    margin: 0;
    padding: 0;
    border: 0;
    border-inline-start: 1px solid var(--border-color);
    font-weight: 600;
    appearance: none;
  }

  button::-moz-focus-inner {
    border: 0;
  }
}
PK
!<�D�HRRabout-compat/aboutCompat.html<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

<!DOCTYPE html>
<html>
  <head>
    <base />

    <!-- If you change this script tag you must update the hash in the extension's
         `content_security_policy` 'sha256-MmZkN2QaIHhfRWPZ8TVRjijTn5Ci1iEabtTEWrt9CCo=' -->
    <script>
      /* globals browser */ document.head.firstElementChild.href =
        browser.runtime.getURL("");
    </script>

    <meta charset="utf-8" />
    <meta name="color-scheme" content="light dark" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="about-compat/aboutCompat.css" />
    <link
      rel="stylesheet"
      media="screen and (pointer:fine), projection"
      type="text/css"
      href="chrome://global/skin/in-content/common.css"
    />
    <link rel="localization" href="toolkit/about/aboutCompat.ftl" />
    <title data-l10n-id="text-title"></title>
    <script src="about-compat/aboutCompat.js"></script>
  </head>
  <body>
    <h2 class="tab active" data-l10n-id="label-overrides"></h2>
    <table id="overrides">
      <col />
      <col />
      <col />
    </table>
    <h2 class="tab" data-l10n-id="label-interventions"></h2>
    <table id="interventions">
      <col />
      <col />
      <col />
    </table>
    <h2 class="tab" data-l10n-id="label-smartblock"></h2>
    <table id="smartblock" class="shims">
      <col />
      <col />
      <col />
    </table>
  </body>
</html>
PK
!<�ib��about-compat/aboutCompat.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser */

let availablePatches;

const portToAddon = (function () {
  let port;

  function connect() {
    port = browser.runtime.connect({ name: "AboutCompatTab" });
    port.onMessage.addListener(onMessageFromAddon);
    port.onDisconnect.addListener(() => {
      port = undefined;
    });
  }

  connect();

  async function send(message) {
    if (port) {
      return port.postMessage(message);
    }
    return Promise.reject("background script port disconnected");
  }

  return { send };
})();

const $ = function (sel) {
  return document.querySelector(sel);
};

const DOMContentLoadedPromise = new Promise(resolve => {
  document.addEventListener(
    "DOMContentLoaded",
    () => {
      resolve();
    },
    { once: true }
  );
});

Promise.all([
  browser.runtime.sendMessage("getAllInterventions"),
  DOMContentLoadedPromise,
]).then(([info]) => {
  document.body.addEventListener("click", async evt => {
    const ele = evt.target;
    if (ele.nodeName === "BUTTON") {
      const row = ele.closest("[data-id]");
      if (row) {
        evt.preventDefault();
        ele.disabled = true;
        const id = row.getAttribute("data-id");
        try {
          await browser.runtime.sendMessage({ command: "toggle", id });
        } catch (_) {
          ele.disabled = false;
        }
      }
    } else if (ele.classList.contains("tab")) {
      document.querySelectorAll(".tab").forEach(tab => {
        tab.classList.remove("active");
      });
      ele.classList.add("active");
    }
  });

  availablePatches = info;
  redraw();
});

async function onMessageFromAddon(msg) {
  const alsoShowHidden = location.hash === "#all";

  await DOMContentLoadedPromise;

  if ("interventionsChanged" in msg) {
    redrawTable($("#interventions"), msg.interventionsChanged, alsoShowHidden);
  }

  if ("overridesChanged" in msg) {
    redrawTable($("#overrides"), msg.overridesChanged, alsoShowHidden);
  }

  if ("shimsChanged" in msg) {
    updateShimTables(msg.shimsChanged, alsoShowHidden);
  }

  const id = msg.toggling || msg.toggled;
  const button = $(`[data-id="${id}"] button`);
  if (!button) {
    return;
  }
  const active = msg.active;
  document.l10n.setAttributes(
    button,
    active ? "label-disable" : "label-enable"
  );
  button.disabled = !!msg.toggling;
}

function redraw() {
  if (!availablePatches) {
    return;
  }
  const { overrides, interventions, shims } = availablePatches;
  const alsoShowHidden = location.hash === "#all";
  redrawTable($("#overrides"), overrides, alsoShowHidden);
  redrawTable($("#interventions"), interventions, alsoShowHidden);
  updateShimTables(shims, alsoShowHidden);
}

function clearTableAndAddMessage(table, msgId) {
  table.querySelectorAll("tr").forEach(tr => {
    tr.remove();
  });

  const tr = document.createElement("tr");
  tr.className = "message";
  tr.id = msgId;

  const td = document.createElement("td");
  td.setAttribute("colspan", "3");
  document.l10n.setAttributes(td, msgId);
  tr.appendChild(td);

  table.appendChild(tr);
}

function hideMessagesOnTable(table) {
  table.querySelectorAll("tr.message").forEach(tr => {
    tr.remove();
  });
}

function updateShimTables(shimsChanged, alsoShowHidden) {
  const tables = document.querySelectorAll("table.shims");
  if (!tables.length) {
    return;
  }

  for (const { bug, disabledReason, hidden, id, name, type } of shimsChanged) {
    // if any shim is disabled by global pref, all of them are. just show the
    // "disabled in about:config" message on each shim table in that case.
    if (disabledReason === "globalPref") {
      for (const table of tables) {
        clearTableAndAddMessage(table, "text-disabled-in-about-config");
      }
      return;
    }

    // otherwise, find which table the shim belongs in. if there is none,
    // ignore the shim (we're not showing it on the UI for whatever reason).
    const table = document.querySelector(`table.shims#${type}`);
    if (!table) {
      continue;
    }

    // similarly, skip shims hidden from the UI (only for testing, etc).
    if (!alsoShowHidden && hidden) {
      continue;
    }

    // also, hide the shim if it is disabled because it is not meant for this
    // platform, release (etc) rather than being disabled by pref/about:compat
    const notApplicable =
      disabledReason &&
      disabledReason !== "pref" &&
      disabledReason !== "session";
    if (!alsoShowHidden && notApplicable) {
      continue;
    }

    // create an updated table-row for the shim
    const tr = document.createElement("tr");
    tr.setAttribute("data-id", id);

    let td = document.createElement("td");
    td.innerText = name;
    tr.appendChild(td);

    td = document.createElement("td");
    const a = document.createElement("a");
    a.href = `https://bugzilla.mozilla.org/show_bug.cgi?id=${bug}`;
    document.l10n.setAttributes(a, "label-more-information", { bug });
    a.target = "_blank";
    td.appendChild(a);
    tr.appendChild(td);

    td = document.createElement("td");
    tr.appendChild(td);
    const button = document.createElement("button");
    document.l10n.setAttributes(
      button,
      disabledReason ? "label-enable" : "label-disable"
    );
    td.appendChild(button);

    // is it already in the table?
    const row = table.querySelector(`tr[data-id="${id}"]`);
    if (row) {
      row.replaceWith(tr);
    } else {
      table.appendChild(tr);
    }
  }

  for (const table of tables) {
    if (!table.querySelector("tr:not(.message)")) {
      // no shims? then add a message that none are available for this platform/config
      clearTableAndAddMessage(table, `text-no-${table.id}`);
    } else {
      // otherwise hide any such message, since we have shims on the list
      hideMessagesOnTable(table);
    }
  }
}

function redrawTable(table, data, alsoShowHidden) {
  const df = document.createDocumentFragment();
  table.querySelectorAll("tr").forEach(tr => {
    tr.remove();
  });

  let noEntriesMessage;
  if (data === false) {
    noEntriesMessage = "text-disabled-in-about-config";
  } else if (data.length === 0) {
    noEntriesMessage = `text-no-${table.id}`;
  }

  if (noEntriesMessage) {
    const tr = document.createElement("tr");
    df.appendChild(tr);

    const td = document.createElement("td");
    td.setAttribute("colspan", "3");
    document.l10n.setAttributes(td, noEntriesMessage);
    tr.appendChild(td);

    table.appendChild(df);
    return;
  }

  for (const row of data) {
    if (row.hidden && !alsoShowHidden) {
      continue;
    }

    const tr = document.createElement("tr");
    tr.setAttribute("data-id", row.id);
    df.appendChild(tr);

    let td = document.createElement("td");
    td.innerText = row.domain;
    tr.appendChild(td);

    td = document.createElement("td");
    const a = document.createElement("a");
    const bug = row.bug;
    a.href = `https://bugzilla.mozilla.org/show_bug.cgi?id=${bug}`;
    document.l10n.setAttributes(a, "label-more-information", { bug });
    a.target = "_blank";
    td.appendChild(a);
    tr.appendChild(td);

    td = document.createElement("td");
    tr.appendChild(td);
    const button = document.createElement("button");
    document.l10n.setAttributes(
      button,
      row.active ? "label-disable" : "label-enable"
    );
    td.appendChild(button);
  }
  table.appendChild(df);
}

window.onhashchange = redraw;
PK
!<u!o�__about-compat/aboutPage.json[
  {
    "namespace": "aboutCompat",
    "description": "Enables the about:compat page"
  }
]
PK
!<�T�&about-compat/aboutPageProcessScript.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* eslint-env mozilla/process-script */

"use strict";

// Note: This script is used only when a static registration for our
// component is not already present in the libxul binary.

const Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);

const classID = Components.ID("{97bf9550-2a7b-11e9-b56e-0800200c9a66}");

if (!Cm.isCIDRegistered(classID)) {
  const { ComponentUtils } = ChromeUtils.importESModule(
    "resource://gre/modules/ComponentUtils.sys.mjs"
  );

  const factory = ComponentUtils.generateSingletonFactory(function () {
    const { AboutCompat } = ChromeUtils.importESModule(
      "resource://webcompat/AboutCompat.sys.mjs"
    );
    return new AboutCompat();
  });

  Cm.registerFactory(
    classID,
    "about:compat",
    "@mozilla.org/network/protocol/about;1?what=compat",
    factory
  );
}
PK
!<<N7�n�ndata/injections.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals module, require */

// This is a hack for the tests.
if (typeof InterventionHelpers === "undefined") {
  var InterventionHelpers = require("../lib/intervention_helpers");
}

/**
 * For detailed information on our policies, and a documention on this format
 * and its possibilites, please check the Mozilla-Wiki at
 *
 * https://wiki.mozilla.org/Compatibility/Go_Faster_Addon/Override_Policies_and_Workflows#User_Agent_overrides
 */
const AVAILABLE_INJECTIONS = [
  {
    id: "testbed-injection",
    platform: "all",
    domain: "webcompat-addon-testbed.herokuapp.com",
    bug: "0000000",
    hidden: true,
    contentScripts: {
      matches: ["*://webcompat-addon-testbed.herokuapp.com/*"],
      css: [
        {
          file: "injections/css/bug0000000-testbed-css-injection.css",
        },
      ],
      js: [
        {
          file: "injections/js/bug0000000-testbed-js-injection.js",
        },
      ],
    },
  },
  {
    id: "bug1452707",
    platform: "all",
    domain: "ib.absa.co.za",
    bug: "1452707",
    contentScripts: {
      matches: ["https://ib.absa.co.za/*"],
      js: [
        {
          file: "injections/js/bug1452707-window.controllers-shim-ib.absa.co.za.js",
        },
      ],
    },
  },
  {
    id: "bug1457335",
    platform: "desktop",
    domain: "histography.io",
    bug: "1457335",
    contentScripts: {
      matches: ["*://histography.io/*"],
      js: [
        {
          file: "injections/js/bug1457335-histography.io-ua-change.js",
        },
      ],
    },
  },
  {
    id: "bug1472075",
    platform: "desktop",
    domain: "bankofamerica.com",
    bug: "1472075",
    contentScripts: {
      matches: [
        "*://*.bankofamerica.com/*",
        "*://*.ml.com/*", // #120104
      ],
      js: [
        {
          file: "injections/js/bug1472075-bankofamerica.com-ua-change.js",
        },
      ],
    },
  },
  {
    id: "bug1579159",
    platform: "android",
    domain: "m.tailieu.vn",
    bug: "1579159",
    contentScripts: {
      matches: ["*://m.tailieu.vn/*", "*://m.elib.vn/*"],
      js: [
        {
          file: "injections/js/bug1579159-m.tailieu.vn-pdfjs-worker-disable.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1583366",
    platform: "desktop",
    domain: "Download prompt for files with no content-type",
    bug: "1583366",
    data: {
      urls: ["https://ads-us.rd.linksynergy.com/as.php*"],
      contentType: {
        name: "content-type",
        value: "text/html; charset=utf-8",
      },
    },
    customFunc: "noSniffFix",
  },
  {
    id: "bug1575000",
    platform: "all",
    domain: "apply.lloydsbank.co.uk",
    bug: "1575000",
    contentScripts: {
      matches: ["*://apply.lloydsbank.co.uk/*"],
      css: [
        {
          file: "injections/css/bug1575000-apply.lloydsbank.co.uk-radio-buttons-fix.css",
        },
      ],
    },
  },
  {
    id: "bug1610344",
    platform: "all",
    domain: "directv.com.co",
    bug: "1610344",
    contentScripts: {
      matches: [
        "https://*.directv.com.co/*",
        "https://*.directv.com.ec/*", // bug 1827706
      ],
      css: [
        {
          file: "injections/css/bug1610344-directv.com.co-hide-unsupported-message.css",
        },
      ],
    },
  },
  {
    id: "bug1644830",
    platform: "desktop",
    domain: "usps.com",
    bug: "1644830",
    contentScripts: {
      matches: ["https://*.usps.com/*"],
      css: [
        {
          file: "injections/css/bug1644830-missingmail.usps.com-checkboxes-not-visible.css",
        },
      ],
    },
  },
  {
    id: "bug1651917",
    platform: "android",
    domain: "teletrader.com",
    bug: "1651917",
    contentScripts: {
      matches: ["*://*.teletrader.com/*"],
      css: [
        {
          file: "injections/css/bug1651917-teletrader.com.body-transform-origin.css",
        },
      ],
    },
  },
  {
    id: "bug1653075",
    platform: "desktop",
    domain: "livescience.com",
    bug: "1653075",
    contentScripts: {
      matches: ["*://*.livescience.com/*"],
      css: [
        {
          file: "injections/css/bug1653075-livescience.com-scrollbar-width.css",
        },
      ],
    },
  },
  {
    id: "bug1654907",
    platform: "android",
    domain: "reactine.ca",
    bug: "1654907",
    contentScripts: {
      matches: ["*://*.reactine.ca/*"],
      css: [
        {
          file: "injections/css/bug1654907-reactine.ca-hide-unsupported.css",
        },
      ],
    },
  },
  {
    id: "bug1694470",
    platform: "android",
    domain: "m.myvidster.com",
    bug: "1694470",
    contentScripts: {
      matches: ["https://m.myvidster.com/*"],
      css: [
        {
          file: "injections/css/bug1694470-myvidster.com-content-not-shown.css",
        },
      ],
    },
  },
  {
    id: "bug1707795",
    platform: "desktop",
    domain: "Office Excel spreadsheets",
    bug: "1707795",
    contentScripts: {
      matches: [
        "*://*.live.com/*",
        "*://*.office.com/*",
        "*://*.sharepoint.com/*",
      ],
      css: [
        {
          file: "injections/css/bug1707795-office365-sheets-overscroll-disable.css",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1722955",
    platform: "android",
    domain: "frontgate.com",
    bug: "1722955",
    contentScripts: {
      matches: ["*://*.frontgate.com/*"],
      js: [
        {
          file: "lib/ua_helpers.js",
        },
        {
          file: "injections/js/bug1722955-frontgate.com-ua-override.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1724868",
    platform: "android",
    domain: "news.yahoo.co.jp",
    bug: "1724868",
    contentScripts: {
      matches: ["*://news.yahoo.co.jp/articles/*", "*://s.yimg.jp/*"],
      js: [
        {
          file: "injections/js/bug1724868-news.yahoo.co.jp-ua-override.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1741234",
    platform: "all",
    domain: "patient.alphalabs.ca",
    bug: "1741234",
    contentScripts: {
      matches: ["*://patient.alphalabs.ca/*"],
      css: [
        {
          file: "injections/css/bug1741234-patient.alphalabs.ca-height-fix.css",
        },
      ],
    },
  },
  {
    id: "bug1739489",
    platform: "desktop",
    domain: "Sites using draft.js",
    bug: "1739489",
    contentScripts: {
      matches: [
        "*://draftjs.org/*", // Bug 1739489
        "*://www.facebook.com/*", // Bug 1739489
        "*://twitter.com/*", // Bug 1776229
        "*://mobile.twitter.com/*", // Bug 1776229
        "*://x.com/*", // Bug 1776229
        "*://mobile.x.com/*", // Bug 1776229
        "*://*.reddit.com/*", // Bug 1829755
      ],
      js: [
        {
          file: "injections/js/bug1739489-draftjs-beforeinput.js",
        },
      ],
    },
  },
  {
    id: "bug1765947",
    platform: "android",
    domain: "veniceincoming.com",
    bug: "1765947",
    contentScripts: {
      matches: ["*://veniceincoming.com/*"],
      css: [
        {
          file: "injections/css/bug1765947-veniceincoming.com-left-fix.css",
        },
      ],
    },
  },
  {
    id: "bug11769762",
    platform: "all",
    domain: "tiktok.com",
    bug: "1769762",
    contentScripts: {
      matches: ["https://www.tiktok.com/*"],
      js: [
        {
          file: "injections/js/bug1769762-tiktok.com-plugins-shim.js",
        },
      ],
    },
  },
  {
    id: "bug1770962",
    platform: "all",
    domain: "coldwellbankerhomes.com",
    bug: "1770962",
    contentScripts: {
      matches: ["*://*.coldwellbankerhomes.com/*"],
      css: [
        {
          file: "injections/css/bug1770962-coldwellbankerhomes.com-image-height.css",
        },
      ],
    },
  },
  {
    id: "bug1774490",
    platform: "all",
    domain: "rainews.it",
    bug: "1774490",
    contentScripts: {
      matches: ["*://www.rainews.it/*"],
      css: [
        {
          file: "injections/css/bug1774490-rainews.it-gallery-fix.css",
        },
      ],
    },
  },
  {
    id: "bug1774005",
    platform: "all",
    domain: "Sites relying on window.InstallTrigger",
    bug: "1774005",
    contentScripts: {
      matches: [
        "*://*.crunchyroll.com/*", // Bug 1777597
        "*://*.ersthelfer.tv/*", // Bug 1817520
        "*://*.webex.com/*", // Bug 1788934
        "*://ifcinema.institutfrancais.com/*", // Bug 1806423
        "*://islamionline.islamicbank.ps/*", // Bug 1821439
        "*://*.itv.com/*", // Bug 1830203
        "*://mobilevikings.be/*/registration/*", // Bug 1797400
        "*://www.schoolnutritionandfitness.com/*", // Bug 1793761
      ],
      js: [
        {
          file: "injections/js/bug1774005-installtrigger-shim.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1859617",
    platform: "all",
    domain: "Sites relying on there being no window.InstallTrigger",
    bug: "1859617",
    contentScripts: {
      matches: [
        "*://*.stallionexpress.ca/*", // Bug 1859617
      ],
      js: [
        {
          file: "injections/js/bug1859617-installtrigger-removal-shim.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1784141",
    platform: "android",
    domain: "aveeno.com and acuvue.com",
    bug: "1784141",
    contentScripts: {
      matches: [
        "*://*.aveeno.com/*",
        "*://*.aveeno.ca/*",
        "*://*.aveeno.com.au/*",
        "*://*.aveeno.co.kr/*",
        "*://*.aveeno.co.uk/*",
        "*://*.aveeno.ie/*",
        "*://*.acuvue.com/*", // 1804730
        "*://*.acuvue.com.ar/*",
        "*://*.acuvue.com.br/*",
        "*://*.acuvue.ca/*",
        "*://*.acuvue-fr.ca/*",
        "*://*.acuvue.cl/*",
        "*://*.acuvue.co.cr/*",
        "*://*.acuvue.com.co/*",
        "*://*.acuvue.com.do/*",
        "*://*.acuvue.com.pe/*",
        "*://*.acuvue.com.sv/*",
        "*://*.acuvue.com.gt/*",
        "*://*.acuvue.hn/*",
        "*://*.acuvue.com.mx/*",
        "*://*.acuvue.com.pa/*",
        "*://*.acuvue.com.py/*",
        "*://*.acuvue.com.pr/*",
        "*://*.acuvue.com.uy/*",
        "*://*.acuvue.com.au/*",
        "*://*.acuvue.com.cn/*",
        "*://*.acuvue.com.hk/*",
        "*://*.acuvue.co.in/*",
        "*://*.acuvue.co.id/*",
        "*://acuvuevision.jp/*",
        "*://*.acuvue.co.kr/*",
        "*://*.acuvue.com.my/*",
        "*://*.acuvue.co.nz/*",
        "*://*.acuvue.com.sg/*",
        "*://*.acuvue.com.tw/*",
        "*://*.acuvue.co.th/*",
        "*://*.acuvue.com.vn/*",
        "*://*.acuvue.at/*",
        "*://*.acuvue.be/*",
        "*://*.fr.acuvue.be/*",
        "*://*.acuvue-croatia.com/*",
        "*://*.acuvue.cz/*",
        "*://*.acuvue.dk/*",
        "*://*.acuvue.fi/*",
        "*://*.acuvue.fr/*",
        "*://*.acuvue.de/*",
        "*://*.acuvue.gr/*",
        "*://*.acuvue.hu/*",
        "*://*.acuvue.ie/*",
        "*://*.acuvue.co.il/*",
        "*://*.acuvue.it/*",
        "*://*.acuvuekz.com/*",
        "*://*.acuvue.lu/*",
        "*://*.en.acuvuearabia.com/*",
        "*://*.acuvuearabia.com/*",
        "*://*.acuvue.nl/*",
        "*://*.acuvue.no/*",
        "*://*.acuvue.pl/*",
        "*://*.acuvue.pt/*",
        "*://*.acuvue.ro/*",
        "*://*.acuvue.ru/*",
        "*://*.acuvue.sk/*",
        "*://*.acuvue.si/*",
        "*://*.acuvue.co.za/*",
        "*://*.jnjvision.com.tr/*",
        "*://*.acuvue.co.uk/*",
        "*://*.acuvue.ua/*",
        "*://*.acuvue.com.pe/*",
        "*://*.acuvue.es/*",
        "*://*.acuvue.se/*",
        "*://*.acuvue.ch/*",
      ],
      css: [
        {
          file: "injections/css/bug1784141-aveeno.com-acuvue.com-unsupported.css",
        },
      ],
    },
  },
  {
    id: "bug1784199",
    platform: "all",
    domain: "Sites based on Entrata Platform",
    bug: "1784199",
    contentScripts: {
      matches: [
        "*://*.7streetbrownstones.com/*", // #129553
        "*://*.aptsovation.com/*",
        "*://*.avanabayview.com/*", // #118617
        "*://*.breakpointeandcoronado.com/*", // #117735
        "*://*.courtsatspringmill.com/*", // #128404
        "*://*.fieldstoneamherst.com/*", // #132974
        "*://*.gslbriarcreek.com/*", // #126401
        "*://*.hpixeniatrails.com/*", // #131703
        "*://*.liveobserverpark.com/*", // #105244
        "*://*.liveupark.com/*", // #121083
        "*://*.midwayurban.com/*", // #116523
        "*://*.nhcalaska.com/*",
        "*://*.prospectportal.com/*", // #115206
        "*://*.securityproperties.com/*",
        "*://*.thefoundryat41st.com/*", // #128994
        "*://*.theloftsorlando.com/*",
        "*://*.vanallenapartments.com/*", // #120056
      ],
      css: [
        {
          file: "injections/css/bug1784199-entrata-platform-unsupported.css",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1799968",
    platform: "linux",
    domain: "www.samsung.com",
    bug: "1799968",
    contentScripts: {
      matches: ["*://www.samsung.com/*"],
      js: [
        {
          file: "injections/js/bug1799968-www.samsung.com-appVersion-linux-fix.js",
        },
      ],
    },
  },
  {
    id: "bug1860417",
    platform: "android",
    domain: "www.samsung.com",
    bug: "1860417",
    contentScripts: {
      matches: ["*://www.samsung.com/*"],
      js: [
        {
          file: "injections/js/bug1799968-www.samsung.com-appVersion-linux-fix.js",
        },
      ],
    },
  },
  {
    id: "bug1799980",
    platform: "all",
    domain: "healow.com",
    bug: "1799980",
    contentScripts: {
      matches: ["*://healow.com/*"],
      js: [
        {
          file: "injections/js/bug1799980-healow.com-infinite-loop-fix.js",
        },
      ],
    },
  },
  {
    id: "bug1448747",
    platform: "android",
    domain: "FastClick breakage",
    bug: "1448747",
    contentScripts: {
      matches: [
        "*://*.co2meter.com/*", // 10959
        "*://*.franmar.com/*", // 27273
        "*://*.themusiclab.org/*", // 49667
        "*://*.oregonfoodbank.org/*", // 53203
        "*://*.fourbarrelcoffee.com/*", // 59427
        "*://bluetokaicoffee.com/*", // 99867
        "*://bathpublishing.com/*", // 100145
        "*://dylantalkstone.com/*", // 101356
        "*://renewd.com.au/*", // 104998
        "*://*.lamudi.co.id/*", // 106767
        "*://*.thehawksmoor.com/*", // 107549
        "*://weaversofireland.com/*", // 116816
        "*://*.iledefrance-mobilites.fr/*", // 117344
        "*://*.lawnmowerpartsworld.com/*", // 117577
        "*://*.discountcoffee.co.uk/*", // 118757
        "*://torguard.net/*", // 120113
        "*://*.arcsivr.com/*", // 120716
        "*://drafthouse.com/*", // 126385
        "*://*.lafoodbank.org/*", // 127006
        "*://rutamayacoffee.com/*", // 129353
        "*://ottoandspike.com.au/*", // bugzilla 1644602
      ],
      js: [
        {
          file: "injections/js/bug1448747-fastclick-shim.js",
        },
      ],
    },
  },
  {
    id: "bug1818818",
    platform: "android",
    domain: "FastClick breakage - legacy",
    bug: "1818818",
    contentScripts: {
      matches: [
        "*://*.chatiw.com/*", // 5544
        "*://*.wellcare.com/*", // 116595
      ],
      js: [
        {
          file: "injections/js/bug1818818-fastclick-legacy-shim.js",
        },
      ],
    },
  },
  {
    id: "bug1819476",
    platform: "all",
    domain: "axisbank.com",
    bug: "1819476",
    contentScripts: {
      matches: ["*://*.axisbank.com/*"],
      js: [
        {
          file: "injections/js/bug1819476-axisbank.com-webkitSpeechRecognition-shim.js",
        },
      ],
    },
  },
  {
    id: "bug1819450",
    platform: "android",
    domain: "cmbchina.com",
    bug: "1819450",
    contentScripts: {
      matches: ["*://www.cmbchina.com/*", "*://cmbchina.com/*"],
      js: [
        {
          file: "injections/js/bug1819450-cmbchina.com-ua-change.js",
        },
      ],
    },
  },
  {
    id: "bug1827678-webc77727-js",
    platform: "android",
    domain: "free4talk.com",
    bug: "1827678",
    contentScripts: {
      matches: ["*://www.free4talk.com/*"],
      js: [
        {
          file: "injections/js/bug1819678-free4talk.com-window-chrome-shim.js",
        },
      ],
    },
  },
  {
    id: "bug1827678-webc119017",
    platform: "desktop",
    domain: "nppes.cms.hhs.gov",
    bug: "1827678",
    contentScripts: {
      matches: ["*://nppes.cms.hhs.gov/*"],
      css: [
        {
          file: "injections/css/bug1819678-nppes.cms.hhs.gov-unsupported-banner.css",
        },
      ],
    },
  },
  {
    id: "bug1830776",
    platform: "all",
    domain: "blueshieldca.com",
    bug: "1830776",
    contentScripts: {
      matches: ["*://*.blueshieldca.com/*"],
      js: [
        {
          file: "injections/js/bug1830776-blueshieldca.com-unsupported.js",
        },
      ],
    },
  },
  {
    id: "bug1829949",
    platform: "desktop",
    domain: "tomshardware.com",
    bug: "1829949",
    contentScripts: {
      matches: ["*://*.tomshardware.com/*"],
      css: [
        {
          file: "injections/css/bug1829949-tomshardware.com-scrollbar-width.css",
        },
      ],
    },
  },
  {
    id: "bug1830752",
    platform: "all",
    domain: "afisha.ru",
    bug: "1830752",
    contentScripts: {
      matches: ["*://*.afisha.ru/*"],
      css: [
        {
          file: "injections/css/bug1830752-afisha.ru-slider-pointer-events.css",
        },
      ],
    },
  },
  {
    id: "bug1830761",
    platform: "all",
    domain: "91mobiles.com",
    bug: "1830761",
    contentScripts: {
      matches: ["*://*.91mobiles.com/*"],
      css: [
        {
          file: "injections/css/bug1830761-91mobiles.com-content-height.css",
        },
      ],
    },
  },
  {
    id: "bug1830796",
    platform: "android",
    domain: "copyleaks.com",
    bug: "1830796",
    contentScripts: {
      matches: ["*://*.copyleaks.com/*"],
      css: [
        {
          file: "injections/css/bug1830796-copyleaks.com-hide-unsupported.css",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1830810",
    platform: "all",
    domain: "interceramic.com",
    bug: "1830810",
    contentScripts: {
      matches: ["*://interceramic.com/*"],
      css: [
        {
          file: "injections/css/bug1830810-interceramic.com-hide-unsupported.css",
        },
      ],
    },
  },
  {
    id: "bug1830813",
    platform: "desktop",
    domain: "onstove.com",
    bug: "1830813",
    contentScripts: {
      matches: ["*://*.onstove.com/*"],
      css: [
        {
          file: "injections/css/bug1830813-page.onstove.com-hide-unsupported.css",
        },
      ],
    },
  },
  {
    id: "bug1831007",
    platform: "all",
    domain: "All international Nintendo domains",
    bug: "1831007",
    contentScripts: {
      matches: [
        "*://*.mojenintendo.cz/*",
        "*://*.nintendo-europe.com/*",
        "*://*.nintendo.at/*",
        "*://*.nintendo.be/*",
        "*://*.nintendo.ch/*",
        "*://*.nintendo.co.il/*",
        "*://*.nintendo.co.jp/*",
        "*://*.nintendo.co.kr/*",
        "*://*.nintendo.co.nz/*",
        "*://*.nintendo.co.uk/*",
        "*://*.nintendo.co.za/*",
        "*://*.nintendo.com.au/*",
        "*://*.nintendo.com.hk/*",
        "*://*.nintendo.com/*",
        "*://*.nintendo.de/*",
        "*://*.nintendo.dk/*",
        "*://*.nintendo.es/*",
        "*://*.nintendo.fi/*",
        "*://*.nintendo.fr/*",
        "*://*.nintendo.gr/*",
        "*://*.nintendo.hu/*",
        "*://*.nintendo.it/*",
        "*://*.nintendo.nl/*",
        "*://*.nintendo.no/*",
        "*://*.nintendo.pt/*",
        "*://*.nintendo.ru/*",
        "*://*.nintendo.se/*",
        "*://*.nintendo.sk/*",
        "*://*.nintendo.tw/*",
        "*://*.nintendoswitch.com.cn/*",
      ],
      js: [
        {
          file: "injections/js/bug1831007-nintendo-window-OnetrustActiveGroups.js",
        },
      ],
    },
  },
  {
    id: "bug1836157",
    platform: "android",
    domain: "thai-masszazs.net",
    bug: "1836157",
    contentScripts: {
      matches: ["*://*.thai-masszazs.net/*"],
      js: [
        {
          file: "injections/js/bug1836157-thai-masszazs-niceScroll-disable.js",
        },
      ],
    },
  },
  {
    id: "bug1836103",
    platform: "all",
    domain: "autostar-novoross.ru",
    bug: "1836103",
    contentScripts: {
      matches: ["*://autostar-novoross.ru/*"],
      css: [
        {
          file: "injections/css/bug1836103-autostar-novoross.ru-make-map-taller.css",
        },
      ],
    },
  },
  {
    id: "bug1836105",
    platform: "all",
    domain: "cnn.com",
    bug: "1836105",
    contentScripts: {
      matches: ["*://*.cnn.com/*"],
      css: [
        {
          file: "injections/css/bug1836105-cnn.com-fix-blank-pages-when-printing.css",
        },
      ],
    },
  },
  {
    id: "bug1842437",
    platform: "desktop",
    domain: "www.youtube.com",
    bug: "1842437",
    contentScripts: {
      matches: ["*://www.youtube.com/*"],
      js: [
        {
          file: "injections/js/bug1842437-www.youtube.com-performance-now-precision.js",
        },
      ],
    },
  },
  {
    id: "bug1848711",
    platform: "android",
    domain: "vio.com",
    bug: "1848711",
    contentScripts: {
      matches: ["*://*.vio.com/*"],
      css: [
        {
          file: "injections/css/bug1848711-vio.com-page-height.css",
        },
      ],
    },
  },
  {
    id: "bug1848713",
    platform: "all",
    domain: "cleanrider.com",
    bug: "1848713",
    contentScripts: {
      matches: ["*://*.cleanrider.com/*"],
      css: [
        {
          file: "injections/css/bug1848713-cleanrider.com-slider.css",
        },
      ],
    },
  },
  {
    id: "bug1848849",
    platform: "all",
    domain: "theaa.com",
    bug: "1848849",
    contentScripts: {
      matches: ["*://*.theaa.com/route-planner/*"],
      css: [
        {
          file: "injections/css/bug1848849-theaa.com-printing-mode-fix.css",
        },
      ],
    },
  },
  {
    id: "bug1849058",
    platform: "all",
    domain: "nicochannel.jp",
    bug: "1849058",
    contentScripts: {
      matches: ["*://nicochannel.jp/*", "*://gs-ch.com/*"],
      js: [
        {
          file: "injections/js/bug1849058-nicochannel.jp-picture-in-picture-shim.js",
        },
      ],
    },
  },
  {
    id: "bug1849388",
    platform: "android",
    domain: "kucharkaprodceru.cz",
    bug: "1849388",
    contentScripts: {
      matches: ["*://*.kucharkaprodceru.cz/*"],
      css: [
        {
          file: "injections/css/bug1849388-kucharkaprodceru.cz-scroll-fix.css",
        },
      ],
    },
  },
  {
    id: "bug1855014",
    platform: "android",
    domain: "eksiseyler.com",
    bug: "1855014",
    contentScripts: {
      matches: ["*://eksiseyler.com/*"],
      js: [
        {
          file: "injections/js/bug1855014-eksiseyler.com.js",
        },
      ],
    },
  },
  {
    id: "bug1855071",
    platform: "android",
    domain: "www.meteoam.it",
    bug: "1855071",
    contentScripts: {
      matches: ["*://www.meteoam.it/*"],
      js: [
        {
          file: "injections/js/bug1855071-www.meteoam.it.js",
        },
      ],
    },
  },
  {
    id: "bug1864564",
    platform: "all",
    domain: "Esri breakage",
    bug: "1864564",
    contentScripts: {
      matches: [
        "*://*.ncep.noaa.gov/*",
        "*://*.northumberland.gov.uk/*",
        "*://webmap.gis.gov.mo/*",
      ],
      js: [
        {
          file: "injections/js/bug1864564-esri-transfrom-names-shim.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1868345",
    platform: "desktop",
    domain: "tvmovie.de",
    bug: "1868345",
    contentScripts: {
      matches: [
        "*://www.tvmovie.de/tv/fernsehprogramm",
        "*://www.tvmovie.de/tv/fernsehprogramm*",
        "*://www.goodcarbadcar.net/*",
      ],
      css: [
        {
          file: "injections/css/bug1868345-tvmovie.de-scroll-fix.css",
        },
      ],
    },
  },
  {
    id: "bug1884842",
    platform: "android",
    domain: "foodora.cz",
    bug: "1884842",
    contentScripts: {
      matches: ["*://*.foodora.cz/*"],
      css: [
        {
          file: "injections/css/bug1884842-foodora.cz-height-fix.css",
        },
      ],
    },
  },
  {
    id: "bug1897120",
    platform: "desktop",
    domain: "turn.js breakage",
    bug: "1897120",
    contentScripts: {
      matches: ["*://flipbook.se.com/*", "*://*.flipbookpdf.net/*"],
      js: [
        {
          file: "injections/js/bug1897120-turnjs-zoom-fix.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "1896383",
    platform: "all",
    domain: "unimarc.cl",
    bug: "1896383",
    contentScripts: {
      matches: ["*://*.unimarc.cl/*"],
      js: [
        {
          file: "injections/js/bug1896383-error-capturestacktrace-shim.js",
        },
      ],
    },
  },
  {
    id: "bug1889326",
    platform: "desktop",
    domain: "Office 365 email handling prompt",
    bug: "1889326",
    contentScripts: {
      matches: [
        "*://*.live.com/*",
        "*://*.office.com/*",
        "*://*.office365.com/*",
        "*://*.office365.us/*",
        "*://*.outlook.cn/*",
        "*://*.outlook.com/*",
        "*://*.sharepoint.com/*",
      ],
      js: [
        {
          file: "injections/js/bug1889326-office365-email-handling-prompt-autohide.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1881922",
    platform: "all",
    domain: "helpdeskgeek.com",
    bug: "1881922",
    contentScripts: {
      matches: ["*://helpdeskgeek.com/*"],
      js: [
        {
          file: "injections/js/bug1881922-disable-legacy-mutation-events.js",
        },
      ],
    },
  },
  {
    id: "bug1901780",
    platform: "all",
    domain: "vanbreda-health.be",
    bug: "1901780",
    contentScripts: {
      matches: ["*://www.vanbreda-health.be/*"],
      js: [
        {
          file: "injections/js/bug1881922-disable-legacy-mutation-events.js",
        },
      ],
    },
  },
  {
    id: "bug1896571",
    platform: "all",
    domain: "gracobaby.ca",
    bug: "1896571",
    contentScripts: {
      matches: ["*://www.gracobaby.ca/*"],
      css: [
        {
          file: "injections/css/bug1896571-gracobaby.ca-unlock-scrolling.css",
        },
      ],
    },
  },
  {
    id: "bug1895994",
    platform: "android",
    domain: "www.softrans.ro",
    bug: "1895994",
    contentScripts: {
      matches: ["*://*.softrans.ro/*"],
      css: [
        {
          file: "injections/css/bug1895994-softtrans.ro-unlock-scrolling.css",
        },
      ],
    },
  },
  {
    id: "bug1898952",
    platform: "desktop",
    domain: "digits.t-mobile.com",
    bug: "1898952",
    contentScripts: {
      matches: ["*://digits.t-mobile.com/*"],
      js: [
        {
          file: "injections/js/bug1898952-digits.t-mobile.com.js",
        },
      ],
    },
  },
  {
    id: "bug1815733",
    platform: "desktop",
    domain: "Office 365 Outlook locations",
    bug: "1815733",
    contentScripts: {
      matches: [
        "*://outlook.live.com/*",
        "*://outlook.office.com/*",
        "*://outlook.office365.com/*",
        "*://outlook.office365.us/*",
        "*://*.outlook.cn/*",
        "*://*.outlook.com/*",
      ],
      js: [
        {
          file: "injections/js/bug1815733-outlook365-clipboard-read-noop.js",
        },
      ],
      allFrames: true,
    },
  },
  {
    id: "bug1899937",
    platform: "all",
    domain: "plus.nhk.jp",
    bug: "1899937",
    contentScripts: {
      matches: ["*://plus.nhk.jp/*"],
      js: [
        {
          file: "injections/js/bug1899937-plus.nhk.jp-request-picture-in-picture.js",
        },
      ],
    },
  },
  {
    id: "bug1905278",
    platform: "all",
    domain: "personalizedplates.revenue.tn.gov",
    bug: "1905278",
    contentScripts: {
      matches: ["*://personalizedplates.revenue.tn.gov/*"],
      css: [
        {
          file: "injections/css/bug1905278-personalizedplates.revenue.tn.gov-pointer-events.css",
        },
      ],
    },
  },
];

module.exports = AVAILABLE_INJECTIONS;
PK
!<'�U]^]^
data/shims.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals module, require */

const AVAILABLE_SHIMS = [
  {
    hiddenInAboutCompat: true,
    id: "LiveTestShim",
    platform: "all",
    name: "Live test shim",
    bug: "livetest",
    file: "live-test-shim.js",
    matches: ["*://webcompat-addon-testbed.herokuapp.com/shims_test.js"],
    needsShimHelpers: ["getOptions", "optIn"],
  },
  {
    hiddenInAboutCompat: true,
    id: "MochitestShim",
    platform: "all",
    branch: ["all:ignoredOtherPlatform"],
    name: "Test shim for Mochitests",
    bug: "mochitest",
    file: "mochitest-shim-1.js",
    matches: [
      "*://example.com/browser/browser/extensions/webcompat/tests/browser/shims_test.js",
    ],
    needsShimHelpers: ["getOptions", "optIn"],
    options: {
      simpleOption: true,
      complexOption: { a: 1, b: "test" },
      branchValue: { value: true, branches: [] },
      platformValue: { value: true, platform: "neverUsed" },
    },
    unblocksOnOptIn: ["*://trackertest.org/*"],
  },
  {
    hiddenInAboutCompat: true,
    disabled: true,
    id: "MochitestShim2",
    platform: "all",
    name: "Test shim for Mochitests (disabled by default)",
    bug: "mochitest",
    file: "mochitest-shim-2.js",
    matches: [
      "*://example.com/browser/browser/extensions/webcompat/tests/browser/shims_test_2.js",
    ],
    needsShimHelpers: ["getOptions", "optIn"],
    options: {
      simpleOption: true,
      complexOption: { a: 1, b: "test" },
      branchValue: { value: true, branches: [] },
      platformValue: { value: true, platform: "neverUsed" },
    },
    unblocksOnOptIn: ["*://trackertest.org/*"],
  },
  {
    hiddenInAboutCompat: true,
    id: "MochitestShim3",
    platform: "all",
    name: "Test shim for Mochitests (host)",
    bug: "mochitest",
    file: "mochitest-shim-3.js",
    notHosts: ["example.com"],
    matches: [
      "*://example.com/browser/browser/extensions/webcompat/tests/browser/shims_test_3.js",
    ],
  },
  {
    hiddenInAboutCompat: true,
    id: "MochitestShim4",
    platform: "all",
    name: "Test shim for Mochitests (notHost)",
    bug: "mochitest",
    file: "mochitest-shim-3.js",
    hosts: ["example.net"],
    matches: [
      "*://example.com/browser/browser/extensions/webcompat/tests/browser/shims_test_3.js",
    ],
  },
  {
    hiddenInAboutCompat: true,
    id: "MochitestShim5",
    platform: "all",
    name: "Test shim for Mochitests (branch)",
    bug: "mochitest",
    file: "mochitest-shim-3.js",
    branches: ["never matches"],
    matches: [
      "*://example.com/browser/browser/extensions/webcompat/tests/browser/shims_test_3.js",
    ],
  },
  {
    hiddenInAboutCompat: true,
    id: "MochitestShim6",
    platform: "never matches",
    name: "Test shim for Mochitests (platform)",
    bug: "mochitest",
    file: "mochitest-shim-3.js",
    matches: [
      "*://example.com/browser/browser/extensions/webcompat/tests/browser/shims_test_3.js",
    ],
  },
  {
    id: "AddThis",
    platform: "all",
    name: "AddThis",
    bug: "1713694",
    file: "addthis-angular.js",
    matches: [
      "*://s7.addthis.com/icons/official-addthis-angularjs/current/dist/official-addthis-angularjs.min.js*",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Adform",
    platform: "all",
    name: "Adform",
    bug: "1713695",
    file: "adform.js",
    matches: [
      "*://track.adform.net/serving/scripts/trackpoint/",
      "*://track.adform.net/serving/scripts/trackpoint/async/",
      {
        patterns: ["*://track.adform.net/Serving/TrackPoint/*"],
        target: "tracking-pixel.png",
        types: ["image", "imageset", "xmlhttprequest"],
      },
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "AdNexusAST",
    platform: "all",
    name: "AdNexus AST",
    bug: "1734130",
    file: "adnexus-ast.js",
    matches: ["*://*.adnxs.com/*/ast.js*"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "AdNexusPrebid",
    platform: "all",
    name: "AdNexus Prebid",
    bug: "1713696",
    file: "adnexus-prebid.js",
    matches: ["*://*.adnxs.com/*/pb.js*", "*://*.adnxs.com/*/prebid*"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "AdobeEverestJS",
    platform: "all",
    name: "Adobe EverestJS",
    bug: "1728114",
    file: "everest.js",
    matches: ["*://www.everestjs.net/static/st.v3.js*"],
    onlyIfBlockedByETP: true,
  },
  {
    // keep this above AdSafeProtectedTrackingPixels
    id: "AdSafeProtectedGoogleIMAAdapter",
    platform: "all",
    name: "Ad Safe Protected Google IMA Adapter",
    bug: "1508639",
    file: "adsafeprotected-ima.js",
    matches: ["*://static.adsafeprotected.com/vans-adapter-google-ima.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "AdsByGoogle",
    platform: "all",
    name: "Ads by Google",
    bug: "1713726",
    file: "google-ads.js",
    matches: [
      "*://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",
      {
        patterns: [
          "*://pagead2.googlesyndication.com/pagead/*.js*fcd=true",
          "*://pagead2.googlesyndication.com/pagead/js/*.js*fcd=true",
        ],
        target: "empty-script.js",
        types: ["xmlhttprequest"],
      },
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "AdvertisingCom",
    platform: "all",
    name: "advertising.com",
    bug: "1701685",
    matches: [
      {
        patterns: ["*://pixel.advertising.com/firefox-etp"],
        target: "tracking-pixel.png",
        types: ["image", "imageset", "xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
      {
        patterns: ["*://cdn.cmp.advertising.com/firefox-etp"],
        target: "empty-script.js",
        types: ["xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
      {
        patterns: ["*://*.advertising.com/*.js*"],
        target: "https://cdn.cmp.advertising.com/firefox-etp",
        types: ["image", "imageset", "xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
      {
        patterns: ["*://*.advertising.com/*"],
        target: "https://pixel.advertising.com/firefox-etp",
        types: ["image", "imageset", "xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
    ],
  },
  {
    id: "Branch",
    platform: "all",
    name: "Branch Web SDK",
    bug: "1716220",
    file: "branch.js",
    matches: ["*://cdn.branch.io/branch-latest.min.js*"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "DoubleVerify",
    platform: "all",
    name: "DoubleVerify",
    bug: "1771557",
    file: "doubleverify.js",
    matches: ["*://pub.doubleverify.com/signals/pub.js*"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "AmazonTAM",
    platform: "all",
    name: "Amazon Transparent Ad Marketplace",
    bug: "1713698",
    file: "apstag.js",
    matches: ["*://c.amazon-adsystem.com/aax2/apstag.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "BmAuth",
    platform: "all",
    name: "BmAuth by 9c9media",
    bug: "1486337",
    file: "bmauth.js",
    matches: ["*://auth.9c9media.ca/auth/main.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Chartbeat",
    platform: "all",
    name: "Chartbeat",
    bug: "1713699",
    file: "chartbeat.js",
    matches: [
      "*://static.chartbeat.com/js/chartbeat.js",
      "*://static.chartbeat.com/js/chartbeat_video.js",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Criteo",
    platform: "all",
    name: "Criteo",
    bug: "1713720",
    file: "criteo.js",
    matches: ["*://static.criteo.net/js/ld/publishertag.js"],
    onlyIfBlockedByETP: true,
  },
  {
    // keep this above AdSafeProtectedTrackingPixels
    id: "Doubleclick",
    platform: "all",
    name: "Doubleclick",
    bug: "1713693",
    matches: [
      {
        patterns: [
          "*://securepubads.g.doubleclick.net/gampad/*ad-blk*",
          "*://pubads.g.doubleclick.net/gampad/*ad-blk*",
        ],
        target: "empty-shim.txt",
        types: ["image", "imageset", "xmlhttprequest"],
      },
      {
        patterns: [
          "*://securepubads.g.doubleclick.net/gampad/*xml_vmap1*",
          "*://pubads.g.doubleclick.net/gampad/*xml_vmap1*",
        ],
        target: "vmad.xml",
        types: ["image", "imageset", "xmlhttprequest"],
      },
      {
        patterns: [
          "*://vast.adsafeprotected.com/vast*",
          "*://securepubads.g.doubleclick.net/gampad/*xml_vmap2*",
          "*://pubads.g.doubleclick.net/gampad/*xml_vmap2*",
        ],
        target: "vast2.xml",
        types: ["image", "imageset", "xmlhttprequest"],
      },
      {
        patterns: [
          "*://securepubads.g.doubleclick.net/gampad/*ad*",
          "*://pubads.g.doubleclick.net/gampad/*ad*",
        ],
        target: "vast3.xml",
        types: ["image", "imageset", "xmlhttprequest"],
      },
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Eluminate",
    platform: "all",
    name: "Eluminate",
    bug: "1503211",
    file: "eluminate.js",
    matches: ["*://libs.coremetrics.com/eluminate.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "FacebookSDK",
    platform: "all",
    branches: ["nightly:android"],
    name: "Facebook SDK",
    bug: "1226498",
    file: "facebook-sdk.js",
    logos: ["facebook.svg", "play.svg"],
    matches: [
      "*://connect.facebook.net/*/sdk.js*",
      "*://connect.facebook.net/*/all.js*",
      {
        patterns: ["*://www.facebook.com/platform/impression.php*"],
        target: "tracking-pixel.png",
        types: ["image", "imageset", "xmlhttprequest"],
      },
    ],
    needsShimHelpers: ["optIn", "getOptions"],
    onlyIfBlockedByETP: true,
    unblocksOnOptIn: [
      "*://connect.facebook.net/*/sdk.js*",
      "*://connect.facebook.net/*/all.js*",
      "*://*.xx.fbcdn.net/*", // covers:
      // "*://scontent-.*-\d.xx.fbcdn.net/*",
      // "*://static.xx.fbcdn.net/rsrc.php/*",
      "*://graph.facebook.com/v2*access_token*",
      "*://graph.facebook.com/v*/me*",
      "*://graph.facebook.com/*/picture*",
      "*://www.facebook.com/*/plugins/login_button.php*",
      "*://www.facebook.com/x/oauth/status*",
      {
        patterns: [
          "*://www.facebook.com/*/plugins/video.php*",
          "*://www.facebook.com/rsrc.php/*",
        ],
        branches: ["nightly"],
      },
    ],
  },
  {
    id: "Fastclick",
    platform: "all",
    name: "Fastclick",
    bug: "1738220",
    file: "fastclick.js",
    matches: [
      "*://secure.cdn.fastclick.net/js/cnvr-launcher/*/launcher-stub.min.js*",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "GoogleAnalyticsAndTagManager",
    platform: "all",
    name: "Google Analytics and Tag Manager",
    bug: "1713687",
    file: "google-analytics-and-tag-manager.js",
    matches: [
      "*://www.google-analytics.com/analytics.js*",
      "*://www.google-analytics.com/gtm/js*",
      "*://www.googletagmanager.com/gtm.js*",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "GoogleAnalyticsECommercePlugin",
    platform: "all",
    name: "Google Analytics E-Commerce Plugin",
    bug: "1620533",
    file: "google-analytics-ecommerce-plugin.js",
    matches: ["*://www.google-analytics.com/plugins/ua/ec.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "GoogleAnalyticsLegacy",
    platform: "all",
    name: "Google Analytics (legacy version)",
    bug: "1487072",
    file: "google-analytics-legacy.js",
    matches: ["*://ssl.google-analytics.com/ga.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "GoogleIMA",
    platform: "all",
    name: "Google Interactive Media Ads",
    bug: "1713690",
    file: "google-ima.js",
    matches: [
      "*://s0.2mdn.net/instream/html5/ima3.js",
      "*://imasdk.googleapis.com/js/sdkloader/ima3.js",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "GooglePageAd",
    platform: "all",
    name: "Google Page Ad",
    bug: "1713692",
    file: "google-page-ad.js",
    matches: ["*://www.googleadservices.com/pagead/conversion_async.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "GooglePublisherTags",
    platform: "all",
    name: "Google Publisher Tags",
    bug: "1713685",
    file: "google-publisher-tags.js",
    matches: [
      "*://www.googletagservices.com/tag/js/gpt.js*",
      "*://pagead2.googlesyndication.com/tag/js/gpt.js*",
      "*://pagead2.googlesyndication.com/gpt/pubads_impl_*.js*",
      "*://securepubads.g.doubleclick.net/tag/js/gpt.js*",
      "*://securepubads.g.doubleclick.net/gpt/pubads_impl_*.js*",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Google SafeFrame",
    platform: "all",
    name: "Google SafeFrame",
    bug: "1713691",
    matches: [
      {
        patterns: [
          "*://tpc.googlesyndication.com/safeframe/*/html/container.html",
          "*://*.safeframe.googlesyndication.com/safeframe/*/html/container.html",
        ],
        target: "google-safeframe.html",
        types: ["sub_frame"],
      },
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "GoogleTrends",
    platform: "all",
    name: "Google Trends",
    bug: "1624914",
    custom: "google-trends-dfpi-fix",
    onlyIfDFPIActive: true,
    matches: [
      {
        patterns: ["*://trends.google.com/trends/embed*"],
        types: ["sub_frame"],
      },
    ],
  },
  {
    id: "IAM",
    platform: "all",
    name: "INFOnline IAM",
    bug: "1761774",
    file: "iam.js",
    matches: ["*://script.ioam.de/iam.js"],
    onlyIfBlockedByETP: true,
  },
  {
    // keep this above AdSafeProtectedTrackingPixels
    id: "IASPET",
    platform: "all",
    name: "Integral Ad Science PET",
    bug: "1713701",
    file: "iaspet.js",
    matches: [
      "*://cdn.adsafeprotected.com/iasPET.1.js",
      "*://static.adsafeprotected.com/iasPET.1.js",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "MNet",
    platform: "all",
    name: "Media.net Ads",
    bug: "1713703",
    file: "empty-script.js",
    matches: ["*://adservex.media.net/videoAds.js*"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Moat",
    platform: "all",
    name: "Moat",
    bug: "1713704",
    file: "moat.js",
    matches: [
      "*://*.moatads.com/*/moatad.js*",
      "*://*.moatads.com/*/moatapi.js*",
      "*://*.moatads.com/*/moatheader.js*",
      "*://*.moatads.com/*/yi.js*",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Nielsen",
    platform: "all",
    name: "Nielsen",
    bug: "1760754",
    file: "nielsen.js",
    matches: ["*://*.imrworldwide.com/v60.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Optimizely",
    platform: "all",
    name: "Optimizely",
    bug: "1714431",
    file: "optimizely.js",
    matches: [
      "*://cdn.optimizely.com/js/*.js",
      "*://cdn.optimizely.com/public/*.js",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Rambler",
    platform: "all",
    name: "Rambler Authenticator",
    bug: "1606428",
    file: "rambler-authenticator.js",
    matches: ["*://id.rambler.ru/rambler-id-helper/auth_events.js"],
    needsShimHelpers: ["optIn"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "RichRelevance",
    platform: "all",
    name: "Rich Relevance",
    bug: "1713725",
    file: "rich-relevance.js",
    matches: ["*://media.richrelevance.com/rrserver/js/1.2/p13n.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Firebase",
    platform: "all",
    name: "Firebase",
    bug: "1771783",
    onlyIfPrivateBrowsing: true,
    runFirst: "firebase.js",
    matches: [
      // bugs 1750699, 1767407
      "*://www.gstatic.com/firebasejs/*/firebase-messaging.js*",
    ],
    contentScripts: [
      {
        js: "firebase.js",
        runAt: "document_start",
        matches: [
          "*://www.homedepot.ca/*", // bug 1778993
          "*://orangerie.eu/*", // bug 1758442
          "*://web.whatsapp.com/*", // bug 1767407
          "*://www.tripadvisor.com/*", // bug 1779536
          "*://www.office.com/*", // bug 1783921
        ],
      },
    ],
  },
  {
    id: "StickyAdsTV",
    platform: "all",
    name: "StickyAdsTV",
    bug: "1717806",
    matches: [
      {
        patterns: ["https://ads.stickyadstv.com/firefox-etp"],
        target: "tracking-pixel.png",
        types: ["image", "imageset", "xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
      {
        patterns: [
          "*://ads.stickyadstv.com/auto-user-sync*",
          "*://ads.stickyadstv.com/user-matching*",
        ],
        target: "https://ads.stickyadstv.com/firefox-etp",
        types: ["image", "imageset", "xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
    ],
  },
  {
    id: "Vidible",
    branch: ["nightly"],
    platform: "all",
    name: "Vidible",
    bug: "1713710",
    file: "vidible.js",
    logos: ["play.svg"],
    matches: [
      "*://*.vidible.tv/*/vidible-min.js*",
      "*://vdb-cdn-files.s3.amazonaws.com/*/vidible-min.js*",
    ],
    needsShimHelpers: ["optIn"],
    onlyIfBlockedByETP: true,
    unblocksOnOptIn: [
      "*://delivery.vidible.tv/jsonp/pid=*/vid=*/*.js*",
      "*://delivery.vidible.tv/placement/*",
      "*://img.vidible.tv/prod/*",
      "*://cdn-ssl.vidible.tv/prod/player/js/*.js",
      "*://hlsrv.vidible.tv/prod/*.m3u8*",
      "*://videos.vidible.tv/prod/*.key*",
      "*://videos.vidible.tv/prod/*.mp4*",
      "*://videos.vidible.tv/prod/*.webm*",
      "*://videos.vidible.tv/prod/*.ts*",
    ],
  },
  {
    id: "Kinja",
    platform: "all",
    name: "Kinja",
    bug: "1656171",
    contentScripts: [
      {
        js: "kinja.js",
        matches: [
          "*://www.avclub.com/*",
          "*://deadspin.com/*",
          "*://gizmodo.com/*",
          "*://jalopnik.com/*",
          "*://jezebel.com/*",
          "*://kotaku.com/*",
          "*://lifehacker.com/*",
          "*://www.theonion.com/*",
          "*://www.theroot.com/*",
          "*://thetakeout.com/*",
          "*://theinventory.com/*",
        ],
        runAt: "document_start",
        allFrames: true,
      },
    ],
    onlyIfDFPIActive: true,
  },
  {
    id: "MicrosoftLogin",
    platform: "desktop",
    name: "Microsoft Login",
    bug: "1638383",
    requestStorageAccessForRedirect: [
      ["*://web.powerva.microsoft.com/*", "*://login.microsoftonline.com/*"],
      ["*://teams.microsoft.com/*", "*://login.microsoftonline.com/*"],
      ["*://*.teams.microsoft.us/*", "*://login.microsoftonline.us/*"],
      ["*://www.msn.com/*", "*://login.microsoftonline.com/*"],
      ["*://support.microsoft.com/*", "*://login.microsoftonline.com/*"],
      ["*://answers.microsoft.com/*", "*://login.microsoftonline.com/*"],
    ],
    contentScripts: [
      {
        js: "microsoftLogin.js",
        matches: [
          "*://web.powerva.microsoft.com/*",
          "*://teams.microsoft.com/*",
          "*://*.teams.microsoft.us/*",
          "*://www.msn.com/*",
          "*://support.microsoft.com/*",
          "*://answers.microsoft.com/*",
        ],
        runAt: "document_start",
      },
    ],
    onlyIfDFPIActive: true,
  },
  {
    id: "MicrosoftVirtualAssistant",
    platform: "all",
    name: "Microsoft Virtual Assistant",
    bug: "1801277",
    contentScripts: [
      {
        js: "microsoftVirtualAssistant.js",
        matches: ["*://publisher.liveperson.net/*"],
        runAt: "document_start",
        allFrames: true,
      },
    ],
  },
  {
    id: "History",
    platform: "all",
    name: "History.com",
    bug: "1624853",
    contentScripts: [
      {
        js: "history.js",
        matches: ["*://play.history.com/*"],
        runAt: "document_start",
      },
    ],
    onlyIfDFPIActive: true,
  },
  {
    id: "Crave.ca",
    platform: "all",
    name: "Crave.ca",
    bug: "1746439",
    contentScripts: [
      {
        js: "crave-ca.js",
        matches: ["*://account.bellmedia.ca/login*service=crave*"],
        runAt: "document_start",
      },
    ],
    onlyIfDFPIActive: true,
  },
  {
    id: "Instagram.com",
    platform: "android",
    name: "Instagram.com",
    bug: "1804445",
    contentScripts: [
      {
        js: "instagram.js",
        matches: ["*://www.instagram.com/*"],
        runAt: "document_start",
      },
    ],
    onlyIfDFPIActive: true,
  },
  {
    id: "MaxMindGeoIP",
    platform: "all",
    name: "MaxMind GeoIP",
    bug: "1754389",
    file: "maxmind-geoip.js",
    matches: ["*://js.maxmind.com/js/apis/geoip2/*/geoip2.js"],
    onlyIfBlockedByETP: true,
  },
  {
    id: "WebTrends",
    platform: "all",
    name: "WebTrends",
    bug: "1766414",
    file: "webtrends.js",
    matches: [
      "*://s.webtrends.com/js/advancedLinkTracking.js",
      "*://s.webtrends.com/js/webtrends.js",
      "*://s.webtrends.com/js/webtrends.min.js",
    ],
    onlyIfBlockedByETP: true,
  },
  {
    id: "Blogger",
    platform: "all",
    name: "Blogger",
    bug: "1776869",
    contentScripts: [
      {
        js: "blogger.js",
        matches: ["*://www.blogger.com/comment/frame/*"],
        runAt: "document_start",
        allFrames: true,
      },
      {
        js: "bloggerAccount.js",
        matches: ["*://www.blogger.com/blog/*"],
        runAt: "document_end",
      },
    ],
    onlyIfDFPIActive: true,
  },
  {
    // keep this below any other shims checking adsafeprotected URLs
    id: "AdSafeProtectedTrackingPixels",
    platform: "all",
    name: "Ad Safe Protected tracking pixels",
    bug: "1717806",
    matches: [
      {
        patterns: ["https://static.adsafeprotected.com/firefox-etp-pixel"],
        target: "tracking-pixel.png",
        types: ["image", "imageset", "xmlhttprequest"],
      },
      {
        patterns: ["https://static.adsafeprotected.com/firefox-etp-js"],
        target: "empty-script.js",
        types: ["xmlhttprequest"],
      },
      {
        patterns: [
          "*://*.adsafeprotected.com/*.gif*",
          "*://*.adsafeprotected.com/*.png*",
        ],
        target: "https://static.adsafeprotected.com/firefox-etp-pixel",
        types: ["image", "imageset", "xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
      {
        patterns: [
          "*://*.adsafeprotected.com/*.js*",
          "*://*.adsafeprotected.com/*/adj*",
          "*://*.adsafeprotected.com/*/imp/*",
          "*://*.adsafeprotected.com/*/Serving/*",
          "*://*.adsafeprotected.com/*/unit/*",
          "*://*.adsafeprotected.com/jload",
          "*://*.adsafeprotected.com/jload?*",
          "*://*.adsafeprotected.com/jsvid",
          "*://*.adsafeprotected.com/jsvid?*",
          "*://*.adsafeprotected.com/mon*",
          "*://*.adsafeprotected.com/tpl",
          "*://*.adsafeprotected.com/tpl?*",
          "*://*.adsafeprotected.com/services/pub*",
        ],
        target: "https://static.adsafeprotected.com/firefox-etp-js",
        types: ["image", "imageset", "xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
      {
        // note, fallback case seems to be an image
        patterns: ["*://*.adsafeprotected.com/*"],
        target: "https://static.adsafeprotected.com/firefox-etp-pixel",
        types: ["image", "imageset", "xmlhttprequest"],
        onlyIfBlockedByETP: true,
      },
    ],
  },
  {
    id: "SpotifyEmbed",
    platform: "all",
    name: "SpotifyEmbed",
    bug: "1792395",
    contentScripts: [
      {
        js: "spotify-embed.js",
        matches: ["*://open.spotify.com/embed/*"],
        runAt: "document_start",
        allFrames: true,
      },
    ],
    onlyIfDFPIActive: true,
  },
  {
    id: "tsn.ca",
    platform: "all",
    name: "tsn.ca login",
    bug: "1802340",
    contentScripts: [
      {
        js: "tsn-ca.js",
        matches: ["*://account.bellmedia.ca/login*service=tsn*"],
        runAt: "document_start",
      },
    ],
    onlyIfDFPIActive: true,
  },
  {
    id: "emeraude.my.salesforce.com",
    platform: "all",
    name: "Salesforce IndexedDB Script Access",
    bug: "1855139",
    contentScripts: [
      {
        js: "salesforce.js",
        matches: ["*://emeraude.my.salesforce.com/*"],
        runAt: "document_start",
        allFrames: true,
      },
    ],
  },
];

module.exports = AVAILABLE_SHIMS;
PK
!<�M�@��data/ua_overrides.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser, module, require */

// This is a hack for the tests.
if (typeof InterventionHelpers === "undefined") {
  var InterventionHelpers = require("../lib/intervention_helpers");
}
if (typeof UAHelpers === "undefined") {
  var UAHelpers = require("../lib/ua_helpers");
}

/**
 * For detailed information on our policies, and a documention on this format
 * and its possibilites, please check the Mozilla-Wiki at
 *
 * https://wiki.mozilla.org/Compatibility/Go_Faster_Addon/Override_Policies_and_Workflows#User_Agent_overrides
 */
const AVAILABLE_UA_OVERRIDES = [
  {
    id: "testbed-override",
    platform: "all",
    domain: "webcompat-addon-testbed.herokuapp.com",
    bug: "0000000",
    config: {
      hidden: true,
      matches: ["*://webcompat-addon-testbed.herokuapp.com/*"],
      uaTransformer: originalUA => {
        return (
          UAHelpers.getPrefix(originalUA) +
          " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36 for WebCompat"
        );
      },
    },
  },
  {
    /*
     * Bug 1577519 - directv.com - Create a UA override for directv.com for playback on desktop
     * WebCompat issue #3846 - https://webcompat.com/issues/3846
     *
     * directv.com (attwatchtv.com) is blocking Firefox via UA sniffing. Spoofing as Chrome allows
     * to access the site and playback works fine. This is former directvnow.com
     */
    id: "bug1577519",
    platform: "desktop",
    domain: "directv.com",
    bug: "1577519",
    config: {
      matches: [
        "*://*.attwatchtv.com/*",
        "*://*.directv.com.ec/*", // bug 1827706
        "*://*.directv.com/*",
      ],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1570108 - steamcommunity.com - UA override for steamcommunity.com
     * WebCompat issue #34171 - https://webcompat.com/issues/34171
     *
     * steamcommunity.com blocks chat feature for Firefox users showing unsupported browser message.
     * When spoofing as Chrome the chat works fine
     */
    id: "bug1570108",
    platform: "desktop",
    domain: "steamcommunity.com",
    bug: "1570108",
    config: {
      matches: ["*://steamcommunity.com/chat*"],
      uaTransformer: originalUA => {
        return (
          UAHelpers.getPrefix(originalUA) +
          " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"
        );
      },
    },
  },
  {
    /*
     * Bug 1582582 - sling.com - UA override for sling.com
     * WebCompat issue #17804 - https://webcompat.com/issues/17804
     *
     * sling.com blocks Firefox users showing unsupported browser message.
     * When spoofing as Chrome playing content works fine
     */
    id: "bug1582582",
    platform: "desktop",
    domain: "sling.com",
    bug: "1582582",
    config: {
      matches: ["https://watch.sling.com/*", "https://www.sling.com/*"],
      uaTransformer: originalUA => {
        return (
          UAHelpers.getPrefix(originalUA) +
          " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
        );
      },
    },
  },
  {
    /*
     * Bug 1610026 - www.mobilesuica.com - UA override for www.mobilesuica.com
     * WebCompat issue #4608 - https://webcompat.com/issues/4608
     *
     * mobilesuica.com showing unsupported message for Firefox users
     * Spoofing as Chrome allows to access the page
     */
    id: "bug1610026",
    platform: "all",
    domain: "www.mobilesuica.com",
    bug: "1610026",
    config: {
      matches: ["https://www.mobilesuica.com/*"],
      uaTransformer: originalUA => {
        return (
          UAHelpers.getPrefix(originalUA) +
          " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
        );
      },
    },
  },
  {
    /*
     * Bug 1385206 - Create UA override for rakuten.co.jp on Firefox Android
     * (Imported from ua-update.json.in)
     *
     * rakuten.co.jp serves a Desktop version if Firefox is included in the UA.
     */
    id: "bug1385206",
    platform: "android",
    domain: "rakuten.co.jp",
    bug: "1385206",
    config: {
      matches: ["*://*.rakuten.co.jp/*"],
      uaTransformer: originalUA => {
        return originalUA.replace(/Firefox.+$/, "");
      },
    },
  },
  {
    /*
     * Bug 969844 - mobile.de sends desktop site to Firefox on Android
     *
     * mobile.de sends the desktop site to Firefox Mobile.
     * Spoofing as Chrome works fine.
     */
    id: "bug969844",
    platform: "android",
    domain: "mobile.de",
    bug: "969844",
    config: {
      matches: ["*://*.mobile.de/*"],
      uaTransformer: _ => {
        return "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36";
      },
    },
  },
  {
    /*
     * Bug 1509873 - zmags.com - Add UA override for secure.viewer.zmags.com
     * WebCompat issue #21576 - https://webcompat.com/issues/21576
     *
     * The zmags viewer locks out Firefox Mobile with a "Browser unsupported"
     * message, but tests showed that it works just fine with a Chrome UA.
     * Outreach attempts were unsuccessful, and as the site has a relatively
     * high rank, we alter the UA.
     */
    id: "bug1509873",
    platform: "android",
    domain: "zmags.com",
    bug: "1509873",
    config: {
      matches: ["*://*.viewer.zmags.com/*"],
      uaTransformer: originalUA => {
        return (
          UAHelpers.getPrefix(originalUA) +
          " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36"
        );
      },
    },
  },
  {
    /*
     * Bug 1574522 - UA override for enuri.com on Firefox for Android
     * WebCompat issue #37139 - https://webcompat.com/issues/37139
     *
     * enuri.com returns a different template for Firefox on Android
     * based on server side UA detection. This results in page content cut offs.
     * Spoofing as Chrome fixes the issue
     */
    id: "bug1574522",
    platform: "android",
    domain: "enuri.com",
    bug: "1574522",
    config: {
      matches: ["*://enuri.com/*"],
      uaTransformer: _ => {
        return "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.111 Mobile Safari/537.36";
      },
    },
  },
  {
    /*
     * Bug 1574564 - UA override for ceskatelevize.cz on Firefox for Android
     * WebCompat issue #15467 - https://webcompat.com/issues/15467
     *
     * ceskatelevize sets streamingProtocol depending on the User-Agent it sees
     * in the request headers, returning DASH for Chrome, HLS for iOS,
     * and Flash for Firefox Mobile. Since Mobile has no Flash, the video
     * doesn't work. Spoofing as Chrome makes the video play
     */
    id: "bug1574564",
    platform: "android",
    domain: "ceskatelevize.cz",
    bug: "1574564",
    config: {
      matches: ["*://*.ceskatelevize.cz/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1577267 - UA override for metfone.com.kh on Firefox for Android
     * WebCompat issue #16363 - https://webcompat.com/issues/16363
     *
     * metfone.com.kh has a server side UA detection which returns desktop site
     * for Firefox for Android. Spoofing as Chrome allows to receive mobile version
     */
    id: "bug1577267",
    platform: "android",
    domain: "metfone.com.kh",
    bug: "1577267",
    config: {
      matches: ["*://*.metfone.com.kh/*"],
      uaTransformer: originalUA => {
        return (
          UAHelpers.getPrefix(originalUA) +
          " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.111 Mobile Safari/537.36"
        );
      },
    },
  },
  {
    /*
     * Bug 1598198 - User Agent extension for Samsung's galaxy.store URLs
     *
     * Samsung's galaxy.store shortlinks are supposed to redirect to a Samsung
     * intent:// URL on Samsung devices, but to an error page on other brands.
     * As we do not provide device info in our user agent string, this check
     * fails, and even Samsung users land on an error page if they use Firefox
     * for Android.
     * This intervention adds a simple "Samsung" identifier to the User Agent
     * on only the Galaxy Store URLs if the device happens to be a Samsung.
     */
    id: "bug1598198",
    platform: "android",
    domain: "galaxy.store",
    bug: "1598198",
    config: {
      matches: [
        "*://galaxy.store/*",
        "*://dev.galaxy.store/*",
        "*://stg.galaxy.store/*",
      ],
      uaTransformer: originalUA => {
        if (!browser.systemManufacturer) {
          return originalUA;
        }

        const manufacturer = browser.systemManufacturer.getManufacturer();
        if (manufacturer && manufacturer.toLowerCase() === "samsung") {
          return originalUA.replace("Mobile;", "Mobile; Samsung;");
        }

        return originalUA;
      },
    },
  },
  {
    /*
     * Bug 1622063 - UA override for wp1-ext.usps.gov
     * Webcompat issue #29867 - https://webcompat.com/issues/29867
     *
     * The Job Search site for USPS does not work for Firefox Mobile
     * browsers (a 500 is returned).
     */
    id: "bug1622063",
    platform: "android",
    domain: "wp1-ext.usps.gov",
    bug: "1622063",
    config: {
      matches: ["*://wp1-ext.usps.gov/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1646791 - bancosantander.es - Re-add UA override.
     * Bug 1665129 - *.gruposantander.es - Add wildcard domains.
     * WebCompat issue #33462 - https://webcompat.com/issues/33462
     * SuMo request - https://support.mozilla.org/es/questions/1291085
     *
     * santanderbank expects UA to have 'like Gecko', otherwise it runs
     * xmlDoc.onload whose support has been dropped. It results in missing labels in forms
     * and some other issues.  Adding 'like Gecko' fixes those issues.
     */
    id: "bug1646791",
    platform: "all",
    domain: "santanderbank.com",
    bug: "1646791",
    config: {
      matches: [
        "*://*.bancosantander.es/*",
        "*://*.gruposantander.es/*",
        "*://*.santander.co.uk/*",
      ],
      uaTransformer: originalUA => {
        // The first line related to Firefox 100 is for Bug 1743445.
        // [TODO]: Remove when bug 1743429 gets backed out.
        return UAHelpers.capVersionTo99(originalUA).replace(
          "Gecko",
          "like Gecko"
        );
      },
    },
  },
  {
    /*
     * Bug 1651292 - UA override for www.jp.square-enix.com
     * Webcompat issue #53018 - https://webcompat.com/issues/53018
     *
     * Unless the UA string contains "Chrome 66+", a section of
     * www.jp.square-enix.com will show a never ending LOADING
     * page.
     */
    id: "bug1651292",
    platform: "android",
    domain: "www.jp.square-enix.com",
    bug: "1651292",
    config: {
      matches: ["*://www.jp.square-enix.com/music/sem/page/FF7R/ost/*"],
      uaTransformer: originalUA => {
        return originalUA + " Chrome/83";
      },
    },
  },
  {
    /*
     * Bug 1666754 - Mobile UA override for lffl.org
     * Bug 1665720 - lffl.org article page takes 2x as much time to load on Moto G
     *
     * This site returns desktop site based on server side UA detection.
     * Spoofing as Chrome allows to get mobile experience
     */
    id: "bug1666754",
    platform: "android",
    domain: "lffl.org",
    bug: "1666754",
    config: {
      matches: ["*://*.lffl.org/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1704673 - Add UA override for app.xiaomi.com
     * Webcompat issue #66163 - https://webcompat.com/issues/66163
     *
     * The page isn’t redirecting properly error message received.
     * Spoofing as Chrome makes the page load
     */
    id: "bug1704673",
    platform: "android",
    domain: "app.xiaomi.com",
    bug: "1704673",
    config: {
      matches: ["*://app.xiaomi.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1712807 - Add UA override for www.dealnews.com
     * Webcompat issue #39341 - https://webcompat.com/issues/39341
     *
     * The sites shows Firefox a different layout compared to Chrome.
     * Spoofing as Chrome fixes this.
     */
    id: "bug1712807",
    platform: "android",
    domain: "www.dealnews.com",
    bug: "1712807",
    config: {
      matches: ["*://www.dealnews.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1719859 - Add UA override for saxoinvestor.fr
     * Webcompat issue #74678 - https://webcompat.com/issues/74678
     *
     * The site blocks Firefox with a server-side UA sniffer. Appending a
     * Chrome version segment to the UA makes it work.
     */
    id: "bug1719859",
    platform: "android",
    domain: "saxoinvestor.fr",
    bug: "1719859",
    config: {
      matches: ["*://*.saxoinvestor.fr/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1738317 - Add UA override for vmos.cn
     * Webcompat issue #90432 - https://github.com/webcompat/web-bugs/issues/90432
     *
     * Firefox for Android receives a desktop-only layout based on server-side
     * UA sniffing. Spoofing as Chrome works fine.
     */
    id: "bug1738317",
    platform: "android",
    domain: "vmos.cn",
    bug: "1738317",
    config: {
      matches: ["*://*.vmos.cn/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1743627 - Add UA override for renaud-bray.com
     * Webcompat issue #55276 - https://github.com/webcompat/web-bugs/issues/55276
     *
     * Firefox for Android depends on "Version/" being there in the UA string,
     * or it'll throw a runtime error.
     */
    id: "bug1743627",
    platform: "android",
    domain: "renaud-bray.com",
    bug: "1743627",
    config: {
      matches: ["*://*.renaud-bray.com/*"],
      uaTransformer: originalUA => {
        return originalUA + " Version/0";
      },
    },
  },
  {
    /*
     * Bug 1743751 - Add UA override for slrclub.com
     * Webcompat issue #91373 - https://github.com/webcompat/web-bugs/issues/91373
     *
     * On Firefox Android, the browser is receiving the desktop layout.
     * Spoofing as Chrome works fine.
     */
    id: "bug1743751",
    platform: "android",
    domain: "slrclub.com",
    bug: "1743751",
    config: {
      matches: ["*://*.slrclub.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1743754 - Add UA override for slrclub.com
     * Webcompat issue #86839 - https://github.com/webcompat/web-bugs/issues/86839
     *
     * On Firefox Android, the browser is failing a UA parsing on Firefox UA.
     */
    id: "bug1743754",
    platform: "android",
    domain: "workflow.base.vn",
    bug: "1743754",
    config: {
      matches: ["*://workflow.base.vn/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1743429 - Add UA override for sites broken with the Version 100 User Agent
     *
     * Some sites have issues with a UA string with Firefox version 100 or higher,
     * so present as version 99 for now.
     */
    id: "bug1743429",
    platform: "all",
    domain: "Sites with known Version 100 User Agent breakage",
    bug: "1743429",
    config: {
      matches: [
        "*://411.ca/", // #121332
        "*://*.mms.telekom.de/*", // #1800241
        "*://ubank.com.au/*", // #104099
        "*://wifi.sncf/*", // #100194
      ],
      uaTransformer: originalUA => {
        return UAHelpers.capVersionTo99(originalUA);
      },
    },
  },
  {
    /*
     * Bug 1753461 - UA override for serieson.naver.com
     * Webcompat issue #99993 - https://webcompat.com/issues/97298
     *
     * The site locks out Firefox users unless a Chrome UA is given,
     * and locks out Linux users as well (so we use Windows+Chrome).
     */
    id: "bug1753461",
    platform: "desktop",
    domain: "serieson.naver.com",
    bug: "1753461",
    config: {
      matches: ["*://serieson.naver.com/*"],
      uaTransformer: () => {
        return "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36";
      },
    },
  },
  {
    /*
     * Bug 1771200 - UA override for animalplanet.com
     * Webcompat issue #99993 - https://webcompat.com/issues/103727
     *
     * The videos are not playing and an error message is displayed
     * in Firefox for Android, but work with Chrome UA
     */
    id: "bug1771200",
    platform: "android",
    domain: "animalplanet.com",
    bug: "1771200",
    config: {
      matches: ["*://*.animalplanet.com/video/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1771200 - UA override for lazada.co.id
     * Webcompat issue #106229 - https://webcompat.com/issues/106229
     *
     * The map is not playing and an error message is displayed
     * in Firefox for Android, but work with Chrome UA
     */
    id: "bug1779059",
    platform: "android",
    domain: "lazada.co.id",
    bug: "1779059",
    config: {
      matches: ["*://member-m.lazada.co.id/address/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1778168 - UA override for watch.antennaplus.gr
     * Webcompat issue #106529 - https://webcompat.com/issues/106529
     *
     * The site's content is not loaded unless a Chrome UA is used,
     * and breaks on Linux (so we claim Windows instead in that case).
     */
    id: "bug1778168",
    platform: "desktop",
    domain: "watch.antennaplus.gr",
    bug: "1778168",
    config: {
      matches: ["*://watch.antennaplus.gr/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA({
          desktopOS: "nonLinux",
        });
      },
    },
  },
  {
    /*
     * Bug 1776897 - UA override for www.edencast.fr
     * Webcompat issue #106545 - https://webcompat.com/issues/106545
     *
     * The site's podcast audio player does not load unless a Chrome UA is used.
     */
    id: "bug1776897",
    platform: "all",
    domain: "www.edencast.fr",
    bug: "1776897",
    config: {
      matches: ["*://www.edencast.fr/zoomcast*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1784361 - UA override for coldwellbankerhomes.com
     * Webcompat issue #108535 - https://webcompat.com/issues/108535
     *
     * An error is thrown due to missing element, unless Chrome UA is used
     */
    id: "bug1784361",
    platform: "android",
    domain: "coldwellbankerhomes.com",
    bug: "1784361",
    config: {
      matches: ["*://*.coldwellbankerhomes.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1786404 - UA override for business.help.royalmail.com
     * Webcompat issue #109070 - https://webcompat.com/issues/109070
     *
     * Replacing `Firefox` with `FireFox` to evade one of their UA tests...
     */
    id: "bug1786404",
    platform: "all",
    domain: "business.help.royalmail.com",
    bug: "1786404",
    config: {
      matches: ["*://business.help.royalmail.com/app/webforms/*"],
      uaTransformer: originalUA => {
        return originalUA.replace("Firefox", "FireFox");
      },
    },
  },
  {
    /*
     * Bug 1823966 - UA override for elearning.dmv.ca.gov
     * Original report: https://bugzilla.mozilla.org/show_bug.cgi?id=1823785
     */
    id: "bug1823966",
    platform: "all",
    domain: "elearning.dmv.ca.gov",
    bug: "1823966",
    config: {
      matches: ["*://*.elearning.dmv.ca.gov/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for admissions.nid.edu
     * Webcompat issue #65753 - https://webcompat.com/issues/65753
     */
    id: "bug1827678-webc65753",
    platform: "all",
    domain: "admissions.nid.edu",
    bug: "1827678",
    config: {
      matches: ["*://*.admissions.nid.edu/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for bankmandiri.co.id
     * Webcompat issue #67924 - https://webcompat.com/issues/67924
     */
    id: "bug1827678-webc67924",
    platform: "all",
    domain: "bankmandiri.co.id",
    bug: "1827678",
    config: {
      matches: ["*://*.bankmandiri.co.id/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for frankfred.com
     * Webcompat issue #68007 - https://webcompat.com/issues/68007
     */
    id: "bug1827678-webc68007",
    platform: "android",
    domain: "frankfred.com",
    bug: "1827678",
    config: {
      matches: ["*://*.frankfred.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for onvue.com
     * Webcompat issue #68520 - https://webcompat.com/issues/68520
     */
    id: "bug1827678-webc68520",
    platform: "all",
    domain: "onvue.com",
    bug: "1827678",
    config: {
      matches: ["*://*.onvue.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for avizia.com
     * Webcompat issue #68635 - https://webcompat.com/issues/68635
     */
    id: "bug1827678-webc68635",
    platform: "all",
    domain: "avizia.com",
    bug: "1827678",
    config: {
      matches: ["*://*.avizia.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for www.yourtexasbenefits.com
     * Webcompat issue #76785 - https://webcompat.com/issues/76785
     */
    id: "bug1827678-webc76785",
    platform: "android",
    domain: "www.yourtexasbenefits.com",
    bug: "1827678",
    config: {
      matches: ["*://www.yourtexasbenefits.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for www.free4talk.com
     * Webcompat issue #77727 - https://webcompat.com/issues/77727
     */
    id: "bug1827678-webc77727-ua",
    platform: "android",
    domain: "www.free4talk.com",
    bug: "1827678",
    config: {
      matches: ["*://www.free4talk.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for watch.indee.tv
     * Webcompat issue #77912 - https://webcompat.com/issues/77912
     */
    id: "bug1827678-webc77912",
    platform: "all",
    domain: "watch.indee.tv",
    bug: "1827678",
    config: {
      matches: ["*://watch.indee.tv/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for viewer-ebook.books.com.tw
     * Webcompat issue #80180 - https://webcompat.com/issues/80180
     */
    id: "bug1827678-webc80180",
    platform: "all",
    domain: "viewer-ebook.books.com.tw",
    bug: "1827678",
    config: {
      matches: ["*://viewer-ebook.books.com.tw/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for jelly.jd.com
     * Webcompat issue #83269 - https://webcompat.com/issues/83269
     */
    id: "bug1827678-webc83269",
    platform: "all",
    domain: "jelly.jd.com",
    bug: "1827678",
    config: {
      matches: ["*://jelly.jd.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for kt.com
     * Webcompat issue #119012 - https://webcompat.com/issues/119012
     */
    id: "bug1827678-webc119012",
    platform: "all",
    domain: "kt.com",
    bug: "1827678",
    config: {
      matches: ["*://*.kt.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for oirsa.org
     * Webcompat issue #119402 - https://webcompat.com/issues/119402
     */
    id: "bug1827678-webc119402",
    platform: "all",
    domain: "oirsa.org",
    bug: "1827678",
    config: {
      matches: ["*://*.oirsa.org/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1827678 - UA override for onp.cloud.waterloo.ca
     * Webcompat issue #120450 - https://webcompat.com/issues/120450
     */
    id: "bug1827678-webc120450",
    platform: "all",
    domain: "onp.cloud.waterloo.ca",
    bug: "1827678",
    config: {
      matches: ["*://onp.cloud.waterloo.ca/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1830739 - UA override for casino sites
     *
     * The sites are showing unsupported message with the same UI
     */
    id: "bug1830739",
    platform: "android",
    domain: "casino sites",
    bug: "1830739",
    config: {
      matches: [
        "*://*.captainjackcasino.com/*", // 79490
        "*://*.casinoextreme.eu/*", // 118175
        "*://*.cryptoloko.com/*", // 117911
        "*://*.123lobbygames.com/*", // 120027
        "*://*.planet7casino.com/*", // 120609
        "*://*.yebocasino.co.za/*", // 88409
        "*://*.yabbycasino.com/*", // 108025
      ],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1830821 - UA override for webcartop.jp
     * Webcompat issue #113663 - https://webcompat.com/issues/113663
     */
    id: "bug1830821-webc113663",
    platform: "android",
    domain: "webcartop.jp",
    bug: "1830821",
    config: {
      matches: ["*://*.webcartop.jp/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1830821 - UA override for enjoy.point.auone.jp
     * Webcompat issue #90981 - https://webcompat.com/issues/90981
     */
    id: "bug1830821-webc90981",
    platform: "android",
    domain: "enjoy.point.auone.jp",
    bug: "1830821",
    config: {
      matches: ["*://enjoy.point.auone.jp/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1836109 - UA override for watch.tonton.com.my
     *
     * The site's content is not loaded unless a Chrome UA is used.
     */
    id: "bug1836109",
    platform: "all",
    domain: "watch.tonton.com.my",
    bug: "1836109",
    config: {
      matches: ["*://watch.tonton.com.my/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1836112 - UA override for www.capcut.cn
     *
     * The site's content is not loaded unless a Chrome UA is used.
     */
    id: "bug1836112",
    platform: "all",
    domain: "www.capcut.cn",
    bug: "1836112",
    config: {
      matches: ["*://www.capcut.cn/editor*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1836135 - UA override for gts-pro.sdimedia.com
     *
     * The site's content is not loaded without a Chrome UA spoof.
     */
    id: "bug1836135",
    platform: "all",
    domain: "gts-pro.sdimedia.com",
    bug: "1836135",
    config: {
      matches: ["*://gts-pro.sdimedia.com/*"],
      uaTransformer: originalUA => {
        return originalUA.replace("Firefox/", "Fx/") + " Chrome/113.0.0.0";
      },
    },
  },
  {
    /*
     * Bug 1836140 - UA override for indices.iriworldwide.com
     *
     * The site's content is not loaded without a UA spoof.
     */
    id: "bug1836140",
    platform: "all",
    domain: "indices.iriworldwide.com",
    bug: "1836140",
    config: {
      matches: ["*://indices.iriworldwide.com/covid19/*"],
      uaTransformer: originalUA => {
        return originalUA.replace("Firefox/", "Fx/");
      },
    },
  },
  {
    /*
     * Bug 1836178 - UA override for atracker.pro
     *
     * The site's content is not loaded without a Chrome UA spoof.
     */
    id: "bug1836178",
    platform: "all",
    domain: "atracker.pro",
    bug: "1836178",
    config: {
      matches: ["*://atracker.pro/*"],
      uaTransformer: originalUA => {
        return originalUA + " Chrome/113.0.0.0";
      },
    },
  },
  {
    /*
     * Bug 1849018 - UA override for carefirst.com
     * Webcompat issue #125341 - https://webcompat.com/issues/125341
     *
     * The site is showing "Application Blocked" message
     * for Firefox UA.
     */
    id: "bug1849018",
    platform: "all",
    domain: "carefirst.com",
    bug: "1849018",
    config: {
      matches: ["*://*.carefirst.com/myaccount*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1850455 - UA override for frontgate.com
     * Webcompat issue #36277 - https://webcompat.com/issues/36277
     *
     * The site is showing a desktop view to Firefox mobile user-agents
     */
    id: "bug1850455",
    platform: "android",
    domain: "frontgate.com",
    bug: "1850455",
    config: {
      matches: ["*://*.frontgate.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1855088 - UA override for hrmis2.eghrmis.gov.my
     * Webcompat issue #125039 - https://webcompat.com/issues/125039
     *
     * hrmis2.eghrmis.gov.my showing unsupported message for Firefox users
     * Spoofing as Chrome allows to access the page
     */
    id: "bug1855088",
    platform: "all",
    domain: "hrmis2.eghrmis.gov.my",
    bug: "1855088",
    config: {
      matches: ["*://hrmis2.eghrmis.gov.my/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1855102 - UA override for my.southerncross.co.nz
     * Webcompat issue #121877 - https://webcompat.com/issues/121877
     *
     * Spoofing as Chrome for Android allows to access the page
     */
    id: "bug1855102",
    platform: "android",
    domain: "my.southerncross.co.nz",
    bug: "1855102",
    config: {
      matches: ["*://my.southerncross.co.nz/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1864999 - UA override for autotrader.ca
     * Webcompat issue #126822 - https://webcompat.com/issues/126822
     *
     * Spoofing as Chrome for Android makes filters work on the site
     */
    id: "bug1864999",
    platform: "android",
    domain: "autotrader.ca",
    bug: "1864999",
    config: {
      matches: ["*://*.autotrader.ca/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1865000 - UA override for bmo.com
     * Webcompat issue #127620 - https://webcompat.com/issues/127620
     *
     * Spoofing as Chrome removes the unsupported message and allows
     * to proceed with application
     */
    id: "bug1865000",
    platform: "all",
    domain: "bmo.com",
    bug: "1865000",
    config: {
      matches: ["*://*.bmo.com/main/personal/*/getting-started/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1865004 - UA override for digimart.net
     * Webcompat issue #126647 - https://webcompat.com/issues/126647
     *
     * The site returns desktop layout on Firefox for Android
     */
    id: "bug1865004",
    platform: "android",
    domain: "digimart.net",
    bug: "1865004",
    config: {
      matches: ["*://*.digimart.net/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1865007 - UA override for portal.circle.ms
     * Webcompat issue #127739 - https://webcompat.com/issues/127739
     *
     * The site returns desktop layout on Firefox for Android
     */
    id: "bug1865007",
    platform: "android",
    domain: "portal.circle.ms",
    bug: "1865007",
    config: {
      matches: ["*://*.circle.ms/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1884779 - UA override for
     * Webcompat issue #134287 - https://webcompat.com/issues/134287
     *
     * The site returns desktop layout on Firefox for Android
     */
    id: "bug1884779",
    platform: "android",
    domain: "memurlar.net",
    bug: "1884779",
    config: {
      matches: ["*://*.memurlar.net/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1898531 - UA override for www.cwb.digital
     * Webcompat issue #137285 - https://webcompat.com/issues/137285
     *
     * Spoofing as Chrome makes the login form work
     */
    id: "bug1898531",
    platform: "all",
    domain: "cwb.digital",
    bug: "1898531",
    config: {
      matches: ["*://*.cwb.digital/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1842767 - UA override for passport.bilibili.com
     *
     * Spoofing as Chrome makes the login page use a mobile layout.
     */
    id: "bug1842767",
    platform: "android",
    domain: "passport.bilibili.com",
    bug: "1842767",
    config: {
      matches: ["*://*.passport.bilibili.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1896354 - UA override for my.rhinoshield.fr
     *
     * Sites only supports Chrome, but seems to work with a UA spoof.
     */
    id: "bug1896354",
    platform: "all",
    domain: "my.rhinoshield.fr",
    bug: "1896354",
    config: {
      matches: ["*://my.rhinoshield.fr/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1813177 - UA override for rbi.org.in
     *
     * The site endlessly redirects for a Firefox mobile UA string.
     */
    id: "bug1813177",
    platform: "android",
    domain: "m.rbi.org.in",
    bug: "1813177",
    config: {
      matches: ["*://m.rbi.org.in/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1903970 - UA override for unimedlitoral.com.br
     * Webcompat issue #138342 - https://webcompat.com/issues/138342
     *
     * Site blocks Firefox, but seems to work with a UA spoof.
     */
    id: "bug1903970",
    platform: "all",
    domain: "www.unimedlitoral.com.br",
    bug: "1903970",
    config: {
      matches: ["*://www.unimedlitoral.com.br/agendaonline/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1902474 - UA override for lg.jio.com
     * Webcompat issue #124681 - https://webcompat.com/issues/124681
     *
     * Site incorrectly blocks Firefox on Android. A desktop UA works.
     */
    id: "bug1902474",
    platform: "android",
    domain: "lg.jio.com",
    bug: "1902474",
    config: {
      matches: ["*://lg.jio.com/*"],
      uaTransformer: originalUA => {
        return originalUA.replace(/ (Mobile|Tablet);/, "");
      },
    },
  },
  {
    /*
     * Bug 1909448 - UA override for fire.honeywell.com
     *
     * Site doesn't load on Firefox, but works fine with a UA spoof.
     */
    id: "bug1909448",
    platform: "all",
    domain: "fire.honeywell.com",
    bug: "1909448",
    config: {
      matches: ["*://fire.honeywell.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1899937 - UA override for plus.nhk.jp
     * Webcompat issue #103463 - https://webcompat.com/issues/103463
     *
     * Site blocks Firefox, so a UA spoof and an intervention is needed.
     */
    id: "bug1899937-ua",
    platform: "all",
    domain: "plus.nhk.jp",
    bug: "1899937",
    config: {
      matches: ["*://plus.nhk.jp/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1897724 - UA override for app.homewyse.com
     * Webcompat issue #137164 - https://webcompat.com/issues/137164
     *
     * Site blocks Firefox, but seems to work with a UA spoof.
     */
    id: "bug1897724",
    platform: "all",
    domain: "app.homewyse.com",
    bug: "1897724",
    config: {
      matches: ["*://app.homewyse.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1898923 - UA override for trade-in.vodafone.com
     * Webcompat issue #127158 - https://webcompat.com/issues/127158
     *
     * Site blocks Firefox, but seems to work with a UA spoof.
     */
    id: "bug1898923",
    platform: "all",
    domain: "trade-in.vodafone.com",
    bug: "1898923",
    config: {
      matches: ["*://trade-in.vodafone.com/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1899067 - UA override for game.granbluefantasy.jp
     * Webcompat issue #43155 - https://webcompat.com/issues/43155
     *
     * Site blocks Firefox, but seems to work with a UA spoof.
     */
    id: "bug1899067",
    platform: "desktop",
    domain: "game.granbluefantasy.jp",
    bug: "1899067",
    config: {
      matches: ["*://game.granbluefantasy.jp/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
  {
    /*
     * Bug 1898941 - UA override for events.webinar.ru
     * Webcompat issue #121871 - https://webcompat.com/issues/121871
     *
     * Site blocks Firefox, but seems to work with a UA spoof.
     */
    id: "bug1898941",
    platform: "all",
    domain: "events.webinar.ru",
    bug: "1898941",
    config: {
      matches: ["*://events.webinar.ru/*"],
      uaTransformer: () => {
        return UAHelpers.getDeviceAppropriateChromeUA();
      },
    },
  },
];

module.exports = AVAILABLE_UA_OVERRIDES;
PK
!<�l��C	C	%experiment-apis/aboutConfigPrefs.json[
  {
    "namespace": "aboutConfigPrefs",
    "description": "experimental API extension to allow access to about:config preferences",
    "events": [
      {
        "name": "onPrefChange",
        "type": "function",
        "parameters": [
          {
            "name": "name",
            "type": "string",
            "description": "The preference which changed"
          }
        ],
        "extraParameters": [
          {
            "name": "name",
            "type": "string",
            "description": "The preference to monitor"
          }
        ]
      }
    ],
    "functions": [
      {
        "name": "getBranch",
        "type": "function",
        "description": "Get all child prefs for a branch",
        "parameters": [
          {
            "name": "branchName",
            "type": "string",
            "description": "The branch name"
          }
        ],
        "async": true
      },
      {
        "name": "getPref",
        "type": "function",
        "description": "Get a preference's value",
        "parameters": [
          {
            "name": "name",
            "type": "string",
            "description": "The preference name"
          }
        ],
        "async": true
      },
      {
        "name": "getBoolPrefSync",
        "type": "function",
        "description": "Get a webcompat preference's boolean value synchronously",
        "parameters": [
          {
            "name": "name",
            "type": "string",
            "description": "The preference name"
          },
          {
            "name": "defaultValue",
            "type": "boolean",
            "optional": true,
            "description": "Default value to return if the pref is not set (defaults to false if omitted)"
          }
        ],
        "returns": {
          "type": "boolean",
          "description": "returns the value of a boolean pref."
        }
      },
      {
        "name": "setPref",
        "type": "function",
        "description": "Set a preference's value",
        "parameters": [
          {
            "name": "name",
            "type": "string",
            "description": "The preference name"
          },
          {
            "name": "value",
            "type": "boolean",
            "description": "The new value"
          }
        ],
        "async": true
      }
    ]
  }
]
PK
!<Ա�oBB(experiment-apis/aboutConfigPrefsChild.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* global ExtensionAPI, Services, XPCOMUtils */

this.aboutConfigPrefs = class extends ExtensionAPI {
  getAPI(context) {
    const extensionIDBase = context.extension.id.split("@")[0];
    const extensionPrefNameBase = `extensions.${extensionIDBase}.`;

    return {
      aboutConfigPrefs: {
        getBoolPrefSync(prefName, defaultValue = false) {
          try {
            return Services.prefs.getBoolPref(
              `${extensionPrefNameBase}${prefName}`,
              defaultValue
            );
          } catch (_) {
            return defaultValue;
          }
        },
      },
    };
  }
};
PK
!<��Mf%%!experiment-apis/appConstants.json[
  {
    "namespace": "appConstants",
    "description": "experimental API to expose some app constants",
    "functions": [
      {
        "name": "getReleaseBranch",
        "type": "function",
        "description": "",
        "async": true,
        "parameters": []
      }
    ]
  }
]
PK
!<u�q��� experiment-apis/matchPatterns.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* global ExtensionAPI */

this.matchPatterns = class extends ExtensionAPI {
  getAPI(context) {
    return {
      matchPatterns: {
        getMatcher(patterns) {
          const set = new MatchPatternSet(patterns);
          return Cu.cloneInto(
            {
              matches: url => {
                return set.matches(url);
              },
            },
            context.cloneScope,
            {
              cloneFunctions: true,
            }
          );
        },
      },
    };
  }
};
PK
!<u�#r��"experiment-apis/matchPatterns.json[
  {
    "namespace": "matchPatterns",
    "description": "experimental API extension to expose MatchPattern functionality",
    "functions": [
      {
        "name": "getMatcher",
        "type": "function",
        "description": "get a MatchPatternSet",
        "parameters": [
          {
            "name": "patterns",
            "description": "Array of string URL patterns to match",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        ],
        "returns": {
          "type": "object",
          "properties": {
            "matches": { "type": "function" }
          }
        }
      }
    ]
  }
]
PK
!<�N'LL%experiment-apis/systemManufacturer.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* global ExtensionAPI, Services, XPCOMUtils */

this.systemManufacturer = class extends ExtensionAPI {
  getAPI() {
    return {
      systemManufacturer: {
        getManufacturer() {
          try {
            return Services.sysinfo.getProperty("manufacturer");
          } catch (_) {
            return undefined;
          }
        },
      },
    };
  }
};
PK
!<(��		'experiment-apis/systemManufacturer.json[
  {
    "namespace": "systemManufacturer",
    "description": "experimental API extension to allow reading the device's manufacturer",
    "functions": [
      {
        "name": "getManufacturer",
        "type": "function",
        "description": "Get the device's manufacturer",
        "parameters": [],
        "returns": {
          "type": "string",
          "properties": {},
          "additionalProperties": { "type": "any" },
          "description": "The manufacturer's name."
        }
      }
    ]
  }
]
PK
!<y�ڋ�
�
'experiment-apis/trackingProtection.json[
  {
    "namespace": "trackingProtection",
    "description": "experimental API allow requests through ETP",
    "functions": [
      {
        "name": "isDFPIActive",
        "type": "function",
        "description": "Returns whether dFPI is active for private/non-private browsing tabs",
        "parameters": [
          {
            "type": "boolean",
            "name": "isPrivate"
          }
        ],
        "async": true
      },
      {
        "name": "shim",
        "type": "function",
        "description": "Set specified URL patterns as intended to be shimmed",
        "parameters": [
          {
            "name": "allowlistId",
            "description": "Identfier for the allow-list, so it may be added-to or revoked",
            "type": "string"
          },
          {
            "name": "patterns",
            "description": "Array of match patterns",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          {
            "name": "notHosts",
            "description": "Hosts on which to not shim these patterns",
            "type": "array",
            "optional": true,
            "items": {
              "type": "string"
            }
          }
        ]
      },
      {
        "name": "allow",
        "type": "function",
        "description": "Set specified URL patterns as intended to be allowed through the content blocker for the specified top hosts",
        "parameters": [
          {
            "name": "allowlistId",
            "description": "Identfier for the allow-list, so it may be added-to or revoked",
            "type": "string"
          },
          {
            "name": "patterns",
            "description": "Array of match patterns",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          {
            "name": "hosts",
            "description": "Hosts to allow the patterns on",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        ],
        "async": true
      },
      {
        "name": "revoke",
        "type": "function",
        "description": "Revokes the given allow-list entirely (both shims and allows)",
        "parameters": [
          {
            "name": "allowListId",
            "type": "string"
          }
        ],
        "async": true
      },
      {
        "name": "wasRequestUnblocked",
        "type": "function",
        "description": "Whether the given requestId was unblocked by any allowList",
        "parameters": [
          {
            "name": "requestId",
            "type": "string"
          }
        ],
        "async": true
      }
    ]
  }
]
PK
!<�s����3injections/css/bug0000000-testbed-css-injection.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#css-injection.red {
  background-color: #0f0;
}
PK
!<�	�7��Finjections/css/bug1575000-apply.lloydsbank.co.uk-radio-buttons-fix.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * apply.lloydsbank.co.uk - radio buttons are misplaced
 * Bug #1575000 - https://bugzilla.mozilla.org/show_bug.cgi?id=1575000
 * WebCompat issue #34969 - https://webcompat.com/issues/34969
 *
 * Radio buttons are displaced to the left due to positioning issue of ::before
 * pseudo element, adding position relative to it's parent fixes the issue.
 */
.radio-content-field .radio.inline label span.text {
  position: relative;
}
PK
!<����Einjections/css/bug1610344-directv.com.co-hide-unsupported-message.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * directv.com.co - Browser is not supported message
 * Bug #1610344 - https://bugzilla.mozilla.org/show_bug.cgi?id=1610344
 * WebCompat issue #41822 - https://webcompat.com/issues/41822
 *
 * directv.com.co is showing a "This browser is not supported" message in
 * Firefox. Our tests indicated that everything is working just fine, and our
 * previous contact attempts have not been successful. This intervention
 * hides the large red unsupported banner.
 */
.browser-compatible.compatible.incompatible {
  display: none;
}
PK
!<轤��Iinjections/css/bug1644830-missingmail.usps.com-checkboxes-not-visible.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * missingmail.usps.com - Unable to mark the check-boxes from "Disclaimer and
 * Terms and Conditions" section
 * Bug #1644830 - https://bugzilla.mozilla.org/show_bug.cgi?id=1644830
 * WebCompat issue #53950 - https://webcompat.com/issues/53950
 *
 * missingmail.usps.com runs into a case of bug 997189, where an absolutely
 * positioned inline-block element with floating siblings is shifter to the
 * right, and thus invisible.
 */
.mrc-custom-checkbox-container input {
  margin-left: -3rem;
}
PK
!<������Binjections/css/bug1651917-teletrader.com.body-transform-origin.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * teletrader.com - content is shifted down and right
 * Bug #1651917 - https://bugzilla.mozilla.org/show_bug.cgi?id=1651917
 * WebCompat issue #55217 - https://webcompat.com/issues/55217
 *
 * The content is shifted down and right, because they use webkit prefixes
 * for scaling and redefining the origin. Firefox doesn't support
 *     -webkit-transform-origin-x/y
 * This is the object of https://bugzilla.mozilla.org/show_bug.cgi?id=1584881
 * Adding transform-origin: 0 0; to body fixes the issue
 */
body {
  transform-origin: 0 0;
}
PK
!<�3��=injections/css/bug1653075-livescience.com-scrollbar-width.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * livescience.com - a scrollbar covering navigation menu
 * Bug #1653075 - https://bugzilla.mozilla.org/show_bug.cgi?id=1653075
 *
 * The scrollbar is covering navigation items and that makes them half hidden.
 * There are some ::-webkit-scrollbar css rules applied to the scrollbar,
 * making it thinner. Adding similar rules for Firefox fixes the issue.
 */

.trending__list {
  scrollbar-width: thin;
  scrollbar-color: #f9ae3b #f5f5f5;
}
PK
!<��l���:injections/css/bug1654907-reactine.ca-hide-unsupported.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * reactine.ca - Unsupported browser message
 * Bug #1654907 - https://bugzilla.mozilla.org/show_bug.cgi?id=1654907
 * WebCompat issue #55481 - https://webcompat.com/issues/55481
 *
 * reactine.ca is showing "Sorry this browser is not supported."
 * message if Firefox for Android based on UA detection. Site seems
 * to be working fine, so this intervention is to hide this message
 */
#browser-alert {
  display: none !important;
}
PK
!<��=injections/css/bug1694470-myvidster.com-content-not-shown.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * m.myvidster.com - Content is not shown
 * Bug #1694470 - https://bugzilla.mozilla.org/show_bug.cgi?id=1694470
 * WebCompat issue #67308 - https://webcompat.com/issues/67308
 *
 * The site depends on Sencha Touch and should receive some specific
 * -webkit-box-flex be working.
 */
#home_refresh_var {
  -webkit-box-flex: 1;
}
PK
!<��J*��Ainjections/css/bug1707795-office365-sheets-overscroll-disable.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * www.office.com - There is an overscroll effect on Excel sheets which is
 * not a very pleasant user experience. This invention disables it.
 */

.ewr-sheetcontainer {
  overscroll-behavior: none;
}
PK
!<�0ZZ��=injections/css/bug1741234-patient.alphalabs.ca-height-fix.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * patient.alphalabs.ca - "Continue" button is overlapped by displaced page footer
 * Bug #1741234 - https://bugzilla.mozilla.org/show_bug.cgi?id=1741234
 * WebCompat issue #93156 - https://webcompat.com/issues/93156
 */

body {
  height: 100%;
}
PK
!<�p\��9injections/css/bug1765947-veniceincoming.com-left-fix.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * veniceincoming.com - site is not usable
 * Bug #1765947 - https://bugzilla.mozilla.org/show_bug.cgi?id=1765947
 * WebCompat issue #102133 - https://webcompat.com/issues/102133
 */

.tour-list .single-tour .mobile-link {
  left: 0;
}
PK
!<�R%%%Binjections/css/bug1770962-coldwellbankerhomes.com-image-height.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * coldwellbankerhomes.com - Property images are displayed squeezed
 * Bug #1770962 - https://bugzilla.mozilla.org/show_bug.cgi?id=1770962
 * WebCompat issue #102872 - https://webcompat.com/issues/102872
 */

.property-snapshot-psr-panel
  .prop-pix
  .photo-carousel.owl
  .owl-stage-outer
  .owl-item
  img {
  height: -moz-available;
}
PK
!<����4injections/css/bug1774490-rainews.it-gallery-fix.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * rainews.it - Image slideshow is not shown
 * Bug #1774490 - https://bugzilla.mozilla.org/show_bug.cgi?id=1774490
 * WebCompat issue #105402 - https://webcompat.com/issues/105402
 */

.photogallery-swiper .swiper-slide {
  height: auto;
}
PK
!<БF�vv?injections/css/bug1784141-aveeno.com-acuvue.com-unsupported.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * aveeno.com and acuvue.com - Unsupported message is displayed
 *
 * Bug #1784141 - aveeno.com - https://bugzilla.mozilla.org/show_bug.cgi?id=1784141
 * Bug #1804730 - acuvue.com - https://bugzilla.mozilla.org/show_bug.cgi?id=1804730
 *
 * WebCompat issue #103557 - https://webcompat.com/issues/103557
 * WebCompat issue #103557 - https://webcompat.com/issues/110797
 */

#browser-alert {
  display: none !important;
}
PK
!<,��:injections/css/bug1784199-entrata-platform-unsupported.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * aptsovation.com - Unsupported message is displayed on sites based on Entrata platform
 * Bug #1784199 - https://bugzilla.mozilla.org/show_bug.cgi?id=1784199
 * WebCompat issue #100131 - https://webcompat.com/issues/100131
 */

* {
  color: unset;
}

#propertyProduct,
.banner_overlay {
  display: none;
}
PK
!<ic����Binjections/css/bug1819678-nppes.cms.hhs.gov-unsupported-banner.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * nppes.cms.hhs.gov - Firefox is an unsupported browser
 * WebCompat issue #119017 - https://github.com/webcompat/web-bugs/issues/119017
 *
 * As everything seems to work just fine, this intervention simply hides the
 * banner.
 */

#unsupportedDiv {
  display: none !important;
}
PK
!<�t���>injections/css/bug1829949-tomshardware.com-scrollbar-width.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * tomshardware.com - a scrollbar covering navigation menu
 * Bug #1829949 - https://bugzilla.mozilla.org/show_bug.cgi?id=1829949
 * WebCompat issue #121170 - https://github.com/webcompat/web-bugs/issues/121170
 *
 * The scrollbar is covering navigation items and that makes them half hidden.
 * There are some ::-webkit-scrollbar css rules applied to the scrollbar,
 * making it thinner. Adding similar rules for Firefox fixes the issue.
 */

.trending__list {
  scrollbar-width: thin;
  scrollbar-color: #000 #f5f5f5;
}
PK
!<��ģ��=injections/css/bug1830752-afisha.ru-slider-pointer-events.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * afisha.ru - Slider not working
 * Bug #1830752 - https://bugzilla.mozilla.org/show_bug.cgi?id=1830752
 * WebCompat issue #120455 - https://github.com/webcompat/web-bugs/issues/120455
 *
 * The range slider for price filtering is not working because of pointer-events:none applied
 * on the slider element. It's working in Chrome because of webkit specific rules
 * set with -moz-range-thumb that override the pointer events on the slider thumb to auto.
 * Setting the same rule with -moz-range-thumb makes the slider to work.
 */

.XdRPG,
.gkKBB {
  pointer-events: auto;
}
.XdRPG::-moz-range-thumb,
.gkKBB::-moz-range-thumb {
  background-color: #ff3118;
  border-color: #ff3118;
  border-radius: 50%;
  cursor: pointer;
  pointer-events: auto;
}
PK
!<��i��:injections/css/bug1830761-91mobiles.com-content-height.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * 91mobiles.com - Text overlapping
 * Bug #1830761 - https://bugzilla.mozilla.org/show_bug.cgi?id=1830761
 * WebCompat issue #117029 - https://github.com/webcompat/web-bugs/issues/117029
 *
 * The content overlaps dedicated space since Firefox honors small heights on <td>
 * due to https://bugzilla.mozilla.org/show_bug.cgi?id=1461852. Setting the height to
 * fit-content makes it work as expected.
 */

#fixed-table tr td .cmp-summary-box,
.cmpr-table .textpanel {
  height: fit-content;
}
PK
!<�_���<injections/css/bug1830796-copyleaks.com-hide-unsupported.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * copyleaks.com - Unsupported message
 * Bug #1830796 - https://bugzilla.mozilla.org/show_bug.cgi?id=1830796
 * WebCompat issue #121395 - https://github.com/webcompat/web-bugs/issues/121395
 */

#outdated {
  display: none !important;
}
PK
!<3�	|��?injections/css/bug1830810-interceramic.com-hide-unsupported.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * interceramic.com - Unsupported message
 * Bug #1830810 - https://bugzilla.mozilla.org/show_bug.cgi?id=1830810
 * WebCompat issue #117807 - https://github.com/webcompat/web-bugs/issues/117807
 */

#ff-modal {
  display: none !important;
}
PK
!<.�33?injections/css/bug1830813-page.onstove.com-hide-unsupported.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * onstove.com - Unsupported message
 * Bug #1830813 - https://bugzilla.mozilla.org/show_bug.cgi?id=1830813
 * WebCompat issue #116760 - https://github.com/webcompat/web-bugs/issues/116760
 */

.gnb-alerts.gnb-old-browser {
  max-height: 0;
}

.isCampaign .gnb-stove.gnb-default-fixed,
.isCampaign .layout.layout-base .layout-header {
  height: 68px;
}
PK
!<��C���Binjections/css/bug1836103-autostar-novoross.ru-make-map-taller.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * autostar-novoross.ru - Map is not as tall as expected
 * Bug #1836103 - https://bugzilla.mozilla.org/show_bug.cgi?id=1836103
 * WebCompat issue #80763 - https://github.com/webcompat/web-bugs/issues/80763
 */

.t396 .tn-atom {
  height: 100%;
}
PK
!<)�|}}Cinjections/css/bug1836105-cnn.com-fix-blank-pages-when-printing.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * cnn.com - Printing in portrait mode results in blank pages
 * Bug #1836105 - https://bugzilla.mozilla.org/show_bug.cgi?id=1836105
 *
 * Disable some of CNN's giant styles for height, top and margin-bottom,
 * since they break print layout in Firefox (as per bug 1830307)
 */

@media print {
  .header__wrapper-outer {
    height: initial !important;
    top: initial !important;
    margin-bottom: initial !important;
  }
}
PK
!<�A'OO1injections/css/bug1848711-vio.com-page-height.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * vio.com - Map is not displayed
 * Bug #1848711 - https://bugzilla.mozilla.org/show_bug.cgi?id=1848711
 * WebCompat issue #118126 - https://github.com/webcompat/web-bugs/issues/118126
 *
 * vio.com uses min-height: -webkit-fill-available; on the canvas map parent
 * element, which is not supported in Firefox, so the element has zero height.
 */

.ec-44lvm8 {
  height: 100%;
}
PK
!<
��3injections/css/bug1848713-cleanrider.com-slider.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * www.cleanrider.com - The price slider does not work
 * Bug #1848713 - https://bugzilla.mozilla.org/show_bug.cgi?id=1848713
 * WebCompat issue #123642 - https://github.com/webcompat/web-bugs/issues/123642
 *
 * the site disables pointer events on the slider and only allows them
 * in -webkit-slider-thumb style which is not supported in Firefox and
 * depends on https://bugzilla.mozilla.org/show_bug.cgi?id=1735575
 */

input[type="range"]::-moz-range-thumb {
  -webkit-appearance: none;
  height: 24px;
  pointer-events: all;
  width: 24px;
}
PK
!<�q���9injections/css/bug1848849-theaa.com-printing-mode-fix.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * www.theaa.com - Print preview is blank
 * Bug #1848849 - https://bugzilla.mozilla.org/show_bug.cgi?id=1848849
 * WebCompat issue #117996 - https://github.com/webcompat/web-bugs/issues/117996
 *
 * The site is adding a style rule of size: 16px for @page, which is very small and Chrome
 * is ignoring the rule, while Firefox honours it.
 * Depends on https://bugzilla.mozilla.org/show_bug.cgi?id=1807985
 */

@media print {
  @page {
    size: a3 !important;
  }
}
PK
!<ڶL��<injections/css/bug1849388-kucharkaprodceru.cz-scroll-fix.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * www.kucharkaprodceru.cz - Scrolling up triggers pull-refresh
 * Bug #1849388 - https://bugzilla.mozilla.org/show_bug.cgi?id=1849388
 * WebCompat issue #123452 - https://github.com/webcompat/web-bugs/issues/123452
 *
 * The site uses older version of jquery.nicescroll.js which adds
 * overflow-y: auto to the body element only in Firefox. Resetting
 * makes the scrolling work as expected
 */

body {
  overflow-y: auto !important;
}
PK
!<�ʹ��3injections/css/bug1868345-tvmovie.de-scroll-fix.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * www.tvmovie.de - Can't scroll tv program on tvmovie.de
 * Bug #1868345 - https://bugzilla.mozilla.org/show_bug.cgi?id=1868345
 * Bug #1840166 - https://bugzilla.mozilla.org/show_bug.cgi?id=1840166
 * WebCompat issue #123254 - https://github.com/webcompat/web-bugs/issues/123254
 *
 * Due to an unfortunate combination of table layout issues and schroll
 * anchoring issues, the page keeps scrolling down forever, with no ability
 * to scroll back up.
 */
:root {
  overflow-anchor: none;
}
PK
!<��:3223injections/css/bug1884842-foodora.cz-height-fix.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * foodora.cz - Unable to pick an address
 * Bug #1884842 - https://bugzilla.mozilla.org/show_bug.cgi?id=1884842
 * WebCompat issue #130975 - https://github.com/webcompat/web-bugs/issues/130975
 *
 * Unable to confirm an adress on the delivery site due to button being outside
 * the viewport and parent container unscrollable.
 * Depends on https://bugzilla.mozilla.org/show_bug.cgi?id=1481876
 */

@media (max-width: 527.98px) {
  .bds-c-modal--is-mobile-bottom-sheet .bds-c-modal__content-window {
    height: 100%;
  }
}

@media (min-height: 528px) {
  .map-modal__map.map-box {
    height: 362px;
  }
}
PK
!<^�x77;injections/css/bug1895994-softtrans.ro-unlock-scrolling.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * softtrans.ro - users cannot scroll the page horizontally on Android
 * Bug #1895994 - https://bugzilla.mozilla.org/show_bug.cgi?id=1895994
 *
 * The page uses a meta viewport tag on Android, and also hides overflow-x
 * on the body tag, making it impossible to scroll the page. We can unset
 * the overflow to fix this.
 */

body {
  overflow-x: auto;
}
PK
!<_��/aa;injections/css/bug1896571-gracobaby.ca-unlock-scrolling.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * gracobaby.ca - users cannot scroll the page on narrow viewports
 * Bug #1896571 - https://bugzilla.mozilla.org/show_bug.cgi?id=1896571
 *
 * The page uses a meta viewport on narrower screen widths, and also
 * hides overflow on the html tag, making it impossible to scroll the
 * page. We can unset the overflow to fix this.
 */

@media (max-width: 767.98px) {
  html {
    overflow: auto;
  }
}
PK
!<�|����Ninjections/css/bug1905278-personalizedplates.revenue.tn.gov-pointer-events.css/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * personalizedplates.revenue.tn.gov - popup for personalizing plates not opening
 * Bug #1905278 - https://bugzilla.mozilla.org/show_bug.cgi?id=1905278
 *
 * The page uses an object tag for an img that is swallowing mouse events,
 * therefore a click on a parent element is not registered. This is being tracked
 * in https://bugzilla.mozilla.org/show_bug.cgi?id=1909584.
 * Adding pointer-events: none temporarily fixes the issue.
 */

#plateDiv {
  pointer-events: none;
}
PK
!<����0injections/js/bug0000000-testbed-js-injection.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals exportFunction */

Object.defineProperty(window.wrappedJSObject, "isTestFeatureSupported", {
  get: exportFunction(function () {
    return true;
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<��P���*injections/js/bug1448747-fastclick-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1448747 - Neutralize FastClick
 *
 * The patch is applied on sites using FastClick library
 * to make sure `FastClick.notNeeded` returns `true`.
 * This allows to disable FastClick and fix various breakage caused
 * by the library (mainly non-functioning drop-down lists).
 */

/* globals exportFunction */

(function () {
  const proto = CSS2Properties.prototype.wrappedJSObject;
  const descriptor = Object.getOwnPropertyDescriptor(proto, "touchAction");
  const { get } = descriptor;

  descriptor.get = exportFunction(function () {
    try {
      throw Error();
    } catch (e) {
      if (e.stack?.includes("notNeeded")) {
        return "none";
      }
    }
    return get.call(this);
  }, window);

  Object.defineProperty(proto, "touchAction", descriptor);
})();
PK
!<��T�ooAinjections/js/bug1452707-window.controllers-shim-ib.absa.co.za.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1452707 - Build site patch for ib.absa.co.za
 * WebCompat issue #16401 - https://webcompat.com/issues/16401
 *
 * The online banking at ib.absa.co.za detect if window.controllers is a
 * non-falsy value to detect if the current browser is Firefox or something
 * else. In bug 1448045, this shim has been disabled for Firefox Nightly 61+,
 * which breaks the UA detection on this site and results in a "Browser
 * unsuppored" error message.
 *
 * This site patch simply sets window.controllers to a string, resulting in
 * their check to work again.
 */

/* globals exportFunction */

console.info(
  "window.controllers has been shimmed for compatibility reasons. See https://webcompat.com/issues/16401 for details."
);

Object.defineProperty(window.wrappedJSObject, "controllers", {
  get: exportFunction(function () {
    return true;
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<�i�
��4injections/js/bug1457335-histography.io-ua-change.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1457335 - histography.io - Override UA & navigator.vendor
 * WebCompat issue #1804 - https://webcompat.com/issues/1804
 *
 * This site is using a strict matching of navigator.userAgent and
 * navigator.vendor to allow access for Safari or Chrome. Here, we set the
 * values appropriately so we get recognized as Chrome.
 */

/* globals exportFunction */

console.info(
  "The user agent has been overridden for compatibility reasons. See https://webcompat.com/issues/1804 for details."
);

const CHROME_UA = navigator.userAgent + " Chrome for WebCompat";

Object.defineProperty(window.navigator.wrappedJSObject, "userAgent", {
  get: exportFunction(function () {
    return CHROME_UA;
  }, window),

  set: exportFunction(function () {}, window),
});

Object.defineProperty(window.navigator.wrappedJSObject, "vendor", {
  get: exportFunction(function () {
    return "Google Inc.";
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<g��227injections/js/bug1472075-bankofamerica.com-ua-change.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1472075 - Build UA override for Bank of America for OSX & Linux
 * WebCompat issue #2787 - https://webcompat.com/issues/2787
 *
 * BoA is showing a red warning to Linux and macOS users, while accepting
 * Windows users without warning. From our side, there is no difference here
 * and we receive a lot of user complains about the warnings, so we spoof
 * as Firefox on Windows in those cases.
 */

/* globals exportFunction */

if (!navigator.platform.includes("Win")) {
  console.info(
    "The user agent has been overridden for compatibility reasons. See https://webcompat.com/issues/2787 for details."
  );

  const WINDOWS_UA = navigator.userAgent.replace(
    /\(.*; rv:/i,
    "(Windows NT 10.0; Win64; x64; rv:"
  );

  Object.defineProperty(window.navigator.wrappedJSObject, "userAgent", {
    get: exportFunction(function () {
      return WINDOWS_UA;
    }, window),

    set: exportFunction(function () {}, window),
  });

  Object.defineProperty(window.navigator.wrappedJSObject, "appVersion", {
    get: exportFunction(function () {
      return "appVersion";
    }, window),

    set: exportFunction(function () {}, window),
  });

  Object.defineProperty(window.navigator.wrappedJSObject, "platform", {
    get: exportFunction(function () {
      return "Win64";
    }, window),

    set: exportFunction(function () {}, window),
  });
}
PK
!<��%���=injections/js/bug1579159-m.tailieu.vn-pdfjs-worker-disable.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * m.tailieu.vn - Override PDFJS.disableWorker to be true
 * WebCompat issue #39057 - https://webcompat.com/issues/39057
 *
 * Custom viewer built with PDF.js is not working in Firefox for Android
 * Disabling worker to match Chrome behavior fixes the issue
 */

/* globals exportFunction */

console.info(
  "window.PDFJS.disableWorker has been set to true for compatibility reasons. See https://webcompat.com/issues/39057 for details."
);

let globals = {};

Object.defineProperty(window.wrappedJSObject, "PDFJS", {
  get: exportFunction(function () {
    return globals;
  }, window),

  set: exportFunction(function (value = {}) {
    globals = value;
    globals.disableWorker = true;
  }, window),
});
PK
!<��p��5injections/js/bug1722955-frontgate.com-ua-override.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/*
 * Bug 1722955 - Add UA override for frontgate.com
 * Webcompat issue #36277 - https://github.com/webcompat/web-bugs/issues/36277
 *
 * The website is sending the desktop version to Firefox on mobile devices
 * based on UA sniffing. Spoofing as Chrome fixes this.
 */

/* globals exportFunction, UAHelpers */

console.info(
  "The user agent has been overridden for compatibility reasons. See https://webcompat.com/issues/36277 for details."
);

UAHelpers.overrideWithDeviceAppropriateChromeUA();
PK
!<���AA8injections/js/bug1724868-news.yahoo.co.jp-ua-override.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1724868 - news.yahoo.co.jp - Override UA
 * WebCompat issue #82605 - https://webcompat.com/issues/82605
 *
 * Yahoo Japan news doesn't allow playing video in Firefox on Android
 * as they don't have it in their support matrix. They check UA override twice
 * and display different ui with the same error. Changing UA to Chrome via
 * content script allows playing the videos.
 */

/* globals exportFunction */

console.info(
  "The user agent has been overridden for compatibility reasons. See https://webcompat.com/issues/82605 for details."
);

Object.defineProperty(window.navigator.wrappedJSObject, "userAgent", {
  get: exportFunction(function () {
    return "Mozilla/5.0 (Linux; Android 11; Pixel 4a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36";
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<q/injections/js/bug1739489-draftjs-beforeinput.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1739489 - Entering an emoji using the MacOS IME "crashes" Draft.js editors.
 */

/* globals exportFunction */

console.info(
  "textInput event has been remapped to beforeinput for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1739489 for details."
);

window.wrappedJSObject.TextEvent = window.wrappedJSObject.InputEvent;

const { CustomEvent, Event, EventTarget } = window.wrappedJSObject;
var Remapped = [
  [CustomEvent, "constructor"],
  [Event, "constructor"],
  [Event, "initEvent"],
  [EventTarget, "addEventListener"],
  [EventTarget, "removeEventListener"],
];

for (const [obj, name] of Remapped) {
  const { prototype } = obj;
  const orig = prototype[name];
  Object.defineProperty(prototype, name, {
    value: exportFunction(function (type, b, c, d) {
      if (type?.toLowerCase() === "textinput") {
        type = "beforeinput";
      }
      return orig.call(this, type, b, c, d);
    }, window),
  });
}

if (location.host === "www.reddit.com") {
  (function () {
    const EditorCSS = ".public-DraftEditor-content[contenteditable=true]";
    let obsEditor, obsStart, obsText, obsKey, observer;
    const obsConfig = { characterData: true, childList: true, subtree: true };
    const obsHandler = () => {
      observer.disconnect();
      const finalTextNode = obsEditor.querySelector(
        `[data-offset-key="${obsKey}"] [data-text='true']`
      ).firstChild;
      const end = obsStart + obsText.length;
      window
        .getSelection()
        .setBaseAndExtent(finalTextNode, end, finalTextNode, end);
    };
    observer = new MutationObserver(obsHandler);

    document.documentElement.addEventListener(
      "beforeinput",
      e => {
        if (e.inputType != "insertFromPaste") {
          return;
        }
        const { target } = e;
        obsEditor = target.closest(EditorCSS);
        if (!obsEditor) {
          return;
        }
        const items = e?.dataTransfer.items;
        for (let item of items) {
          if (item.type === "text/plain") {
            e.preventDefault();
            item.getAsString(text => {
              obsText = text;

              // find the editor-managed <span> which contains the text node the
              // cursor starts on, and the cursor's location (or the selection start)
              const sel = window.getSelection();
              obsStart = sel.anchorOffset;
              let anchor = sel.anchorNode;
              if (!anchor.closest) {
                anchor = anchor.parentElement;
              }
              anchor = anchor.closest("[data-offset-key]");
              obsKey = anchor.getAttribute("data-offset-key");

              // set us up to wait for the editor to either update or replace the
              // <span> with that key (the one containing the text to be changed).
              // we will then make sure the cursor is after the pasted text, as if
              // the editor recreates the node, the cursor position is lost
              observer.observe(obsEditor, obsConfig);

              // force the editor to "paste". sending paste or other events will not
              // work, nor using execCommand (adding HTML will screw up the DOM that
              // the editor expects, and adding plain text will make it ignore newlines).
              target.dispatchEvent(
                new InputEvent("beforeinput", {
                  inputType: "insertText",
                  data: text,
                  bubbles: true,
                  cancelable: true,
                })
              );

              // blur the editor to force it to update/flush its state, because otherwise
              // the paste works, but the editor doesn't show it (until it is re-focused).
              obsEditor.blur();
            });
            break;
          }
        }
      },
      true
    );
  })();
}
PK
!<�?#���3injections/js/bug1769762-tiktok.com-plugins-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1769762 - Empty out navigator.plugins
 * WebCompat issue #103612 - https://webcompat.com/issues/103612
 *
 * Certain features of the site are breaking if navigator.plugins array is not empty:
 *
 * 1. "Likes" on the comments are not saved
 * 2. Can't reply to other people's comments
 * 3. "Likes" on the videos are not saved
 * 4. Can't follow an account (after refreshing "Follow" button is visible again)
 *
 * (note that the first 2 are still broken if you open devtools even with this intervention)
 */

/* globals exportFunction */

console.info(
  "The PluginArray has been overridden for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1753874 for details."
);

const pluginsArray = new window.wrappedJSObject.Array();
Object.setPrototypeOf(pluginsArray, PluginArray.prototype);

Object.defineProperty(navigator.wrappedJSObject, "plugins", {
  get: exportFunction(function () {
    return pluginsArray;
  }, window),
  set: exportFunction(function () {}, window),
});
PK
!<�M�Ю�/injections/js/bug1774005-installtrigger-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1774005 - Generic window.InstallTrigger shim
 *
 * This interventions shims window.InstallTrigger to a string, which evaluates
 * as `true` in web developers browser sniffing code. This intervention will
 * be applied to multiple domains, see bug 1774005 for more information.
 */

/* globals exportFunction */

console.info(
  "The InstallTrigger has been shimmed for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1774005 for details."
);

Object.defineProperty(window.wrappedJSObject, "InstallTrigger", {
  get: exportFunction(function () {
    return "This property has been shimed for Web Compatibility reasons.";
  }, window),
  set: exportFunction(function (_) {}, window),
});
PK
!<���**@injections/js/bug1799968-www.samsung.com-appVersion-linux-fix.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1799968 - Build site patch for www.samsung.com on Linux
 * Bug 1860417 - and Android
 * WebCompat issue #108993 - https://webcompat.com/issues/108993
 *
 * Samsung's Watch pages try to detect the OS via navigator.appVersion,
 * but fail with Linux and Android because they expect it to contain the
 * literal string "linux", and their JS breaks.
 *
 * As such this site patch sets appVersion to "5.0 (Linux)", and is
 * only meant to be applied on Linux or Android.
 */

/* globals exportFunction */

console.info(
  "navigator.appVersion has been shimmed for compatibility reasons. See https://webcompat.com/issues/108993 for details."
);

Object.defineProperty(navigator.wrappedJSObject, "appVersion", {
  get: exportFunction(function () {
    return "5.0 (Linux)";
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<��(���8injections/js/bug1799980-healow.com-infinite-loop-fix.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1799980 - Healow gets stuck in an infinite loop while pages load
 *
 * This patch keeps Healow's localization scripts from getting stuck in
 * an infinite loop while their pages are loading.
 *
 * This happens because they use synchronous XMLHttpRequests to fetch a
 * JSON file with their localized text on the first call to their i18n
 * function, and then force subsequent calls to wait for it by waiting
 * in an infinite loop.
 *
 * But since they're in an infinite loop, the code after the syncXHR will
 * never be able to run, so this ultimately triggers a slow script warning.
 *
 * We can improve this by just preventing the infinite loop from happening,
 * though since they disable caching on their JSON files it means that more
 * XHRs may happen. But since those files are small, this seems like a
 * reasonable compromise until they migrate to a better i18n solution.
 *
 * See https://bugzilla.mozilla.org/show_bug.cgi?id=1799980 for details.
 */

/* globals exportFunction */

Object.defineProperty(window.wrappedJSObject, "ajaxRequestProcessing", {
  get: exportFunction(function () {
    return false;
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<�PR���:injections/js/bug1815733-outlook365-clipboard-read-noop.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1815733 - Annoying "Paste" overlay when trying to paste
 *
 * As per https://bugzilla.mozilla.org/show_bug.cgi?id=1815733#c13, Outlook
 * is calling clipboard.read() again when they shouldn't. This is causing a
 * visible "Paste" prompt for the user, which is stealing focus and can be
 * annoying.
 */

/* globals exportFunction */

Object.defineProperty(navigator.clipboard.wrappedJSObject, "read", {
  value: exportFunction(function () {
    return new Promise((resolve, _) => {
      console.log(
        "clipboard.read() has been overwriten with a no-op. See https://bugzilla.mozilla.org/show_bug.cgi?id=1815733#c13 for details."
      );

      resolve();
    });
  }, navigator.clipboard),
});
PK
!<�
����1injections/js/bug1818818-fastclick-legacy-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1818818 - Neutralize FastClick
 *
 * The patch is applied on sites using older version of FastClick library.
 * This allows to disable FastClick and fix various breakage caused
 * by the library.
 */

/* globals exportFunction */

const proto = CSS2Properties.prototype.wrappedJSObject;
Object.defineProperty(proto, "msTouchAction", {
  get: exportFunction(function () {
    return "none";
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<0�pp2injections/js/bug1819450-cmbchina.com-ua-change.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1819450 - cmbchina.com - Override UA
 *
 * The site is using UA detection to redirect to
 * m.cmbchina.com (mobile version of the site). Adding `SAMSUNG` allows
 * to bypass the detection of mobile browser.
 */

/* globals exportFunction */

console.info(
  "The user agent has been overridden for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1081239 for details."
);

const MODIFIED_UA = navigator.userAgent + " SAMSUNG";

Object.defineProperty(window.navigator.wrappedJSObject, "userAgent", {
  get: exportFunction(function () {
    return MODIFIED_UA;
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<�w@�YYEinjections/js/bug1819476-axisbank.com-webkitSpeechRecognition-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * axisbank.com - Shim webkitSpeechRecognition
 * WebCompat issue #117770 - https://webcompat.com/issues/117770
 *
 * The page with bank offerings is not loading options due to the
 * site relying on webkitSpeechRecognition, which is undefined in Firefox.
 * Shimming it to `class {}` makes the pages work.
 */

/* globals exportFunction */

console.info(
  "webkitSpeechRecognition was shimmed for compatibility reasons. See https://webcompat.com/issues/117770 for details."
);

Object.defineProperty(window.wrappedJSObject, "webkitSpeechRecognition", {
  value: exportFunction(function () {
    return class {};
  }, window),
});
PK
!<��7��<injections/js/bug1819678-free4talk.com-window-chrome-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1827678 - UA spoof for www.free4talk.com
 *
 * This site is checking for window.chrome, so let's spoof that.
 */

/* globals exportFunction */

console.info(
  "window.chrome has been shimmed for compatibility reasons. See https://github.com/webcompat/web-bugs/issues/77727 for details."
);

Object.defineProperty(window.wrappedJSObject, "chrome", {
  get: exportFunction(function () {
    return true;
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<�B�d{{8injections/js/bug1830776-blueshieldca.com-unsupported.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1830776 - blueshieldca.com
 * WebCompat issue #112630 - https://webcompat.com/issues/112630
 *
 * The site is showing unsupported message in Firefox.
 * They're also checking for "browserCollapsed" item in sessionStorage
 * before showing the message, to only show it once. Adding this
 * item to sessionStorage will make sure the message is not shown
 * on the initial load.
 */

console.info(
  "browserCollapsed in sessionStorage has been shimmed for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1830776 for details."
);

if (!sessionStorage.getItem("browserCollapsed")) {
  sessionStorage.setItem("browserCollapsed", "true");
}
PK
!<j{���@injections/js/bug1831007-nintendo-window-OnetrustActiveGroups.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1831007 - Shim window.OnetrustActiveGroups for Nintendo sites
 *
 * Nintendo relies on `window.OnetrustActiveGroups` being defined. If it's not,
 * users may have intermittent issues signing into their account, as they're
 * then trying to call `.split()` on `undefined`.
 *
 * This intervention sets a default value (an empty string), but still allows
 * the value to be overwritten at any time.
 */

/* globals exportFunction */

console.info(
  "The window.OnetrustActiveGroups property has been shimmed for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1831007 for details."
);

Object.defineProperty(window.wrappedJSObject, "OnetrustActiveGroups", {
  value: "",
  writable: true,
});
PK
!<[�ff<injections/js/bug1836157-thai-masszazs-niceScroll-disable.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * Bug 1836157 - Shim navigator.platform on www.thai-massaszs.net/en/
 *
 * This page adds niceScroll on Android, which breaks scrolling and
 * zooming on Firefox. Adding ` Mac` to `navigator.platform` makes
 * the page avoid adding niceScroll entirely, unbreaking the page.
 */

var plat = navigator.platform;
if (!plat.includes("Mac")) {
  console.info(
    "The navigator.platform property has been shimmed to include 'Mac' for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1836157 for details."
  );

  Object.defineProperty(navigator.__proto__.wrappedJSObject, "platform", {
    value: plat + " Mac",
    writable: true,
  });
}
PK
!<S�7Einjections/js/bug1842437-www.youtube.com-performance-now-precision.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1842437 - When attempting to go back on youtube.com, the content remains the same
 *
 * If consecutive session history entries had history.state.entryTime set to same value,
 * back button doesn't work as expected. The entryTime value is coming from performance.now()
 * and modifying its return value slightly to make sure two close consecutive calls don't
 * get the same result helped with resolving the issue.
 */

/* globals exportFunction */

console.info(
  "performance.now precision has been modified for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1756970 for details."
);

const origPerf = performance.wrappedJSObject;
const origNow = origPerf.now;

let counter = 0;
let previousVal = 0;

Object.defineProperty(window.performance.wrappedJSObject, "now", {
  value: exportFunction(function () {
    let originalVal = origNow.call(origPerf);
    if (originalVal === previousVal) {
      originalVal += 0.00000003 * ++counter;
    } else {
      previousVal = originalVal;
      counter = 0;
    }
    return originalVal;
  }, window),
});
PK
!<+<��hhBinjections/js/bug1849058-nicochannel.jp-picture-in-picture-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1849058 - Shim PictureInPictureWindow for nicochannel.jp
 * WebCompat issue #124463 - https://webcompat.com/issues/124463
 *
 * The page is showing unsupported message based on typeof
 * window.PictureInPictureWindow, which is undefined in Firefox.
 * Shimming it to `class {}` makes the pages work.
 */

/* globals exportFunction */

console.info(
  "PictureInPictureWindow was shimmed for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1849058 for details."
);

Object.defineProperty(window.wrappedJSObject, "PictureInPictureWindow", {
  value: exportFunction(function () {
    return class {};
  }, window),
});
PK
!<���*injections/js/bug1855014-eksiseyler.com.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * eksiseyler.com - Set window.loggingEnabled = false
 * WebCompat issue #77221 - https://webcompat.com/issues/77221
 *
 * A scripting error on the site causes images to not load unless
 * window.loggingEnabled = false
 */

/* globals exportFunction */

console.info(
  "loggingEnabled been set to true for compatibility reasons. See https://webcompat.com/issues/77221 for details."
);

Object.defineProperty(window.wrappedJSObject, "loggingEnabled", {
  get: exportFunction(function () {
    return false;
  }, window),

  set: exportFunction(function () {}, window),
});
PK
!<�,u4��*injections/js/bug1855071-www.meteoam.it.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * www.meteoam.it - virtual keyboard is hidden as it is opened
 * webcompat issue #121197 - https://webcompat.com/issues/121197
 *
 * the site's map is 75vh tall, and it hides the keyboard onresize,
 * meaning the keyboard is closed as it it brought up in Firefox.
 */

console.info(
  "Map iframe height is being managed for compatibility reasons. see https://webcompat.com/issues/77221 for details."
);

const selector = "#iframe_map";

const moOptions = {
  childList: true,
  subtree: true,
};

const mo = new MutationObserver(() => {
  const map = document.querySelector(selector);
  let lastSize;
  if (map) {
    mo.disconnect();
    const maybeGrowMap = () => {
      const winHeight = window.outerHeight;
      if (lastSize && lastSize > winHeight) {
        return;
      }
      map.style.height = winHeight * 0.75 + "px";
      lastSize = winHeight;
    };
    maybeGrowMap();
    window.addEventListener("resize", () =>
      window.requestAnimationFrame(maybeGrowMap)
    );
  }
});

mo.observe(document.documentElement, moOptions);
PK
!<�b�++7injections/js/bug1859617-installtrigger-removal-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1859617 - Generic window.InstallTrigger removal shim
 *
 * This interventions shims window.InstallTrigger to undefine it.
 */

/* globals exportFunction */

if (typeof window.InstallTrigger !== "undefined") {
  console.info(
    "window.InstallTrigger has been undefined for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1859617 for details."
  );

  Object.defineProperty(window.wrappedJSObject, "InstallTrigger", {
    get: exportFunction(function () {
      return undefined;
    }, window),
    set: exportFunction(function (_) {}, window),
  });
}
PK
!<$q����5injections/js/bug1864564-esri-transfrom-names-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/*
 * Bug 1864564 - Override esri._css.names containing -moz-prefixed css rules names
 * Webcompat issue #129144 - https://github.com/webcompat/web-bugs/issues/129144
 *
 * Esri library is applying -moz-transform to maps built with it, based on UA detection.
 * Since support for -moz-transform has been removed in
 * https://bugzilla.mozilla.org/show_bug.cgi?id=1855763, this results
 * in maps partially or incorrectly displayed. Overriding  esri._css.names
 * containing -moz-prefixed css properties to their unprefixed versions
 * fixes the issues.
 */

/* globals exportFunction, cloneInto */

console.info(
  "Overriding esri._css.names for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1864564 for details."
);

const transformNames = {
  transition: "transition",
  transform: "transform",
  transformName: "transform",
  origin: "transformOrigin",
  endEvent: "transitionend",
};

let esriGlobal;

Object.defineProperty(window.wrappedJSObject, "esri", {
  get: exportFunction(function () {
    if ("_css" in esriGlobal && "names" in esriGlobal._css) {
      esriGlobal._css.names = cloneInto(transformNames, esriGlobal);
    }
    return esriGlobal;
  }, window),

  set: exportFunction(function (value) {
    esriGlobal = value;
  }, window),
});
PK
!<y'���:injections/js/bug1881922-disable-legacy-mutation-events.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bugs 1881922, 1901780 - Disable legacy DOM Mutation Events to prevent performance issues.
 */

/* globals exportFunction */

let bug = "1881922";
if (location.origin.includes("vanbreda")) {
  bug = "1901780";
}
console.info(
  `DOM Mutation Events have been disabled to prevent performance issues. See https://bugzilla.mozilla.org/show_bug.cgi?id=${bug} for details.`
);

(function disableMutationEvents() {
  const whichEvents = [
    "domattrmodified",
    "domcharacterdatamodified",
    "domnodeinserted",
    "domnodeinsertedintodocument",
    "domnoderemoved",
    "domnoderemovedfromdocument",
    "domsubtreemodified",
  ];

  const { prototype } = window.wrappedJSObject.EventTarget;
  const { addEventListener } = prototype;
  Object.defineProperty(prototype, "addEventListener", {
    value: exportFunction(function (_type, b, c, d) {
      const type = _type?.toLowerCase();
      if (whichEvents.includes(type)) {
        return undefined;
      }
      return addEventListener.call(this, type, b, c, d);
    }, window),
  });
})();
PK
!<[�齲�Dinjections/js/bug1889326-office365-email-handling-prompt-autohide.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1889326 - Office 365 email handling prompt autohide
 *
 * This site patch prevents the notification bar on Office 365
 * apps from popping up on each page-load, offering to handle
 * email with Outlook.
 */

/* globals exportFunction */

const warning =
  "Office 365 Outlook email handling prompt has been hidden. See https://bugzilla.mozilla.org/show_bug.cgi?id=1889326 for details.";

const localStorageKey = "mailProtocolHandlerAlreadyOffered";

const nav = navigator.wrappedJSObject;
const { registerProtocolHandler } = nav;
const { localStorage } = window.wrappedJSObject;

Object.defineProperty(navigator.wrappedJSObject, "registerProtocolHandler", {
  value: exportFunction(function (scheme, url, title) {
    if (localStorage.getItem(localStorageKey)) {
      console.info(warning);
      return undefined;
    }
    registerProtocolHandler.call(nav, scheme, url, title);
    localStorage.setItem(localStorageKey, true);
    return undefined;
  }, window),
});
PK
!<vꅖbb8injections/js/bug1896383-error-capturestacktrace-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/*
 * Bug 1896383 - Shim "captureStackTrace" in Error
 * Webcompat issue #136865 - https://github.com/webcompat/web-bugs/issues/136865
 *
 * The site is using Error.captureStackTrace and completely breaks in Firefox
 * since it's not supported. Depends on https://bugzilla.mozilla.org/show_bug.cgi?id=1886820
 */

/* globals exportFunction */

console.info(
  "Shimming captureStackTrace in Error for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1896383 for details."
);

Object.defineProperty(window.Error.wrappedJSObject, "captureStackTrace", {
  value: exportFunction(function () {
    return {};
  }, window),
});
PK
!<(�4�		+injections/js/bug1897120-turnjs-zoom-fix.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/*
 * Bug 1897120 - Override "MozTransform" in element.style and return false
 * Webcompat issue #137038 - https://github.com/webcompat/web-bugs/issues/137038
 *
 * The site is using turn js and detecting "MozTransform" in document.body.style,
 * which returns true at the moment and uses the -moz-transform, which doesn't work,
 * so zooming functionality breaks. Overriding "MozTransform" in element.style to
 * return false fixes the problem.
 */

/* globals exportFunction, cloneInto */

console.info(
  "Overriding MozTransform in element.style for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1897120 for details."
);

(function () {
  const ele = HTMLElement.wrappedJSObject.prototype;
  const obj = window.wrappedJSObject.Object;
  const style = obj.getOwnPropertyDescriptor(ele, "style");
  const { get } = style;
  style.get = exportFunction(function () {
    const styles = get.call(this);
    return new window.wrappedJSObject.Proxy(
      styles,
      cloneInto(
        {
          deleteProperty(target, prop) {
            return Reflect.deleteProperty(target, prop);
          },
          get(target, key) {
            const val = Reflect.get(target, key);
            if (typeof val == "function") {
              // We can't just return the function, as it's a method which
              // needs `this` to be the styles object. So we return a wrapper.
              return exportFunction(function () {
                return val.apply(styles, arguments);
              }, window);
            }
            return val;
          },
          has(target, key) {
            if (key == "MozTransform" || key == "WebkitTransform") {
              return false;
            }
            return Reflect.has(target, key);
          },
          ownKeys(target) {
            return Reflect.ownKeys(target);
          },
          set(target, key, value) {
            return Reflect.set(target, key, value);
          },
        },
        window,
        { cloneFunctions: true }
      )
    );
  }, window);
  obj.defineProperty(ele, "style", style);
})();
PK
!<�����/injections/js/bug1898952-digits.t-mobile.com.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1898952 - Spoof navigator.userAgentData for digits.t-mobile.com
 * Webcompat issue #119767 - https://webcompat.com/issues/119767
 *
 * The site blocks Firefox and Safari, reading info from userAgentData.
 */

/* globals exportFunction, cloneInto */

if (!navigator.userAgentData) {
  console.info(
    "navigator.userAgentData has been overridden for compatibility reasons. See https://webcompat.com/issues/119767 for details."
  );

  const ua = navigator.userAgent;
  const mobile = ua.includes("Mobile") || ua.includes("Tablet");

  // Very roughly matches Chromium's GetPlatformForUAMetadata()
  let platform = "Linux";
  if (mobile) {
    platform = "Android";
  } else if (navigator.platform.startsWith("Win")) {
    platform = "Windows";
  } else if (navigator.platform.startsWith("Mac")) {
    platform = "macOS";
  }

  const version = (ua.match(/Firefox\/([0-9.]+)/) || ["", "58.0"])[1];

  // These match Chrome's output as of version 126.
  const brands = [
    {
      brand: "Not/A)Brand",
      version: "8",
    },
    {
      brand: "Chromium",
      version,
    },
    {
      brand: "Google Chrome",
      version,
    },
  ];

  const userAgentData = cloneInto(
    {
      brands,
      mobile,
      platform,
    },
    window
  );

  Object.defineProperty(window.navigator.wrappedJSObject, "userAgentData", {
    get: exportFunction(function () {
      return userAgentData;
    }, window),

    set: exportFunction(function () {}, window),
  });
}
PK
!<uD~ccBinjections/js/bug1899937-plus.nhk.jp-request-picture-in-picture.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1899937 - Shim requestPictureInPicture for plus.nhk.jp
 * WebCompat issue #103463 - https://webcompat.com/issues/103463
 *
 * plus.nhk.jp is showing an error when attempting to play videos.
 * Shimming requestPictureInPicture to `{}` makes the videos play.
 */

/* globals exportFunction */

console.info(
  "requestPictureInPicture was shimmed for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1899937 for details."
);

const proto = HTMLVideoElement.wrappedJSObject.prototype;

Object.defineProperty(proto, "requestPictureInPicture", {
  value: exportFunction(function () {
    return {};
  }, window),
});
PK
!<�$d`��lib/about_compat_broker.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* global browser, module, onMessageFromTab */

class AboutCompatBroker {
  constructor(bindings) {
    this._injections = bindings.injections;
    this._uaOverrides = bindings.uaOverrides;
    this._shims = bindings.shims;

    if (!this._injections && !this._uaOverrides && !this._shims) {
      throw new Error("No interventions; about:compat broker is not needed");
    }

    this.portsToAboutCompatTabs = this.buildPorts();
    this._injections?.bindAboutCompatBroker(this);
    this._uaOverrides?.bindAboutCompatBroker(this);
    this._shims?.bindAboutCompatBroker(this);
  }

  buildPorts() {
    const ports = new Set();

    browser.runtime.onConnect.addListener(port => {
      ports.add(port);
      port.onDisconnect.addListener(function () {
        ports.delete(port);
      });
    });

    async function broadcast(message) {
      for (const port of ports) {
        port.postMessage(message);
      }
    }

    return { broadcast };
  }

  filterOverrides(overrides) {
    return overrides
      .filter(override => override.availableOnPlatform)
      .map(override => {
        const { id, active, bug, domain, hidden } = override;
        return { id, active, bug, domain, hidden };
      });
  }

  getInterventionById(id) {
    for (const [type, things] of Object.entries({
      overrides: this._uaOverrides?.getAvailableOverrides() || [],
      interventions: this._injections?.getAvailableInjections() || [],
      shims: this._shims?.getAvailableShims() || [],
    })) {
      for (const what of things) {
        if (what.id === id) {
          return { type, what };
        }
      }
    }
    return {};
  }

  bootup() {
    onMessageFromTab(msg => {
      switch (msg.command || msg) {
        case "toggle": {
          const id = msg.id;
          const { type, what } = this.getInterventionById(id);
          if (!what) {
            return Promise.reject(
              `No such override or intervention to toggle: ${id}`
            );
          }
          const active = type === "shims" ? !what.disabledReason : what.active;
          this.portsToAboutCompatTabs
            .broadcast({ toggling: id, active })
            .then(async () => {
              switch (type) {
                case "interventions": {
                  if (active) {
                    await this._injections?.disableInjection(what);
                  } else {
                    await this._injections?.enableInjection(what);
                  }
                  break;
                }
                case "overrides": {
                  if (active) {
                    await this._uaOverrides?.disableOverride(what);
                  } else {
                    await this._uaOverrides?.enableOverride(what);
                  }
                  break;
                }
                case "shims": {
                  if (active) {
                    await this._shims?.disableShimForSession(id);
                  } else {
                    await this._shims?.enableShimForSession(id);
                  }
                  // no need to broadcast the "toggled" signal for shims, as
                  // they send a shimsUpdated message themselves instead
                  return;
                }
              }
              this.portsToAboutCompatTabs.broadcast({
                toggled: id,
                active: !active,
              });
            });
          break;
        }
        case "getAllInterventions": {
          return Promise.resolve({
            overrides:
              (this._uaOverrides?.isEnabled() &&
                this.filterOverrides(
                  this._uaOverrides?.getAvailableOverrides()
                )) ||
              false,
            interventions:
              (this._injections?.isEnabled() &&
                this.filterOverrides(
                  this._injections?.getAvailableInjections()
                )) ||
              false,
            shims: this._shims?.getAvailableShims() || false,
          });
        }
      }
      return undefined;
    });
  }
}

module.exports = AboutCompatBroker;
PK
!<�|K��lib/custom_functions.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser, module */

const replaceStringInRequest = (
  requestId,
  inString,
  outString,
  inEncoding = "utf-8"
) => {
  const filter = browser.webRequest.filterResponseData(requestId);
  const decoder = new TextDecoder(inEncoding);
  const encoder = new TextEncoder();
  const RE = new RegExp(inString, "g");
  const carryoverLength = inString.length;
  let carryover = "";

  filter.ondata = event => {
    const replaced = (
      carryover + decoder.decode(event.data, { stream: true })
    ).replace(RE, outString);
    filter.write(encoder.encode(replaced.slice(0, -carryoverLength)));
    carryover = replaced.slice(-carryoverLength);
  };

  filter.onstop = () => {
    if (carryover.length) {
      filter.write(encoder.encode(carryover));
    }
    filter.close();
  };
};

const CUSTOM_FUNCTIONS = {
  detectSwipeFix: injection => {
    const { urls, types } = injection.data;
    const listener = (injection.data.listener = ({ requestId }) => {
      replaceStringInRequest(
        requestId,
        "preventDefault:true",
        "preventDefault:false"
      );
      return {};
    });
    browser.webRequest.onBeforeRequest.addListener(listener, { urls, types }, [
      "blocking",
    ]);
  },
  detectSwipeFixDisable: injection => {
    const { listener } = injection.data;
    browser.webRequest.onBeforeRequest.removeListener(listener);
    delete injection.data.listener;
  },
  noSniffFix: injection => {
    const { urls, contentType } = injection.data;
    const listener = (injection.data.listener = e => {
      e.responseHeaders.push(contentType);
      return { responseHeaders: e.responseHeaders };
    });

    browser.webRequest.onHeadersReceived.addListener(listener, { urls }, [
      "blocking",
      "responseHeaders",
    ]);
  },
  noSniffFixDisable: injection => {
    const { listener } = injection.data;
    browser.webRequest.onHeadersReceived.removeListener(listener);
    delete injection.data.listener;
  },
  runScriptBeforeRequest: injection => {
    const { bug, message, request, script, types } = injection;
    const warning = `${message} See https://bugzilla.mozilla.org/show_bug.cgi?id=${bug} for details.`;

    const listener = (injection.listener = e => {
      const { tabId, frameId } = e;
      return browser.tabs
        .executeScript(tabId, {
          file: script,
          frameId,
          runAt: "document_start",
        })
        .then(() => {
          browser.tabs.executeScript(tabId, {
            code: `console.warn(${JSON.stringify(warning)})`,
            runAt: "document_start",
          });
        })
        .catch(_ => {});
    });

    browser.webRequest.onBeforeRequest.addListener(
      listener,
      { urls: request, types: types || ["script"] },
      ["blocking"]
    );
  },
  runScriptBeforeRequestDisable: injection => {
    const { listener } = injection;
    browser.webRequest.onBeforeRequest.removeListener(listener);
    delete injection.data.listener;
  },
};

module.exports = CUSTOM_FUNCTIONS;
PK
!<0G�� ! !lib/injections.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser, module */

class Injections {
  constructor(availableInjections, customFunctions) {
    this.INJECTION_PREF = "perform_injections";

    this._injectionsEnabled = true;

    this._availableInjections = availableInjections;
    this._activeInjections = new Set();
    // Only used if this.shouldUseScriptingAPI is false and we are falling back
    // to use the contentScripts API.
    this._activeInjectionHandles = new Map();
    this._customFunctions = customFunctions;

    this.shouldUseScriptingAPI =
      browser.aboutConfigPrefs.getBoolPrefSync("useScriptingAPI");
    // Debug log emit only on nightly (similarly to the debug
    // helper used in shims.js for similar purpose).
    browser.appConstants.getReleaseBranch().then(releaseBranch => {
      if (releaseBranch !== "release_or_beta") {
        console.debug(
          `WebCompat Injections will be injected using ${
            this.shouldUseScriptingAPI ? "scripting" : "contentScripts"
          } API`
        );
      }
    });
  }

  bindAboutCompatBroker(broker) {
    this._aboutCompatBroker = broker;
  }

  bootup() {
    browser.aboutConfigPrefs.onPrefChange.addListener(() => {
      this.checkInjectionPref();
    }, this.INJECTION_PREF);
    this.checkInjectionPref();
  }

  checkInjectionPref() {
    browser.aboutConfigPrefs.getPref(this.INJECTION_PREF).then(value => {
      if (value === undefined) {
        browser.aboutConfigPrefs.setPref(this.INJECTION_PREF, true);
      } else if (value === false) {
        this.unregisterContentScripts();
      } else {
        this.registerContentScripts();
      }
    });
  }

  getAvailableInjections() {
    return this._availableInjections;
  }

  isEnabled() {
    return this._injectionsEnabled;
  }

  async getPromiseRegisteredScriptIds(scriptIds) {
    let registeredScriptIds = [];

    // Try to avoid re-registering scripts already registered
    // (e.g. if the webcompat background page is restarted
    // after an extension process crash, after having registered
    // the content scripts already once), but do not prevent
    // to try registering them again if the getRegisteredContentScripts
    // method returns an unexpected rejection.
    try {
      const registeredScripts =
        await browser.scripting.getRegisteredContentScripts({
          // By default only look for script ids that belongs to Injections
          // (and ignore the ones that may belong to Shims).
          ids: scriptIds ?? this._availableInjections.map(inj => inj.id),
        });
      registeredScriptIds = registeredScripts.map(script => script.id);
    } catch (ex) {
      console.error(
        "Retrieve WebCompat GoFaster registered content scripts failed: ",
        ex
      );
    }

    return registeredScriptIds;
  }

  async registerContentScripts() {
    const platformInfo = await browser.runtime.getPlatformInfo();
    const platformMatches = [
      "all",
      platformInfo.os,
      platformInfo.os == "android" ? "android" : "desktop",
    ];

    let registeredScriptIds = this.shouldUseScriptingAPI
      ? await this.getPromiseRegisteredScriptIds()
      : [];

    for (const injection of this._availableInjections) {
      if (platformMatches.includes(injection.platform)) {
        injection.availableOnPlatform = true;
        await this.enableInjection(injection, registeredScriptIds);
      }
    }

    this._injectionsEnabled = true;
    this._aboutCompatBroker.portsToAboutCompatTabs.broadcast({
      interventionsChanged: this._aboutCompatBroker.filterOverrides(
        this._availableInjections
      ),
    });
  }

  buildContentScriptRegistrations(contentScripts) {
    let finalConfig = Object.assign({}, contentScripts);

    if (!finalConfig.runAt) {
      finalConfig.runAt = "document_start";
    }

    if (this.shouldUseScriptingAPI) {
      // Don't persist the content scripts across browser restarts
      // (at least not yet, we would need to apply some more changes
      // to adjust webcompat for accounting for the scripts to be
      // already registered).
      //
      // NOTE: scripting API has been introduced in Gecko 102,
      // prior to Gecko 105 persistAcrossSessions option was required
      // and only accepted false persistAcrossSessions, after Gecko 105
      // is optional and defaults to true.

      finalConfig.persistAcrossSessions = false;

      // Convert js/css from contentScripts.register API method
      // format to scripting.registerContentScripts API method
      // format.
      if (Array.isArray(finalConfig.js)) {
        finalConfig.js = finalConfig.js.map(e => e.file);
      }

      if (Array.isArray(finalConfig.css)) {
        finalConfig.css = finalConfig.css.map(e => e.file);
      }
    }

    return finalConfig;
  }

  async enableInjection(injection, registeredScriptIds) {
    if (injection.active) {
      return undefined;
    }

    if (injection.customFunc) {
      return this.enableCustomInjection(injection);
    }

    return this.enableContentScripts(injection, registeredScriptIds);
  }

  enableCustomInjection(injection) {
    if (injection.customFunc in this._customFunctions) {
      this._customFunctions[injection.customFunc](injection);
      injection.active = true;
    } else {
      console.error(
        `Provided function ${injection.customFunc} wasn't found in functions list`
      );
    }
  }

  async enableContentScripts(injection, registeredScriptIds) {
    let injectProps;
    try {
      const { id } = injection;
      if (this.shouldUseScriptingAPI) {
        // enableContentScripts receives a registeredScriptIds already
        // pre-computed once from registerContentScripts to register all
        // the injection, whereas it does not expect to receive one when
        // it is called from the AboutCompatBroker to re-enable one specific
        // injection.
        let activeScriptIds = Array.isArray(registeredScriptIds)
          ? registeredScriptIds
          : await this.getPromiseRegisteredScriptIds([id]);
        injectProps = this.buildContentScriptRegistrations(
          injection.contentScripts
        );
        injectProps.id = id;
        if (!activeScriptIds.includes(id)) {
          await browser.scripting.registerContentScripts([injectProps]);
        }
        this._activeInjections.add(id);
      } else {
        const handle = await browser.contentScripts.register(
          this.buildContentScriptRegistrations(injection.contentScripts)
        );
        this._activeInjections.add(id);
        this._activeInjectionHandles.set(id, handle);
      }

      injection.active = true;
    } catch (ex) {
      console.error(
        "Registering WebCompat GoFaster content scripts failed: ",
        { injection, injectProps },
        ex
      );
    }
  }

  unregisterContentScripts() {
    for (const injection of this._availableInjections) {
      this.disableInjection(injection);
    }

    this._injectionsEnabled = false;
    this._aboutCompatBroker.portsToAboutCompatTabs.broadcast({
      interventionsChanged: false,
    });
  }

  async disableInjection(injection) {
    if (!injection.active) {
      return undefined;
    }

    if (injection.customFunc) {
      return this.disableCustomInjections(injection);
    }

    return this.disableContentScripts(injection);
  }

  disableCustomInjections(injection) {
    const disableFunc = injection.customFunc + "Disable";

    if (disableFunc in this._customFunctions) {
      this._customFunctions[disableFunc](injection);
      injection.active = false;
    } else {
      console.error(
        `Provided function ${disableFunc} for disabling injection wasn't found in functions list`
      );
    }
  }

  async disableContentScripts(injection) {
    if (this._activeInjections.has(injection.id)) {
      if (this.shouldUseScriptingAPI) {
        await browser.scripting.unregisterContentScripts({
          ids: [injection.id],
        });
      } else {
        const handle = this._activeInjectionHandles.get(injection.id);
        await handle.unregister();
        this._activeInjectionHandles.delete(injection.id);
      }
      this._activeInjections.delete(injection);
    }
    injection.active = false;
  }
}

module.exports = Injections;
PK
!<*܍�UUlib/intervention_helpers.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals module */

const GOOGLE_TLDS = [
  "com",
  "ac",
  "ad",
  "ae",
  "com.af",
  "com.ag",
  "com.ai",
  "al",
  "am",
  "co.ao",
  "com.ar",
  "as",
  "at",
  "com.au",
  "az",
  "ba",
  "com.bd",
  "be",
  "bf",
  "bg",
  "com.bh",
  "bi",
  "bj",
  "com.bn",
  "com.bo",
  "com.br",
  "bs",
  "bt",
  "co.bw",
  "by",
  "com.bz",
  "ca",
  "com.kh",
  "cc",
  "cd",
  "cf",
  "cat",
  "cg",
  "ch",
  "ci",
  "co.ck",
  "cl",
  "cm",
  "cn",
  "com.co",
  "co.cr",
  "com.cu",
  "cv",
  "com.cy",
  "cz",
  "de",
  "dj",
  "dk",
  "dm",
  "com.do",
  "dz",
  "com.ec",
  "ee",
  "com.eg",
  "es",
  "com.et",
  "fi",
  "com.fj",
  "fm",
  "fr",
  "ga",
  "ge",
  "gf",
  "gg",
  "com.gh",
  "com.gi",
  "gl",
  "gm",
  "gp",
  "gr",
  "com.gt",
  "gy",
  "com.hk",
  "hn",
  "hr",
  "ht",
  "hu",
  "co.id",
  "iq",
  "ie",
  "co.il",
  "im",
  "co.in",
  "io",
  "is",
  "it",
  "je",
  "com.jm",
  "jo",
  "co.jp",
  "co.ke",
  "ki",
  "kg",
  "co.kr",
  "com.kw",
  "kz",
  "la",
  "com.lb",
  "com.lc",
  "li",
  "lk",
  "co.ls",
  "lt",
  "lu",
  "lv",
  "com.ly",
  "co.ma",
  "md",
  "me",
  "mg",
  "mk",
  "ml",
  "com.mm",
  "mn",
  "ms",
  "com.mt",
  "mu",
  "mv",
  "mw",
  "com.mx",
  "com.my",
  "co.mz",
  "com.na",
  "ne",
  "com.nf",
  "com.ng",
  "com.ni",
  "nl",
  "no",
  "com.np",
  "nr",
  "nu",
  "co.nz",
  "com.om",
  "com.pk",
  "com.pa",
  "com.pe",
  "com.ph",
  "pl",
  "com.pg",
  "pn",
  "com.pr",
  "ps",
  "pt",
  "com.py",
  "com.qa",
  "ro",
  "rs",
  "ru",
  "rw",
  "com.sa",
  "com.sb",
  "sc",
  "se",
  "com.sg",
  "sh",
  "si",
  "sk",
  "com.sl",
  "sn",
  "sm",
  "so",
  "st",
  "sr",
  "com.sv",
  "td",
  "tg",
  "co.th",
  "com.tj",
  "tk",
  "tl",
  "tm",
  "to",
  "tn",
  "com.tr",
  "tt",
  "com.tw",
  "co.tz",
  "com.ua",
  "co.ug",
  "co.uk",
  "com",
  "com.uy",
  "co.uz",
  "com.vc",
  "co.ve",
  "vg",
  "co.vi",
  "com.vn",
  "vu",
  "ws",
  "co.za",
  "co.zm",
  "co.zw",
];

var InterventionHelpers = {
  /**
   * Useful helper to generate a list of domains with a fixed base domain and
   * multiple country-TLDs or other cases with various TLDs.
   *
   * Example:
   *   matchPatternsForTLDs("*://mozilla.", "/*", ["com", "org"])
   *     => ["*://mozilla.com/*", "*://mozilla.org/*"]
   */
  matchPatternsForTLDs(base, suffix, tlds) {
    return tlds.map(tld => base + tld + suffix);
  },

  /**
   * A modified version of matchPatternsForTLDs that always returns the match
   * list for all known Google country TLDs.
   */
  matchPatternsForGoogle(base, suffix = "/*") {
    return InterventionHelpers.matchPatternsForTLDs(base, suffix, GOOGLE_TLDS);
  },
};

module.exports = InterventionHelpers;
PK
!<K�$i��lib/messaging_helper.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser */

// By default, only the first handler for browser.runtime.onMessage which
// returns a value will get to return one. As such, we need to let them all
// receive the message, and all have a chance to return a response (with the
// first non-undefined result being the one that is ultimately returned).
// This way, about:compat and the shims library can both get a chance to
// process a message, and just return undefined if they wish to ignore it.

const onMessageFromTab = (function () {
  const handlers = new Set();

  browser.runtime.onMessage.addListener((msg, sender) => {
    const promises = [...handlers.values()].map(fn => fn(msg, sender));
    return Promise.allSettled(promises).then(results => {
      for (const { reason, value } of results) {
        if (reason) {
          console.error(reason);
        } else if (value !== undefined) {
          return value;
        }
      }
      return undefined;
    });
  });

  return function (handler) {
    handlers.add(handler);
  };
})();
PK
!<r���lib/module_shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * We cannot yet use proper JS modules within webextensions, as support for them
 * is highly experimental and highly instable. So we end up just including all
 * the JS files we need as separate background scripts, and since they all are
 * executed within the same context, this works for our in-browser deployment.
 *
 * However, this code is tracked outside of mozilla-central, and we work on
 * shipping this code in other products, like android-components as well.
 * Because of that, we have automated tests running within that repository. To
 * make our lives easier, we add `module.exports` statements to the JS source
 * files, so we can easily import their contents into our NodeJS-based test
 * suite.
 *
 * This works fine, but obviously, `module` is not defined when running
 * in-browser. So let's use this empty object as a shim, so we don't run into
 * runtime exceptions because of that.
 */
var module = {};
PK
!<6AA"lib/requestStorageAccess_helper.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* globals browser */

// Helper for calling the internal requestStorageAccessForOrigin method. The
// method is called on the first-party document for the third-party which needs
// first-party storage access.
browser.runtime.onMessage.addListener(request => {
  let { requestStorageAccessOrigin, warning } = request;
  if (!requestStorageAccessOrigin) {
    return false;
  }

  // Log a warning to the web console, informing about the shim.
  console.warn(warning);

  // Call the internal storage access API. Passing false means we don't require
  // user activation, but will always show the storage access prompt. The user
  // has to explicitly allow storage access.
  return document
    .requestStorageAccessForOrigin(requestStorageAccessOrigin, false)
    .then(() => {
      return { success: true };
    })
    .catch(() => {
      return { success: false };
    });
});
PK
!<�'Ŕ�lib/shim_messaging_helper.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser */

if (!window.Shims) {
  window.Shims = new Map();
}

if (!window.ShimsHelperReady) {
  window.ShimsHelperReady = true;

  browser.runtime.onMessage.addListener(details => {
    const { shimId, warning } = details;
    if (!shimId) {
      return;
    }
    window.Shims.set(shimId, details);
    if (warning) {
      console.warn(warning);
    }
  });

  async function handleMessage(port, shimId, messageId, message) {
    let response;
    const shim = window.Shims.get(shimId);
    if (shim) {
      const { needsShimHelpers, origin } = shim;
      if (origin === location.origin) {
        if (needsShimHelpers?.includes(message)) {
          const msg = { shimId, message };
          try {
            response = await browser.runtime.sendMessage(msg);
          } catch (_) {}
        }
      }
    }
    port.postMessage({ messageId, response });
  }

  window.addEventListener(
    "ShimConnects",
    e => {
      e.stopPropagation();
      e.preventDefault();
      const { port, pendingMessages, shimId } = e.detail;
      const shim = window.Shims.get(shimId);
      if (!shim) {
        return;
      }
      port.onmessage = ({ data }) => {
        handleMessage(port, shimId, data.messageId, data.message);
      };
      for (const [messageId, message] of pendingMessages) {
        handleMessage(port, shimId, messageId, message);
      }
    },
    true
  );

  window.dispatchEvent(new CustomEvent("ShimHelperReady"));
}
PK
!<1#h�|�|lib/shims.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser, module, onMessageFromTab */

// To grant shims access to bundled logo images without risking
// exposing our moz-extension URL, we have the shim request them via
// nonsense URLs which we then redirect to the actual files (but only
// on tabs where a shim using a given logo happens to be active).
const LogosBaseURL = "https://smartblock.firefox.etp/";

const releaseBranchPromise = browser.appConstants.getReleaseBranch();

const platformPromise = browser.runtime.getPlatformInfo().then(info => {
  return info.os === "android" ? "android" : "desktop";
});

let debug = async function () {
  if ((await releaseBranchPromise) !== "release_or_beta") {
    console.debug.apply(this, arguments);
  }
};
let error = async function () {
  if ((await releaseBranchPromise) !== "release_or_beta") {
    console.error.apply(this, arguments);
  }
};
let warn = async function () {
  if ((await releaseBranchPromise) !== "release_or_beta") {
    console.warn.apply(this, arguments);
  }
};

class Shim {
  constructor(opts, manager) {
    this.manager = manager;

    const { contentScripts, matches, unblocksOnOptIn } = opts;

    this.branches = opts.branches;
    this.bug = opts.bug;
    this.isGoogleTrendsDFPIFix = opts.custom == "google-trends-dfpi-fix";
    this.file = opts.file;
    this.hiddenInAboutCompat = opts.hiddenInAboutCompat;
    this.hosts = opts.hosts;
    this.id = opts.id;
    this.logos = opts.logos || [];
    this.matches = [];
    this.name = opts.name;
    this.notHosts = opts.notHosts;
    this.onlyIfBlockedByETP = opts.onlyIfBlockedByETP;
    this.onlyIfDFPIActive = opts.onlyIfDFPIActive;
    this.onlyIfPrivateBrowsing = opts.onlyIfPrivateBrowsing;
    this._options = opts.options || {};
    this.needsShimHelpers = opts.needsShimHelpers;
    this.platform = opts.platform || "all";
    this.runFirst = opts.runFirst;
    this.unblocksOnOptIn = unblocksOnOptIn;
    this.requestStorageAccessForRedirect = opts.requestStorageAccessForRedirect;
    this.shouldUseScriptingAPI =
      browser.aboutConfigPrefs.getBoolPrefSync("useScriptingAPI");
    debug(
      `WebCompat Shim ${this.id} will be injected using ${
        this.shouldUseScriptingAPI ? "scripting" : "contentScripts"
      } API`
    );

    this._hostOptIns = new Set();

    this._disabledByConfig = opts.disabled;
    this._disabledGlobally = false;
    this._disabledForSession = false;
    this._disabledByPlatform = false;
    this._disabledByReleaseBranch = false;

    this._activeOnTabs = new Set();
    this._showedOptInOnTabs = new Set();

    const pref = `disabled_shims.${this.id}`;

    this.redirectsRequests = !!this.file && matches?.length;

    // NOTE: _contentScriptRegistrations is an array of string ids when
    // shouldUseScriptingAPI is true and an array of script handles returned
    // by contentScripts.register otherwise.
    this._contentScriptRegistrations = [];

    this.contentScripts = contentScripts || [];
    for (const script of this.contentScripts) {
      if (typeof script.css === "string") {
        script.css = [
          this.shouldUseScriptingAPI
            ? `/shims/${script.css}`
            : { file: `/shims/${script.css}` },
        ];
      }
      if (typeof script.js === "string") {
        script.js = [
          this.shouldUseScriptingAPI
            ? `/shims/${script.js}`
            : { file: `/shims/${script.js}` },
        ];
      }
    }

    for (const match of matches || []) {
      if (!match.types) {
        this.matches.push({ patterns: [match], types: ["script"] });
      } else {
        this.matches.push(match);
      }
      if (match.target) {
        this.redirectsRequests = true;
      }
    }

    browser.aboutConfigPrefs.onPrefChange.addListener(async () => {
      const value = await browser.aboutConfigPrefs.getPref(pref);
      this._disabledPrefValue = value;
      this._onEnabledStateChanged();
    }, pref);

    this.ready = Promise.all([
      browser.aboutConfigPrefs.getPref(pref),
      platformPromise,
      releaseBranchPromise,
    ]).then(([disabledPrefValue, platform, branch]) => {
      this._disabledPrefValue = disabledPrefValue;

      this._disabledByPlatform =
        this.platform !== "all" && this.platform !== platform;

      this._disabledByReleaseBranch = false;
      for (const supportedBranchAndPlatform of this.branches || []) {
        const [supportedBranch, supportedPlatform] =
          supportedBranchAndPlatform.split(":");
        if (
          (!supportedPlatform || supportedPlatform == platform) &&
          supportedBranch != branch
        ) {
          this._disabledByReleaseBranch = true;
        }
      }

      this._preprocessOptions(platform, branch);
      this._onEnabledStateChanged();
    });
  }

  _preprocessOptions(platform, branch) {
    // options may be any value, but can optionally be gated for specified
    // platform/branches, if in the format `{value, branches, platform}`
    this.options = {};
    for (const [k, v] of Object.entries(this._options)) {
      if (v?.value) {
        if (
          (!v.platform || v.platform === platform) &&
          (!v.branches || v.branches.includes(branch))
        ) {
          this.options[k] = v.value;
        }
      } else {
        this.options[k] = v;
      }
    }
  }

  get enabled() {
    if (this._disabledGlobally || this._disabledForSession) {
      return false;
    }

    if (this._disabledPrefValue !== undefined) {
      return !this._disabledPrefValue;
    }

    return (
      !this._disabledByConfig &&
      !this._disabledByPlatform &&
      !this._disabledByReleaseBranch
    );
  }

  get disabledReason() {
    if (this._disabledGlobally) {
      return "globalPref";
    }

    if (this._disabledForSession) {
      return "session";
    }

    if (this._disabledPrefValue !== undefined) {
      if (this._disabledPrefValue === true) {
        return "pref";
      }
      return false;
    }

    if (this._disabledByConfig) {
      return "config";
    }

    if (this._disabledByPlatform) {
      return "platform";
    }

    if (this._disabledByReleaseBranch) {
      return "releaseBranch";
    }

    return false;
  }

  onAllShimsEnabled() {
    const wasEnabled = this.enabled;
    this._disabledGlobally = false;
    if (!wasEnabled) {
      this._onEnabledStateChanged();
    }
  }

  onAllShimsDisabled() {
    const wasEnabled = this.enabled;
    this._disabledGlobally = true;
    if (wasEnabled) {
      this._onEnabledStateChanged();
    }
  }

  enableForSession() {
    const wasEnabled = this.enabled;
    this._disabledForSession = false;
    if (!wasEnabled) {
      this._onEnabledStateChanged();
    }
  }

  disableForSession() {
    const wasEnabled = this.enabled;
    this._disabledForSession = true;
    if (wasEnabled) {
      this._onEnabledStateChanged();
    }
  }

  async _onEnabledStateChanged() {
    this.manager?.onShimStateChanged(this.id);
    if (!this.enabled) {
      await this._unregisterContentScripts();
      return this._revokeRequestsInETP();
    }
    await this._registerContentScripts();
    return this._allowRequestsInETP();
  }

  async _registerContentScripts() {
    if (
      this.contentScripts.length &&
      !this._contentScriptRegistrations.length
    ) {
      const matches = [];
      let idx = 0;
      for (const options of this.contentScripts) {
        matches.push(options.matches);
        if (this.shouldUseScriptingAPI) {
          // Some shims includes more than one script (e.g. Blogger one contains
          // a content script to be run on document_start and one to be run
          // on document_end.
          options.id = `shim-${this.id}-${idx++}`;
          options.persistAcrossSessions = false;
          // Having to call getRegisteredContentScripts each time we are going to
          // register a Shim content script is suboptimal, but avoiding that
          // may require a bit more changes (e.g. rework both Injections, Shim and Shims
          // classes to more easily register all content scripts with a single
          // call to the scripting API methods when the background script page is loading
          // and one per injection or shim being enabled from the AboutCompatBroker).
          // In the short term we call getRegisteredContentScripts and restrict it to
          // the script id we are about to register.
          let isAlreadyRegistered = false;
          try {
            const registeredScripts =
              await browser.scripting.getRegisteredContentScripts({
                ids: [options.id],
              });
            isAlreadyRegistered = !!registeredScripts.length;
          } catch (ex) {
            console.error(
              "Retrieve WebCompat GoFaster registered content scripts failed: ",
              ex
            );
          }
          try {
            if (!isAlreadyRegistered) {
              await browser.scripting.registerContentScripts([options]);
            }
            this._contentScriptRegistrations.push(options.id);
          } catch (ex) {
            console.error(
              "Registering WebCompat Shim content scripts failed: ",
              options,
              ex
            );
          }
        } else {
          const reg = await browser.contentScripts.register(options);
          this._contentScriptRegistrations.push(reg);
        }
      }
      const urls = Array.from(new Set(matches.flat()));
      debug("Enabling content scripts for these URLs:", urls);
    }
  }

  async _unregisterContentScripts() {
    if (this.shouldUseScriptingAPI) {
      const ids = this._contentScriptRegistrations;
      await browser.scripting.unregisterContentScripts({ ids });
    } else {
      for (const registration of this._contentScriptRegistrations) {
        registration.unregister();
      }
    }
    this._contentScriptRegistrations = [];
  }

  async _allowRequestsInETP() {
    const matches = this.matches.map(m => m.patterns).flat();
    if (matches.length) {
      await browser.trackingProtection.shim(this.id, matches);
    }

    if (this._hostOptIns.size) {
      const optIns = this.getApplicableOptIns();
      if (optIns.length) {
        await browser.trackingProtection.allow(
          this.id,
          this._optInPatterns,
          Array.from(this._hostOptIns)
        );
      }
    }
  }

  _revokeRequestsInETP() {
    return browser.trackingProtection.revoke(this.id);
  }

  setActiveOnTab(tabId, active = true) {
    if (active) {
      this._activeOnTabs.add(tabId);
    } else {
      this._activeOnTabs.delete(tabId);
      this._showedOptInOnTabs.delete(tabId);
    }
  }

  isActiveOnTab(tabId) {
    return this._activeOnTabs.has(tabId);
  }

  meantForHost(host) {
    const { hosts, notHosts } = this;
    if (hosts || notHosts) {
      if (
        (notHosts && notHosts.includes(host)) ||
        (hosts && !hosts.includes(host))
      ) {
        return false;
      }
    }
    return true;
  }

  async unblocksURLOnOptIn(url) {
    if (!this._optInPatterns) {
      this._optInPatterns = await this.getApplicableOptIns();
    }

    if (!this._optInMatcher) {
      this._optInMatcher = browser.matchPatterns.getMatcher(
        Array.from(this._optInPatterns)
      );
    }

    return this._optInMatcher.matches(url);
  }

  isTriggeredByURLAndType(url, type) {
    for (const entry of this.matches || []) {
      if (!entry.types.includes(type)) {
        continue;
      }
      if (!entry.matcher) {
        entry.matcher = browser.matchPatterns.getMatcher(
          Array.from(entry.patterns)
        );
      }
      if (entry.matcher.matches(url)) {
        return entry;
      }
    }

    return undefined;
  }

  async getApplicableOptIns() {
    if (this._applicableOptIns) {
      return this._applicableOptIns;
    }
    const optins = [];
    for (const unblock of this.unblocksOnOptIn || []) {
      if (typeof unblock === "string") {
        optins.push(unblock);
        continue;
      }
      const { branches, patterns, platforms } = unblock;
      if (platforms?.length) {
        const platform = await platformPromise;
        if (platform !== "all" && !platforms.includes(platform)) {
          continue;
        }
      }
      if (branches?.length) {
        const branch = await releaseBranchPromise;
        if (!branches.includes(branch)) {
          continue;
        }
      }
      optins.push.apply(optins, patterns);
    }
    this._applicableOptIns = optins;
    return optins;
  }

  async onUserOptIn(host) {
    const optins = await this.getApplicableOptIns();
    if (optins.length) {
      this.userHasOptedIn = true;
      this._hostOptIns.add(host);
      await browser.trackingProtection.allow(
        this.id,
        optins,
        Array.from(this._hostOptIns)
      );
    }
  }

  hasUserOptedInAlready(host) {
    return this._hostOptIns.has(host);
  }

  showOptInWarningOnce(tabId, origin) {
    if (this._showedOptInOnTabs.has(tabId)) {
      return Promise.resolve();
    }
    this._showedOptInOnTabs.add(tabId);

    const { bug, name } = this;
    const warning = `${name} is allowed on ${origin} for this browsing session due to user opt-in. See https://bugzilla.mozilla.org/show_bug.cgi?id=${bug} for details.`;
    return browser.tabs
      .executeScript(tabId, {
        code: `console.warn(${JSON.stringify(warning)})`,
        runAt: "document_start",
      })
      .catch(() => {});
  }
}

class Shims {
  constructor(availableShims) {
    if (!browser.trackingProtection) {
      console.error("Required experimental add-on APIs for shims unavailable");
      return;
    }

    this._registerShims(availableShims);

    onMessageFromTab(this._onMessageFromShim.bind(this));

    this.ENABLED_PREF = "enable_shims";
    browser.aboutConfigPrefs.onPrefChange.addListener(() => {
      this._checkEnabledPref();
    }, this.ENABLED_PREF);
    this._haveCheckedEnabledPref = this._checkEnabledPref();
  }

  bindAboutCompatBroker(broker) {
    this._aboutCompatBroker = broker;
  }

  getShimInfoForAboutCompat(shim) {
    const { bug, disabledReason, hiddenInAboutCompat, id, name } = shim;
    const type = "smartblock";
    return { bug, disabledReason, hidden: hiddenInAboutCompat, id, name, type };
  }

  disableShimForSession(id) {
    const shim = this.shims.get(id);
    shim?.disableForSession();
  }

  enableShimForSession(id) {
    const shim = this.shims.get(id);
    shim?.enableForSession();
  }

  onShimStateChanged(id) {
    if (!this._aboutCompatBroker) {
      return;
    }

    const shim = this.shims.get(id);
    if (!shim) {
      return;
    }

    const shimsChanged = [this.getShimInfoForAboutCompat(shim)];
    this._aboutCompatBroker.portsToAboutCompatTabs.broadcast({ shimsChanged });
  }

  getAvailableShims() {
    const shims = Array.from(this.shims.values()).map(
      this.getShimInfoForAboutCompat
    );
    shims.sort((a, b) => a.name.localeCompare(b.name));
    return shims;
  }

  _registerShims(shims) {
    if (this.shims) {
      throw new Error("_registerShims has already been called");
    }

    this.shims = new Map();
    for (const shimOpts of shims) {
      const { id } = shimOpts;
      if (!this.shims.has(id)) {
        this.shims.set(shimOpts.id, new Shim(shimOpts, this));
      }
    }

    // Register onBeforeRequest listener which handles storage access requests
    // on matching redirects.
    let redirectTargetUrls = Array.from(shims.values())
      .filter(shim => shim.requestStorageAccessForRedirect)
      .flatMap(shim => shim.requestStorageAccessForRedirect)
      .map(([, dstUrl]) => dstUrl);

    // Unique target urls.
    redirectTargetUrls = Array.from(new Set(redirectTargetUrls));

    if (redirectTargetUrls.length) {
      debug("Registering redirect listener for requestStorageAccess helper", {
        redirectTargetUrls,
      });
      browser.webRequest.onBeforeRequest.addListener(
        this._onRequestStorageAccessRedirect.bind(this),
        { urls: redirectTargetUrls, types: ["main_frame"] },
        ["blocking"]
      );
    }

    function addTypePatterns(type, patterns, set) {
      if (!set.has(type)) {
        set.set(type, { patterns: new Set() });
      }
      const allSet = set.get(type).patterns;
      for (const pattern of patterns) {
        allSet.add(pattern);
      }
    }

    const allMatchTypePatterns = new Map();
    const allHeaderChangingMatchTypePatterns = new Map();
    const allLogos = [];
    for (const shim of this.shims.values()) {
      const { logos, matches } = shim;
      allLogos.push(...logos);
      for (const { patterns, target, types } of matches || []) {
        for (const type of types) {
          if (shim.isGoogleTrendsDFPIFix) {
            addTypePatterns(type, patterns, allHeaderChangingMatchTypePatterns);
          }
          if (target || shim.file || shim.runFirst) {
            addTypePatterns(type, patterns, allMatchTypePatterns);
          }
        }
      }
    }

    if (allLogos.length) {
      const urls = Array.from(new Set(allLogos)).map(l => {
        return `${LogosBaseURL}${l}`;
      });
      debug("Allowing access to these logos:", urls);
      const unmarkShimsActive = tabId => {
        for (const shim of this.shims.values()) {
          shim.setActiveOnTab(tabId, false);
        }
      };
      browser.tabs.onRemoved.addListener(unmarkShimsActive);
      browser.tabs.onUpdated.addListener((tabId, changeInfo) => {
        if (changeInfo.discarded || changeInfo.url) {
          unmarkShimsActive(tabId);
        }
      });
      browser.webRequest.onBeforeRequest.addListener(
        this._redirectLogos.bind(this),
        { urls, types: ["image"] },
        ["blocking"]
      );
    }

    if (allHeaderChangingMatchTypePatterns) {
      for (const [
        type,
        { patterns },
      ] of allHeaderChangingMatchTypePatterns.entries()) {
        const urls = Array.from(patterns);
        debug("Shimming these", type, "URLs:", urls);
        browser.webRequest.onBeforeSendHeaders.addListener(
          this._onBeforeSendHeaders.bind(this),
          { urls, types: [type] },
          ["blocking", "requestHeaders"]
        );
        browser.webRequest.onHeadersReceived.addListener(
          this._onHeadersReceived.bind(this),
          { urls, types: [type] },
          ["blocking", "responseHeaders"]
        );
      }
    }

    if (!allMatchTypePatterns.size) {
      debug("Skipping shims; none enabled");
      return;
    }

    for (const [type, { patterns }] of allMatchTypePatterns.entries()) {
      const urls = Array.from(patterns);
      debug("Shimming these", type, "URLs:", urls);

      browser.webRequest.onBeforeRequest.addListener(
        this._ensureShimForRequestOnTab.bind(this),
        { urls, types: [type] },
        ["blocking"]
      );
    }
  }

  async _checkEnabledPref() {
    await browser.aboutConfigPrefs.getPref(this.ENABLED_PREF).then(value => {
      if (value === undefined) {
        browser.aboutConfigPrefs.setPref(this.ENABLED_PREF, true);
      } else if (value === false) {
        this.enabled = false;
      } else {
        this.enabled = true;
      }
    });
  }

  get enabled() {
    return this._enabled;
  }

  set enabled(enabled) {
    if (enabled === this._enabled) {
      return;
    }

    this._enabled = enabled;

    for (const shim of this.shims.values()) {
      if (enabled) {
        shim.onAllShimsEnabled();
      } else {
        shim.onAllShimsDisabled();
      }
    }
  }

  async _onRequestStorageAccessRedirect({
    originUrl: srcUrl,
    url: dstUrl,
    tabId,
  }) {
    debug("Detected redirect", { srcUrl, dstUrl, tabId });

    // Check if a shim needs to request storage access for this redirect. This
    // handler is called when the *source url* matches a shims redirect pattern,
    // but we still need to check if the *destination url* matches.
    const matchingShims = Array.from(this.shims.values()).filter(shim => {
      const { enabled, requestStorageAccessForRedirect } = shim;

      if (!enabled || !requestStorageAccessForRedirect) {
        return false;
      }

      return requestStorageAccessForRedirect.some(
        ([srcPattern, dstPattern]) =>
          browser.matchPatterns.getMatcher([srcPattern]).matches(srcUrl) &&
          browser.matchPatterns.getMatcher([dstPattern]).matches(dstUrl)
      );
    });

    // For each matching shim, find out if its enabled in regard to dFPI state.
    const bugNumbers = new Set();
    let isDFPIActive = null;
    await Promise.all(
      matchingShims.map(async shim => {
        if (shim.onlyIfDFPIActive) {
          // Only get the dFPI state for the first shim which requires it.
          if (isDFPIActive === null) {
            const tabIsPB = (await browser.tabs.get(tabId)).incognito;
            isDFPIActive = await browser.trackingProtection.isDFPIActive(
              tabIsPB
            );
          }
          if (!isDFPIActive) {
            return;
          }
        }
        bugNumbers.add(shim.bug);
      })
    );

    // If there is no shim which needs storage access for this redirect src/dst
    // pair, resume it.
    if (!bugNumbers.size) {
      return;
    }

    // Inject the helper to call requestStorageAccessForOrigin on the document.
    await browser.tabs.executeScript(tabId, {
      file: "/lib/requestStorageAccess_helper.js",
      runAt: "document_start",
    });

    const bugUrls = Array.from(bugNumbers)
      .map(bugNo => `https://bugzilla.mozilla.org/show_bug.cgi?id=${bugNo}`)
      .join(", ");
    const warning = `Firefox calls the Storage Access API for ${dstUrl} on behalf of ${srcUrl}. See the following bugs for details: ${bugUrls}`;

    // Request storage access for the origin of the destination url of the
    // redirect.
    const { origin: requestStorageAccessOrigin } = new URL(dstUrl);

    // Wait for the requestStorageAccess request to finish before resuming the
    // redirect.
    const { success } = await browser.tabs.sendMessage(tabId, {
      requestStorageAccessOrigin,
      warning,
    });
    debug("requestStorageAccess callback", {
      success,
      requestStorageAccessOrigin,
      srcUrl,
      dstUrl,
      bugNumbers,
    });
  }

  async _onMessageFromShim(payload, sender) {
    const { tab, frameId } = sender;
    const { id, url } = tab;
    const { shimId, message } = payload;

    // Ignore unknown messages (for instance, from about:compat).
    if (message !== "getOptions" && message !== "optIn") {
      return undefined;
    }

    if (sender.id !== browser.runtime.id || id === -1) {
      throw new Error("not allowed");
    }

    // Important! It is entirely possible for sites to spoof
    // these messages, due to shims allowing web pages to
    // communicate with the extension.

    const shim = this.shims.get(shimId);
    if (!shim?.needsShimHelpers?.includes(message)) {
      throw new Error("not allowed");
    }

    if (message === "getOptions") {
      return Object.assign(
        {
          platform: await platformPromise,
          releaseBranch: await releaseBranchPromise,
        },
        shim.options
      );
    } else if (message === "optIn") {
      try {
        await shim.onUserOptIn(new URL(url).hostname);
        const origin = new URL(tab.url).origin;
        warn(
          "** User opted in for",
          shim.name,
          "shim on",
          origin,
          "on tab",
          id,
          "frame",
          frameId
        );
        await shim.showOptInWarningOnce(id, origin);
      } catch (err) {
        console.error(err);
        throw new Error("error");
      }
    }

    return undefined;
  }

  async _redirectLogos(details) {
    await this._haveCheckedEnabledPref;

    if (!this.enabled) {
      return { cancel: true };
    }

    const { tabId, url } = details;
    const logo = new URL(url).pathname.slice(1);

    for (const shim of this.shims.values()) {
      await shim.ready;

      if (!shim.enabled) {
        continue;
      }

      if (shim.onlyIfDFPIActive) {
        const isPB = (await browser.tabs.get(details.tabId)).incognito;
        if (!(await browser.trackingProtection.isDFPIActive(isPB))) {
          continue;
        }
      }

      if (!shim.logos.includes(logo)) {
        continue;
      }

      if (shim.isActiveOnTab(tabId)) {
        return { redirectUrl: browser.runtime.getURL(`shims/${logo}`) };
      }
    }

    return { cancel: true };
  }

  async _onHeadersReceived(details) {
    await this._haveCheckedEnabledPref;

    for (const shim of this.shims.values()) {
      await shim.ready;

      if (!shim.enabled) {
        continue;
      }

      if (shim.onlyIfDFPIActive) {
        const isPB = (await browser.tabs.get(details.tabId)).incognito;
        if (!(await browser.trackingProtection.isDFPIActive(isPB))) {
          continue;
        }
      }

      if (shim.isGoogleTrendsDFPIFix) {
        if (shim.GoogleNidCookieToUse) {
          continue;
        }

        for (const header of details.responseHeaders) {
          if (header.name == "set-cookie") {
            shim.GoogleNidCookieToUse = header.value;
            return { redirectUrl: details.url };
          }
        }
      }
    }

    return undefined;
  }

  async _onBeforeSendHeaders(details) {
    await this._haveCheckedEnabledPref;

    const { frameId, requestHeaders, tabId } = details;

    if (!this.enabled) {
      return { requestHeaders };
    }

    for (const shim of this.shims.values()) {
      await shim.ready;

      if (!shim.enabled) {
        continue;
      }

      if (shim.isGoogleTrendsDFPIFix) {
        const value = shim.GoogleNidCookieToUse;

        if (!value) {
          continue;
        }

        let found;
        for (let header of requestHeaders) {
          if (header.name.toLowerCase() === "cookie") {
            header.value = value;
            found = true;
          }
        }
        if (!found) {
          requestHeaders.push({ name: "Cookie", value });
        }

        browser.tabs
          .get(tabId)
          .then(({ url }) => {
            debug(
              `Google Trends dFPI fix used on tab ${tabId} frame ${frameId} (${url})`
            );
          })
          .catch(() => {});

        const warning = `Working around Google Trends tracking protection breakage. See https://bugzilla.mozilla.org/show_bug.cgi?id=${shim.bug} for details.`;
        browser.tabs
          .executeScript(tabId, {
            code: `console.warn(${JSON.stringify(warning)})`,
            runAt: "document_start",
          })
          .catch(() => {});
      }
    }

    return { requestHeaders };
  }

  async _ensureShimForRequestOnTab(details) {
    await this._haveCheckedEnabledPref;

    if (!this.enabled) {
      return undefined;
    }

    // We only ever reach this point if a request is for a URL which ought to
    // be shimmed. We never get here if a request is blocked, and we only
    // unblock requests if at least one shim matches it.

    const { frameId, originUrl, requestId, tabId, type, url } = details;

    // Ignore requests unrelated to tabs
    if (tabId < 0) {
      return undefined;
    }

    // We need to base our checks not on the frame's host, but the tab's.
    const topHost = new URL((await browser.tabs.get(tabId)).url).hostname;
    const unblocked = await browser.trackingProtection.wasRequestUnblocked(
      requestId
    );

    let match;
    let shimToApply;
    for (const shim of this.shims.values()) {
      await shim.ready;

      if (!shim.enabled || (!shim.redirectsRequests && !shim.runFirst)) {
        continue;
      }

      if (shim.onlyIfDFPIActive || shim.onlyIfPrivateBrowsing) {
        const isPB = (await browser.tabs.get(details.tabId)).incognito;
        if (!isPB && shim.onlyIfPrivateBrowsing) {
          continue;
        }
        if (
          shim.onlyIfDFPIActive &&
          !(await browser.trackingProtection.isDFPIActive(isPB))
        ) {
          continue;
        }
      }

      // Do not apply the shim if it is only meant to apply when strict mode ETP
      // (content blocking) was going to block the request.
      if (!unblocked && shim.onlyIfBlockedByETP) {
        continue;
      }

      if (!shim.meantForHost(topHost)) {
        continue;
      }

      // If this URL and content type isn't meant for this shim, don't apply it.
      match = shim.isTriggeredByURLAndType(url, type);
      if (match) {
        if (!unblocked && match.onlyIfBlockedByETP) {
          continue;
        }

        // If the user has already opted in for this shim, all requests it covers
        // should be allowed; no need for a shim anymore.
        if (shim.hasUserOptedInAlready(topHost)) {
          warn(
            `Allowing tracking ${type} ${url} on tab ${tabId} frame ${frameId} due to opt-in`
          );
          shim.showOptInWarningOnce(tabId, new URL(originUrl).origin);
          return undefined;
        }
        shimToApply = shim;
        break;
      }
    }

    let runFirst = false;

    if (shimToApply) {
      // Note that sites may request the same shim twice, but because the requests
      // may differ enough for some to fail (CSP/CORS/etc), we always let the request
      // complete via local redirect. Shims should gracefully handle this as well.

      const { target } = match;
      const { bug, file, id, name, needsShimHelpers } = shimToApply;
      runFirst = shimToApply.runFirst;

      const redirect = target || file;

      warn(
        `Shimming tracking ${type} ${url} on tab ${tabId} frame ${frameId} with ${
          redirect || runFirst
        }`
      );

      const warning = `${name} is being shimmed by Firefox. See https://bugzilla.mozilla.org/show_bug.cgi?id=${bug} for details.`;

      let needConsoleMessage = true;

      if (runFirst) {
        try {
          await browser.tabs.executeScript(tabId, {
            file: `/shims/${runFirst}`,
            frameId,
            runAt: "document_start",
          });
        } catch (_) {}
      }

      // For scripts, we also set up any needed shim helpers.
      if (type === "script" && needsShimHelpers?.length) {
        try {
          await browser.tabs.executeScript(tabId, {
            file: "/lib/shim_messaging_helper.js",
            frameId,
            runAt: "document_start",
          });
          const origin = new URL(originUrl).origin;
          await browser.tabs.sendMessage(
            tabId,
            { origin, shimId: id, needsShimHelpers, warning },
            { frameId }
          );
          needConsoleMessage = false;
          shimToApply.setActiveOnTab(tabId);
        } catch (_) {}
      }

      if (needConsoleMessage) {
        try {
          await browser.tabs.executeScript(tabId, {
            code: `console.warn(${JSON.stringify(warning)})`,
            runAt: "document_start",
          });
        } catch (_) {}
      }

      if (!redirect.indexOf("http://") || !redirect.indexOf("https://")) {
        return { redirectUrl: redirect };
      }

      // If any shims matched the request to replace it, then redirect to the local
      // file bundled with SmartBlock, so the request never hits the network.
      return { redirectUrl: browser.runtime.getURL(`shims/${redirect}`) };
    }

    // Sanity check: if no shims end up handling this request,
    // yet it was meant to be blocked by ETP, then block it now.
    if (unblocked) {
      error(`unexpected: ${url} not shimmed on tab ${tabId} frame ${frameId}`);
      return { cancel: true };
    }

    if (!runFirst) {
      debug(`ignoring ${url} on tab ${tabId} frame ${frameId}`);
    }
    return undefined;
  }
}

module.exports = Shims;
PK
!<�S�Q��lib/ua_helpers.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals exportFunction, module */

var UAHelpers = {
  _deviceAppropriateChromeUAs: {},
  getDeviceAppropriateChromeUA(config = {}) {
    const { version = "103.0.5060.71", androidDevice, desktopOS } = config;
    const key = `${version}:${androidDevice}:${desktopOS}`;
    if (!UAHelpers._deviceAppropriateChromeUAs[key]) {
      const userAgent =
        typeof navigator !== "undefined" ? navigator.userAgent : "";
      const RunningFirefoxVersion = (userAgent.match(/Firefox\/([0-9.]+)/) || [
        "",
        "58.0",
      ])[1];

      if (userAgent.includes("Android")) {
        const RunningAndroidVersion =
          userAgent.match(/Android [0-9.]+/) || "Android 6.0";
        if (androidDevice) {
          UAHelpers._deviceAppropriateChromeUAs[
            key
          ] = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; ${androidDevice}) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Mobile Safari/537.36`;
        } else {
          const ChromePhoneUA = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; Nexus 5 Build/MRA58N) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Mobile Safari/537.36`;
          const ChromeTabletUA = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; Nexus 7 Build/JSS15Q) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`;
          const IsPhone = userAgent.includes("Mobile");
          UAHelpers._deviceAppropriateChromeUAs[key] = IsPhone
            ? ChromePhoneUA
            : ChromeTabletUA;
        }
      } else {
        let osSegment = "Windows NT 10.0; Win64; x64";
        if (desktopOS === "macOS" || userAgent.includes("Macintosh")) {
          osSegment = "Macintosh; Intel Mac OS X 10_15_7";
        }
        if (
          desktopOS !== "nonLinux" &&
          (desktopOS === "linux" || userAgent.includes("Linux"))
        ) {
          osSegment = "X11; Ubuntu; Linux x86_64";
        }

        UAHelpers._deviceAppropriateChromeUAs[
          key
        ] = `Mozilla/5.0 (${osSegment}) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`;
      }
    }
    return UAHelpers._deviceAppropriateChromeUAs[key];
  },
  getPrefix(originalUA) {
    return originalUA.substr(0, originalUA.indexOf(")") + 1);
  },
  overrideWithDeviceAppropriateChromeUA(config) {
    const chromeUA = UAHelpers.getDeviceAppropriateChromeUA(config);
    Object.defineProperty(window.navigator.wrappedJSObject, "userAgent", {
      get: exportFunction(() => chromeUA, window),
      set: exportFunction(function () {}, window),
    });
  },
  capVersionTo99(originalUA) {
    const ver = originalUA.match(/Firefox\/(\d+\.\d+)/);
    if (!ver || parseFloat(ver[1]) < 100) {
      return originalUA;
    }
    return originalUA
      .replace(`Firefox/${ver[1]}`, "Firefox/99.0")
      .replace(`rv:${ver[1]}`, "rv:99.0");
  },
  capRvTo109(originalUA) {
    const ver = originalUA.match(/rv:(\d+\.\d+)/);
    if (!ver || parseFloat(ver[1]) <= 109) {
      return originalUA;
    }
    return originalUA.replace(`rv:${ver[1]}`, "rv:109.0");
  },
  capVersionToNumber(originalUA, cap = 120) {
    const ver = originalUA.match(/Firefox\/(\d+\.\d+)/);
    if (!ver || parseFloat(ver[1]) <= cap) {
      return originalUA;
    }
    const capped = `Firefox/${cap}.0`;
    return originalUA.replace(`Firefox/${ver[1]}`, capped);
  },
  getWindowsUA(originalUA) {
    const rv = originalUA.match("rv:[0-9]+.[0-9]+")[0];
    const ver = originalUA.match("Firefox/[0-9]+.[0-9]+")[0];
    return `Mozilla/5.0 (Windows NT 10.0; Win64; x64; ${rv}) Gecko/20100101 ${ver}`;
  },
};

if (typeof module !== "undefined") {
  module.exports = UAHelpers;
}
PK
!<�`a>lib/ua_overrides.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser, module */

class UAOverrides {
  constructor(availableOverrides) {
    this.OVERRIDE_PREF = "perform_ua_overrides";

    this._overridesEnabled = true;

    this._availableOverrides = availableOverrides;
    this._activeListeners = new Map();
  }

  bindAboutCompatBroker(broker) {
    this._aboutCompatBroker = broker;
  }

  bootup() {
    browser.aboutConfigPrefs.onPrefChange.addListener(() => {
      this.checkOverridePref();
    }, this.OVERRIDE_PREF);
    this.checkOverridePref();
  }

  checkOverridePref() {
    browser.aboutConfigPrefs.getPref(this.OVERRIDE_PREF).then(value => {
      if (value === undefined) {
        browser.aboutConfigPrefs.setPref(this.OVERRIDE_PREF, true);
      } else if (value === false) {
        this.unregisterUAOverrides();
      } else {
        this.registerUAOverrides();
      }
    });
  }

  getAvailableOverrides() {
    return this._availableOverrides;
  }

  isEnabled() {
    return this._overridesEnabled;
  }

  enableOverride(override) {
    if (override.active) {
      return;
    }

    const { blocks, matches, uaTransformer } = override.config;
    const listener = details => {
      // Don't actually override the UA for an experiment if the user is not
      // part of the experiment (unless they force-enabed the override).
      if (
        !override.config.experiment ||
        override.permanentPrefEnabled === true
      ) {
        for (const header of details.requestHeaders) {
          if (header.name.toLowerCase() === "user-agent") {
            // Don't override the UA if we're on a mobile device that has the
            // "Request Desktop Site" mode enabled. The UA for the desktop mode
            // is set inside Gecko with a simple string replace, so we can use
            // that as a check, see https://searchfox.org/mozilla-central/rev/89d33e1c3b0a57a9377b4815c2f4b58d933b7c32/mobile/android/chrome/geckoview/GeckoViewSettingsChild.js#23-28
            let isMobileWithDesktopMode =
              override.currentPlatform == "android" &&
              header.value.includes("X11; Linux x86_64");

            if (!isMobileWithDesktopMode) {
              header.value = uaTransformer(header.value);
            }
          }
        }
      }
      return { requestHeaders: details.requestHeaders };
    };

    browser.webRequest.onBeforeSendHeaders.addListener(
      listener,
      { urls: matches },
      ["blocking", "requestHeaders"]
    );

    const listeners = { onBeforeSendHeaders: listener };
    if (blocks) {
      const blistener = () => {
        return { cancel: true };
      };

      browser.webRequest.onBeforeRequest.addListener(
        blistener,
        { urls: blocks },
        ["blocking"]
      );

      listeners.onBeforeRequest = blistener;
    }
    this._activeListeners.set(override, listeners);
    override.active = true;
  }

  onOverrideConfigChanged(override) {
    // Check whether the override should be hidden from about:compat.
    override.hidden = override.config.hidden;

    // Setting the override's permanent pref overrules whether it is hidden.
    if (override.permanentPrefEnabled !== undefined) {
      override.hidden = !override.permanentPrefEnabled;
    }

    // Also check whether the override should be active.
    let shouldBeActive = true;

    // Overrides can be force-deactivated by their permanent preference.
    if (override.permanentPrefEnabled === false) {
      shouldBeActive = false;
    }

    // Overrides gated behind an experiment the user is not part of do not
    // have to be activated, unless they are gathering telemetry, or the
    // user has force-enabled them with their permanent pref.
    if (override.config.experiment && override.permanentPrefEnabled !== true) {
      shouldBeActive = false;
    }

    if (shouldBeActive) {
      this.enableOverride(override);
    } else {
      this.disableOverride(override);
    }

    if (this._overridesEnabled) {
      this._aboutCompatBroker.portsToAboutCompatTabs.broadcast({
        overridesChanged: this._aboutCompatBroker.filterOverrides(
          this._availableOverrides
        ),
      });
    }
  }

  async registerUAOverrides() {
    const platformMatches = ["all"];
    let platformInfo = await browser.runtime.getPlatformInfo();
    platformMatches.push(platformInfo.os == "android" ? "android" : "desktop");

    for (const override of this._availableOverrides) {
      if (platformMatches.includes(override.platform)) {
        override.availableOnPlatform = true;
        override.currentPlatform = platformInfo.os;

        // If there is a specific about:config preference governing
        // this override, monitor its state.
        const pref = override.config.permanentPref;
        override.permanentPrefEnabled =
          pref && (await browser.aboutConfigPrefs.getPref(pref));
        if (pref) {
          const checkOverridePref = () => {
            browser.aboutConfigPrefs.getPref(pref).then(value => {
              override.permanentPrefEnabled = value;
              this.onOverrideConfigChanged(override);
            });
          };
          browser.aboutConfigPrefs.onPrefChange.addListener(
            checkOverridePref,
            pref
          );
        }

        this.onOverrideConfigChanged(override);
      }
    }

    this._overridesEnabled = true;
    this._aboutCompatBroker.portsToAboutCompatTabs.broadcast({
      overridesChanged: this._aboutCompatBroker.filterOverrides(
        this._availableOverrides
      ),
    });
  }

  unregisterUAOverrides() {
    for (const override of this._availableOverrides) {
      this.disableOverride(override);
    }

    this._overridesEnabled = false;
    this._aboutCompatBroker.portsToAboutCompatTabs.broadcast({
      overridesChanged: false,
    });
  }

  disableOverride(override) {
    if (!override.active) {
      return;
    }

    const listeners = this._activeListeners.get(override);
    for (const [name, listener] of Object.entries(listeners)) {
      browser.webRequest[name].removeListener(listener);
    }
    override.active = false;
    this._activeListeners.delete(override);
  }
}

module.exports = UAOverrides;
PK
!<���666
manifest.json{
  "manifest_version": 2,
  "name": "Web Compatibility Interventions",
  "description": "Urgent post-release fixes for web compatibility.",
  "version": "130.2.0",
  "browser_specific_settings": {
    "gecko": {
      "id": "webcompat@mozilla.org",
      "strict_min_version": "102.0"
    }
  },

  "experiment_apis": {
    "aboutConfigPrefs": {
      "schema": "experiment-apis/aboutConfigPrefs.json",
      "parent": {
        "scopes": ["addon_parent"],
        "script": "experiment-apis/aboutConfigPrefs.js",
        "paths": [["aboutConfigPrefs"]]
      },
      "child": {
        "scopes": ["addon_child"],
        "script": "experiment-apis/aboutConfigPrefsChild.js",
        "paths": [["aboutConfigPrefs"]]
      }
    },
    "appConstants": {
      "schema": "experiment-apis/appConstants.json",
      "parent": {
        "scopes": ["addon_parent"],
        "script": "experiment-apis/appConstants.js",
        "paths": [["appConstants"]]
      }
    },
    "aboutPage": {
      "schema": "about-compat/aboutPage.json",
      "parent": {
        "scopes": ["addon_parent"],
        "script": "about-compat/aboutPage.js",
        "events": ["startup"]
      }
    },
    "matchPatterns": {
      "schema": "experiment-apis/matchPatterns.json",
      "child": {
        "scopes": ["addon_child"],
        "script": "experiment-apis/matchPatterns.js",
        "paths": [["matchPatterns"]]
      }
    },
    "systemManufacturer": {
      "schema": "experiment-apis/systemManufacturer.json",
      "child": {
        "scopes": ["addon_child"],
        "script": "experiment-apis/systemManufacturer.js",
        "paths": [["systemManufacturer"]]
      }
    },
    "trackingProtection": {
      "schema": "experiment-apis/trackingProtection.json",
      "parent": {
        "scopes": ["addon_parent"],
        "script": "experiment-apis/trackingProtection.js",
        "paths": [["trackingProtection"]]
      }
    }
  },

  "content_security_policy": "script-src 'self' 'sha256-PeZc2H1vv7M8NXqlFyNbN4y4oM6wXmYEbf73m+Aqpak='; default-src 'self'; base-uri moz-extension://*; object-src 'none'",

  "permissions": [
    "mozillaAddons",
    "scripting",
    "tabs",
    "webNavigation",
    "webRequest",
    "webRequestBlocking",
    "<all_urls>"
  ],

  "background": {
    "scripts": [
      "lib/module_shim.js",
      "lib/messaging_helper.js",
      "lib/intervention_helpers.js",
      "lib/requestStorageAccess_helper.js",
      "lib/ua_helpers.js",
      "data/injections.js",
      "data/shims.js",
      "data/ua_overrides.js",
      "lib/about_compat_broker.js",
      "lib/custom_functions.js",
      "lib/injections.js",
      "lib/shims.js",
      "lib/ua_overrides.js",
      "run.js"
    ]
  },

  "web_accessible_resources": [
    "shims/addthis-angular.js",
    "shims/adform.js",
    "shims/adnexus-ast.js",
    "shims/adnexus-prebid.js",
    "shims/adsafeprotected-ima.js",
    "shims/apstag.js",
    "shims/blogger.js",
    "shims/bloggerAccount.js",
    "shims/bmauth.js",
    "shims/branch.js",
    "shims/chartbeat.js",
    "shims/crave-ca.js",
    "shims/criteo.js",
    "shims/cxense.js",
    "shims/doubleverify.js",
    "shims/eluminate.js",
    "shims/empty-script.js",
    "shims/empty-shim.txt",
    "shims/everest.js",
    "shims/facebook-sdk.js",
    "shims/facebook.svg",
    "shims/fastclick.js",
    "shims/firebase.js",
    "shims/google-ads.js",
    "shims/google-analytics-and-tag-manager.js",
    "shims/google-analytics-ecommerce-plugin.js",
    "shims/google-analytics-legacy.js",
    "shims/google-ima.js",
    "shims/google-page-ad.js",
    "shims/google-publisher-tags.js",
    "shims/google-safeframe.html",
    "shims/history.js",
    "shims/iam.js",
    "shims/iaspet.js",
    "shims/instagram.js",
    "shims/kinja.js",
    "shims/live-test-shim.js",
    "shims/maxmind-geoip.js",
    "shims/microsoftLogin.js",
    "shims/microsoftVirtualAssistant.js",
    "shims/moat.js",
    "shims/mochitest-shim-1.js",
    "shims/mochitest-shim-2.js",
    "shims/mochitest-shim-3.js",
    "shims/nielsen.js",
    "shims/optimizely.js",
    "shims/play.svg",
    "shims/rambler-authenticator.js",
    "shims/rich-relevance.js",
    "shims/salesforce.js",
    "shims/spotify-embed.js",
    "shims/tracking-pixel.png",
    "shims/tsn-ca.js",
    "shims/vast2.xml",
    "shims/vast3.xml",
    "shims/vidible.js",
    "shims/vmad.xml",
    "shims/webtrends.js"
  ]
}
PK
!<�����run.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals AboutCompatBroker, AVAILABLE_INJECTIONS, AVAILABLE_SHIMS,
           AVAILABLE_PIP_OVERRIDES, AVAILABLE_UA_OVERRIDES, CUSTOM_FUNCTIONS,
           Injections, Shims, UAOverrides */

let injections, shims, uaOverrides;

try {
  injections = new Injections(AVAILABLE_INJECTIONS, CUSTOM_FUNCTIONS);
  injections.bootup();
} catch (e) {
  console.error("Injections failed to start", e);
  injections = undefined;
}

try {
  uaOverrides = new UAOverrides(AVAILABLE_UA_OVERRIDES);
  uaOverrides.bootup();
} catch (e) {
  console.error("UA overrides failed to start", e);
  uaOverrides = undefined;
}

try {
  shims = new Shims(AVAILABLE_SHIMS);
} catch (e) {
  console.error("Shims failed to start", e);
  shims = undefined;
}

try {
  const aboutCompatBroker = new AboutCompatBroker({
    injections,
    shims,
    uaOverrides,
  });
  aboutCompatBroker.bootup();
} catch (e) {
  console.error("about:compat broker failed to start", e);
}
PK
!<���shims/addthis-angular.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713694 - Shim AddThis Angular module
 *
 * Sites using Angular with AddThis can break entirely if the module is
 * blocked. This shim mitigates that breakage by loading an empty module.
 */

if (!window.addthisModule) {
  window.addthisModule = window?.angular?.module("addthis", ["ng"]);
}
PK
!<KHm#shims/adform.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713695 - Shim Adform tracking
 *
 * Sites such as m.tim.it may gate content behind AdForm's trackpoint,
 * breaking download links and such if blocked. This shim stubs out the
 * script and its related tracking pixel, so the content still works.
 */

if (!window.Adform) {
  window.Adform = {
    Opt: {
      disableRedirect() {},
      getStatus(clientID, callback) {
        callback({
          clientID,
          errorMessage: undefined,
          optIn() {},
          optOut() {},
          status: "nocookie",
        });
      },
    },
  };
}
PK
!<!hv(shims/adnexus-ast.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1734130 - Shim AdNexus AST
 *
 * Some sites expect AST to successfully load, or they break.
 * This shim mitigates that breakage.
 */

if (!window.apntag?.loaded) {
  const anq = window.apntag?.anq || [];

  const gTags = new Map();
  const gAds = new Map();
  const gEventHandlers = {};

  const Ad = class {
    adType = "banner";
    auctionId = "-";
    banner = {
      width: 1,
      height: 1,
      content: "",
      trackers: {
        impression_urls: [],
        video_events: {},
      },
    };
    brandCategoryId = 0;
    buyerMemberId = 0;
    cpm = 0.1;
    cpm_publisher_currency = 0.1;
    creativeId = 0;
    dealId = undefined;
    height = 1;
    mediaSubtypeId = 1;
    mediaTypeId = 1;
    publisher_currency_code = "US";
    source = "-";
    tagId = -1;
    targetId = "";
    width = 1;

    constructor(tagId, targetId) {
      this.tagId = tagId;
      this.targetId = targetId;
    }
  };

  const fireAdEvent = (type, adObj) => {
    const { targetId } = adObj;
    const handlers = gEventHandlers[type]?.[targetId];
    if (!handlers) {
      return Promise.resolve();
    }
    const evt = { adObj, type };
    return new Promise(done => {
      setTimeout(() => {
        for (const cb of handlers) {
          try {
            cb(evt);
          } catch (e) {
            console.error(e);
          }
        }
        done();
      }, 1);
    });
  };

  const refreshTag = targetId => {
    const tag = gTags.get(targetId);
    if (!tag) {
      return;
    }
    if (!gAds.has(targetId)) {
      gAds.set(targetId, new Ad(tag.tagId, targetId));
    }
    const adObj = gAds.get(targetId);
    fireAdEvent("adRequested", adObj).then(() => {
      // TODO: do some sites expect adAvailable+adLoaded instead of adNoBid?
      fireAdEvent("adNoBid", adObj);
    });
  };

  const off = (type, targetId, cb) => {
    gEventHandlers[type]?.[targetId]?.delete(cb);
  };

  const on = (type, targetId, cb) => {
    gEventHandlers[type] = gEventHandlers[type] || {};
    gEventHandlers[type][targetId] =
      gEventHandlers[type][targetId] || new Set();
    gEventHandlers[type][targetId].add(cb);
  };

  const Tag = class {
    static #nextId = 0;
    debug = undefined;
    displayed = false;
    initialHeight = 1;
    initialWidth = 1;
    keywords = {};
    member = 0;
    showTagCalled = false;
    sizes = [];
    targetId = "";
    utCalled = true;
    utDivId = "";
    utiframeId = "";
    uuid = "";

    constructor(raw) {
      const { keywords, sizes, targetId } = raw;
      this.tagId = Tag.#nextId++;
      this.keywords = keywords || {};
      this.sizes = sizes || [];
      this.targetId = targetId || "";
    }
    modifyTag() {}
    off(type, cb) {
      off(type, this.targetId, cb);
    }
    on(type, cb) {
      on(type, this.targetId, cb);
    }
    setKeywords(kw) {
      this.keywords = kw;
    }
  };

  window.apntag = {
    anq,
    attachClickTrackers() {},
    checkAdAvailable() {},
    clearPageTargeting() {},
    clearRequest() {},
    collapseAd() {},
    debug: false,
    defineTag(dfn) {
      const { targetId } = dfn;
      if (!targetId) {
        return;
      }
      gTags.set(targetId, new Tag(dfn));
    },
    disableDebug() {},
    dongle: undefined,
    emitEvent(adObj, type) {
      fireAdEvent(type, adObj);
    },
    enableCookieSet() {},
    enableDebug() {},
    fireImpressionTrackers() {},
    getAdMarkup: () => "",
    getAdWrap() {},
    getAstVersion: () => "0.49.0",
    getPageTargeting() {},
    getTag(targetId) {
      return gTags.get(targetId);
    },
    handleCb() {},
    handleMediationBid() {},
    highlightAd() {},
    loaded: true,
    loadTags() {
      for (const tagName of gTags.keys()) {
        refreshTag(tagName);
      }
    },
    modifyTag() {},
    notify() {},
    offEvent(type, target, cb) {
      off(type, target, cb);
    },
    onEvent(type, target, cb) {
      on(type, target, cb);
    },
    recordErrorEvent() {},
    refresh() {},
    registerRenderer() {},
    requests: {},
    resizeAd() {},
    setEndpoint() {},
    setKeywords() {},
    setPageOpts() {},
    setPageTargeting() {},
    setSafeFrameConfig() {},
    setSizes() {},
    showTag() {},
  };

  const push = function (fn) {
    if (typeof fn === "function") {
      try {
        fn();
      } catch (e) {
        console.trace(e);
      }
    }
  };

  anq.push = push;

  anq.forEach(push);
}
PK
!<���99shims/adnexus-prebid.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1694401 - Shim Prebid.js
 *
 * Some sites rely on prebid.js to place content, perhaps in conjunction with
 * other services like Google Publisher Tags and Amazon TAM. This shim prevents
 * site breakage like image galleries breaking as the user browsers them, by
 * allowing the content placement to succeed.
 */

if (!window.pbjs?.requestBids) {
  const que = window.pbjs?.que || [];
  const cmd = window.pbjs?.cmd || [];
  const adUnits = window.pbjs?.adUnits || [];

  window.pbjs = {
    adUnits,
    addAdUnits(arr) {
      if (!Array.isArray(arr)) {
        arr = [arr];
      }
      adUnits.push(arr);
    },
    cmd,
    offEvent() {},
    que,
    refreshAds() {},
    removeAdUnit(codes) {
      if (!Array.isArray(codes)) {
        codes = [codes];
      }
      for (const code of codes) {
        for (let i = adUnits.length - 1; i >= 0; i--) {
          if (adUnits[i].code === code) {
            adUnits.splice(i, 1);
          }
        }
      }
    },
    renderAd() {},
    requestBids(params) {
      params?.bidsBackHandler?.();
    },
    setConfig() {},
    setTargetingForGPTAsync() {},
  };

  const push = function (fn) {
    if (typeof fn === "function") {
      try {
        fn();
      } catch (e) {
        console.trace(e);
      }
    }
  };

  que.push = push;
  cmd.push = push;

  que.forEach(push);
  cmd.forEach(push);
}
PK
!<�v�shims/adsafeprotected-ima.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 *
 * Sites relying on Ad Safe Protected's adapter for Google IMA may
 * have broken videos when the script is blocked. This shim stubs
 * out the API to help mitigate major breakage.
 */

if (!window.googleImaVansAdapter) {
  window.googleImaVansAdapter = {
    init() {},
    dispose() {},
  };
}
PK
!<LJ�22shims/apstag.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713698 - Shim Amazon Transparent Ad Marketplace's apstag.js
 *
 * Some sites such as politico.com rely on Amazon TAM tracker to serve ads,
 * breaking functionality like galleries if it is blocked. This shim helps
 * mitigate major breakage in that case.
 */

if (!window.apstag?._getSlotIdToNameMapping) {
  const _Q = window.apstag?._Q || [];

  const newBid = config => {
    return {
      amznbid: "",
      amzniid: "",
      amznp: "",
      amznsz: "0x0",
      size: "0x0",
      slotID: config.slotID,
    };
  };

  window.apstag = {
    _Q,
    _getSlotIdToNameMapping() {},
    bids() {},
    debug() {},
    deleteId() {},
    fetchBids(cfg, cb) {
      if (!Array.isArray(cfg?.slots)) {
        return;
      }
      setTimeout(() => {
        cb(cfg.slots.map(s => newBid(s)));
      }, 1);
    },
    init() {},
    punt() {},
    renderImp() {},
    renewId() {},
    setDisplayBids() {},
    targetingKeys: () => [],
    thirdPartyData: {},
    updateId() {},
  };

  window.apstagLOADED = true;

  _Q.push = function (prefix, args) {
    try {
      switch (prefix) {
        case "f":
          window.apstag.fetchBids(...args);
          break;
        case "i":
          window.apstag.init(...args);
          break;
      }
    } catch (e) {
      console.trace(e);
    }
  };

  for (const cmd of _Q) {
    _Q.push(cmd);
  }
}
PK
!<�Ɩo��shims/blogger.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* globals exportFunction */

"use strict";

/**
 * Blogger powered blogs rely on storage access to https://blogger.com to enable
 * oauth with Google. For dFPI, sites need to use the Storage Access API to gain
 * first party storage access. This shim calls requestStorageAccess on behalf of
 * the site when a user wants to log in via oauth.
 */

console.warn(
  `When using oauth, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1776869 for details.`
);

const GOOGLE_OAUTH_PATH_PREFIX = "https://accounts.google.com/ServiceLogin";

// After permission was granted request (use) storage access and reload
async function requestGrantedAccess() {
  const storageAccessPermission = await navigator.permissions.query({
    name: "storage-access",
  });
  const hasStorageAccess = await document.hasStorageAccess();
  if (storageAccessPermission.state === "granted" && !hasStorageAccess) {
    await document.requestStorageAccess();
    location.reload();
  }
}

requestGrantedAccess();

// Overwrite the window.open method so we can detect oauth related popups.
const origOpen = window.wrappedJSObject.open;
Object.defineProperty(window.wrappedJSObject, "open", {
  value: exportFunction((url, ...args) => {
    // Filter oauth popups.
    if (!url.startsWith(GOOGLE_OAUTH_PATH_PREFIX)) {
      return origOpen(url, ...args);
    }
    // Request storage access for the Blogger iframe.
    document.requestStorageAccess().then(() => {
      origOpen(url, ...args);
    });
    // We don't have the window object yet which window.open returns, since the
    // sign-in flow is dependent on the async storage access request. This isn't
    // a problem as long as the website does not consume it.
    return null;
  }, window),
});
PK
!<�����shims/bloggerAccount.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* globals exportFunction */

"use strict";

/**
 * Blogger uses Google as the auth provider. The account panel uses a
 * third-party iframe of https://ogs.google.com, which requires first-party
 * storage access to authenticate. This shim calls requestStorageAccess on
 * behalf of the site when the user opens the account panel.
 */

console.warn(
  `When logging in with Google, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1777690 for details.`
);

const STORAGE_ACCESS_ORIGIN = "https://ogs.google.com";

document.documentElement.addEventListener(
  "click",
  e => {
    const { target, isTrusted } = e;
    if (!isTrusted) {
      return;
    }

    const anchorEl = target.closest("a");
    if (!anchorEl) {
      return;
    }

    if (
      !anchorEl.href.startsWith("https://accounts.google.com/SignOutOptions")
    ) {
      return;
    }

    // The storage access request below runs async so the panel won't open
    // immediately. Mitigate this UX issue by updating the clicked element's
    // style so the user gets some immediate feedback.
    anchorEl.style.opacity = 0.5;
    e.stopPropagation();
    e.preventDefault();

    document
      .requestStorageAccessForOrigin(STORAGE_ACCESS_ORIGIN)
      .then(() => {
        // Reload all iframes of ogs.google.com so the first-party cookies are
        // sent to the server.
        // The reload mechanism here is a bit of a hack, since we don't have
        // access to the content window of a cross-origin iframe.
        document
          .querySelectorAll("iframe[src^='https://ogs.google.com/']")
          .forEach(frame => (frame.src += ""));
      })
      // Show the panel in both success and error state. When the user denies
      // the storage access prompt they will see an error message in the account
      // panel.
      .finally(() => {
        anchorEl.style.opacity = 1.0;
        target.click();
      });
  },
  true
);
PK
!<��	�shims/bmauth.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

if (!window.BmAuth) {
  window.BmAuth = {
    init: () => new Promise(() => {}),
    handleSignIn: () => {
      // TODO: handle this properly!
    },
    isAuthenticated: () => Promise.resolve(false),
    addListener: () => {},
    api: {
      event: {
        addListener: () => {},
      },
    },
  };
}
PK
!<� ��shims/branch.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1716220 - Shim Branch Web SDK
 *
 * Sites such as TataPlay may not load properly if Branch Web SDK is
 * blocked. This shim stubs out its script so the page still loads.
 */

if (!window?.branch?.b) {
  const queue = window?.branch?._q || [];
  window.branch = new (class {
    V = {};
    g = 0;
    X = "web2.62.0";
    b = {
      A: {},
      clear() {},
      get() {},
      getAll() {},
      isEnabled: () => true,
      remove() {},
      set() {},
      ca() {},
      g: [],
      l: 0,
      o: 0,
      s: null,
    };
    addListener() {}
    applyCode() {}
    autoAppIndex() {}
    banner() {}
    c() {}
    closeBanner() {}
    closeJourney() {}
    constructor() {}
    creditHistory() {}
    credits() {}
    crossPlatformIds() {}
    data() {}
    deepview() {}
    deepviewCta() {}
    disableTracking() {}
    first() {}
    getBrowserFingerprintId() {}
    getCode() {}
    init(key, ...args) {
      const cb = args.pop();
      if (typeof cb === "function") {
        cb(undefined, {});
      }
    }
    lastAttributedTouchData() {}
    link() {}
    logEvent() {}
    logout() {}
    qrCode() {}
    redeem() {}
    referrals() {}
    removeListener() {}
    renderFinalize() {}
    renderQueue() {}
    sendSMS() {}
    setAPIResponseCallback() {}
    setBranchViewData() {}
    setIdentity() {}
    track() {}
    trackCommerceEvent() {}
    validateCode() {}
  })();
  const push = ([fn, ...args]) => {
    try {
      window.branch[fn].apply(window.branch, args);
    } catch (e) {
      console.error(e);
    }
  };
  queue.forEach(push);
}
PK
!<�	�shims/chartbeat.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713699 - Shim ChartBeat tracking
 *
 * Sites may rely on chartbeat's tracking as they might with Google Analytics,
 * expecting it to be present for interactive site content to function. This
 * shim mitigates related breakage.
 */

window.pSUPERFLY = {
  activity() {},
  virtualPage() {},
};
PK
!<�e'�LLshims/crave-ca.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/*
 * Bug 1746439 - crave.ca login broken with dFPI enabled
 *
 * Crave.ca relies upon a login page that is out-of-origin. That login page
 * sets a cookie for https://www.crave.ca, which is then used as an proof of
 * authentication on redirect back to the main site. This shim adds a request
 * for storage access for https://www.crave.ca when the user tries to log in.
 */

console.warn(
  `When logging in, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1746439 for details.`
);

// Third-party origin we need to request storage access for.
const STORAGE_ACCESS_ORIGIN = "https://www.crave.ca";

document.documentElement.addEventListener(
  "click",
  e => {
    const { target, isTrusted } = e;
    if (!isTrusted) {
      return;
    }
    const button = target.closest("button");
    if (!button) {
      return;
    }
    const form = target.closest(".login-form");
    if (!form) {
      return;
    }

    console.warn(
      "Calling the Storage Access API on behalf of " + STORAGE_ACCESS_ORIGIN
    );
    button.disabled = true;
    e.stopPropagation();
    e.preventDefault();
    document
      .requestStorageAccessForOrigin(STORAGE_ACCESS_ORIGIN)
      .then(() => {
        button.disabled = false;
        target.click();
      })
      .catch(() => {
        button.disabled = false;
      });
  },
  true
);
PK
!<���	��shims/criteo.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713720 - Shim Criteo
 *
 * Sites relying on window.Criteo to be loaded can experience
 * breakage if it is blocked. Stubbing out the API in a shim can
 * mitigate this breakage.
 */

if (window.Criteo?.CallRTA === undefined) {
  window.Criteo = {
    CallRTA() {},
    ComputeStandaloneDFPTargeting() {},
    DisplayAcceptableAdIfAdblocked() {},
    DisplayAd() {},
    GetBids() {},
    GetBidsForAdUnit() {},
    Passback: {
      RequestBids() {},
      RenderAd() {},
    },
    PubTag: {
      Adapters: {
        AMP() {},
        Prebid() {},
      },
      Context: {
        GetIdfs() {},
        SetIdfs() {},
      },
      DirectBidding: {
        DirectBiddingEvent() {},
        DirectBiddingSlot() {},
        DirectBiddingUrlBuilder() {},
        Size() {},
      },
      RTA: {
        DefaultCrtgContentName: "crtg_content",
        DefaultCrtgRtaCookieName: "crtg_rta",
      },
    },
    RenderAd() {},
    RequestBids() {},
    RequestBidsOnGoogleTagSlots() {},
    SetCCPAExplicitOptOut() {},
    SetCeh() {},
    SetDFPKeyValueTargeting() {},
    SetLineItemRanges() {},
    SetPublisherExt() {},
    SetSlotsExt() {},
    SetTargeting() {},
    SetUserExt() {},
    events: {
      push() {},
    },
    passbackEvents: [],
    usePrebidEvents: true,
  };
}
PK
!<��QAQAshims/cxense.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713721 - Shim Cxense
 *
 * Sites relying on window.cX can experience breakage if it is blocked.
 * Stubbing out the API in a shim can mitigate this breakage. There are
 * two versions of the API, one including window.cX.CCE, but both appear
 * to be very similar so we use one shim for both.
 */

if (window.cX?.getUserSegmentIds === undefined) {
  const callQueue = window.cX?.callQueue || [];
  const callQueueCCE = window.cX?.CCE?.callQueue || [];

  function getRandomString(l = 16) {
    const v = crypto.getRandomValues(new Uint8Array(l));
    const s = Array.from(v, c => c.toString(16)).join("");
    return s.slice(0, l);
  }

  const call = (cb, ...args) => {
    if (typeof cb !== "function") {
      return;
    }
    try {
      cb(...args);
    } catch (e) {
      console.error(e);
    }
  };

  const invokeOn = lib => {
    return (fn, ...args) => {
      try {
        lib[fn](...args);
      } catch (e) {
        console.error(e);
      }
    };
  };

  const userId = getRandomString();
  const cxUserId = `cx:${getRandomString(25)}:${getRandomString(12)}`;
  const topLeft = { left: 0, top: 0 };
  const margins = { left: 0, top: 0, right: 0, bottom: 0 };
  const ccePushUrl =
    "https://comcluster.cxense.com/cce/push?callback={{callback}}";
  const displayWidget = (divId, a, ctx, callback) => call(callback, ctx, divId);
  const getUserSegmentIds = a => call(a?.callback, a?.defaultValue || []);
  const init = (a, b, c, d, callback) => call(callback);
  const render = (a, data, ctx, callback) => call(callback, data, ctx);
  const run = (params, ctx, callback) => call(callback, params, ctx);
  const runCtrlVersion = (a, b, callback) => call(callback);
  const runCxVersion = (a, data, b, ctx, callback) => call(callback, data, ctx);
  const runTest = (a, divId, b, c, ctx, callback) => call(callback, divId, ctx);
  const sendConversionEvent = (a, options) => call(options?.callback, {});
  const sendEvent = (a, b, args) => call(args?.callback, {});

  const getDivId = className => {
    const e = document.querySelector(`.${className}`);
    if (e) {
      return `${className}-01`;
    }
    return null;
  };

  const getDocumentSize = () => {
    const width = document.body.clientWidth;
    const height = document.body.clientHeight;
    return { width, height };
  };

  const getNowSeconds = () => {
    return Math.round(new Date().getTime() / 1000);
  };

  const getPageContext = () => {
    return {
      location: location.href,
      pageViewRandom: "",
      userId,
    };
  };

  const getWindowSize = () => {
    const width = window.innerWidth;
    const height = window.innerHeight;
    return { width, height };
  };

  const isObject = i => {
    return typeof i === "object" && i !== null && !Array.isArray(i);
  };

  const runMulti = widgets => {
    widgets?.forEach(({ widgetParams, widgetContext, widgetCallback }) => {
      call(widgetCallback, widgetParams, widgetContext);
    });
  };

  let testGroup = -1;
  let snapPoints = [];
  const startTime = new Date();

  const library = {
    addCustomerScript() {},
    addEventListener() {},
    addExternalId() {},
    afterInitializePage() {},
    allUserConsents() {},
    backends: {
      production: {
        baseAdDeliveryUrl: "http://adserver.cxad.cxense.com/adserver/search",
        secureBaseAdDeliveryUrl:
          "https://s-adserver.cxad.cxense.com/adserver/search",
      },
      sandbox: {
        baseAdDeliveryUrl:
          "http://adserver.sandbox.cxad.cxense.com/adserver/search",
        secureBaseAdDeliveryUrl:
          "https://s-adserver.sandbox.cxad.cxense.com/adserver/search",
      },
    },
    calculateAdSpaceSize(adCount, adUnitSize, marginA, marginB) {
      return adCount * (adUnitSize + marginA + marginB);
    },
    cdn: {
      template: {
        direct: {
          http: "http://cdn.cxpublic.com/",
          https: "https://cdn.cxpublic.com/",
        },
        mapped: {
          http: "http://cdn-templates.cxpublic.com/",
          https: "https://cdn-templates.cxpublic.com/",
        },
      },
    },
    cint() {},
    cleanUpGlobalIds: [],
    clearBaseUrl: "https://scdn.cxense.com/sclear.html",
    clearCustomParameters() {},
    clearIdUrl: "https://scomcluster.cxense.com/public/clearid",
    clearIds() {},
    clickTracker: (a, b, callback) => call(callback),
    clientStorageUrl: "https://clientstorage.cxense.com",
    combineArgs: () => Object.create(),
    combineKeywordsIntoArray: () => [],
    consentClasses: ["pv", "segment", "ad", "recs"],
    consentClassesV2: ["geo", "device"],
    cookieSyncRUrl: "csyn-r.cxense.com",
    createDelegate() {},
    csdUrls: {
      domainScriptUrl: "//csd.cxpublic.com/d/",
      customerScriptUrl: "//csd.cxpublic.com/t/",
    },
    cxenseGlobalIdIframeUrl: "https://scdn.cxense.com/sglobal.html",
    cxenseUserIdUrl: "https://id.cxense.com/public/user/id",
    decodeUrlEncodedNameValuePairs: () => Object.create(),
    defaultAdRenderer: () => "",
    deleteCookie() {},
    denyWithoutConsent: {
      addExternalId: "pv",
      getUserSegmentIds: "segment",
      insertAdSpace: "ad",
      insertMultipleAdSpaces: "ad",
      sendEvent: "pv",
      sendPageViewEvent: "pv",
      sync: "ad",
    },
    dmpPushUrl: "https://comcluster.cxense.com/dmp/push?callback={{callback}}",
    emptyWidgetUrl: "https://scdn.cxense.com/empty.html",
    eventReceiverBaseUrl: "https://scomcluster.cxense.com/Repo/rep.html",
    eventReceiverBaseUrlGif: "https://scomcluster.cxense.com/Repo/rep.gif",
    getAllText: () => "",
    getClientStorageVariable() {},
    getCookie: () => null,
    getCxenseUserId: () => cxUserId,
    getDocumentSize,
    getElementPosition: () => topLeft,
    getHashFragment: () => location.hash.substr(1),
    getLocalStats: () => Object.create(),
    getNodeValue: n => n.nodeValue,
    getNowSeconds,
    getPageContext,
    getRandomString,
    getScrollPos: () => topLeft,
    getSessionId: () => "",
    getSiteId: () => "",
    getTimezoneOffset: () => new Date().getTimezoneOffset(),
    getTopLevelDomain: () => location.hostname,
    getUserId: () => userId,
    getUserSegmentIds,
    getWindowSize,
    hasConsent: () => true,
    hasHistory: () => true,
    hasLocalStorage: () => true,
    hasPassiveEventListeners: () => true,
    hasPostMessage: () => true,
    hasSessionStorage() {},
    initializePage() {},
    insertAdSpace() {},
    insertMultipleAdSpaces() {},
    insertWidget() {},
    invoke: invokeOn(library),
    isAmpIFrame() {},
    isArray() {},
    isCompatModeActive() {},
    isConsentRequired() {},
    isEdge: () => false,
    isFirefox: () => true,
    isIE6Or7: () => false,
    isObject,
    isRecsDestination: () => false,
    isSafari: () => false,
    isTextNode: n => n?.nodeType === 3,
    isTopWindow: () => window === top,
    jsonpRequest: () => false,
    loadScript() {},
    m_accountId: "0",
    m_activityEvents: false,
    m_activityState: {
      activeTime: startTime,
      currScrollLeft: 0,
      currScrollTop: 0,
      exitLink: "",
      hadHIDActivity: false,
      maxViewLeft: 1,
      maxViewTop: 1,
      parentMetrics: undefined,
      prevActivityTime: startTime + 2,
      prevScreenX: 0,
      prevScreenY: 0,
      prevScrollLeft: 0,
      prevScrollTop: 0,
      prevTime: startTime + 1,
      prevWindowHeight: 1,
      prevWindowWidth: 1,
      scrollDepthPercentage: 0,
      scrollDepthPixels: 0,
    },
    m_atfr: null,
    m_c1xTpWait: 0,
    m_clientStorage: {
      iframeEl: null,
      iframeIsLoaded: false,
      iframeOrigin: "https://clientstorage.cxense.com",
      iframePath: "/clientstorage_v2.html",
      messageContexts: {},
      messageQueue: [],
    },
    m_compatMode: {},
    m_compatModeActive: false,
    m_compatPvSent: false,
    m_consentVersion: 1,
    m_customParameters: [],
    m_documentSizeRequestedFromChild: false,
    m_externalUserIds: [],
    m_globalIdLoading: {
      globalIdIFrameEl: null,
      globalIdIFrameElLoaded: false,
    },
    m_isSpaRecsDestination: false,
    m_knownMessageSources: [],
    m_p1Complete: false,
    m_prevLocationHash: "",
    m_previousPageViewReport: null,
    m_rawCustomParameters: {},
    m_rnd: getRandomString(),
    m_scriptStartTime: startTime,
    m_siteId: "0",
    m_spaRecsClickUrl: null,
    m_thirdPartyIds: true,
    m_usesConsent: false,
    m_usesIabConsent: false,
    m_usesSecureCookies: true,
    m_usesTcf20Consent: false,
    m_widgetSpecs: {},
    Object,
    onClearIds() {},
    onFFP1() {},
    onP1() {},
    p1BaseUrl: "https://scdn.cxense.com/sp1.html",
    p1JsUrl: "https://p1cluster.cxense.com/p1.js",
    parseHashArgs: () => Object.create(),
    parseMargins: () => margins,
    parseUrlArgs: () => Object.create(),
    postMessageToParent() {},
    publicWidgetDataUrl: "https://api.cxense.com/public/widget/data",
    removeClientStorageVariable() {},
    removeEventListener() {},
    renderContainedImage: () => "<div/>",
    renderTemplate: () => "<div/>",
    reportActivity() {},
    requireActivityEvents() {},
    requireConsent() {},
    requireOnlyFirstPartyIds() {},
    requireSecureCookies() {},
    requireTcf20() {},
    sendEvent,
    sendSpaRecsClick: (a, callback) => call(callback),
    setAccountId() {},
    setAllConsentsTo() {},
    setClientStorageVariable() {},
    setCompatMode() {},
    setConsent() {},
    setCookie() {},
    setCustomParameters() {},
    setEventAttributes() {},
    setGeoPosition() {},
    setNodeValue() {},
    setRandomId() {},
    setRestrictionsToConsentClasses() {},
    setRetargetingParameters() {},
    setSiteId() {},
    setUserProfileParameters() {},
    setupIabCmp() {},
    setupTcfApi() {},
    shouldPollActivity() {},
    startLocalStats() {},
    startSessionAnnotation() {},
    stopAllSessionAnnotations() {},
    stopSessionAnnotation() {},
    sync() {},
    trackAmpIFrame() {},
    trackElement() {},
    trim: s => s.trim(),
    tsridUrl: "https://tsrid.cxense.com/lookup?callback={{callback}}",
    userSegmentUrl:
      "https://api.cxense.com/profile/user/segment?callback={{callback}}",
  };

  const libraryCCE = {
    "__cx-toolkit__": {
      isShown: true,
      data: [],
    },
    activeSnapPoint: null,
    activeWidgets: [],
    ccePushUrl,
    clickTracker: () => "",
    displayResult() {},
    displayWidget,
    getDivId,
    getTestGroup: () => testGroup,
    init,
    insertMaster() {},
    instrumentClickLinks() {},
    invoke: invokeOn(libraryCCE),
    noCache: false,
    offerProductId: null,
    persistedQueryId: null,
    prefix: null,
    previewCampaign: null,
    previewDiv: null,
    previewId: null,
    previewTestId: null,
    processCxResult() {},
    render,
    reportTestImpression() {},
    run,
    runCtrlVersion,
    runCxVersion,
    runMulti,
    runTest,
    sendConversionEvent,
    sendPageViewEvent: (a, b, c, callback) => call(callback),
    setSnapPoints(x) {
      snapPoints = x;
    },
    setTestGroup(x) {
      testGroup = x;
    },
    setVisibilityField() {},
    get snapPoints() {
      return snapPoints;
    },
    startTime,
    get testGroup() {
      return testGroup;
    },
    testVariant: null,
    trackTime: 0.5,
    trackVisibility() {},
    updateRecsClickUrls() {},
    utmParams: [],
    version: "2.42",
    visibilityField: "timeHalf",
  };

  const CCE = {
    activeSnapPoint: null,
    activeWidgets: [],
    callQueue: callQueueCCE,
    ccePushUrl,
    clickTracker: () => "",
    displayResult() {},
    displayWidget,
    getDivId,
    getTestGroup: () => testGroup,
    init,
    insertMaster() {},
    instrumentClickLinks() {},
    invoke: invokeOn(libraryCCE),
    library: libraryCCE,
    noCache: false,
    offerProductId: null,
    persistedQueryId: null,
    prefix: null,
    previewCampaign: null,
    previewDiv: null,
    previewId: null,
    previewTestId: null,
    processCxResult() {},
    render,
    reportTestImpression() {},
    run,
    runCtrlVersion,
    runCxVersion,
    runMulti,
    runTest,
    sendConversionEvent,
    sendPageViewEvent: (a, b, c, callback) => call(callback),
    setSnapPoints(x) {
      snapPoints = x;
    },
    setTestGroup(x) {
      testGroup = x;
    },
    setVisibilityField() {},
    get snapPoints() {
      return snapPoints;
    },
    startTime,
    get testGroup() {
      return testGroup;
    },
    testVariant: null,
    trackTime: 0.5,
    trackVisibility() {},
    updateRecsClickUrls() {},
    utmParams: [],
    version: "2.42",
    visibilityField: "timeHalf",
  };

  window.cX = {
    addCustomerScript() {},
    addEventListener() {},
    addExternalId() {},
    afterInitializePage() {},
    allUserConsents: () => undefined,
    Array,
    calculateAdSpaceSize: () => 0,
    callQueue,
    CCE,
    cint: () => undefined,
    clearCustomParameters() {},
    clearIds() {},
    clickTracker: () => "",
    combineArgs: () => Object.create(),
    combineKeywordsIntoArray: () => [],
    createDelegate() {},
    decodeUrlEncodedNameValuePairs: () => Object.create(),
    defaultAdRenderer: () => "",
    deleteCookie() {},
    getAllText: () => "",
    getClientStorageVariable() {},
    getCookie: () => null,
    getCxenseUserId: () => cxUserId,
    getDocumentSize,
    getElementPosition: () => topLeft,
    getHashFragment: () => location.hash.substr(1),
    getLocalStats: () => Object.create(),
    getNodeValue: n => n.nodeValue,
    getNowSeconds,
    getPageContext,
    getRandomString,
    getScrollPos: () => topLeft,
    getSessionId: () => "",
    getSiteId: () => "",
    getTimezoneOffset: () => new Date().getTimezoneOffset(),
    getTopLevelDomain: () => location.hostname,
    getUserId: () => userId,
    getUserSegmentIds,
    getWindowSize,
    hasConsent: () => true,
    hasHistory: () => true,
    hasLocalStorage: () => true,
    hasPassiveEventListeners: () => true,
    hasPostMessage: () => true,
    hasSessionStorage() {},
    initializePage() {},
    insertAdSpace() {},
    insertMultipleAdSpaces() {},
    insertWidget() {},
    invoke: invokeOn(library),
    isAmpIFrame() {},
    isArray() {},
    isCompatModeActive() {},
    isConsentRequired() {},
    isEdge: () => false,
    isFirefox: () => true,
    isIE6Or7: () => false,
    isObject,
    isRecsDestination: () => false,
    isSafari: () => false,
    isTextNode: n => n?.nodeType === 3,
    isTopWindow: () => window === top,
    JSON,
    jsonpRequest: () => false,
    library,
    loadScript() {},
    Object,
    onClearIds() {},
    onFFP1() {},
    onP1() {},
    parseHashArgs: () => Object.create(),
    parseMargins: () => margins,
    parseUrlArgs: () => Object.create(),
    postMessageToParent() {},
    removeClientStorageVariable() {},
    removeEventListener() {},
    renderContainedImage: () => "<div/>",
    renderTemplate: () => "<div/>",
    reportActivity() {},
    requireActivityEvents() {},
    requireConsent() {},
    requireOnlyFirstPartyIds() {},
    requireSecureCookies() {},
    requireTcf20() {},
    sendEvent,
    sendPageViewEvent: (a, callback) => call(callback, {}),
    sendSpaRecsClick() {},
    setAccountId() {},
    setAllConsentsTo() {},
    setClientStorageVariable() {},
    setCompatMode() {},
    setConsent() {},
    setCookie() {},
    setCustomParameters() {},
    setEventAttributes() {},
    setGeoPosition() {},
    setNodeValue() {},
    setRandomId() {},
    setRestrictionsToConsentClasses() {},
    setRetargetingParameters() {},
    setSiteId() {},
    setUserProfileParameters() {},
    setupIabCmp() {},
    setupTcfApi() {},
    shouldPollActivity() {},
    startLocalStats() {},
    startSessionAnnotation() {},
    stopAllSessionAnnotations() {},
    stopSessionAnnotation() {},
    sync() {},
    trackAmpIFrame() {},
    trackElement() {},
    trim: s => s.trim(),
  };

  window.cxTest = window.cX;

  window.cx_pollActiveTime = () => undefined;
  window.cx_pollActivity = () => undefined;
  window.cx_pollFragmentMessage = () => undefined;

  const execQueue = (lib, queue) => {
    return () => {
      const invoke = invokeOn(lib);
      setTimeout(() => {
        queue.push = cmd => {
          setTimeout(() => invoke(...cmd), 1);
        };
        for (const cmd of queue) {
          invoke(...cmd);
        }
      }, 25);
    };
  };

  window.cx_callQueueExecute = execQueue(library, callQueue);
  window.cxCCE_callQueueExecute = execQueue(libraryCCE, callQueueCCE);

  window.cx_callQueueExecute();
  window.cxCCE_callQueueExecute();
}
PK
!<yaYT))shims/doubleverify.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1771557 - Shim DoubleVerify analytics
 *
 * Some sites such as Sports Illustrated expect DoubleVerify's
 * analytics script to load, otherwise odd breakage may occur.
 * This shim helps mitigate such breakage.
 */

if (!window?.PQ?.loaded) {
  const cmd = [];
  cmd.push = function (c) {
    try {
      c?.();
    } catch (_) {}
  };

  window.apntag = {
    anq: [],
  };

  window.PQ = {
    cmd,
    loaded: true,
    getTargeting: (_, cb) => cb?.([]),
    init: () => {},
    loadSignals: (_, cb) => cb?.(),
    loadSignalsForSlots: (_, cb) => cb?.(),
    PTS: {},
  };
}
PK
!<��iW
W
shims/eluminate.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1606448 - Shim CoreMetrics Eluminate analytics
 *
 * Sites may rely on eluminate.js tracking in ways which cause breakage,
 * which has been seen on shopping sites such as Vans.com, where the
 * search filtering UX is broken. This shim mitigates such breakage.
 */

if (!window.CM_DDX) {
  window.CM_DDX = {
    domReadyFired: false,
    headScripts: true,
    dispatcherLoadRequested: false,
    firstPassFunctionBinding: false,
    BAD_PAGE_ID_ELAPSED_TIMEOUT: 5000,
    version: -1,
    standalone: false,
    test: {
      syndicate: true,
      testCounter: "",
      doTest: false,
      newWin: false,
      process: () => {},
    },
    partner: {},
    invokeFunctionWhenAvailable: a => {
      a();
    },
    gup: _d => "",
    privacy: {
      isDoNotTrackEnabled: () => false,
      setDoNotTrack: () => {},
      getDoNotTrack: () => false,
    },
    setSubCookie: () => {},
  };
  const noopfn = () => {};
  const w = window;
  w.cmAddShared = noopfn;
  w.cmCalcSKUString = noopfn;
  w.cmCreateManualImpressionTag = noopfn;
  w.cmCreateManualLinkClickTag = noopfn;
  w.cmCreateManualPageviewTag = noopfn;
  w.cmCreateOrderTag = noopfn;
  w.cmCreatePageviewTag = noopfn;
  w.cmExecuteTagQueue = noopfn;
  w.cmRetrieveUserID = noopfn;
  w.cmSetClientID = noopfn;
  w.cmSetCurrencyCode = noopfn;
  w.cmSetFirstPartyIDs = noopfn;
  w.cmSetSubCookie = noopfn;
  w.cmSetupCookieMigration = noopfn;
  w.cmSetupNormalization = noopfn;
  w.cmSetupOther = noopfn;
  w.cmStartTagSet = noopfn;
  w.cmCreateConversionEventTag = noopfn;
  w.cmCreateDefaultPageviewTag = noopfn;
  w.cmCreateElementTag = noopfn;
  w.cmCreateManualImpressionTag = noopfn;
  w.cmCreateManualLinkClickTag = noopfn;
  w.cmCreateManualPageviewTag = noopfn;
  w.cmCreatePageElementTag = noopfn;
  w.cmCreatePageviewTag = noopfn;
  w.cmCreateProductElementTag = noopfn;
  w.cmCreateProductviewTag = noopfn;
  w.cmCreateTechPropsTag = noopfn;
  w.cmLoadIOConfig = noopfn;
  w.cmSetClientID = noopfn;
  w.cmSetCurrencyCode = noopfn;
  w.cmSetFirstPartyIDs = noopfn;
  w.cmSetupCookieMigration = noopfn;
  w.cmSetupNormalization = noopfn;

  w.cmSetupOther = b => {
    for (const a in b) {
      window[a] = b[a];
    }
  };

  const techProps = {};

  w.coremetrics = {
    cmLastReferencedPageID: "",
    cmLoad: noopfn,
    cmUpdateConfig: noopfn,
    getTechProps: () => techProps,
    isDef: c => typeof c !== "undefined" && c,
  };
}
PK
!<�4���shims/empty-script.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* This script is intentionally empty */
PK
!<shims/empty-shim.txtPK
!<�	����shims/everest.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1728114 - Shim Adobe EverestJS
 *
 * Sites assuming EverestJS will load can break if it is blocked.
 * This shim mitigates that breakage.
 */

if (!window.__ql) {
  window.__ql = {};
}

if (!window.EF) {
  const AdCloudLocalStorage = {
    get: (_, cb) => cb(),
    isInitDone: true,
    isInitSuccess: true,
  };

  const emptyObj = {};

  const nullSrc = {
    getHosts: () => [undefined],
    getProtocols: () => [undefined],
    hash: {},
    hashParamsOrder: [],
    host: undefined,
    path: [],
    port: undefined,
    query: {},
    queryDelimiter: "&",
    queryParamsOrder: [],
    queryPrefix: "?",
    queryWithoutEncode: {},
    respectEmptyQueryParamValue: undefined,
    scheme: undefined,
    text: "//",
    userInfo: undefined,
  };

  const pixelDetailsEvent = {
    addToDom() {},
    canAddToDom: () => false,
    fire() {},
    getDomElement() {},
    initializeUri() {},
    pixelDetailsReceiver() {},
    scheme: "https:",
    uri: nullSrc,
    userid: 0,
  };

  window.EF = {
    AdCloudLocalStorage,
    accessTopUrl: 0,
    acquireCookieMatchingSlot() {},
    addListener() {},
    addPixelDetailsReadyListener() {},
    addToDom() {},
    allow3rdPartyPixels: 1,
    appData: "",
    appendDictionary() {},
    checkGlobalSid() {},
    checkUrlParams() {},
    cmHost: "cm.everesttech.net",
    context: {
      isFbApp: () => 0,
      isPageview: () => false,
      isSegmentation: () => false,
      isTransaction: () => false,
    },
    conversionData: "",
    cookieMatchingSlots: 1,
    debug: 0,
    deserializeUrlParams: () => emptyObj,
    doCookieMatching() {},
    ef_itp_ls: false,
    eventType: "",
    executeAfterLoad() {},
    executeOnloadCallbacks() {},
    expectedTrackingParams: ["ev_cl", "ev_sid"],
    fbIsApp: 0,
    fbsCM: 0,
    fbsPixelId: 0,
    filterList: () => [],
    getArrayIndex: -1,
    getConversionData: () => "",
    getConversionDataFromLocalStorage: cb => cb(),
    getDisplayClickUri: () => "",
    getEpochFromEfUniq: () => 0,
    getFirstLevelObjectCopy: () => emptyObj,
    getInvisibleIframeElement() {},
    getInvisibleImageElement() {},
    getMacroSubstitutedText: () => "",
    getPixelDetails: cb => cb({}),
    getScriptElement() {},
    getScriptSrc: () => "",
    getServerParams: () => emptyObj,
    getSortedAttributes: () => [],
    getTrackingParams: () => emptyObj,
    getTransactionParams: () => emptyObj,
    handleConversionData() {},
    impressionProperties: "",
    impressionTypes: ["impression", "impression_served"],
    inFloodlight: 0,
    init(config) {
      try {
        const { userId } = config;
        window.EF.userId = userId;
        pixelDetailsEvent.userId = userId;
      } catch (_) {}
    },
    initializeEFVariables() {},
    isArray: a => Array.isArray(a),
    isEmptyDictionary: () => true,
    isITPEnabled: () => false,
    isPermanentCookieSet: () => false,
    isSearchClick: () => 0,
    isXSSReady() {},
    jsHost: "www.everestjs.net",
    jsTagAdded: 0,
    location: nullSrc,
    locationHref: nullSrc,
    locationSkipBang: nullSrc,
    log() {},
    main() {},
    main2() {},
    newCookieMatchingEvent: () => emptyObj,
    newFbsCookieMatching: () => emptyObj,
    newImpression: () => emptyObj,
    newPageview: () => emptyObj,
    newPixelDetails: () => emptyObj,
    newPixelEvent: () => emptyObj,
    newPixelServerDisplayClickRedirectUri: () => emptyObj,
    newPixelServerGenericRedirectUri: () => emptyObj,
    newPixelServerUri: () => emptyObj,
    newProductSegment: () => emptyObj,
    newSegmentJavascript: () => emptyObj,
    newTransaction: () => emptyObj,
    newUri: () => emptyObj,
    onloadCallbacks: [],
    pageViewProperties: "",
    pageviewProperties: "",
    pixelDetails: {},
    pixelDetailsAdded: 1,
    pixelDetailsEvent,
    pixelDetailsParams: [],
    pixelDetailsReadyCallbackFns: [],
    pixelDetailsRecieverCalled: 1,
    pixelHost: "pixel.everesttech.net",
    protocol: document?.location?.protocol || "",
    referrer: nullSrc,
    removeListener() {},
    searchSegment: "",
    segment: "",
    serverParamsListener() {},
    sid: 0,
    sku: "",
    throttleCookie: "",
    trackingJavascriptSrc: nullSrc,
    transactionObjectList: [],
    transactionProperties: "",
    userServerParams: {},
    userid: 0,
  };
}
PK
!<H�!D!Dshims/facebook-sdk.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1226498 - Shim Facebook SDK
 *
 * This shim provides functionality to enable Facebook's authenticator on third
 * party sites ("continue/log in with Facebook" buttons). This includes rendering
 * the button as the SDK would, if sites require it. This way, if users wish to
 * opt into the Facebook login process regardless of the tracking consequences,
 * they only need to click the button as usual.
 *
 * In addition, the shim also attempts to provide placeholders for Facebook
 * videos, which users may click to opt into seeing the video (also despite
 * the increased tracking risks). This is an experimental feature enabled
 * that is only currently enabled on nightly builds.
 *
 * Finally, this shim also stubs out as much of the SDK as possible to prevent
 * breaking on sites which expect that it will always successfully load.
 */

if (!window.FB) {
  const FacebookLogoURL = "https://smartblock.firefox.etp/facebook.svg";
  const PlayIconURL = "https://smartblock.firefox.etp/play.svg";

  const originalUrl = (() => {
    const src = document.currentScript?.src;
    try {
      const { protocol, hostname, pathname, href } = new URL(src);
      if (
        (protocol === "http:" || protocol === "https:") &&
        hostname === "connect.facebook.net" &&
        (pathname.endsWith("/sdk.js") || pathname.endsWith("/all.js"))
      ) {
        return href;
      }
      if (href.includes("all.js")) {
        // Legacy SDK.
        return "https://connect.facebook.net/en_US/all.js";
      }
    } catch (_) {}
    return "https://connect.facebook.net/en_US/sdk.js";
  })();

  let haveUnshimmed;
  let initInfo;
  let activeOnloginAttribute;
  const placeholdersToRemoveOnUnshim = new Set();
  const loggedGraphApiCalls = [];
  const eventHandlers = new Map();

  function getGUID() {
    const v = crypto.getRandomValues(new Uint8Array(20));
    return Array.from(v, c => c.toString(16)).join("");
  }

  const sendMessageToAddon = (function () {
    const shimId = "FacebookSDK";
    const pendingMessages = new Map();
    const channel = new MessageChannel();
    channel.port1.onerror = console.error;
    channel.port1.onmessage = event => {
      const { messageId, response } = event.data;
      const resolve = pendingMessages.get(messageId);
      if (resolve) {
        pendingMessages.delete(messageId);
        resolve(response);
      }
    };
    function reconnect() {
      const detail = {
        pendingMessages: [...pendingMessages.values()],
        port: channel.port2,
        shimId,
      };
      window.dispatchEvent(new CustomEvent("ShimConnects", { detail }));
    }
    window.addEventListener("ShimHelperReady", reconnect);
    reconnect();
    return function (message) {
      const messageId = getGUID();
      return new Promise(resolve => {
        const payload = { message, messageId, shimId };
        pendingMessages.set(messageId, resolve);
        channel.port1.postMessage(payload);
      });
    };
  })();

  const isNightly = sendMessageToAddon("getOptions").then(opts => {
    return opts.releaseBranch === "nightly";
  });

  function makeLoginPlaceholder(target) {
    // Sites may provide their own login buttons, or rely on the Facebook SDK
    // to render one for them. For the latter case, we provide placeholders
    // which try to match the examples and documentation here:
    // https://developers.facebook.com/docs/facebook-login/web/login-button/

    if (target.textContent || target.hasAttribute("fb-xfbml-state")) {
      return;
    }
    target.setAttribute("fb-xfbml-state", "");

    const size = target.getAttribute("data-size") || "large";

    let font, margin, minWidth, maxWidth, height, iconHeight;
    if (size === "small") {
      font = 11;
      margin = 8;
      minWidth = maxWidth = 200;
      height = 20;
      iconHeight = 12;
    } else if (size === "medium") {
      font = 13;
      margin = 8;
      minWidth = 200;
      maxWidth = 320;
      height = 28;
      iconHeight = 16;
    } else {
      font = 16;
      minWidth = 240;
      maxWidth = 400;
      margin = 12;
      height = 40;
      iconHeight = 24;
    }

    const wattr = target.getAttribute("data-width") || "";
    const width =
      wattr === "100%" ? wattr : `${parseFloat(wattr) || minWidth}px`;

    const round = target.getAttribute("data-layout") === "rounded" ? 20 : 4;

    const text =
      target.getAttribute("data-button-type") === "continue_with"
        ? "Continue with Facebook"
        : "Log in with Facebook";

    const button = document.createElement("div");
    button.style = `
      display: flex;
      align-items: center;
      justify-content: center;
      padding-left: ${margin + iconHeight}px;
      ${width};
      min-width: ${minWidth}px;
      max-width: ${maxWidth}px;
      height: ${height}px;
      border-radius: ${round}px;
      -moz-text-size-adjust: none;
      -moz-user-select: none;
      color: #fff;
      font-size: ${font}px;
      font-weight: bold;
      font-family: Helvetica, Arial, sans-serif;
      letter-spacing: .25px;
      background-color: #1877f2;
      background-repeat: no-repeat;
      background-position: ${margin}px 50%;
      background-size: ${iconHeight}px ${iconHeight}px;
      background-image: url(${FacebookLogoURL});
    `;
    button.textContent = text;
    target.appendChild(button);
    target.addEventListener("click", () => {
      activeOnloginAttribute = target.getAttribute("onlogin");
    });
  }

  async function makeVideoPlaceholder(target) {
    // For videos, we provide a more generic placeholder of roughly the
    // expected size with a play button, as well as a Facebook logo.
    if (!(await isNightly) || target.hasAttribute("fb-xfbml-state")) {
      return;
    }
    target.setAttribute("fb-xfbml-state", "");

    let width = parseInt(target.getAttribute("data-width"));
    let height = parseInt(target.getAttribute("data-height"));
    if (height) {
      height = `${width * 0.6}px`;
    } else {
      height = `100%; min-height:${width * 0.75}px`;
    }
    if (width) {
      width = `${width}px`;
    } else {
      width = `100%; min-width:200px`;
    }

    const placeholder = document.createElement("div");
    placeholdersToRemoveOnUnshim.add(placeholder);
    placeholder.style = `
      width: ${width};
      height: ${height};
      top: 0px;
      left: 0px;
      background: #000;
      color: #fff;
      text-align: center;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      background-image: url(${FacebookLogoURL}), url(${PlayIconURL});
      background-position: calc(100% - 24px) 24px, 50% 47.5%;
      background-repeat: no-repeat, no-repeat;
      background-size: 43px 42px, 25% 25%;
      -moz-text-size-adjust: none;
      -moz-user-select: none;
      color: #fff;
      align-items: center;
      padding-top: 200px;
      font-size: 14pt;
    `;
    placeholder.textContent = "Click to allow blocked Facebook content";
    placeholder.addEventListener("click", evt => {
      if (!evt.isTrusted) {
        return;
      }
      allowFacebookSDK(() => {
        placeholdersToRemoveOnUnshim.forEach(p => p.remove());
      });
    });

    target.innerHTML = "";
    target.appendChild(placeholder);
  }

  // We monitor for XFBML objects as Facebook SDK does, so we
  // can provide placeholders for dynamically-added ones.
  const xfbmlObserver = new MutationObserver(mutations => {
    for (let { addedNodes, target, type } of mutations) {
      const nodes = type === "attributes" ? [target] : addedNodes;
      for (const node of nodes) {
        if (node?.classList?.contains("fb-login-button")) {
          makeLoginPlaceholder(node);
        }
        if (node?.classList?.contains("fb-video")) {
          makeVideoPlaceholder(node);
        }
      }
    }
  });

  xfbmlObserver.observe(document.documentElement, {
    childList: true,
    subtree: true,
    attributes: true,
    attributeFilter: ["class"],
  });

  const needPopup =
    !/app_runner/.test(window.name) && !/iframe_canvas/.test(window.name);
  const popupName = getGUID();
  let activePopup;

  if (needPopup) {
    const oldWindowOpen = window.open;
    window.open = function (href, name, params) {
      try {
        const url = new URL(href, window.location.href);
        if (
          url.protocol === "https:" &&
          (url.hostname === "m.facebook.com" ||
            url.hostname === "www.facebook.com") &&
          url.pathname.endsWith("/oauth")
        ) {
          name = popupName;
        }
      } catch (e) {
        console.error(e);
      }
      return oldWindowOpen.call(window, href, name, params);
    };
  }

  let allowingFacebookPromise;

  async function allowFacebookSDK(postInitCallback) {
    if (allowingFacebookPromise) {
      return allowingFacebookPromise;
    }

    let resolve, reject;
    allowingFacebookPromise = new Promise((_resolve, _reject) => {
      resolve = _resolve;
      reject = _reject;
    });

    await sendMessageToAddon("optIn");

    xfbmlObserver.disconnect();

    const shim = window.FB;
    window.FB = undefined;

    // We need to pass the site's initialization info to the real
    // SDK as it loads, so we use the fbAsyncInit mechanism to
    // do so, also ensuring our own post-init callbacks are called.
    const oldInit = window.fbAsyncInit;
    window.fbAsyncInit = () => {
      try {
        if (typeof initInfo !== "undefined") {
          window.FB.init(initInfo);
        } else if (oldInit) {
          oldInit();
        }
      } catch (e) {
        console.error(e);
      }

      // Also re-subscribe any SDK event listeners as early as possible.
      for (const [name, fns] of eventHandlers.entries()) {
        for (const fn of fns) {
          window.FB.Event.subscribe(name, fn);
        }
      }

      // Allow the shim to do any post-init work early as well, while the
      // SDK script finishes loading and we ask it to re-parse XFBML etc.
      postInitCallback?.();
    };

    const script = document.createElement("script");
    script.src = originalUrl;

    script.addEventListener("error", () => {
      allowingFacebookPromise = null;
      script.remove();
      activePopup?.close();
      window.FB = shim;
      reject();
      alert("Failed to load Facebook SDK; please try again");
    });

    script.addEventListener("load", () => {
      haveUnshimmed = true;

      // After the real SDK has fully loaded we re-issue any Graph API
      // calls the page is waiting on, as well as requesting for it to
      // re-parse any XBFML elements (including ones with placeholders).

      for (const args of loggedGraphApiCalls) {
        try {
          window.FB.api.apply(window.FB, args);
        } catch (e) {
          console.error(e);
        }
      }

      window.FB.XFBML.parse(document.body, resolve);
    });

    document.head.appendChild(script);

    return allowingFacebookPromise;
  }

  function buildPopupParams() {
    // We try to match Facebook's popup size reasonably closely.
    const { outerWidth, outerHeight, screenX, screenY } = window;
    const { width, height } = window.screen;
    const w = Math.min(width, 400);
    const h = Math.min(height, 400);
    const ua = navigator.userAgent;
    const isMobile = ua.includes("Mobile") || ua.includes("Tablet");
    const left = screenX + (screenX < 0 ? width : 0) + (outerWidth - w) / 2;
    const top = screenY + (screenY < 0 ? height : 0) + (outerHeight - h) / 2.5;
    let params = `left=${left},top=${top},width=${w},height=${h},scrollbars=1,toolbar=0,location=1`;
    if (!isMobile) {
      params = `${params},width=${w},height=${h}`;
    }
    return params;
  }

  // If a page stores the window.FB reference of the shim, then we
  // want to have it proxy calls to the real SDK once we've unshimmed.
  function ensureProxiedToUnshimmed(obj) {
    const shim = {};
    for (const key in obj) {
      const value = obj[key];
      if (typeof value === "function") {
        shim[key] = function () {
          if (haveUnshimmed) {
            return window.FB[key].apply(window.FB, arguments);
          }
          return value.apply(this, arguments);
        };
      } else if (typeof value !== "object" || value === null) {
        shim[key] = value;
      } else {
        shim[key] = ensureProxiedToUnshimmed(value);
      }
    }
    return new Proxy(shim, {
      get: (shimmed, key) => (haveUnshimmed ? window.FB : shimmed)[key],
    });
  }

  window.FB = ensureProxiedToUnshimmed({
    api() {
      loggedGraphApiCalls.push(arguments);
    },
    AppEvents: {
      activateApp() {},
      clearAppVersion() {},
      clearUserID() {},
      EventNames: {
        ACHIEVED_LEVEL: "fb_mobile_level_achieved",
        ADDED_PAYMENT_INFO: "fb_mobile_add_payment_info",
        ADDED_TO_CART: "fb_mobile_add_to_cart",
        ADDED_TO_WISHLIST: "fb_mobile_add_to_wishlist",
        COMPLETED_REGISTRATION: "fb_mobile_complete_registration",
        COMPLETED_TUTORIAL: "fb_mobile_tutorial_completion",
        INITIATED_CHECKOUT: "fb_mobile_initiated_checkout",
        PAGE_VIEW: "fb_page_view",
        RATED: "fb_mobile_rate",
        SEARCHED: "fb_mobile_search",
        SPENT_CREDITS: "fb_mobile_spent_credits",
        UNLOCKED_ACHIEVEMENT: "fb_mobile_achievement_unlocked",
        VIEWED_CONTENT: "fb_mobile_content_view",
      },
      getAppVersion: () => "",
      getUserID: () => "",
      logEvent() {},
      logPageView() {},
      logPurchase() {},
      ParameterNames: {
        APP_USER_ID: "_app_user_id",
        APP_VERSION: "_appVersion",
        CONTENT_ID: "fb_content_id",
        CONTENT_TYPE: "fb_content_type",
        CURRENCY: "fb_currency",
        DESCRIPTION: "fb_description",
        LEVEL: "fb_level",
        MAX_RATING_VALUE: "fb_max_rating_value",
        NUM_ITEMS: "fb_num_items",
        PAYMENT_INFO_AVAILABLE: "fb_payment_info_available",
        REGISTRATION_METHOD: "fb_registration_method",
        SEARCH_STRING: "fb_search_string",
        SUCCESS: "fb_success",
      },
      setAppVersion() {},
      setUserID() {},
      updateUserProperties() {},
    },
    Canvas: {
      getHash: () => "",
      getPageInfo(cb) {
        cb?.call(this, {
          clientHeight: 1,
          clientWidth: 1,
          offsetLeft: 0,
          offsetTop: 0,
          scrollLeft: 0,
          scrollTop: 0,
        });
      },
      Plugin: {
        hidePluginElement() {},
        showPluginElement() {},
      },
      Prefetcher: {
        COLLECT_AUTOMATIC: 0,
        COLLECT_MANUAL: 1,
        addStaticResource() {},
        setCollectionMode() {},
      },
      scrollTo() {},
      setAutoGrow() {},
      setDoneLoading() {},
      setHash() {},
      setSize() {},
      setUrlHandler() {},
      startTimer() {},
      stopTimer() {},
    },
    Event: {
      subscribe(e, f) {
        if (!eventHandlers.has(e)) {
          eventHandlers.set(e, new Set());
        }
        eventHandlers.get(e).add(f);
      },
      unsubscribe(e, f) {
        eventHandlers.get(e)?.delete(f);
      },
    },
    frictionless: {
      init() {},
      isAllowed: () => false,
    },
    gamingservices: {
      friendFinder() {},
      uploadImageToMediaLibrary() {},
    },
    getAccessToken: () => null,
    getAuthResponse() {
      return { status: "" };
    },
    getLoginStatus(cb) {
      cb?.call(this, { status: "unknown" });
    },
    getUserID() {},
    init(_initInfo) {
      initInfo = _initInfo; // in case the site is not using fbAsyncInit
    },
    login(cb, opts) {
      // We have to load Facebook's script, and then wait for it to call
      // window.open. By that time, the popup blocker will likely trigger.
      // So we open a popup now with about:blank, and then make sure FB
      // will re-use that same popup later.
      if (needPopup) {
        activePopup = window.open("about:blank", popupName, buildPopupParams());
      }
      allowFacebookSDK(() => {
        activePopup = undefined;
        function runPostLoginCallbacks() {
          try {
            cb?.apply(this, arguments);
          } catch (e) {
            console.error(e);
          }
          if (activeOnloginAttribute) {
            setTimeout(activeOnloginAttribute, 1);
            activeOnloginAttribute = undefined;
          }
        }
        window.FB.login(runPostLoginCallbacks, opts);
      }).catch(() => {
        activePopup = undefined;
        activeOnloginAttribute = undefined;
        try {
          cb?.({});
        } catch (e) {
          console.error(e);
        }
      });
    },
    logout(cb) {
      cb?.call(this);
    },
    ui(params, fn) {
      if (params.method === "permissions.oauth") {
        window.FB.login(fn, params);
      }
    },
    XFBML: {
      parse(node, cb) {
        node = node || document;
        node.querySelectorAll(".fb-login-button").forEach(makeLoginPlaceholder);
        node.querySelectorAll(".fb-video").forEach(makeVideoPlaceholder);
        try {
          cb?.call(this);
        } catch (e) {
          console.error(e);
        }
      },
    },
  });

  window.FB.XFBML.parse();

  window?.fbAsyncInit?.();
}
PK
!<{�Q��shims/facebook.svg<!-- copyright is dedicated to the Public Domain.
     https://en.wikipedia.org/wiki/File:Facebook_f_logo_(2019).svg -->
<svg xmlns="http://www.w3.org/2000/svg" width="1365.12" height="1365.12" viewBox="0 0 14222 14222"><circle cx="7111" cy="7112" r="7111" fill="#fff"/><path d="M9879 9168l315-2056H8222V5778c0-562 275-1111 1159-1111h897V2917s-814-139-1592-139c-1624 0-2686 984-2686 2767v1567H4194v2056h1806v4969c362 57 733 86 1111 86s749-30 1111-86V9168z" fill="#1977f3"/></svg>
PK
!<�G����shims/fastclick.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1738220 - Shim Conversant FastClick
 *
 * Sites assuming FastClick will load can break if it is blocked.
 * This shim mitigates that breakage.
 */

// FastClick bundles nodeJS packages/core-js/internals/dom-iterables.js
// which is known to be needed by at least one site.
if (!HTMLCollection.prototype.forEach) {
  const DOMIterables = [
    "CSSRuleList",
    "CSSStyleDeclaration",
    "CSSValueList",
    "ClientRectList",
    "DOMRectList",
    "DOMStringList",
    "DOMTokenList",
    "DataTransferItemList",
    "FileList",
    "HTMLAllCollection",
    "HTMLCollection",
    "HTMLFormElement",
    "HTMLSelectElement",
    "MediaList",
    "MimeTypeArray",
    "NamedNodeMap",
    "NodeList",
    "PaintRequestList",
    "Plugin",
    "PluginArray",
    "SVGLengthList",
    "SVGNumberList",
    "SVGPathSegList",
    "SVGPointList",
    "SVGStringList",
    "SVGTransformList",
    "SourceBufferList",
    "StyleSheetList",
    "TextTrackCueList",
    "TextTrackList",
    "TouchList",
  ];

  const forEach = Array.prototype.forEach;

  const handlePrototype = proto => {
    if (!proto || proto.forEach === forEach) {
      return;
    }
    try {
      Object.defineProperty(proto, "forEach", {
        enumerable: false,
        get: () => forEach,
      });
    } catch (_) {
      proto.forEach = forEach;
    }
  };

  for (const name of DOMIterables) {
    handlePrototype(window[name]?.prototype);
  }
}

if (!window.conversant?.launch) {
  const c = (window.conversant = window.conversant || {});
  c.launch = () => {};
}
PK
!<�Y�'	'	shims/firebase.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1767407 - Shim Firebase
 *
 * Sites relying on firebase-messaging.js will break in Private
 * browsing mode because it assumes that they require service
 * workers and indexedDB, when they generally do not.
 */

/* globals cloneInto */

(function () {
  const win = window.wrappedJSObject;
  const emptyObj = new win.Object();
  const emptyArr = new win.Array();
  const emptyMsg = cloneInto({ message: "" }, window);
  const noOpFn = cloneInto(function () {}, window, { cloneFunctions: true });

  if (!win.indexedDB) {
    const idb = {
      open: () => win.Promise.reject(emptyMsg),
    };

    Object.defineProperty(win, "indexedDB", {
      value: cloneInto(idb, window, { cloneFunctions: true }),
    });
  }

  // bug 1778993
  for (const name of [
    "IDBCursor",
    "IDBDatabase",
    "IDBIndex",
    "IDBOpenDBRequest",
    "IDBRequest",
    "IDBTransaction",
  ]) {
    if (!win[name]) {
      Object.defineProperty(win, name, { value: emptyObj });
    }
  }

  if (!win.serviceWorker) {
    const sw = {
      addEventListener() {},
      getRegistrations: () => win.Promise.resolve(emptyArr),
      register: () => win.Promise.reject(emptyMsg),
    };

    Object.defineProperty(navigator.wrappedJSObject, "serviceWorker", {
      value: cloneInto(sw, window, { cloneFunctions: true }),
    });

    // bug 1779536
    Object.defineProperty(navigator.wrappedJSObject.serviceWorker, "ready", {
      value: new win.Promise(noOpFn),
    });
  }

  // bug 1750699
  if (!win.PushManager) {
    Object.defineProperty(win, "PushManager", { value: emptyObj });
  }

  // bug 1750699
  if (!win.PushSubscription) {
    const ps = {
      prototype: {
        getKey() {},
      },
    };

    Object.defineProperty(win, "PushSubscription", {
      value: cloneInto(ps, window, { cloneFunctions: true }),
    });
  }

  // bug 1750699
  if (!win.ServiceWorkerRegistration) {
    const swr = {
      prototype: {
        showNotification() {},
      },
    };

    Object.defineProperty(win, "ServiceWorkerRegistration", {
      value: cloneInto(swr, window, { cloneFunctions: true }),
    });
  }
})();
PK
!<<���ppshims/google-ads.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713726 - Shim Ads by Google
 *
 * Sites relying on window.adsbygoogle may encounter breakage if it is blocked.
 * This shim provides a stub for that API to mitigate that breakage.
 */

if (window.adsbygoogle?.loaded === undefined) {
  window.adsbygoogle = {
    loaded: true,
    push() {},
  };
}

if (window.gapi?._pl === undefined) {
  const stub = {
    go() {},
    render: () => "",
  };
  window.gapi = {
    _pl: true,
    additnow: stub,
    autocomplete: stub,
    backdrop: stub,
    blogger: stub,
    commentcount: stub,
    comments: stub,
    community: stub,
    donation: stub,
    family_creation: stub,
    follow: stub,
    hangout: stub,
    health: stub,
    interactivepost: stub,
    load() {},
    logutil: {
      enableDebugLogging() {},
    },
    page: stub,
    partnersbadge: stub,
    person: stub,
    platform: {
      go() {},
    },
    playemm: stub,
    playreview: stub,
    plus: stub,
    plusone: stub,
    post: stub,
    profile: stub,
    ratingbadge: stub,
    recobar: stub,
    savetoandroidpay: stub,
    savetodrive: stub,
    savetowallet: stub,
    share: stub,
    sharetoclassroom: stub,
    shortlists: stub,
    signin: stub,
    signin2: stub,
    surveyoptin: stub,
    visibility: stub,
    youtube: stub,
    ytsubscribe: stub,
    zoomableimage: stub,
  };
}

for (const e of document.querySelectorAll("ins.adsbygoogle")) {
  e.style.maxWidth = "0px";
}
PK
!<�f��UU)shims/google-analytics-and-tag-manager.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713687 - Shim Google Analytics and Tag Manager
 *
 * Sites often rely on the Google Analytics window object and will
 * break if it fails to load or is blocked. This shim works around
 * such breakage.
 *
 * Sites also often use the Google Optimizer (asynchide) code snippet,
 * only for it to cause multi-second delays if Google Analytics does
 * not load. This shim also avoids such delays.
 *
 * They also rely on Google Tag Manager, which often goes hand-in-
 * hand with Analytics, but is not always blocked by anti-tracking
 * lists. Handling both in the same shim handles both cases.
 */

if (window[window.GoogleAnalyticsObject || "ga"]?.loaded === undefined) {
  const DEFAULT_TRACKER_NAME = "t0";

  const trackers = new Map();

  const run = function (fn, ...args) {
    if (typeof fn === "function") {
      try {
        fn(...args);
      } catch (e) {
        console.error(e);
      }
    }
  };

  const create = (id, cookie, name, opts) => {
    id = id || opts?.trackerId;
    if (!id) {
      return undefined;
    }
    cookie = cookie || opts?.cookieDomain || "_ga";
    name = name || opts?.name || DEFAULT_TRACKER_NAME;
    if (!trackers.has(name)) {
      let props;
      try {
        props = new Map(Object.entries(opts));
      } catch (_) {
        props = new Map();
      }
      trackers.set(name, {
        get(p) {
          if (p === "name") {
            return name;
          } else if (p === "trackingId") {
            return id;
          } else if (p === "cookieDomain") {
            return cookie;
          }
          return props.get(p);
        },
        ma() {},
        requireSync() {},
        send() {},
        set(p, v) {
          if (typeof p !== "object") {
            p = Object.fromEntries([[p, v]]);
          }
          for (const k in p) {
            props.set(k, p[k]);
            if (k === "hitCallback") {
              run(p[k]);
            }
          }
        },
      });
    }
    return trackers.get(name);
  };

  const cmdRE = /((?<name>.*?)\.)?((?<plugin>.*?):)?(?<method>.*)/;

  function ga(cmd, ...args) {
    if (arguments.length === 1 && typeof cmd === "function") {
      run(cmd, trackers.get(DEFAULT_TRACKER_NAME));
      return undefined;
    }

    if (typeof cmd !== "string") {
      return undefined;
    }

    const groups = cmdRE.exec(cmd)?.groups;
    if (!groups) {
      console.error("Could not parse GA command", cmd);
      return undefined;
    }

    let { name, plugin, method } = groups;

    if (plugin) {
      return undefined;
    }

    if (cmd === "set") {
      trackers.get(name)?.set(args[0], args[1]);
    }

    if (method === "remove") {
      trackers.delete(name);
      return undefined;
    }

    if (cmd === "send") {
      run(args.at(-1)?.hitCallback);
      return undefined;
    }

    if (method === "create") {
      let id, cookie, fields;
      for (const param of args.slice(0, 4)) {
        if (typeof param === "object") {
          fields = param;
          break;
        }
        if (id === undefined) {
          id = param;
        } else if (cookie === undefined) {
          cookie = param;
        } else {
          name = param;
        }
      }
      return create(id, cookie, name, fields);
    }

    return undefined;
  }

  Object.assign(ga, {
    create: (a, b, c, d) => ga("create", a, b, c, d),
    getAll: () => Array.from(trackers.values()),
    getByName: name => trackers.get(name),
    loaded: true,
    remove: t => ga("remove", t),
  });

  // Process any GA command queue the site pre-declares (bug 1736850)
  const q = window[window.GoogleAnalyticsObject || "ga"]?.q;
  window[window.GoogleAnalyticsObject || "ga"] = ga;

  if (Array.isArray(q)) {
    const push = o => {
      ga(...o);
      return true;
    };
    q.push = push;
    q.forEach(o => push(o));
  }

  // Also process the Google Tag Manager dataLayer (bug 1713688)
  const dl = window.dataLayer;

  if (Array.isArray(dl) && !dl.find(e => e["gtm.start"])) {
    const push = function (o) {
      setTimeout(() => run(o?.eventCallback), 1);
      return true;
    };
    dl.push = push;
    dl.forEach(o => push(o));
  }

  // Run dataLayer.hide.end to handle asynchide (bug 1628151)
  run(window.dataLayer?.hide?.end);
}

if (!window?.gaplugins?.Linker) {
  window.gaplugins = window.gaplugins || {};
  window.gaplugins.Linker = class {
    autoLink() {}
    decorate(url) {
      return url;
    }
    passthrough() {}
  };
}
PK
!<����RR*shims/google-analytics-ecommerce-plugin.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

if (!window.gaplugins) {
  window.gaplugins = {};
}

if (!window.gaplugins.EC) {
  window.gaplugins.EC = () => {};
}
PK
!<*�pU"
"
 shims/google-analytics-legacy.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// based on https://github.com/gorhill/uBlock/blob/6f49e079db0262e669b70f4169924f796ac8db7c/src/web_accessible_resources/google-analytics_ga.js

"use strict";

if (!window._gaq) {
  function noopfn() {}

  const gaq = {
    Na: noopfn,
    O: noopfn,
    Sa: noopfn,
    Ta: noopfn,
    Va: noopfn,
    _createAsyncTracker: noopfn,
    _getAsyncTracker: noopfn,
    _getPlugin: noopfn,
    push: a => {
      if (typeof a === "function") {
        a();
        return;
      }
      if (!Array.isArray(a)) {
        return;
      }
      if (
        typeof a[0] === "string" &&
        /(^|\.)_link$/.test(a[0]) &&
        typeof a[1] === "string"
      ) {
        window.location.assign(a[1]);
      }
      if (
        a[0] === "_set" &&
        a[1] === "hitCallback" &&
        typeof a[2] === "function"
      ) {
        a[2]();
      }
    },
  };

  const tracker = {
    _addIgnoredOrganic: noopfn,
    _addIgnoredRef: noopfn,
    _addItem: noopfn,
    _addOrganic: noopfn,
    _addTrans: noopfn,
    _clearIgnoredOrganic: noopfn,
    _clearIgnoredRef: noopfn,
    _clearOrganic: noopfn,
    _cookiePathCopy: noopfn,
    _deleteCustomVar: noopfn,
    _getName: noopfn,
    _setAccount: noopfn,
    _getAccount: noopfn,
    _getClientInfo: noopfn,
    _getDetectFlash: noopfn,
    _getDetectTitle: noopfn,
    _getLinkerUrl: a => a,
    _getLocalGifPath: noopfn,
    _getServiceMode: noopfn,
    _getVersion: noopfn,
    _getVisitorCustomVar: noopfn,
    _initData: noopfn,
    _link: noopfn,
    _linkByPost: noopfn,
    _setAllowAnchor: noopfn,
    _setAllowHash: noopfn,
    _setAllowLinker: noopfn,
    _setCampContentKey: noopfn,
    _setCampMediumKey: noopfn,
    _setCampNameKey: noopfn,
    _setCampNOKey: noopfn,
    _setCampSourceKey: noopfn,
    _setCampTermKey: noopfn,
    _setCampaignCookieTimeout: noopfn,
    _setCampaignTrack: noopfn,
    _setClientInfo: noopfn,
    _setCookiePath: noopfn,
    _setCookiePersistence: noopfn,
    _setCookieTimeout: noopfn,
    _setCustomVar: noopfn,
    _setDetectFlash: noopfn,
    _setDetectTitle: noopfn,
    _setDomainName: noopfn,
    _setLocalGifPath: noopfn,
    _setLocalRemoteServerMode: noopfn,
    _setLocalServerMode: noopfn,
    _setReferrerOverride: noopfn,
    _setRemoteServerMode: noopfn,
    _setSampleRate: noopfn,
    _setSessionTimeout: noopfn,
    _setSiteSpeedSampleRate: noopfn,
    _setSessionCookieTimeout: noopfn,
    _setVar: noopfn,
    _setVisitorCookieTimeout: noopfn,
    _trackEvent: noopfn,
    _trackPageLoadTime: noopfn,
    _trackPageview: noopfn,
    _trackSocial: noopfn,
    _trackTiming: noopfn,
    _trackTrans: noopfn,
    _visitCode: noopfn,
  };

  const gat = {
    _anonymizeIP: noopfn,
    _createTracker: noopfn,
    _forceSSL: noopfn,
    _getPlugin: noopfn,
    _getTracker: () => tracker,
    _getTrackerByName: () => tracker,
    _getTrackers: noopfn,
    aa: noopfn,
    ab: noopfn,
    hb: noopfn,
    la: noopfn,
    oa: noopfn,
    pa: noopfn,
    u: noopfn,
  };

  window._gat = gat;

  const aa = window._gaq || [];
  if (Array.isArray(aa)) {
    while (aa[0]) {
      gaq.push(aa.shift());
    }
  }

  window._gaq = gaq.qf = gaq;
}
PK
!<�A�s�5�5shims/google-ima.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * Bug 1713690 - Shim Google Interactive Media Ads ima3.js
 *
 * Many sites use ima3.js for ad bidding and placement, often in conjunction
 * with Google Publisher Tags, Prebid.js and/or other scripts. This shim
 * provides a stubbed-out version of the API which helps work around related
 * site breakage, such as black bxoes where videos ought to be placed.
 */

if (!window.google?.ima?.VERSION) {
  const VERSION = "3.517.2";

  const CheckCanAutoplay = (function () {
    // Sourced from: https://searchfox.org/mozilla-central/source/dom/media/gtest/negative_duration.mp4
    const TEST_VIDEO = new Blob(
      [
        new Uint32Array([
          469762048, 1887007846, 1752392036, 0, 913273705, 1717987696,
          828601953, -1878917120, 1987014509, 1811939328, 1684567661, 0, 0, 0,
          -402456576, 0, 256, 1, 0, 0, 256, 0, 0, 0, 256, 0, 0, 0, 64, 0, 0, 0,
          0, 0, 0, 33554432, -201261056, 1801548404, 1744830464, 1684564852,
          251658241, 0, 0, 0, 0, 16777216, 0, -1, -1, 0, 0, 0, 0, 256, 0, 0, 0,
          256, 0, 0, 0, 64, 5, 53250, -2080309248, 1634296941, 738197504,
          1684563053, 1, 0, 0, 0, 0, -2137614336, -1, -1, 50261, 754974720,
          1919706216, 0, 0, 1701079414, 0, 0, 0, 1701079382, 1851869295,
          1919249508, 16777216, 1852402979, 102, 1752004116, 100, 1, 0, 0,
          1852400676, 102, 1701995548, 102, 0, 1, 1819440396, 32, 1, 1651799011,
          108, 1937011607, 100, 0, 1, 1668702599, 49, 0, 1, 0, 0, 0, 33555712,
          4718800, 4718592, 0, 65536, 0, 0, 0, 0, 0, 0, 0, 0, 16776984,
          1630601216, 21193590, -14745500, 1729626337, -1407254428, 89161945,
          1049019, 9453056, -251611125, 27269507, -379058688, -1329024392,
          268435456, 1937011827, 0, 0, 268435456, 1668510835, 0, 0, 335544320,
          2054386803, 0, 0, 0, 268435456, 1868788851, 0, 0, 671088640,
          2019915373, 536870912, 2019914356, 0, 16777216, 16777216, 0, 0, 0,
        ]),
      ],
      { type: "video/mp4" }
    );

    let testVideo = undefined;

    return function () {
      if (!testVideo) {
        testVideo = document.createElement("video");
        testVideo.style =
          "position:absolute; width:0; height:0; left:0; right:0; z-index:-1; border:0";
        testVideo.setAttribute("muted", "muted");
        testVideo.setAttribute("playsinline", "playsinline");
        testVideo.src = URL.createObjectURL(TEST_VIDEO);
        document.body.appendChild(testVideo);
      }
      return testVideo.play();
    };
  })();

  let ima = {};

  class AdDisplayContainer {
    destroy() {}
    initialize() {}
  }

  class ImaSdkSettings {
    #c = true;
    #f = {};
    #i = false;
    #l = "";
    #p = "";
    #r = 0;
    #t = "";
    #v = "";
    getCompanionBackfill() {}
    getDisableCustomPlaybackForIOS10Plus() {
      return this.#i;
    }
    getFeatureFlags() {
      return this.#f;
    }
    getLocale() {
      return this.#l;
    }
    getNumRedirects() {
      return this.#r;
    }
    getPlayerType() {
      return this.#t;
    }
    getPlayerVersion() {
      return this.#v;
    }
    getPpid() {
      return this.#p;
    }
    isCookiesEnabled() {
      return this.#c;
    }
    setAutoPlayAdBreaks() {}
    setCompanionBackfill() {}
    setCookiesEnabled(c) {
      this.#c = !!c;
    }
    setDisableCustomPlaybackForIOS10Plus(i) {
      this.#i = !!i;
    }
    setFeatureFlags(f) {
      this.#f = f;
    }
    setLocale(l) {
      this.#l = l;
    }
    setNumRedirects(r) {
      this.#r = r;
    }
    setPlayerType(t) {
      this.#t = t;
    }
    setPlayerVersion(v) {
      this.#v = v;
    }
    setPpid(p) {
      this.#p = p;
    }
    setSessionId(_s) {}
    setVpaidAllowed(_a) {}
    setVpaidMode(_m) {}
  }
  ImaSdkSettings.CompanionBackfillMode = {
    ALWAYS: "always",
    ON_MASTER_AD: "on_master_ad",
  };
  ImaSdkSettings.VpaidMode = {
    DISABLED: 0,
    ENABLED: 1,
    INSECURE: 2,
  };

  class EventHandler {
    #listeners = new Map();

    _dispatch(e) {
      const listeners = this.#listeners.get(e.type) || [];
      for (const listener of Array.from(listeners)) {
        try {
          listener(e);
        } catch (r) {
          console.error(r);
        }
      }
    }

    addEventListener(t, c) {
      if (!this.#listeners.has(t)) {
        this.#listeners.set(t, new Set());
      }
      this.#listeners.get(t).add(c);
    }

    removeEventListener(t, c) {
      this.#listeners.get(t)?.delete(c);
    }
  }

  class AdsLoader extends EventHandler {
    #settings = new ImaSdkSettings();
    contentComplete() {}
    destroy() {}
    getSettings() {
      return this.#settings;
    }
    getVersion() {
      return VERSION;
    }
    requestAds(_r, _c) {
      // If autoplay is disabled and the page is trying to autoplay a tracking
      // ad, then IMA fails with an error, and the page is expected to request
      // ads again later when the user clicks to play.
      CheckCanAutoplay().then(
        () => {
          const { ADS_MANAGER_LOADED } = AdsManagerLoadedEvent.Type;
          this._dispatch(new ima.AdsManagerLoadedEvent(ADS_MANAGER_LOADED));
        },
        () => {
          const e = new ima.AdError(
            "adPlayError",
            1205,
            1205,
            "The browser prevented playback initiated without user interaction."
          );
          this._dispatch(new ima.AdErrorEvent(e));
        }
      );
    }
  }

  class AdsManager extends EventHandler {
    #volume = 1;
    collapse() {}
    configureAdsManager() {}
    destroy() {}
    discardAdBreak() {}
    expand() {}
    focus() {}
    getAdSkippableState() {
      return false;
    }
    getCuePoints() {
      return [0];
    }
    getCurrentAd() {
      return currentAd;
    }
    getCurrentAdCuePoints() {
      return [];
    }
    getRemainingTime() {
      return 0;
    }
    getVolume() {
      return this.#volume;
    }
    init(_w, _h, _m, _e) {}
    isCustomClickTrackingUsed() {
      return false;
    }
    isCustomPlaybackUsed() {
      return false;
    }
    pause() {}
    requestNextAdBreak() {}
    resize(_w, _h, _m) {}
    resume() {}
    setVolume(v) {
      this.#volume = v;
    }
    skip() {}
    start() {
      requestAnimationFrame(() => {
        for (const type of [
          AdEvent.Type.LOADED,
          AdEvent.Type.STARTED,
          AdEvent.Type.CONTENT_RESUME_REQUESTED,
          AdEvent.Type.AD_BUFFERING,
          AdEvent.Type.FIRST_QUARTILE,
          AdEvent.Type.MIDPOINT,
          AdEvent.Type.THIRD_QUARTILE,
          AdEvent.Type.COMPLETE,
          AdEvent.Type.ALL_ADS_COMPLETED,
        ]) {
          try {
            this._dispatch(new ima.AdEvent(type));
          } catch (e) {
            console.error(e);
          }
        }
      });
    }
    stop() {}
    updateAdsRenderingSettings(_s) {}
  }

  class AdsRenderingSettings {}

  class AdsRequest {
    setAdWillAutoPlay() {}
    setAdWillPlayMuted() {}
    setContinuousPlayback() {}
  }

  class AdPodInfo {
    getAdPosition() {
      return 1;
    }
    getIsBumper() {
      return false;
    }
    getMaxDuration() {
      return -1;
    }
    getPodIndex() {
      return 1;
    }
    getTimeOffset() {
      return 0;
    }
    getTotalAds() {
      return 1;
    }
  }

  class Ad {
    _pi = new AdPodInfo();
    getAdId() {
      return "";
    }
    getAdPodInfo() {
      return this._pi;
    }
    getAdSystem() {
      return "";
    }
    getAdvertiserName() {
      return "";
    }
    getApiFramework() {
      return null;
    }
    getCompanionAds() {
      return [];
    }
    getContentType() {
      return "";
    }
    getCreativeAdId() {
      return "";
    }
    getCreativeId() {
      return "";
    }
    getDealId() {
      return "";
    }
    getDescription() {
      return "";
    }
    getDuration() {
      return 8.5;
    }
    getHeight() {
      return 0;
    }
    getMediaUrl() {
      return null;
    }
    getMinSuggestedDuration() {
      return -2;
    }
    getSkipTimeOffset() {
      return -1;
    }
    getSurveyUrl() {
      return null;
    }
    getTitle() {
      return "";
    }
    getTraffickingParameters() {
      return {};
    }
    getTraffickingParametersString() {
      return "";
    }
    getUiElements() {
      return [""];
    }
    getUniversalAdIdRegistry() {
      return "unknown";
    }
    getUniversalAdIds() {
      return [""];
    }
    getUniversalAdIdValue() {
      return "unknown";
    }
    getVastMediaBitrate() {
      return 0;
    }
    getVastMediaHeight() {
      return 0;
    }
    getVastMediaWidth() {
      return 0;
    }
    getWidth() {
      return 0;
    }
    getWrapperAdIds() {
      return [""];
    }
    getWrapperAdSystems() {
      return [""];
    }
    getWrapperCreativeIds() {
      return [""];
    }
    isLinear() {
      return true;
    }
    isSkippable() {
      return true;
    }
  }

  class CompanionAd {
    getAdSlotId() {
      return "";
    }
    getContent() {
      return "";
    }
    getContentType() {
      return "";
    }
    getHeight() {
      return 1;
    }
    getWidth() {
      return 1;
    }
  }

  class AdError {
    #errorCode = -1;
    #message = "";
    #type = "";
    #vastErrorCode = -1;
    constructor(type, code, vast, message) {
      this.#errorCode = code;
      this.#message = message;
      this.#type = type;
      this.#vastErrorCode = vast;
    }
    getErrorCode() {
      return this.#errorCode;
    }
    getInnerError() {}
    getMessage() {
      return this.#message;
    }
    getType() {
      return this.#type;
    }
    getVastErrorCode() {
      return this.#vastErrorCode;
    }
    toString() {
      return `AdError ${this.#errorCode}: ${this.#message}`;
    }
  }
  AdError.ErrorCode = {};
  AdError.Type = {};

  const isEngadget = () => {
    try {
      for (const ctx of Object.values(window.vidible._getContexts())) {
        if (ctx.getPlayer()?.div?.innerHTML.includes("www.engadget.com")) {
          return true;
        }
      }
    } catch (_) {}
    return false;
  };

  const currentAd = isEngadget() ? undefined : new Ad();

  class AdEvent {
    constructor(type) {
      this.type = type;
    }
    getAd() {
      return currentAd;
    }
    getAdData() {
      return {};
    }
  }
  AdEvent.Type = {
    AD_BREAK_READY: "adBreakReady",
    AD_BUFFERING: "adBuffering",
    AD_CAN_PLAY: "adCanPlay",
    AD_METADATA: "adMetadata",
    AD_PROGRESS: "adProgress",
    ALL_ADS_COMPLETED: "allAdsCompleted",
    CLICK: "click",
    COMPLETE: "complete",
    CONTENT_PAUSE_REQUESTED: "contentPauseRequested",
    CONTENT_RESUME_REQUESTED: "contentResumeRequested",
    DURATION_CHANGE: "durationChange",
    EXPANDED_CHANGED: "expandedChanged",
    FIRST_QUARTILE: "firstQuartile",
    IMPRESSION: "impression",
    INTERACTION: "interaction",
    LINEAR_CHANGE: "linearChange",
    LINEAR_CHANGED: "linearChanged",
    LOADED: "loaded",
    LOG: "log",
    MIDPOINT: "midpoint",
    PAUSED: "pause",
    RESUMED: "resume",
    SKIPPABLE_STATE_CHANGED: "skippableStateChanged",
    SKIPPED: "skip",
    STARTED: "start",
    THIRD_QUARTILE: "thirdQuartile",
    USER_CLOSE: "userClose",
    VIDEO_CLICKED: "videoClicked",
    VIDEO_ICON_CLICKED: "videoIconClicked",
    VIEWABLE_IMPRESSION: "viewable_impression",
    VOLUME_CHANGED: "volumeChange",
    VOLUME_MUTED: "mute",
  };

  class AdErrorEvent {
    type = "adError";
    #error = "";
    constructor(error) {
      this.#error = error;
    }
    getError() {
      return this.#error;
    }
    getUserRequestContext() {
      return {};
    }
  }
  AdErrorEvent.Type = {
    AD_ERROR: "adError",
  };

  const manager = new AdsManager();

  class AdsManagerLoadedEvent {
    constructor(type) {
      this.type = type;
    }
    getAdsManager() {
      return manager;
    }
    getUserRequestContext() {
      return {};
    }
  }
  AdsManagerLoadedEvent.Type = {
    ADS_MANAGER_LOADED: "adsManagerLoaded",
  };

  class CustomContentLoadedEvent {}
  CustomContentLoadedEvent.Type = {
    CUSTOM_CONTENT_LOADED: "deprecated-event",
  };

  class CompanionAdSelectionSettings {}
  CompanionAdSelectionSettings.CreativeType = {
    ALL: "All",
    FLASH: "Flash",
    IMAGE: "Image",
  };
  CompanionAdSelectionSettings.ResourceType = {
    ALL: "All",
    HTML: "Html",
    IFRAME: "IFrame",
    STATIC: "Static",
  };
  CompanionAdSelectionSettings.SizeCriteria = {
    IGNORE: "IgnoreSize",
    SELECT_EXACT_MATCH: "SelectExactMatch",
    SELECT_NEAR_MATCH: "SelectNearMatch",
  };

  class AdCuePoints {
    getCuePoints() {
      return [];
    }
  }

  class AdProgressData {}

  class UniversalAdIdInfo {
    getAdIdRegistry() {
      return "";
    }
    getAdIsValue() {
      return "";
    }
  }

  Object.assign(ima, {
    AdCuePoints,
    AdDisplayContainer,
    AdError,
    AdErrorEvent,
    AdEvent,
    AdPodInfo,
    AdProgressData,
    AdsLoader,
    AdsManager: manager,
    AdsManagerLoadedEvent,
    AdsRenderingSettings,
    AdsRequest,
    CompanionAd,
    CompanionAdSelectionSettings,
    CustomContentLoadedEvent,
    gptProxyInstance: {},
    ImaSdkSettings,
    OmidAccessMode: {
      DOMAIN: "domain",
      FULL: "full",
      LIMITED: "limited",
    },
    settings: new ImaSdkSettings(),
    UiElements: {
      AD_ATTRIBUTION: "adAttribution",
      COUNTDOWN: "countdown",
    },
    UniversalAdIdInfo,
    VERSION,
    ViewMode: {
      FULLSCREEN: "fullscreen",
      NORMAL: "normal",
    },
  });

  if (!window.google) {
    window.google = {};
  }

  window.google.ima = ima;
}
PK
!<G]�p''shims/google-page-ad.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713692 - Shim Google Page Ad conversion tracker
 *
 * This shim stubs out the simple API for converstion tracking with
 * Google Page Ad, mitigating major breakage on pages which presume
 * the API will always successfully load.
 */

if (!window.google_trackConversion) {
  window.google_trackConversion = () => {};
}
PK
!<�?��4343shims/google-publisher-tags.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713685 - Shim Google Publisher Tags
 *
 * Many sites rely on googletag to place content or drive ad bidding,
 * and will experience major breakage if it is blocked. This shim provides
 * enough of the API's frame To mitigate much of that breakage.
 */

if (window.googletag?.apiReady === undefined) {
  const version = "2021050601";

  const noopthisfn = function () {
    return this;
  };

  const slots = new Map();
  const slotsById = new Map();
  const slotsPerPath = new Map();
  const slotCreatives = new Map();
  const usedCreatives = new Map();
  const fetchedSlots = new Set();
  const eventCallbacks = new Map();

  const fireSlotEvent = (name, slot) => {
    return new Promise(resolve => {
      requestAnimationFrame(() => {
        const size = [0, 0];
        for (const cb of eventCallbacks.get(name) || []) {
          cb({ isEmpty: true, size, slot });
        }
        resolve();
      });
    });
  };

  const recreateIframeForSlot = slot => {
    const eid = `google_ads_iframe_${slot.getId()}`;
    document.getElementById(eid)?.remove();
    const node = document.getElementById(slot.getSlotElementId());
    if (node) {
      const f = document.createElement("iframe");
      f.id = eid;
      f.srcdoc = "<body></body>";
      f.style =
        "position:absolute; width:0; height:0; left:0; right:0; z-index:-1; border:0";
      f.setAttribute("width", 0);
      f.setAttribute("height", 0);
      node.appendChild(f);
    }
  };

  const emptySlotElement = slot => {
    const node = document.getElementById(slot.getSlotElementId());
    while (node?.lastChild) {
      node.lastChild.remove();
    }
  };

  const SizeMapping = class extends Array {
    getCreatives() {
      const { clientWidth, clientHeight } = document.documentElement;
      for (const [size, creatives] of this) {
        if (clientWidth >= size[0] && clientHeight >= size[1]) {
          return creatives;
        }
      }
      return [];
    }
  };

  const fetchSlot = slot => {
    if (!slot) {
      return;
    }

    const id = slot.getSlotElementId();

    const node = document.getElementById(id);
    if (!node) {
      return;
    }

    let creatives = slotCreatives.get(id);
    if (creatives instanceof SizeMapping) {
      creatives = creatives.getCreatives();
    }

    if (!creatives?.length) {
      return;
    }

    for (const creative of creatives) {
      if (usedCreatives.has(creative)) {
        return;
      }
    }

    const creative = creatives[0];
    usedCreatives.set(creative, slot);
    fetchedSlots.add(id);
  };

  const displaySlot = async slot => {
    if (!slot) {
      return;
    }

    const id = slot.getSlotElementId();
    if (!document.getElementById(id)) {
      return;
    }

    if (!fetchedSlots.has(id)) {
      fetchSlot(slot);
    }

    const parent = document.getElementById(id);
    if (parent) {
      parent.appendChild(document.createElement("div"));
    }

    emptySlotElement(slot);
    recreateIframeForSlot(slot);
    await fireSlotEvent("slotRenderEnded", slot);
    await fireSlotEvent("slotRequested", slot);
    await fireSlotEvent("slotResponseReceived", slot);
    await fireSlotEvent("slotOnload", slot);
    await fireSlotEvent("impressionViewable", slot);
  };

  const addEventListener = function (name, listener) {
    if (!eventCallbacks.has(name)) {
      eventCallbacks.set(name, new Set());
    }
    eventCallbacks.get(name).add(listener);
    return this;
  };

  const removeEventListener = function (name, listener) {
    if (eventCallbacks.has(name)) {
      return eventCallbacks.get(name).delete(listener);
    }
    return false;
  };

  const companionAdsService = {
    addEventListener,
    enable() {},
    fillSlot() {},
    getAttributeKeys: () => [],
    getDisplayAdsCorrelator: () => "",
    getName: () => "companion_ads",
    getSlotIdMap: () => {
      return {};
    },
    getSlots: () => [],
    getVideoStreamCorrelator() {},
    isRoadblockingSupported: () => false,
    isSlotAPersistentRoadblock: () => false,
    notifyUnfilledSlots() {},
    onImplementationLoaded() {},
    refreshAllSlots() {
      for (const slot of slotsById.values()) {
        fetchSlot(slot);
        displaySlot(slot);
      }
    },
    removeEventListener,
    set() {},
    setRefreshUnfilledSlots() {},
    setVideoSession() {},
    slotRenderEnded() {},
  };

  const contentService = {
    addEventListener,
    setContent() {},
    removeEventListener,
  };

  const getTargetingValue = v => {
    if (typeof v === "string") {
      return [v];
    }
    try {
      return [Array.prototype.flat.call(v)[0]];
    } catch (_) {}
    return [];
  };

  const updateTargeting = (targeting, map) => {
    if (typeof map === "object") {
      const entries = Object.entries(map || {});
      for (const [k, v] of entries) {
        targeting.set(k, getTargetingValue(v));
      }
    }
  };

  const defineSlot = (adUnitPath, creatives, opt_div) => {
    if (slotsById.has(opt_div)) {
      document.getElementById(opt_div)?.remove();
      return slotsById.get(opt_div);
    }
    const attributes = new Map();
    const targeting = new Map();
    const exclusions = new Set();
    const response = {
      advertiserId: undefined,
      campaignId: undefined,
      creativeId: undefined,
      creativeTemplateId: undefined,
      lineItemId: undefined,
    };
    const sizes = [
      {
        getHeight: () => 2,
        getWidth: () => 2,
      },
    ];
    const num = (slotsPerPath.get(adUnitPath) || 0) + 1;
    slotsPerPath.set(adUnitPath, num);
    const id = `${adUnitPath}_${num}`;
    let clickUrl = "";
    let collapseEmptyDiv = null;
    let services = new Set();
    const slot = {
      addService(e) {
        services.add(e);
        return slot;
      },
      clearCategoryExclusions: noopthisfn,
      clearTargeting(k) {
        if (k === undefined) {
          targeting.clear();
        } else {
          targeting.delete(k);
        }
      },
      defineSizeMapping(mapping) {
        slotCreatives.set(opt_div, mapping);
        return this;
      },
      get: k => attributes.get(k),
      getAdUnitPath: () => adUnitPath,
      getAttributeKeys: () => Array.from(attributes.keys()),
      getCategoryExclusions: () => Array.from(exclusions),
      getClickUrl: () => clickUrl,
      getCollapseEmptyDiv: () => collapseEmptyDiv,
      getContentUrl: () => "",
      getDivStartsCollapsed: () => null,
      getDomId: () => opt_div,
      getEscapedQemQueryId: () => "",
      getFirstLook: () => 0,
      getId: () => id,
      getHtml: () => "",
      getName: () => id,
      getOutOfPage: () => false,
      getResponseInformation: () => response,
      getServices: () => Array.from(services),
      getSizes: () => sizes,
      getSlotElementId: () => opt_div,
      getSlotId: () => slot,
      getTargeting: k => targeting.get(k) || gTargeting.get(k) || [],
      getTargetingKeys: () =>
        Array.from(
          new Set(Array.of(...gTargeting.keys(), ...targeting.keys()))
        ),
      getTargetingMap: () =>
        Object.assign(
          Object.fromEntries(gTargeting.entries()),
          Object.fromEntries(targeting.entries())
        ),
      set(k, v) {
        attributes.set(k, v);
        return slot;
      },
      setCategoryExclusion(e) {
        exclusions.add(e);
        return slot;
      },
      setClickUrl(u) {
        clickUrl = u;
        return slot;
      },
      setCollapseEmptyDiv(v) {
        collapseEmptyDiv = !!v;
        return slot;
      },
      setSafeFrameConfig: noopthisfn,
      setTagForChildDirectedTreatment: noopthisfn,
      setTargeting(k, v) {
        targeting.set(k, getTargetingValue(v));
        return slot;
      },
      toString: () => id,
      updateTargetingFromMap(map) {
        updateTargeting(targeting, map);
        return slot;
      },
    };
    slots.set(adUnitPath, slot);
    slotsById.set(opt_div, slot);
    slotCreatives.set(opt_div, creatives);
    return slot;
  };

  let initialLoadDisabled = false;

  const gTargeting = new Map();
  const gAttributes = new Map();

  let imaContent = { vid: "", cmsid: "" };
  let videoContent = { vid: "", cmsid: "" };

  const pubadsService = {
    addEventListener,
    clear() {},
    clearCategoryExclusions: noopthisfn,
    clearTagForChildDirectedTreatment: noopthisfn,
    clearTargeting(k) {
      if (k === undefined) {
        gTargeting.clear();
      } else {
        gTargeting.delete(k);
      }
    },
    collapseEmptyDivs() {},
    defineOutOfPagePassback: (a, o) => defineSlot(a, 0, o),
    definePassback: (a, s, o) => defineSlot(a, s, o),
    disableInitialLoad() {
      initialLoadDisabled = true;
      return this;
    },
    display(adUnitPath, sizes, opt_div) {
      const slot = defineSlot(adUnitPath, sizes, opt_div);
      displaySlot(slot);
    },
    enable() {},
    enableAsyncRendering() {},
    enableLazyLoad() {},
    enableSingleRequest() {},
    enableSyncRendering() {},
    enableVideoAds() {},
    forceExperiment() {},
    get: k => gAttributes.get(k),
    getAttributeKeys: () => Array.from(gAttributes.keys()),
    getCorrelator() {},
    getImaContent: () => imaContent,
    getName: () => "publisher_ads",
    getSlots: () => Array.from(slots.values()),
    getSlotIdMap() {
      const map = {};
      slots.values().forEach(s => {
        map[s.getId()] = s;
      });
      return map;
    },
    getTagSessionCorrelator() {},
    getTargeting: k => gTargeting.get(k) || [],
    getTargetingKeys: () => Array.from(gTargeting.keys()),
    getTargetingMap: () => Object.fromEntries(gTargeting.entries()),
    getVersion: () => version,
    getVideoContent: () => videoContent,
    isInitialLoadDisabled: () => initialLoadDisabled,
    isSRA: () => false,
    markAsAmp() {},
    refresh(slts) {
      if (!slts) {
        slts = slots.values();
      } else if (!Array.isArray(slts)) {
        slts = [slts];
      }
      for (const slot of slts) {
        if (slot) {
          try {
            fetchSlot(slot);
            displaySlot(slot);
          } catch (e) {
            console.error(e);
          }
        }
      }
    },
    removeEventListener,
    set(k, v) {
      gAttributes[k] = v;
      return this;
    },
    setCategoryExclusion: noopthisfn,
    setCentering() {},
    setCookieOptions: noopthisfn,
    setCorrelator: noopthisfn,
    setForceSafeFrame: noopthisfn,
    setImaContent(vid, cmsid) {
      imaContent = { vid, cmsid };
      return this;
    },
    setLocation: noopthisfn,
    setPrivacySettings: noopthisfn,
    setPublisherProvidedId: noopthisfn,
    setRequestNonPersonalizedAds: noopthisfn,
    setSafeFrameConfig: noopthisfn,
    setTagForChildDirectedTreatment: noopthisfn,
    setTagForUnderAgeOfConsent: noopthisfn,
    setTargeting(k, v) {
      gTargeting.set(k, getTargetingValue(v));
      return this;
    },
    setVideoContent(vid, cmsid) {
      videoContent = { vid, cmsid };
      return this;
    },
    updateCorrelator() {},
    updateTargetingFromMap(map) {
      updateTargeting(gTargeting, map);
      return this;
    },
  };

  const SizeMappingBuilder = class {
    #mapping;
    constructor() {
      this.#mapping = new SizeMapping();
    }
    addSize(size, creatives) {
      if (
        size !== "fluid" &&
        (!Array.isArray(size) || isNaN(size[0]) || isNaN(size[1]))
      ) {
        this.#mapping = null;
      } else {
        this.#mapping?.push([size, creatives]);
      }
      return this;
    }
    build() {
      return this.#mapping;
    }
  };

  let gt = window.googletag;
  if (!gt) {
    gt = window.googletag = {};
  }

  Object.assign(gt, {
    apiReady: true,
    companionAds: () => companionAdsService,
    content: () => contentService,
    defineOutOfPageSlot: (a, o) => defineSlot(a, 0, o),
    defineSlot: (a, s, o) => defineSlot(a, s, o),
    destroySlots() {
      slots.clear();
      slotsById.clear();
    },
    disablePublisherConsole() {},
    display(arg) {
      let id;
      if (arg?.getSlotElementId) {
        id = arg.getSlotElementId();
      } else if (arg?.nodeType) {
        id = arg.id;
      } else {
        id = String(arg);
      }
      displaySlot(slotsById.get(id));
    },
    enableServices() {},
    enums: {
      OutOfPageFormat: {
        BOTTOM_ANCHOR: 3,
        INTERSTITIAL: 5,
        REWARDED: 4,
        TOP_ANCHOR: 2,
      },
    },
    getVersion: () => version,
    pubads: () => pubadsService,
    pubadsReady: true,
    setAdIframeTitle() {},
    sizeMapping: () => new SizeMappingBuilder(),
  });

  const run = function (fn) {
    if (typeof fn === "function") {
      try {
        fn.call(window);
      } catch (e) {
        console.error(e);
      }
    }
  };

  const cmds = gt.cmd || [];
  const newCmd = [];
  newCmd.push = run;
  gt.cmd = newCmd;

  for (const cmd of cmds) {
    run(cmd);
  }
}
PK
!<wA0�IIshims/google-safeframe.html<!DOCTYPE html>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/.

  Bug 1713691 - Shim Google SafeFrame

  Some sites will break if they cannot load a Google SafeFrame. This
  shim provides a stand-in for the frame to mitigate that breakage.
-->
<html>
  <head>
    <meta charset="UTF-8" />
    <title>SafeFrame Container</title>
    <script>
      try {
        const F = /^([^;]+);(\d+);([\s\S]*)$/.exec(window.name);
        window.name = "";
        const P = window.document;
        P.open("text/html", "replace");
        P.write(F[3].substr(0, +F[2]));
        P.close();
      } catch (e) {
        console.error(e);
      }
    </script>
  </head>
  <body></body>
</html>
PK
!<�L//shims/history.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/*
 * Bug 1624853 - Shim Storage Access API on history.com
 *
 * history.com uses Adobe as a necessary third party to authenticating
 * with a TV provider. In order to accomodate this, we grant storage access
 * to the Adobe domain via the Storage Access API when the login or logout
 * buttons are clicked, then forward the click to continue as normal.
 */

console.warn(
  `When using oauth, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1624853 for details.`
);

// Third-party origin we need to request storage access for.
const STORAGE_ACCESS_ORIGIN = "https://sp.auth.adobe.com";

document.documentElement.addEventListener(
  "click",
  e => {
    const { target, isTrusted } = e;
    if (!isTrusted) {
      return;
    }

    const button = target.closest("a");
    if (!button) {
      return;
    }

    const buttonLink = button.href;
    if (buttonLink?.startsWith("https://www.history.com/mvpd-auth")) {
      button.disabled = true;
      button.style.opacity = 0.5;
      e.stopPropagation();
      e.preventDefault();
      document
        .requestStorageAccessForOrigin(STORAGE_ACCESS_ORIGIN)
        .then(() => {
          target.click();
        })
        .catch(() => {
          button.disabled = false;
          button.style.opacity = 1.0;
        });
    }
  },
  true
);
PK
!<��kH��shims/iam.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1761774 - Shim INFOnline IAM tracker
 *
 * Sites using IAM can break if it is blocked. This shim mitigates that
 * breakage by loading a stand-in module.
 */

if (!window.iom?.c) {
  window.iom = {
    c: () => {},
    consent: () => {},
    count: () => {},
    ct: () => {},
    deloptout: () => {},
    doo: () => {},
    e: () => {},
    event: () => {},
    getInvitation: () => {},
    getPlus: () => {},
    gi: () => {},
    gp: () => {},
    h: () => {},
    hybrid: () => {},
    i: () => {},
    init: () => {},
    oi: () => {},
    optin: () => {},
    setMultiIdentifier: () => {},
    setoptout: () => {},
    smi: () => {},
    soo: () => {},
  };
}
PK
!<�\���shims/iaspet.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713701 - Shim Integral Ad Science iaspet.js
 *
 * Some sites use iaspet to place content, often together with Google Publisher
 * Tags. This shim prevents breakage when the script is blocked.
 */

if (!window.__iasPET?.VERSION) {
  let queue = window?.__iasPET?.queue;
  if (!Array.isArray(queue)) {
    queue = [];
  }

  const response = JSON.stringify({
    brandSafety: {},
    slots: {},
  });

  function run(cmd) {
    try {
      cmd?.dataHandler?.(response);
    } catch (_) {}
  }

  queue.push = run;

  window.__iasPET = {
    VERSION: "1.16.18",
    queue,
    sessionId: "",
    setTargetingForAppNexus() {},
    setTargetingForGPT() {},
    start() {},
  };

  while (queue.length) {
    run(queue.shift());
  }
}
PK
!<5�e�shims/instagram.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/*
 * Bug 1804445 - instagram login broken with dFPI enabled
 *
 * Instagram login with Facebook account requires Facebook to have the storage
 * access under Instagram. This shim adds a request for storage access for
 * Facebook when the user tries to log in with a Facebook account.
 */

console.warn(
  `When logging in, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1804445 for details.`
);

// Third-party origin we need to request storage access for.
const STORAGE_ACCESS_ORIGIN = "https://www.facebook.com";

document.documentElement.addEventListener(
  "click",
  e => {
    const { target, isTrusted } = e;
    if (!isTrusted) {
      return;
    }
    const button = target.closest("button[type=button]");
    if (!button) {
      return;
    }
    const form = target.closest("#loginForm");
    if (!form) {
      return;
    }

    console.warn(
      "Calling the Storage Access API on behalf of " + STORAGE_ACCESS_ORIGIN
    );
    button.disabled = true;
    e.stopPropagation();
    e.preventDefault();
    document
      .requestStorageAccessForOrigin(STORAGE_ACCESS_ORIGIN)
      .then(() => {
        button.disabled = false;
        target.click();
      })
      .catch(() => {
        button.disabled = false;
      });
  },
  true
);
PK
!<�d.z��shims/kinja.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* globals exportFunction */

"use strict";

/**
 * Kinja powered blogs rely on storage access to https://kinja.com to enable
 * oauth with external providers. For dFPI, sites need to use the Storage Access
 * API to gain first party storage access. This shim calls requestStorageAccess
 * on behalf of the site when a user wants to log in via oauth.
 */

// Third-party origin we need to request storage access for.
const STORAGE_ACCESS_ORIGIN = "https://kinja.com";

// Prefix of the path opened in a new window when users click the oauth login
// buttons.
const OAUTH_PATH_PREFIX = "/oauthlogin?provider=";

console.warn(
  `When using oauth, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1656171 for details.`
);

// Overwrite the window.open method so we can detect oauth related popups.
const origOpen = window.wrappedJSObject.open;
Object.defineProperty(window.wrappedJSObject, "open", {
  value: exportFunction((url, ...args) => {
    // Filter oauth popups.
    if (!url.startsWith(OAUTH_PATH_PREFIX)) {
      return origOpen(url, ...args);
    }
    // Request storage access for Kinja.
    document.requestStorageAccessForOrigin(STORAGE_ACCESS_ORIGIN).then(() => {
      origOpen(url, ...args);
    });
    // We don't have the window object yet which window.open returns, since the
    // sign-in flow is dependent on the async storage access request. This isn't
    // a problem as long as the website does not consume it.
    return null;
  }, window),
});
PK
!<n��[��shims/live-test-shim.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser */

if (!window.LiveTestShimPromise) {
  const originalUrl =
    "https://webcompat-addon-testbed.herokuapp.com/shims_test.js";

  const shimId = "LiveTestShim";

  const sendMessageToAddon = (function () {
    const pendingMessages = new Map();
    const channel = new MessageChannel();
    channel.port1.onerror = console.error;
    channel.port1.onmessage = event => {
      const { messageId, response } = event.data;
      const resolve = pendingMessages.get(messageId);
      if (resolve) {
        pendingMessages.delete(messageId);
        resolve(response);
      }
    };
    function reconnect() {
      const detail = {
        pendingMessages: [...pendingMessages.values()],
        port: channel.port2,
        shimId,
      };
      window.dispatchEvent(new CustomEvent("ShimConnects", { detail }));
    }
    window.addEventListener("ShimHelperReady", reconnect);
    reconnect();
    return function (message) {
      const messageId =
        Math.random().toString(36).substring(2) + Date.now().toString(36);
      return new Promise(resolve => {
        const payload = {
          message,
          messageId,
          shimId,
        };
        pendingMessages.set(messageId, resolve);
        channel.port1.postMessage(payload);
      });
    };
  })();

  async function go(options) {
    try {
      const o = document.getElementById("shims");
      const cl = o.classList;
      cl.remove("red");
      cl.add("green");
      o.innerText = JSON.stringify(options || "");
    } catch (_) {}

    if (window !== top) {
      return;
    }

    await sendMessageToAddon("optIn");

    const s = document.createElement("script");
    s.src = originalUrl;
    document.head.appendChild(s);
  }

  window[`${shimId}Promise`] = sendMessageToAddon("getOptions").then(
    options => {
      if (document.readyState !== "loading") {
        go(options);
      } else {
        window.addEventListener("DOMContentLoaded", () => {
          go(options);
        });
      }
    }
  );
}
PK
!<
`�&&shims/maxmind-geoip.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1754389 - Shim Maxmind GeoIP library
 *
 * Some sites rely on Maxmind's GeoIP library which gets blocked by ETP's
 * fingerprinter blocking. With the library window global not being defined
 * functionality may break or the site does not render at all. This shim
 * has it return the United States as the location for all users.
 */

if (!window.geoip2) {
  const continent = {
    code: "NA",
    geoname_id: 6255149,
    names: {
      de: "Nordamerika",
      en: "North America",
      es: "Norteamérica",
      fr: "Amérique du Nord",
      ja: "北アメリカ",
      "pt-BR": "América do Norte",
      ru: "Северная Америка",
      "zh-CN": "北美洲",
    },
  };

  const country = {
    geoname_id: 6252001,
    iso_code: "US",
    names: {
      de: "USA",
      en: "United States",
      es: "Estados Unidos",
      fr: "États-Unis",
      ja: "アメリカ合衆国",
      "pt-BR": "Estados Unidos",
      ru: "США",
      "zh-CN": "美国",
    },
  };

  const city = {
    names: {
      en: "",
    },
  };

  const callback = onSuccess => {
    requestAnimationFrame(() => {
      onSuccess({
        city,
        continent,
        country,
        registered_country: country,
      });
    });
  };

  window.geoip2 = {
    country: callback,
    city: callback,
    insights: callback,
  };
}
PK
!<
o�33shims/microsoftLogin.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const SANDBOX_ATTR = "allow-storage-access-by-user-activation";

console.warn(
  "Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1638383 for details."
);

// Watches for MS auth iframes and adds missing sandbox attribute. The attribute
// is required so the third-party iframe can gain access to its first party
// storage via the Storage Access API.
function init() {
  const observer = new MutationObserver(() => {
    document.body
      .querySelectorAll(
        `iframe:is([id^='msalRenewFrame'], [src^="https://login.microsoftonline.com"])[sandbox]`
      )
      .forEach(frame => {
        frame.sandbox.add(SANDBOX_ATTR);
      });
  });

  observer.observe(document.body, {
    attributes: true,
    subtree: false,
    childList: true,
  });
}
window.addEventListener("DOMContentLoaded", init);
PK
!<oi0��"shims/microsoftVirtualAssistant.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1801277 - Shim Microsoft virtual assistant.
 *
 * The microsoft virtual assistant will break when accessing the indexedDB that
 * will throw a security error because the virtual assistant is under a
 * third-party tracking domain 'liveperson.net'. The shim replaces the indexedDB
 * with a fake interface that won't throw an error.
 */

/* globals cloneInto */

(function () {
  const win = window.wrappedJSObject;

  try {
    // We only replace the indexedDB when liveperson.net is loaded in a
    // third-party context. Note that this is not strictly correct because
    // this is a cross-origin check but not a third-party check.
    if (win.parent == win || win.location.origin == win.top.location.origin) {
      return;
    }
  } catch (e) {
    // If we get a security error when accessing the top-level origin, this
    // shows that the window is in a cross-origin context. In this case, we can
    // proceed to apply the shim.
    if (e.name != "SecurityError") {
      throw e;
    }
  }

  const emptyMsg = cloneInto({ message: "" }, window);

  const idb = {
    open: () => win.Promise.reject(emptyMsg),
  };

  Object.defineProperty(win, "indexedDB", {
    value: cloneInto(idb, window, { cloneFunctions: true }),
  });
})();
PK
!<�v�GG
shims/moat.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713704 - Shim Moat ad tracker
 *
 * Sites such as Forbes may gate content behind Moat ads, resulting in
 * breakage like black boxes where videos should be placed. This shim
 * helps mitigate that breakage by allowing the placement to succeed.
 */

if (!window.moatPrebidAPI?.__A) {
  const targeting = new Map();

  const slotConfig = {
    m_categories: ["moat_safe"],
    m_data: "0",
    m_safety: "safe",
  };

  window.moatPrebidApi = {
    __A() {},
    disableLogging() {},
    enableLogging() {},
    getMoatTargetingForPage: () => slotConfig,
    getMoatTargetingForSlot(slot) {
      return targeting.get(slot?.getSlotElementId());
    },
    pageDataAvailable: () => true,
    safetyDataAvailable: () => true,
    setMoatTargetingForAllSlots() {
      for (const slot of window.googletag.pubads().getSlots() || []) {
        targeting.set(slot.getSlotElementId(), slot.getTargeting());
      }
    },
    setMoatTargetingForSlot(slot) {
      targeting.set(slot?.getSlotElementId(), slotConfig);
    },
    slotDataAvailable() {
      return window.googletag?.pubads().getSlots().length > 0;
    },
  };
}
PK
!<FEhƸ	�	shims/mochitest-shim-1.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser */

if (!window.MochitestShimPromise) {
  const originalUrl =
    "http://example.com/browser/browser/extensions/webcompat/tests/browser/shims_test.js";

  const shimId = "MochitestShim";

  const sendMessageToAddon = (function () {
    const pendingMessages = new Map();
    const channel = new MessageChannel();
    channel.port1.onerror = console.error;
    channel.port1.onmessage = event => {
      const { messageId, response } = event.data;
      const resolve = pendingMessages.get(messageId);
      if (resolve) {
        pendingMessages.delete(messageId);
        resolve(response);
      }
    };
    function reconnect() {
      const detail = {
        pendingMessages: [...pendingMessages.values()],
        port: channel.port2,
        shimId,
      };
      window.dispatchEvent(new CustomEvent("ShimConnects", { detail }));
    }
    window.addEventListener("ShimHelperReady", reconnect);
    reconnect();
    return function (message) {
      const messageId =
        Math.random().toString(36).substring(2) + Date.now().toString(36);
      return new Promise(resolve => {
        const payload = {
          message,
          messageId,
          shimId,
        };
        pendingMessages.set(messageId, resolve);
        channel.port1.postMessage(payload);
      });
    };
  })();

  async function go(options) {
    try {
      const o = document.getElementById("shims");
      const cl = o.classList;
      cl.remove("red");
      cl.add("green");
      o.innerText = JSON.stringify(options || "");
    } catch (_) {}

    window.shimPromiseResolve("shimmed");

    if (window !== top) {
      window.optInPromiseResolve(false);
      return;
    }

    await sendMessageToAddon("optIn");

    window.doingOptIn = true;
    const s = document.createElement("script");
    s.src = originalUrl;
    s.onerror = () => window.optInPromiseResolve("error");
    document.head.appendChild(s);
  }

  window[`${shimId}Promise`] = new Promise(resolve => {
    sendMessageToAddon("getOptions").then(options => {
      if (document.readyState !== "loading") {
        resolve(go(options));
      } else {
        window.addEventListener("DOMContentLoaded", () => {
          resolve(go(options));
        });
      }
    });
  });
}
PK
!<�܎�P	P	shims/mochitest-shim-2.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* globals browser */

if (!window.testPromise) {
  const originalUrl =
    "http://example.com/browser/browser/extensions/webcompat/tests/browser/shims_test_2.js";

  const shimId = "MochitestShim2";

  const sendMessageToAddon = (function () {
    const pendingMessages = new Map();
    const channel = new MessageChannel();
    channel.port1.onerror = console.error;
    channel.port1.onmessage = event => {
      const { messageId, response } = event.data;
      const resolve = pendingMessages.get(messageId);
      if (resolve) {
        pendingMessages.delete(messageId);
        resolve(response);
      }
    };
    function reconnect() {
      const detail = {
        pendingMessages: [...pendingMessages.values()],
        port: channel.port2,
        shimId,
      };
      window.dispatchEvent(new CustomEvent("ShimConnects", { detail }));
    }
    window.addEventListener("ShimHelperReady", reconnect);
    reconnect();
    return function (message) {
      const messageId =
        Math.random().toString(36).substring(2) + Date.now().toString(36);
      return new Promise(resolve => {
        const payload = {
          message,
          messageId,
          shimId,
        };
        pendingMessages.set(messageId, resolve);
        channel.port1.postMessage(payload);
      });
    };
  })();

  async function go(options) {
    try {
      const o = document.getElementById("shims");
      const cl = o.classList;
      cl.remove("red");
      cl.add("green");
      o.innerText = JSON.stringify(options || "");
    } catch (_) {}

    window.shimPromiseResolve("shimmed");

    if (window !== top) {
      window.optInPromiseResolve(false);
      return;
    }

    await sendMessageToAddon("optIn");

    window.doingOptIn = true;
    const s = document.createElement("script");
    s.src = originalUrl;
    s.onerror = () => window.optInPromiseResolve("error");
    document.head.appendChild(s);
  }

  sendMessageToAddon("getOptions").then(options => {
    if (document.readyState !== "loading") {
      go(options);
    } else {
      window.addEventListener("DOMContentLoaded", () => {
        go(options);
      });
    }
  });
}
PK
!<�$K*shims/mochitest-shim-3.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

window.shimPromiseResolve("shimmed");
PK
!<��S
		shims/nielsen.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1760754 - Shim Nielsen tracker
 *
 * Sites expecting the Nielsen tracker to load properly can break if it
 * is blocked. This shim mitigates that breakage by loading a stand-in.
 */

if (!window.nol_t) {
  const cid = "";

  let domain = "";
  let schemeHost = "";
  let scriptName = "";
  try {
    const url = document?.currentScript?.src;
    const { pathname, protocol, host } = new URL(url);
    domain = host.split(".").slice(0, -2).join(".");
    schemeHost = `${protocol}//${host}/`;
    scriptName = pathname.split("/").pop();
  } catch (_) {}

  const NolTracker = class {
    CONST = {
      max_tags: 20,
    };
    feat = {};
    globals = {
      cid,
      content: "0",
      defaultApidFile: "config250",
      defaultErrorParams: {
        nol_vcid: "c00",
        nol_clientid: "",
      },
      domain,
      fpidSfCodeList: [""],
      init() {},
      tagCurrRetry: -1,
      tagMaxRetry: 3,
      wlCurrRetry: -1,
      wlMaxRetry: 3,
    };
    pmap = [];
    pvar = {
      cid,
      content: "0",
      cookies_enabled: "n",
      server: domain,
    };
    scriptName = [scriptName];
    version = "6.0.107";

    addScript() {}
    catchLinkOverlay() {}
    clickEvent() {}
    clickTrack() {}
    do_sample() {}
    downloadEvent() {}
    eventTrack() {}
    filter() {}
    fireToUrl() {}
    getSchemeHost() {
      return schemeHost;
    }
    getVersion() {}
    iframe() {}
    in_sample() {
      return true;
    }
    injectBsdk() {}
    invite() {}
    linkTrack() {}
    mergeFeatures() {}
    pageEvent() {}
    pause() {}
    populateWhitelist() {}
    post() {}
    postClickTrack() {}
    postData() {}
    postEvent() {}
    postEventTrack() {}
    postLinkTrack() {}
    prefix() {
      return "";
    }
    processDdrsSvc() {}
    random() {}
    record() {
      return this;
    }
    regLinkOverlay() {}
    regListen() {}
    retrieveCiFileViaCors() {}
    sectionEvent() {}
    sendALink() {}
    sendForm() {}
    sendIt() {}
    slideEvent() {}
    whitelistAssigned() {}
  };

  window.nol_t = () => {
    return new NolTracker();
  };
}
PK
!<�����shims/optimizely.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * Bug 1714431 - Shim Optimizely
 *
 * This shim stubs out window.optimizely for those sites which
 * break when it is not successfully loaded.
 */

if (!window.optimizely?.state) {
  const behavior = {
    query: () => [],
  };

  const dcp = {
    getAttributeValue() {},
    waitForAttributeValue: () => Promise.resolve(),
  };

  const data = {
    accountId: "",
    audiences: {},
    campaigns: {},
    clientName: "js",
    clientVersion: "0.166.0",
    dcpServiceId: null,
    events: {},
    experiments: {},
    groups: {},
    pages: {},
    projectId: "",
    revision: "",
    snippetId: null,
    variations: {},
  };

  const activationId = String(Date.now());

  const state = {
    getActivationId() {
      return activationId;
    },
    getActiveExperimentIds() {
      return [];
    },
    getCampaignStateLists() {
      return {};
    },
    getCampaignStates() {
      return {};
    },
    getDecisionObject() {
      return null;
    },
    getDecisionString() {
      return null;
    },
    getExperimentStates() {
      return {};
    },
    getPageStates() {
      return {};
    },
    getRedirectInfo() {
      return null;
    },
    getVariationMap() {
      return {};
    },
    isGlobalHoldback() {
      return false;
    },
  };

  const poll = (fn, to) => {
    setInterval(() => {
      try {
        fn();
      } catch (_) {}
    }, to);
  };

  const waitUntil = test => {
    let interval, resolve;
    function check() {
      try {
        if (test()) {
          clearInterval(interval);
          resolve?.();
          return true;
        }
      } catch (_) {}
      return false;
    }
    return new Promise(r => {
      resolve = r;
      if (check()) {
        resolve();
        return;
      }
      interval = setInterval(check, 250);
    });
  };

  const waitForElement = sel => {
    return waitUntil(() => {
      document.querySelector(sel);
    });
  };

  const observeSelector = (sel, fn, opts) => {
    let interval;
    const observed = new Set();
    function check() {
      try {
        for (const e of document.querySelectorAll(sel)) {
          if (observed.has(e)) {
            continue;
          }
          observed.add(e);
          try {
            fn(e);
          } catch (_) {}
          if (opts.once) {
            clearInterval(interval);
          }
        }
      } catch (_) {}
    }
    interval = setInterval(check, 250);
    const timeout = { opts };
    if (timeout) {
      setTimeout(() => {
        clearInterval(interval);
      }, timeout);
    }
  };

  const utils = {
    Promise: window.Promise,
    observeSelector,
    poll,
    waitForElement,
    waitUntil,
  };

  const visitorId = {
    randomId: "",
  };

  let browserVersion = "";
  try {
    browserVersion = navigator.userAgent.match(/rv:(.*)\)/)[1];
  } catch (_) {}

  const visitor = {
    browserId: "ff",
    browserVersion,
    currentTimestamp: Date.now(),
    custom: {},
    customBehavior: {},
    device: "desktop",
    device_type: "desktop_laptop",
    events: [],
    first_session: true,
    offset: 240,
    referrer: null,
    source_type: "direct",
    visitorId,
  };

  window.optimizely = {
    data: {
      note: "Obsolete, use optimizely.get('data') instead",
    },
    get(e) {
      switch (e) {
        case "behavior":
          return behavior;
        case "data":
          return data;
        case "dcp":
          return dcp;
        case "jquery":
          throw new Error("jQuery not implemented");
        case "session":
          return undefined;
        case "state":
          return state;
        case "utils":
          return utils;
        case "visitor":
          return visitor;
        case "visitor_id":
          return visitorId;
      }
      return undefined;
    },
    initialized: true,
    push() {},
    state: {},
  };
}
PK
!<�Viishims/play.svg<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/.
  source: https://searchfox.org/mozilla-central/source/devtools/client/themes/images/play.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path fill="#fff" d="M20.436 11.37L5.904 2.116c-.23-.147-.523-.158-.762-.024-.24.132-.39.384-.39.657v18.5c0 .273.15.525.39.657.112.063.236.093.36.093.14 0 .28-.04.402-.117l14.53-9.248c.218-.138.35-.376.35-.633 0-.256-.132-.495-.348-.633z"/>
</svg>
PK
!<AIEI��shims/rambler-authenticator.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

if (!window.ramblerIdHelper) {
  const originalScript = (() => {
    const src = document.currentScript?.src;
    try {
      const { protocol, hostname, pathname, href } = new URL(src);
      if (
        (protocol === "http:" || protocol === "https:") &&
        hostname === "id.rambler.ru" &&
        pathname === "rambler-id-helper/auth_events.js"
      ) {
        return href;
      }
    } catch (_) {}
    return "https://id.rambler.ru/rambler-id-helper/auth_events.js";
  })();

  const sendMessageToAddon = (function () {
    const shimId = "Rambler";
    const pendingMessages = new Map();
    const channel = new MessageChannel();
    channel.port1.onerror = console.error;
    channel.port1.onmessage = event => {
      const { messageId, response } = event.data;
      const resolve = pendingMessages.get(messageId);
      if (resolve) {
        pendingMessages.delete(messageId);
        resolve(response);
      }
    };
    function reconnect() {
      const detail = {
        pendingMessages: [...pendingMessages.values()],
        port: channel.port2,
        shimId,
      };
      window.dispatchEvent(new CustomEvent("ShimConnects", { detail }));
    }
    window.addEventListener("ShimHelperReady", reconnect);
    reconnect();
    return function (message) {
      const messageId =
        Math.random().toString(36).substring(2) + Date.now().toString(36);
      return new Promise(resolve => {
        const payload = {
          message,
          messageId,
          shimId,
        };
        pendingMessages.set(messageId, resolve);
        channel.port1.postMessage(payload);
      });
    };
  })();

  const ramblerIdHelper = {
    getProfileInfo: (successCallback, _errorCallback) => {
      successCallback({});
    },
    openAuth: () => {
      sendMessageToAddon("optIn").then(function () {
        const openAuthArgs = arguments;
        window.ramblerIdHelper = undefined;
        const s = document.createElement("script");
        s.src = originalScript;
        document.head.appendChild(s);
        s.addEventListener("load", () => {
          const helper = window.ramblerIdHelper;
          for (const { fn, args } of callLog) {
            helper[fn].apply(helper, args);
          }
          helper.openAuth.apply(helper, openAuthArgs);
        });
      });
    },
  };

  const callLog = [];
  function addLoggedCall(fn) {
    ramblerIdHelper[fn] = () => {
      callLog.push({ fn, args: arguments });
    };
  }

  addLoggedCall("registerOnFrameCloseCallback");
  addLoggedCall("registerOnFrameRedirect");
  addLoggedCall("registerOnPossibleLoginCallback");
  addLoggedCall("registerOnPossibleLogoutCallback");
  addLoggedCall("registerOnPossibleOauthLoginCallback");

  window.ramblerIdHelper = ramblerIdHelper;
}
PK
!<g("W��shims/rich-relevance.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713725 - Shim Rich Relevance personalized shopping
 *
 * Sites may expect the Rich Relevance personalized shopping API to load,
 * breaking if it is blocked. This shim attempts to limit breakage on those
 * site to just the personalized shopping aspects, by stubbing out the APIs.
 */

if (!window.r3_common) {
  const jsonCallback = window.RR?.jsonCallback;
  const defaultCallback = window.RR?.defaultCallback;

  const getRandomString = (l = 66) => {
    const v = crypto.getRandomValues(new Uint8Array(l));
    const s = Array.from(v, c => c.toString(16)).join("");
    return s.slice(0, l);
  };

  const call = (fn, ...args) => {
    if (typeof fn === "function") {
      try {
        fn(...args);
      } catch (e) {
        console.error(e);
      }
    }
  };

  class r3_generic {
    type = "GENERIC";
    createScript() {}
    destroy() {}
  }

  class r3_addtocart extends r3_generic {
    type = "ADDTOCART";
    addItemIdToCart() {}
  }

  class r3_addtoregistry extends r3_generic {
    type = "ADDTOREGISTRY";
    addItemIdCentsQuantity() {}
  }

  class r3_brand extends r3_generic {
    type = "BRAND";
  }

  class r3_cart extends r3_generic {
    type = "CART";
    addItemId() {}
    addItemIdCentsQuantity() {}
    addItemIdDollarsAndCentsQuantity() {}
    addItemIdPriceQuantity() {}
  }

  class r3_category extends r3_generic {
    type = "CATEGORY";
    addItemId() {}
    setId() {}
    setName() {}
    setParentId() {}
    setTopName() {}
  }

  class r3_common extends r3_generic {
    type = "COMMON";
    baseUrl = "https://recs.richrelevance.com/rrserver/";
    devFlags = {};
    jsFileName = "p13n_generated.js";
    RICHSORT = {
      paginate() {},
      filterPrice() {},
      filterAttribute() {},
    };
    addCategoryHintId() {}
    addClickthruParams() {}
    addContext() {}
    addFilter() {}
    addFilterBrand() {}
    addFilterCategory() {}
    addItemId() {}
    addItemIdToCart() {}
    addPlacementType() {}
    addRefinement() {}
    addSearchTerm() {}
    addSegment() {}
    blockItemId() {}
    enableCfrad() {}
    enableRad() {}
    forceDebugMode() {}
    forceDevMode() {}
    forceDisplayMode() {}
    forceLocale() {}
    initFromParams() {}
    setApiKey() {}
    setBaseUrl() {}
    setCartValue() {}
    setChannel() {}
    setClickthruServer() {}
    setCurrency() {}
    setDeviceId() {}
    setFilterBrandsIncludeMatchingElements() {}
    setForcedTreatment() {}
    setImageServer() {}
    setLanguage() {}
    setMVTForcedTreatment() {}
    setNoCookieMode() {}
    setPageBrand() {}
    setPrivateMode() {}
    setRefinementFallback() {}
    setRegionId() {}
    setRegistryId() {}
    setRegistryType() {}
    setSessionId() {}
    setUserId() {}
    useDummyData() {}
  }

  class r3_error extends r3_generic {
    type = "ERROR";
  }

  class r3_home extends r3_generic {
    type = "HOME";
  }

  class r3_item extends r3_generic {
    type = "ITEM";
    addAttribute() {}
    addCategory() {}
    addCategoryId() {}
    setBrand() {}
    setEndDate() {}
    setId() {}
    setImageId() {}
    setLinkId() {}
    setName() {}
    setPrice() {}
    setRating() {}
    setRecommendable() {}
    setReleaseDate() {}
    setSalePrice() {}
  }

  class r3_personal extends r3_generic {
    type = "PERSONAL";
  }

  class r3_purchased extends r3_generic {
    type = "PURCHASED";
    addItemId() {}
    addItemIdCentsQuantity() {}
    addItemIdDollarsAndCentsQuantity() {}
    addItemIdPriceQuantity() {}
    setOrderNumber() {}
    setPromotionCode() {}
    setShippingCost() {}
    setTaxes() {}
    setTotalPrice() {}
  }

  class r3_search extends r3_generic {
    type = "SEARCH";
    addItemId() {}
    setTerms() {}
  }

  class r3_wishlist extends r3_generic {
    type = "WISHLIST";
    addItemId() {}
  }

  const RR = {
    add() {},
    addItemId() {},
    addItemIdCentsQuantity() {},
    addItemIdDollarsAndCentsQuantity() {},
    addItemIdPriceQuantity() {},
    addItemIdToCart() {},
    addObject() {},
    addSearchTerm() {},
    c() {},
    charset: "UTF-8",
    checkParamCookieValue: () => null,
    d: document,
    data: {
      JSON: {
        placements: [],
      },
    },
    debugWindow() {},
    set defaultCallback(fn) {
      call(fn);
    },
    fixName: n => n,
    genericAddItemPriceQuantity() {},
    get() {},
    getDomElement(a) {
      return typeof a === "string" && a ? document.querySelector(a) : null;
    },
    id() {},
    insert() {},
    insertDynamicPlacement() {},
    isArray: a => Array.isArray(a),
    js() {},
    set jsonCallback(fn) {
      call(fn, {});
    },
    l: document.location.href,
    lc() {},
    noCookieMode: false,
    ol() {},
    onloadCalled: true,
    pq() {},
    rcsCookieDefaultDuration: 364,
    registerPageType() {},
    registeredPageTypes: {
      ADDTOCART: r3_addtocart,
      ADDTOREGISTRY: r3_addtoregistry,
      BRAND: r3_brand,
      CART: r3_cart,
      CATEGORY: r3_category,
      COMMON: r3_common,
      ERROR: r3_error,
      GENERIC: r3_generic,
      HOME: r3_home,
      ITEM: r3_item,
      PERSONAL: r3_personal,
      PURCHASED: r3_purchased,
      SEARCH: r3_search,
      WISHLIST: r3_wishlist,
    },
    renderDynamicPlacements() {},
    set() {},
    setCharset() {},
    U: "undefined",
    unregisterAllPageType() {},
    unregisterPageType() {},
  };

  Object.assign(window, {
    r3() {},
    r3_addtocart,
    r3_addtoregistry,
    r3_brand,
    r3_cart,
    r3_category,
    r3_common,
    r3_error,
    r3_generic,
    r3_home,
    r3_item,
    r3_personal,
    r3_placement() {},
    r3_purchased,
    r3_search,
    r3_wishlist,
    RR,
    rr_addLoadEvent() {},
    rr_annotations_array: [undefined],
    rr_call_after_flush() {},
    rr_create_script() {},
    rr_dynamic: {
      placements: [],
    },
    rr_flush() {},
    rr_flush_onload() {},
    rr_insert_placement() {},
    rr_onload_called: true,
    rr_placement_place_holders: [],
    rr_placements: [],
    rr_recs: {
      placements: [],
    },
    rr_remote_data: getRandomString(),
    rr_v: "1.2.6.20210212",
  });

  call(jsonCallback);
  call(defaultCallback, {});
}
PK
!<8�f��shims/salesforce.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1855139 - The pop-up for "Où trouver ma référence ?" option is blank at
 * garantie30minutes.sncf.com with ETP set to STANDARD
 *
 * emeraude.my.salesforce.com is marked as a tracker, and it tries to access localstorage, but the
 * script returned does not handle the error. The shim replaces localstorage with a fake
 * interface to avoid the error.
 *
 */

/* globals cloneInto */

(function () {
  const win = window.wrappedJSObject;

  try {
    // We only replace the indexedDB when emeraude.my.salesforce.com is loaded in a
    // third-party context. Note that this is not strictly correct because
    // this is a cross-origin check but not a third-party check.
    if (win.parent == win || win.location.origin == win.top.location.origin) {
      return;
    }
  } catch (e) {
    // If we get a security error when accessing the top-level origin, this
    // shows that the window is in a cross-origin context. In this case, we can
    // proceed to apply the shim.
    if (e.name != "SecurityError") {
      throw e;
    }
  }

  const emptyMsg = cloneInto({ message: "" }, window);

  const idb = {
    open: () => win.Promise.reject(emptyMsg),
  };

  Object.defineProperty(win, "indexedDB", {
    value: cloneInto(idb, window, { cloneFunctions: true }),
  });
})();
PK
!<��A��shims/spotify-embed.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* globals exportFunction */

"use strict";

/**
 * Spotify embeds default to "track preview mode". They require first-party
 * storage access in order to detect the login status and allow the user to play
 * the whole song or add it to their library.
 * Upon clicking the "play" button in the preview view this shim attempts to get
 * storage access and on success, reloads the frame and plays the full track.
 * This only works if the user is already logged in to Spotify in the
 * first-party context.
 */

const AUTOPLAY_FLAG = "shimPlayAfterStorageAccess";
const SELECTOR_PREVIEW_PLAY = 'div[data-testid="preview-play-pause"] > button';
const SELECTOR_FULL_PLAY = 'button[data-testid="play-pause-button"]';

/**
 * Promise-wrapper around DOMContentLoaded event.
 */
function waitForDOMContentLoaded() {
  return new Promise(resolve => {
    window.addEventListener("DOMContentLoaded", resolve, { once: true });
  });
}

/**
 * Listener for the preview playback button which requests storage access and
 * reloads the page.
 */
function previewPlayButtonListener(event) {
  const { target, isTrusted } = event;
  if (!isTrusted) {
    return;
  }

  const button = target.closest("button");
  if (!button) {
    return;
  }

  // Filter for the preview playback button. This won't match the full
  // playback button that is shown when the user is logged in.
  if (!button.matches(SELECTOR_PREVIEW_PLAY)) {
    return;
  }

  // The storage access request below runs async so playback won't start
  // immediately. Mitigate this UX issue by updating the clicked element's
  // style so the user gets some immediate feedback.
  button.style.opacity = 0.5;
  event.stopPropagation();
  event.preventDefault();

  console.debug("Requesting storage access.", location.origin);
  document
    .requestStorageAccess()
    // When storage access is granted, reload the frame for the embedded
    // player to detect the login state and give us full playback
    // capabilities.
    .then(() => {
      // Use a flag to indicate that we want to click play after reload.
      // This is so the user does not have to click play twice.
      sessionStorage.setItem(AUTOPLAY_FLAG, "true");
      console.debug("Reloading after storage access grant.");
      location.reload();
    })
    // If the user denies the storage access prompt we can't use the login
    // state. Attempt start preview playback instead.
    .catch(() => {
      button.click();
    })
    // Reset button style for both success and error case.
    .finally(() => {
      button.style.opacity = 1.0;
    });
}

/**
 * Attempt to start (full) playback. Waits for the play button to appear and
 * become ready.
 */
async function startFullPlayback() {
  await document.requestStorageAccess();

  // Wait for DOMContentLoaded before looking for the playback button.
  await waitForDOMContentLoaded();

  let numTries = 0;
  let intervalId = setInterval(() => {
    try {
      document.querySelector(SELECTOR_FULL_PLAY).click();
      clearInterval(intervalId);
      console.debug("Clicked play after storage access grant.");
    } catch (e) {}
    numTries++;

    if (numTries >= 50) {
      console.debug("Can not start playback. Giving up.");
      clearInterval(intervalId);
    }
  }, 200);
}

(async () => {
  // Only run the shim for embedded iframes.
  if (window.top == window) {
    return;
  }

  console.warn(
    `When using the Spotify embedded player, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1792395 for details.`
  );

  // Already requested storage access before the reload, trigger playback.
  if (sessionStorage.getItem(AUTOPLAY_FLAG) == "true") {
    sessionStorage.removeItem(AUTOPLAY_FLAG);

    await startFullPlayback();
    return;
  }

  // Wait for the user to click the preview play button. If the player has
  // already loaded the full version, this method will do nothing.
  document.documentElement.addEventListener(
    "click",
    previewPlayButtonListener,
    { capture: true }
  );
})();
PK
!<IJ�FFshims/tracking-pixel.png�PNG


IHDRĉ
IDATx�c��������IEND�B`�PK
!<����CCshims/tsn-ca.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/*
 * Bug 1802340 - tsn.ca login broken with dFPI enabled
 *
 * tsn.ca relies upon a login page that is out-of-origin. That login page
 * sets a cookie for https://www.tsn.ca, which is then used as an proof of
 * authentication on redirect back to the main site. This shim adds a request
 * for storage access for https://www.tsn.ca when the user tries to log in.
 */

console.warn(
  `When logging in, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1802340 for details.`
);

// Third-party origin we need to request storage access for.
const STORAGE_ACCESS_ORIGIN = "https://www.tsn.ca";

document.documentElement.addEventListener(
  "click",
  e => {
    const { target, isTrusted } = e;
    if (!isTrusted) {
      return;
    }

    const button = target.closest("button");
    if (!button) {
      return;
    }
    const form = target.closest(".login-form");
    if (!form) {
      return;
    }

    console.warn(
      "Calling the Storage Access API on behalf of " + STORAGE_ACCESS_ORIGIN
    );
    button.disabled = true;
    e.stopPropagation();
    e.preventDefault();
    document
      .requestStorageAccessForOrigin(STORAGE_ACCESS_ORIGIN)
      .then(() => {
        button.disabled = false;
        target.click();
      })
      .catch(() => {
        button.disabled = false;
      });
  },
  true
);
PK
!<�d+���shims/vast2.xml<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/.

  Bug 1713693 - Shim Doubleclick

  Some sites rely on an XML VAST Ad response from Doubleclick, or will
  break (showing black boxes instead of videos, etc). This shim mitigates
  such breakage.
-->
<VAST version="2.0"></VAST>
PK
!<L��U��shims/vast3.xml<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/.

  Bug 1713693 - Shim Doubleclick

  Some sites rely on an XML VAST Ad response from Doubleclick, or will
  break (showing black boxes instead of videos, etc). This shim mitigates
  such breakage.
-->
<VAST version="3.0"></VAST>
PK
!<OCr+1+1shims/vidible.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1713710 - Shim Vidible video player
 *
 * Sites relying on Vidible's video player may experience broken videos if that
 * script is blocked. This shim allows users to opt into viewing those videos
 * regardless of any tracking consequences, by providing placeholders for each.
 */

if (!window.vidible?.version) {
  const PlayIconURL = "https://smartblock.firefox.etp/play.svg";

  const originalScript = (() => {
    const src = document.currentScript?.src;
    try {
      const { protocol, hostname, pathname, href } = new URL(src);
      if (
        (protocol === "http:" || protocol === "https:") &&
        pathname.endsWith("/vidible-min.js") &&
        (hostname.endsWith(".vidible.tv") ||
          hostname === "vdb-cdn-files.s3.amazonaws.com")
      ) {
        return href;
      }
    } catch (_) {}
    return "https://cdn-ssl.vidible.tv/prod/player/js/21.1.1/vidible-min.js";
  })();

  const getGUID = () => {
    const v = crypto.getRandomValues(new Uint8Array(20));
    return Array.from(v, c => c.toString(16)).join("");
  };

  const sendMessageToAddon = (function () {
    const shimId = "Vidible";
    const pendingMessages = new Map();
    const channel = new MessageChannel();
    channel.port1.onerror = console.error;
    channel.port1.onmessage = event => {
      const { messageId, response } = event.data;
      const resolve = pendingMessages.get(messageId);
      if (resolve) {
        pendingMessages.delete(messageId);
        resolve(response);
      }
    };
    function reconnect() {
      const detail = {
        pendingMessages: [...pendingMessages.values()],
        port: channel.port2,
        shimId,
      };
      window.dispatchEvent(new CustomEvent("ShimConnects", { detail }));
    }
    window.addEventListener("ShimHelperReady", reconnect);
    reconnect();
    return function (message) {
      const messageId = getGUID();
      return new Promise(resolve => {
        const payload = { message, messageId, shimId };
        pendingMessages.set(messageId, resolve);
        channel.port1.postMessage(payload);
      });
    };
  })();

  const Shimmer = (function () {
    // If a page might store references to an object before we replace it,
    // ensure that it only receives proxies to that object created by
    // `Shimmer.proxy(obj)`. Later when the unshimmed object is created,
    // call `Shimmer.unshim(proxy, unshimmed)`. This way the references
    // will automatically "become" the unshimmed object when appropriate.

    const shimmedObjects = new WeakMap();
    const unshimmedObjects = new Map();

    function proxy(shim) {
      if (shimmedObjects.has(shim)) {
        return shimmedObjects.get(shim);
      }

      const prox = new Proxy(shim, {
        get: (target, k) => {
          if (unshimmedObjects.has(prox)) {
            return unshimmedObjects.get(prox)[k];
          }
          return target[k];
        },
        apply: (target, thisArg, args) => {
          if (unshimmedObjects.has(prox)) {
            return unshimmedObjects.get(prox)(...args);
          }
          return target.apply(thisArg, args);
        },
        construct: (target, args) => {
          if (unshimmedObjects.has(prox)) {
            return new unshimmedObjects.get(prox)(...args);
          }
          return new target(...args);
        },
      });
      shimmedObjects.set(shim, prox);
      shimmedObjects.set(prox, prox);

      for (const key in shim) {
        const value = shim[key];
        if (typeof value === "function") {
          shim[key] = function () {
            const unshimmed = unshimmedObjects.get(prox);
            if (unshimmed) {
              return unshimmed[key].apply(unshimmed, arguments);
            }
            return value.apply(this, arguments);
          };
        } else if (typeof value !== "object" || value === null) {
          shim[key] = value;
        } else {
          shim[key] = Shimmer.proxy(value);
        }
      }

      return prox;
    }

    function unshim(shim, unshimmed) {
      unshimmedObjects.set(shim, unshimmed);

      for (const prop in shim) {
        if (prop in unshimmed) {
          const un = unshimmed[prop];
          if (typeof un === "object" && un !== null) {
            unshim(shim[prop], un);
          }
        } else {
          unshimmedObjects.set(shim[prop], undefined);
        }
      }
    }

    return { proxy, unshim };
  })();

  const extras = [];
  const playersByNode = new WeakMap();
  const playerData = new Map();

  const getJSONPVideoPlacements = () => {
    return document.querySelectorAll(
      `script[src*="delivery.vidible.tv/jsonp"]`
    );
  };

  const allowVidible = () => {
    if (allowVidible.promise) {
      return allowVidible.promise;
    }

    const shim = window.vidible;
    window.vidible = undefined;

    allowVidible.promise = sendMessageToAddon("optIn")
      .then(() => {
        return new Promise((resolve, reject) => {
          const script = document.createElement("script");
          script.src = originalScript;
          script.addEventListener("load", () => {
            Shimmer.unshim(shim, window.vidible);

            for (const args of extras) {
              window.visible.registerExtra(...args);
            }

            for (const jsonp of getJSONPVideoPlacements()) {
              const { src } = jsonp;
              const jscript = document.createElement("script");
              jscript.onload = resolve;
              jscript.src = src;
              jsonp.replaceWith(jscript);
            }

            for (const [playerShim, data] of playerData.entries()) {
              const { loadCalled, on, parent, placeholder, setup } = data;

              placeholder?.remove();

              const player = window.vidible.player(parent);
              Shimmer.unshim(playerShim, player);

              for (const [type, fns] of on.entries()) {
                for (const fn of fns) {
                  try {
                    player.on(type, fn);
                  } catch (e) {
                    console.error(e);
                  }
                }
              }

              if (setup) {
                player.setup(setup);
              }

              if (loadCalled) {
                player.load();
              }
            }

            resolve();
          });

          script.addEventListener("error", () => {
            script.remove();
            reject();
          });

          document.head.appendChild(script);
        });
      })
      .catch(() => {
        window.vidible = shim;
        delete allowVidible.promise;
      });

    return allowVidible.promise;
  };

  const createVideoPlaceholder = (service, callback) => {
    const placeholder = document.createElement("div");
    placeholder.style = `
      position: absolute;
      width: 100%;
      height: 100%;
      min-width: 160px;
      min-height: 100px;
      top: 0px;
      left: 0px;
      background: #000;
      color: #fff;
      text-align: center;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      background-image: url(${PlayIconURL});
      background-position: 50% 47.5%;
      background-repeat: no-repeat;
      background-size: 25% 25%;
      -moz-text-size-adjust: none;
      -moz-user-select: none;
      color: #fff;
      align-items: center;
      padding-top: 200px;
      font-size: 14pt;
    `;
    placeholder.textContent = `Click to allow blocked ${service} content`;
    placeholder.addEventListener("click", evt => {
      evt.isTrusted && callback();
    });
    return placeholder;
  };

  const Player = function (parent) {
    const existing = playersByNode.get(parent);
    if (existing) {
      return existing;
    }

    const player = Shimmer.proxy(this);
    playersByNode.set(parent, player);

    const placeholder = createVideoPlaceholder("Vidible", allowVidible);
    parent.parentNode.insertBefore(placeholder, parent);

    playerData.set(player, {
      on: new Map(),
      parent,
      placeholder,
    });
    return player;
  };

  const changeData = function (fn) {
    const data = playerData.get(this);
    if (data) {
      fn(data);
      playerData.set(this, data);
    }
  };

  Player.prototype = {
    addEventListener() {},
    destroy() {
      const { placeholder } = playerData.get(this);
      placeholder?.remove();
      playerData.delete(this);
    },
    dispatchEvent() {},
    getAdsPassedTime() {},
    getAllMacros() {},
    getCurrentTime() {},
    getDuration() {},
    getHeight() {},
    getPixelsLog() {},
    getPlayerContainer() {},
    getPlayerInfo() {},
    getPlayerStatus() {},
    getRequestsLog() {},
    getStripUrl() {},
    getVolume() {},
    getWidth() {},
    hidePlayReplayControls() {},
    isMuted() {},
    isPlaying() {},
    load() {
      changeData(data => (data.loadCalled = true));
    },
    mute() {},
    on(type, fn) {
      changeData(({ on }) => {
        if (!on.has(type)) {
          on.set(type, new Set());
        }
        on.get(type).add(fn);
      });
    },
    off(type, fn) {
      changeData(({ on }) => {
        on.get(type)?.delete(fn);
      });
    },
    overrideMacro() {},
    pause() {},
    play() {},
    playVideoByIndex() {},
    removeEventListener() {},
    seekTo() {},
    sendBirthDate() {},
    sendKey() {},
    setup(s) {
      changeData(data => (data.setup = s));
      return this;
    },
    setVideosToPlay() {},
    setVolume() {},
    showPlayReplayControls() {},
    toggleFullscreen() {},
    toggleMute() {},
    togglePlay() {},
    updateBid() {},
    version() {},
    volume() {},
  };

  const vidible = {
    ADVERT_CLOSED: "advertClosed",
    AD_END: "adend",
    AD_META: "admeta",
    AD_PAUSED: "adpaused",
    AD_PLAY: "adplay",
    AD_START: "adstart",
    AD_TIMEUPDATE: "adtimeupdate",
    AD_WAITING: "adwaiting",
    AGE_GATE_DISPLAYED: "agegatedisplayed",
    BID_UPDATED: "BidUpdated",
    CAROUSEL_CLICK: "CarouselClick",
    CONTEXT_ENDED: "contextended",
    CONTEXT_STARTED: "contextstarted",
    ENTER_FULLSCREEN: "playerenterfullscreen",
    EXIT_FULLSCREEN: "playerexitfullscreen",
    FALLBACK: "fallback",
    FLOAT_END_ACTION: "floatended",
    FLOAT_START_ACTION: "floatstarted",
    HIDE_PLAY_REPLAY_BUTTON: "hideplayreplaybutton",
    LIGHTBOX_ACTIVATED: "lightboxactivated",
    LIGHTBOX_DEACTIVATED: "lightboxdeactivated",
    MUTE: "Mute",
    PLAYER_CONTROLS_STATE_CHANGE: "playercontrolsstatechaned",
    PLAYER_DOCKED: "playerDocked",
    PLAYER_ERROR: "playererror",
    PLAYER_FLOATING: "playerFloating",
    PLAYER_READY: "playerready",
    PLAYER_RESIZE: "playerresize",
    PLAYLIST_END: "playlistend",
    SEEK_END: "SeekEnd",
    SEEK_START: "SeekStart",
    SHARE_SCREEN_CLOSED: "sharescreenclosed",
    SHARE_SCREEN_OPENED: "sharescreenopened",
    SHOW_PLAY_REPLAY_BUTTON: "showplayreplaybutton",
    SUBTITLES_DISABLED: "subtitlesdisabled",
    SUBTITLES_ENABLED: "subtitlesenabled",
    SUBTITLES_READY: "subtitlesready",
    UNMUTE: "Unmute",
    VIDEO_DATA_LOADED: "videodataloaded",
    VIDEO_END: "videoend",
    VIDEO_META: "videometadata",
    VIDEO_MODULE_CREATED: "videomodulecreated",
    VIDEO_PAUSE: "videopause",
    VIDEO_PLAY: "videoplay",
    VIDEO_SEEKEND: "videoseekend",
    VIDEO_SELECTED: "videoselected",
    VIDEO_START: "videostart",
    VIDEO_TIMEUPDATE: "videotimeupdate",
    VIDEO_VOLUME_CHANGED: "videovolumechanged",
    VOLUME: "Volume",
    _getContexts: () => [],
    "content.CLICK": "content.click",
    "content.IMPRESSION": "content.impression",
    "content.QUARTILE": "content.quartile",
    "content.VIEW": "content.view",
    createPlayer: parent => new Player(parent),
    createPlayerAsync: parent => new Player(parent),
    createVPAIDPlayer: parent => new Player(parent),
    destroyAll() {},
    extension() {},
    getContext() {},
    player: parent => new Player(parent),
    playerInceptionTime() {
      return { undefined: 1620149827713 };
    },
    registerExtra(a, b, c) {
      extras.push([a, b, c]);
    },
    version: () => "21.1.313",
  };

  window.vidible = Shimmer.proxy(vidible);

  for (const jsonp of getJSONPVideoPlacements()) {
    const player = new Player(jsonp);
    const { placeholder } = playerData.get(player);
    jsonp.parentNode.insertBefore(placeholder, jsonp);
  }
}
PK
!<􅤒��shims/vmad.xml<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/.

  Bug 1713693 - Shim Doubleclick

  Some sites rely on an XML VMAD Ad response from Doubleclick, or will
  break (showing black boxes instead of videos, etc). This shim mitigates
  such breakage.
-->
<vmap:AdBreak></vmap:AdBreak>
PK
!<��)���shims/webtrends.js/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 1766414 - Shim WebTrends Core Tag and Advanced Link Tracking
 *
 * Sites using WebTrends Core Tag or Link Tracking can break if they are
 * are blocked. This shim mitigates that breakage by loading an empty module.
 */

if (!window.dcsMultiTrack) {
  window.dcsMultiTrack = o => {
    o?.callback?.({});
  };
}

if (!window.WebTrends) {
  class dcs {
    addSelector() {
      return this;
    }
    addTransform() {
      return this;
    }
    DCSext = {};
    init(_obj) {
      return this;
    }
    track() {
      return this;
    }
  }

  window.Webtrends = window.WebTrends = {
    dcs,
    multiTrack: window.dcsMultiTrack,
  };

  window.requestAnimationFrame(() => {
    window.webtrendsAsyncLoad?.(dcs);
    window.webtrendsAsyncInit?.();
  });
}
PK���3

Zerion Mini Shell 1.0