diff --git a/README.md b/README.md index 0c53f0a..45a1628 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,17 @@ with Camoufox() as browser: page.goto("https://example.com") ``` +#### Real fingerprint presets (recommended for v149+ binaries) + +By default, fingerprint values are synthesized by BrowserForge. For better evasion against complex consistency checks, opt into the bundled presets — real fingerprints scraped from in-the-wild Firefox traffic: + +```python +with Camoufox(fingerprint_preset=True, os="macos") as browser: + ... +``` + +The library auto-routes by binary version: Firefox ≥ 149 loads `fingerprint-presets-v150.json` (312 presets covering v149–v152, 67 macOS / 180 Windows / 65 Linux); older binaries fall back to the original bundle. UA strings are rewritten to match the active binary, so opting in is safe across versions. Pass a preset dict instead of `True` to pin a specific fingerprint. + --- ## Capabilities diff --git a/additions/juggler/TargetRegistry.js b/additions/juggler/TargetRegistry.js index 55afdad..1fdbbee 100644 --- a/additions/juggler/TargetRegistry.js +++ b/additions/juggler/TargetRegistry.js @@ -58,7 +58,7 @@ class DownloadInterceptor { try { file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); } catch (e) { - dump(`WARNING: interceptDownloadRequest failed to create file: ${e}\n`); + dump(`WARNING: interceptDownloadRequest failed to create file: ${e}`); return false; } } @@ -180,7 +180,6 @@ export class TargetRegistry { const domWindowTabListeners = new Map(); const onOpenWindow = async (appWindow) => { - let domWindow; if (appWindow instanceof Ci.nsIAppWindow) { domWindow = appWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); @@ -203,6 +202,19 @@ export class TargetRegistry { await helper.awaitEvent(domWindow, 'DOMContentLoaded'); } + // Firefox 150+: chrome window may report readyState=complete before + // gBrowser is populated. Wait for it if missing. + if (!domWindow.gBrowser) { + await new Promise((resolve, reject) => { + const start = Date.now(); + const tick = () => { + if (domWindow.gBrowser) return resolve(); + if (Date.now() - start > 15000) return reject(new Error('gBrowser never populated')); + domWindow.setTimeout(tick, 50); + }; + tick(); + }); + } if (!domWindow.gBrowser) return; const tabContainer = domWindow.gBrowser.tabContainer; diff --git a/additions/juggler/TargetRegistry.js.bak b/additions/juggler/TargetRegistry.js.bak new file mode 100644 index 0000000..7ea6f93 --- /dev/null +++ b/additions/juggler/TargetRegistry.js.bak @@ -0,0 +1,1306 @@ +/* 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 {Helper} = ChromeUtils.importESModule('chrome://juggler/content/Helper.js'); +const {Preferences} = ChromeUtils.importESModule("resource://gre/modules/Preferences.sys.mjs"); +const {ContextualIdentityService} = ChromeUtils.importESModule("resource://gre/modules/ContextualIdentityService.sys.mjs"); +const {NetUtil} = ChromeUtils.importESModule('resource://gre/modules/NetUtil.sys.mjs'); +const {AppConstants} = ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs"); + +const Cr = Components.results; + +const helper = new Helper(); + +const IDENTITY_NAME = 'JUGGLER '; +const HUNDRED_YEARS = 60 * 60 * 24 * 365 * 100; + +const ALL_PERMISSIONS = [ + 'geo', + 'desktop-notification', +]; + +let globalTabAndWindowActivationChain = Promise.resolve(); +// This is a workaround for https://github.com/microsoft/playwright/issues/34586 +let didCreateFirstPage = false; +let globalNewPageChain = Promise.resolve(); + +class DownloadInterceptor { + constructor(registry) { + this._registry = registry + this._handlerToUuid = new Map(); + this._uuidToHandler = new Map(); + } + + // + // nsIDownloadInterceptor implementation. + // + interceptDownloadRequest(externalAppHandler, request, browsingContext, outFile) { + if (!(request instanceof Ci.nsIChannel)) + return false; + const channel = request.QueryInterface(Ci.nsIChannel); + let pageTarget = this._registry._browserIdToTarget.get(channel.loadInfo.browsingContext.top.browserId); + if (!pageTarget) + return false; + + const browserContext = pageTarget.browserContext(); + const options = browserContext.downloadOptions; + if (!options) + return false; + + const uuid = helper.generateId(); + let file = null; + if (options.behavior === 'saveToDisk') { + file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + file.initWithPath(options.downloadsDir); + file.append(uuid); + + try { + file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + } catch (e) { + dump(`WARNING: interceptDownloadRequest failed to create file: ${e}`); + return false; + } + } + outFile.value = file; + this._handlerToUuid.set(externalAppHandler, uuid); + this._uuidToHandler.set(uuid, externalAppHandler); + const downloadInfo = { + uuid, + browserContextId: browserContext.browserContextId, + pageTargetId: pageTarget.id(), + frameId: helper.browsingContextToFrameId(channel.loadInfo.browsingContext), + url: request.name, + suggestedFileName: externalAppHandler.suggestedFileName, + }; + this._registry.emit(TargetRegistry.Events.DownloadCreated, downloadInfo); + return true; + } + + onDownloadComplete(externalAppHandler, canceled, errorName) { + const uuid = this._handlerToUuid.get(externalAppHandler); + if (!uuid) + return; + this._handlerToUuid.delete(externalAppHandler); + this._uuidToHandler.delete(uuid); + const downloadInfo = { + uuid, + error: errorName, + }; + if (canceled === 'NS_BINDING_ABORTED') { + downloadInfo.canceled = true; + } + this._registry.emit(TargetRegistry.Events.DownloadFinished, downloadInfo); + } + + async cancelDownload(uuid) { + const externalAppHandler = this._uuidToHandler.get(uuid); + if (!externalAppHandler) { + return; + } + await externalAppHandler.cancel(Cr.NS_BINDING_ABORTED); + } +} + +const screencastService = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); + +export class TargetRegistry { + static instance() { + return TargetRegistry._instance || null; + } + + constructor() { + helper.decorateAsEventEmitter(this); + TargetRegistry._instance = this; + + this._browserContextIdToBrowserContext = new Map(); + this._userContextIdToBrowserContext = new Map(); + this._browserToTarget = new Map(); + this._browserIdToTarget = new Map(); + + this._proxiesWithClashingAuthCacheKeys = new Set(); + this._browserProxy = null; + + // Cleanup containers from previous runs (if any) + for (const identity of ContextualIdentityService.getPublicIdentities()) { + if (identity.name && identity.name.startsWith(IDENTITY_NAME)) { + ContextualIdentityService.remove(identity.userContextId); + ContextualIdentityService.closeContainerTabs(identity.userContextId); + } + } + + this._defaultContext = new BrowserContext(this, undefined, undefined); + + Services.obs.addObserver({ + observe: (subject, topic, data) => { + const browser = subject.ownerElement; + if (!browser) + return; + const target = this._browserToTarget.get(browser); + if (!target) + return; + target.emit(PageTarget.Events.Crashed); + target.dispose(); + } + }, 'oop-frameloader-crashed'); + + const onTabOpenListener = (appWindow, window, event) => { + const tab = event.target; + const userContextId = tab.userContextId; + const browserContext = this._userContextIdToBrowserContext.get(userContextId); + const hasExplicitSize = appWindow && (appWindow.chromeFlags & Ci.nsIWebBrowserChrome.JUGGLER_WINDOW_EXPLICIT_SIZE) !== 0; + const openerContext = tab.linkedBrowser.browsingContext.opener; + let openerTarget; + if (openerContext) { + // Popups usually have opener context. Get top context for the case when opener is + // an iframe. + openerTarget = this._browserIdToTarget.get(openerContext.top.browserId); + } else if (tab.openerTab) { + // Noopener popups from the same window have opener tab instead. + openerTarget = this._browserToTarget.get(tab.openerTab.linkedBrowser); + } + if (!browserContext) + throw new Error(`Internal error: cannot find context for userContextId=${userContextId}`); + const target = new PageTarget(this, window, tab, browserContext, openerTarget); + target.updateOverridesForBrowsingContext(tab.linkedBrowser.browsingContext); + if (!hasExplicitSize) + target.updateViewportSize(); + if (browserContext.videoRecordingOptions) + target._startVideoRecording(browserContext.videoRecordingOptions); + }; + + const onTabCloseListener = event => { + const tab = event.target; + const linkedBrowser = tab.linkedBrowser; + const target = this._browserToTarget.get(linkedBrowser); + if (target) + target.dispose(); + }; + + const domWindowTabListeners = new Map(); + + const onOpenWindow = async (appWindow) => { + + let domWindow; + if (appWindow instanceof Ci.nsIAppWindow) { + domWindow = appWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); + } else { + domWindow = appWindow; + appWindow = null; + } + if (!domWindow.isChromeWindow) + return; + // In persistent mode, window might be opened long ago and might be + // already initialized. + // + // In this case, we want to keep this callback synchronous so that we will call + // `onTabOpenListener` synchronously and before the sync IPc message `juggler:content-ready`. + if (domWindow.document.readyState === 'uninitialized' || domWindow.document.readyState === 'loading') { + // For non-initialized windows, DOMContentLoaded initializes gBrowser + // and starts tab loading (see //browser/base/content/browser.js), so we + // are guaranteed to call `onTabOpenListener` before the sync IPC message + // `juggler:content-ready`. + await helper.awaitEvent(domWindow, 'DOMContentLoaded'); + } + + if (!domWindow.gBrowser) + return; + const tabContainer = domWindow.gBrowser.tabContainer; + domWindowTabListeners.set(domWindow, [ + helper.addEventListener(tabContainer, 'TabOpen', event => onTabOpenListener(appWindow, domWindow, event)), + helper.addEventListener(tabContainer, 'TabClose', onTabCloseListener), + ]); + for (const tab of domWindow.gBrowser.tabs) + onTabOpenListener(appWindow, domWindow, { target: tab }); + }; + + const onCloseWindow = window => { + const domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); + if (!domWindow.isChromeWindow) + return; + if (!domWindow.gBrowser) + return; + + const listeners = domWindowTabListeners.get(domWindow) || []; + domWindowTabListeners.delete(domWindow); + helper.removeListeners(listeners); + for (const tab of domWindow.gBrowser.tabs) + onTabCloseListener({ target: tab }); + }; + + const extHelperAppSvc = Cc["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Ci.nsIExternalHelperAppService); + this._downloadInterceptor = new DownloadInterceptor(this); + extHelperAppSvc.setDownloadInterceptor(this._downloadInterceptor); + + Services.wm.addListener({ onOpenWindow, onCloseWindow }); + for (const win of Services.wm.getEnumerator(null)) + onOpenWindow(win); + } + + // Firefox uses nsHttpAuthCache to cache authentication to the proxy. + // If we're provided with a single proxy with a multiple different authentications, then + // we should clear the nsHttpAuthCache on every request. + shouldBustHTTPAuthCacheForProxy(proxy) { + return this._proxiesWithClashingAuthCacheKeys.has(proxy); + } + + _updateProxiesWithSameAuthCacheAndDifferentCredentials() { + const proxyIdToCredentials = new Map(); + const allProxies = [...this._browserContextIdToBrowserContext.values()].map(bc => bc._proxy).filter(Boolean); + if (this._browserProxy) + allProxies.push(this._browserProxy); + const proxyAuthCacheKeyAndProxy = allProxies.map(proxy => [ + JSON.stringify({ + type: proxy.type, + host: proxy.host, + port: proxy.port, + }), + proxy, + ]); + this._proxiesWithClashingAuthCacheKeys.clear(); + + proxyAuthCacheKeyAndProxy.sort(([cacheKey1], [cacheKey2]) => cacheKey1 < cacheKey2 ? -1 : 1); + for (let i = 0; i < proxyAuthCacheKeyAndProxy.length - 1; ++i) { + const [cacheKey1, proxy1] = proxyAuthCacheKeyAndProxy[i]; + const [cacheKey2, proxy2] = proxyAuthCacheKeyAndProxy[i + 1]; + if (cacheKey1 !== cacheKey2) + continue; + if (proxy1.username === proxy2.username && proxy1.password === proxy2.password) + continue; + // `proxy1` and `proxy2` have the same caching key, but serve different credentials. + // We have to bust HTTP Auth Cache everytime there's a request that will use either of the proxies. + this._proxiesWithClashingAuthCacheKeys.add(proxy1); + this._proxiesWithClashingAuthCacheKeys.add(proxy2); + } + } + + async cancelDownload(options) { + this._downloadInterceptor.cancelDownload(options.uuid); + } + + setBrowserProxy(proxy) { + this._browserProxy = proxy; + this._updateProxiesWithSameAuthCacheAndDifferentCredentials(); + } + + getProxyInfo(channel) { + const originAttributes = channel.loadInfo && channel.loadInfo.originAttributes; + const browserContext = originAttributes ? this.browserContextForUserContextId(originAttributes.userContextId) : null; + // Prefer context proxy and fallback to browser-level proxy. + const proxyInfo = (browserContext && browserContext._proxy) || this._browserProxy; + if (!proxyInfo || proxyInfo.bypass.some(domainSuffix => channel.URI.host.endsWith(domainSuffix))) + return null; + return proxyInfo; + } + + defaultContext() { + return this._defaultContext; + } + + createBrowserContext(removeOnDetach) { + return new BrowserContext(this, helper.generateId(), removeOnDetach); + } + + browserContextForId(browserContextId) { + return this._browserContextIdToBrowserContext.get(browserContextId); + } + + browserContextForUserContextId(userContextId) { + return this._userContextIdToBrowserContext.get(userContextId); + } + + async newPage({browserContextId}) { + // When creating the very first page, we cannot create multiple in parallel. + // See https://github.com/microsoft/playwright/issues/34586. + if (didCreateFirstPage) + return this._newPageInternal({browserContextId}); + const result = globalNewPageChain.then(() => this._newPageInternal({browserContextId})); + globalNewPageChain = result.catch(error => { /* swallow errors to keep chain running */ }); + return result; + } + + async _newPageInternal({browserContextId}) { + console.error(`[TR-DEBUG] _newPageInternal start ctx=${browserContextId}`); + const browserContext = this.browserContextForId(browserContextId); + const features = "chrome,dialog=no,all"; + // See _callWithURIToLoad in browser.js for the structure of window.arguments + // window.arguments[1]: unused (bug 871161) + // [2]: referrerInfo (nsIReferrerInfo) + // [3]: postData (nsIInputStream) + // [4]: allowThirdPartyFixup (bool) + // [5]: userContextId (int) + // [6]: originPrincipal (nsIPrincipal) + // [7]: originStoragePrincipal (nsIPrincipal) + // [8]: triggeringPrincipal (nsIPrincipal) + // [9]: allowInheritPrincipal (bool) + // [10]: csp (nsIContentSecurityPolicy) + // [11]: nsOpenWindowInfo + const args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); + const urlSupports = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + urlSupports.data = 'about:blank'; + args.appendElement(urlSupports); // 0 + args.appendElement(undefined); // 1 + args.appendElement(undefined); // 2 + args.appendElement(undefined); // 3 + args.appendElement(undefined); // 4 + const userContextIdSupports = Cc[ + "@mozilla.org/supports-PRUint32;1" + ].createInstance(Ci.nsISupportsPRUint32); + userContextIdSupports.data = browserContext.userContextId; + args.appendElement(userContextIdSupports); // 5 + args.appendElement(undefined); // 6 + args.appendElement(undefined); // 7 + args.appendElement(Services.scriptSecurityManager.getSystemPrincipal()); // 8 + + console.error(`[TR-DEBUG] opening window with url=${AppConstants.BROWSER_CHROME_URL}`); + const window = Services.ww.openWindow(null, AppConstants.BROWSER_CHROME_URL, '_blank', features, args); + console.error(`[TR-DEBUG] openWindow returned, awaiting ready`); + await waitForWindowReady(window); + console.error(`[TR-DEBUG] window ready, browsers=${window.gBrowser ? window.gBrowser.browsers.length : 'no gBrowser'}`); + if (window.gBrowser.browsers.length !== 1) + throw new Error(`Unexpected number of tabs in the new window: ${window.gBrowser.browsers.length}`); + const browser = window.gBrowser.browsers[0]; + let target = this._browserToTarget.get(browser); + console.error(`[TR-DEBUG] initial target lookup: ${target ? 'found' : 'not found'}`); + let attempts = 0; + while (!target) { + attempts++; + console.error(`[TR-DEBUG] awaiting TargetCreated event (attempt ${attempts})`); + await helper.awaitEvent(this, TargetRegistry.Events.TargetCreated); + target = this._browserToTarget.get(browser); + console.error(`[TR-DEBUG] after TargetCreated: ${target ? 'matched' : 'not matched'}`); + } + browser.focus(); + if (browserContext.crossProcessCookie.settings.timezoneId) { + if (await target.hasFailedToOverrideTimezone()) + throw new Error('Failed to override timezone'); + } + didCreateFirstPage = true; + return target.id(); + } + + targets() { + return Array.from(this._browserToTarget.values()); + } + + targetForBrowser(browser) { + return this._browserToTarget.get(browser); + } + + targetForBrowserId(browserId) { + return this._browserIdToTarget.get(browserId); + } +} + +export class PageTarget { + constructor(registry, win, tab, browserContext, opener) { + helper.decorateAsEventEmitter(this); + + this._targetId = helper.generateId(); + this._registry = registry; + this._window = win; + this._gBrowser = win.gBrowser; + this._tab = tab; + this._linkedBrowser = tab.linkedBrowser; + this._browserContext = browserContext; + this._viewportSize = undefined; + this._zoom = 1; + this._initialDPPX = this._linkedBrowser.browsingContext.overrideDPPX; + this._url = 'about:blank'; + this._openerId = opener ? opener.id() : undefined; + this._actor = undefined; + this._actorSequenceNumber = 0; + this._channel = new SimpleChannel(`browser::page[${this._targetId}]`, 'target-' + this._targetId); + this._videoRecordingInfo = undefined; + this._screencastRecordingInfo = undefined; + this._dialogs = new Map(); + this.forcedColors = 'none'; + this.disableCache = false; + this.mediumOverride = ''; + this.crossProcessCookie = { + initScripts: [], + bindings: [], + interceptFileChooserDialog: false, + }; + + const navigationListener = { + QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), + onLocationChange: (aWebProgress, aRequest, aLocation) => this._onNavigated(aLocation), + }; + this._eventListeners = [ + helper.addObserver(this._updateModalDialogs.bind(this), 'common-dialog-loaded'), + helper.addProgressListener(tab.linkedBrowser, navigationListener, Ci.nsIWebProgress.NOTIFY_LOCATION), + helper.addEventListener(this._linkedBrowser, 'DOMModalDialogClosed', event => this._updateModalDialogs()), + helper.addEventListener(this._linkedBrowser, 'WillChangeBrowserRemoteness', event => this._willChangeBrowserRemoteness()), + ]; + + this._disposed = false; + browserContext.pages.add(this); + this._registry._browserToTarget.set(this._linkedBrowser, this); + this._registry._browserIdToTarget.set(this._linkedBrowser.browsingContext.browserId, this); + + this._registry.emit(TargetRegistry.Events.TargetCreated, this); + } + + async activateAndRun(callback = () => {}, { muteNotificationsPopup = false } = {}) { + const ownerWindow = this._tab.linkedBrowser.ownerGlobal; + const tabBrowser = ownerWindow.gBrowser; + // Serialize all tab-switching commands per tabbed browser + // to disallow concurrent tab switching. + const result = globalTabAndWindowActivationChain.then(async () => { + this._window.focus(); + if (tabBrowser.selectedTab !== this._tab) { + const promise = helper.awaitEvent(ownerWindow, 'TabSwitchDone'); + tabBrowser.selectedTab = this._tab; + await promise; + } + const notificationsPopup = muteNotificationsPopup ? this._linkedBrowser?.ownerDocument.getElementById('notification-popup') : null; + notificationsPopup?.style.setProperty('pointer-events', 'none'); + try { + await callback(); + } finally { + notificationsPopup?.style.removeProperty('pointer-events'); + } + }); + globalTabAndWindowActivationChain = result.catch(error => { /* swallow errors to keep chain running */ }); + return result; + } + + frameIdToBrowsingContext(frameId) { + return helper.collectAllBrowsingContexts(this._linkedBrowser.browsingContext).find(bc => helper.browsingContextToFrameId(bc) === frameId); + } + + nextActorSequenceNumber() { + return ++this._actorSequenceNumber; + } + + setActor(actor) { + this._actor = actor; + this._channel.bindToActor(actor); + } + + removeActor(actor) { + // Note: the order between setActor and removeActor is non-deterministic. + // Therefore we check that we are still bound to the actor that is being removed. + if (this._actor !== actor) + return; + this._actor = undefined; + this._channel.resetTransport(); + } + + _willChangeBrowserRemoteness() { + this.removeActor(this._actor); + } + + dialog(dialogId) { + return this._dialogs.get(dialogId); + } + + dialogs() { + return [...this._dialogs.values()]; + } + + async windowReady() { + await waitForWindowReady(this._window); + } + + linkedBrowser() { + return this._linkedBrowser; + } + + browserContext() { + return this._browserContext; + } + + updateOverridesForBrowsingContext(browsingContext = undefined) { + this.updateTouchOverride(browsingContext); + this.updateUserAgent(browsingContext); + this.updatePlatform(browsingContext); + this.updateDPPXOverride(browsingContext); + this.updateZoom(browsingContext); + this.updateEmulatedMedia(browsingContext); + this.updateColorSchemeOverride(browsingContext); + this.updateReducedMotionOverride(browsingContext); + this.updateContrastOverride(browsingContext); + this.updateForcedColorsOverride(browsingContext); + this.updateForceOffline(browsingContext); + this.updateCacheDisabled(browsingContext); + } + + updateForceOffline(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).forceOffline = this._browserContext.forceOffline; + } + + setCacheDisabled(disabled) { + this.disableCache = disabled; + this.updateCacheDisabled(); + } + + updateCacheDisabled(browsingContext = this._linkedBrowser.browsingContext) { + const enableFlags = Ci.nsIRequest.LOAD_NORMAL; + const disableFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE | + Ci.nsIRequest.INHIBIT_CACHING; + + browsingContext.defaultLoadFlags = (this._browserContext.disableCache || this.disableCache) ? disableFlags : enableFlags; + } + + updateTouchOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).touchEventsOverride = this._browserContext.touchOverride ? 'enabled' : 'none'; + } + + updateUserAgent(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).customUserAgent = this._browserContext.defaultUserAgent; + } + + updatePlatform(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).customPlatform = this._browserContext.defaultPlatform; + } + + updateDPPXOverride(browsingContext = undefined) { + browsingContext ||= this._linkedBrowser.browsingContext; + const dppx = this._zoom * (this._browserContext.deviceScaleFactor || this._initialDPPX); + browsingContext.overrideDPPX = dppx; + } + + async updateZoom(browsingContext = undefined) { + browsingContext ||= this._linkedBrowser.browsingContext; + // Update dpr first, and then UI zoom. + this.updateDPPXOverride(browsingContext); + browsingContext.fullZoom = this._zoom; + } + + _updateModalDialogs() { + const prompts = new Set(this._linkedBrowser.tabDialogBox.getContentDialogManager().dialogs.map(dialog => dialog.frameContentWindow.Dialog)); + for (const dialog of this._dialogs.values()) { + if (!prompts.has(dialog.prompt())) { + this._dialogs.delete(dialog.id()); + this.emit(PageTarget.Events.DialogClosed, dialog); + } else { + prompts.delete(dialog.prompt()); + } + } + for (const prompt of prompts) { + const dialog = Dialog.createIfSupported(prompt); + if (!dialog) + continue; + this._dialogs.set(dialog.id(), dialog); + this.emit(PageTarget.Events.DialogOpened, dialog); + } + } + + async updateViewportSize() { + await waitForWindowReady(this._window); + this.updateDPPXOverride(); + + // Viewport size is defined by three arguments: + // 1. default size. Could be explicit if set as part of `window.open` call, e.g. + // `window.open(url, title, 'width=400,height=400')` + // 2. page viewport size + // 3. browserContext viewport size + // + // The "default size" (1) is only respected when the page is opened. + // Otherwise, explicitly set page viewport prevales over browser context + // default viewport. + const viewportSize = this._viewportSize || this._browserContext.defaultViewportSize; + if (viewportSize) { + const {width, height} = viewportSize; + this._linkedBrowser.style.setProperty('width', width + 'px'); + this._linkedBrowser.style.setProperty('height', height + 'px'); + this._linkedBrowser.style.setProperty('box-sizing', 'content-box'); + this._linkedBrowser.closest('.browserStack').style.setProperty('overflow', 'auto'); + this._linkedBrowser.closest('.browserStack').style.setProperty('contain', 'size'); + this._linkedBrowser.closest('.browserStack').style.setProperty('scrollbar-width', 'none'); + this._linkedBrowser.browsingContext.inRDMPane = true; + + const stackRect = this._linkedBrowser.closest('.browserStack').getBoundingClientRect(); + const toolbarTop = stackRect.y; + this._window.resizeBy(width - this._window.innerWidth, height + toolbarTop - this._window.innerHeight); + + await this._channel.connect('').send('awaitViewportDimensions', { width: width / this._zoom, height: height / this._zoom }); + } else { + this._linkedBrowser.style.removeProperty('width'); + this._linkedBrowser.style.removeProperty('height'); + this._linkedBrowser.style.removeProperty('box-sizing'); + this._linkedBrowser.closest('.browserStack').style.removeProperty('overflow'); + this._linkedBrowser.closest('.browserStack').style.removeProperty('contain'); + this._linkedBrowser.closest('.browserStack').style.removeProperty('scrollbar-width'); + this._linkedBrowser.browsingContext.inRDMPane = false; + + const actualSize = this._linkedBrowser.getBoundingClientRect(); + await this._channel.connect('').send('awaitViewportDimensions', { + width: actualSize.width / this._zoom, + height: actualSize.height / this._zoom, + }); + } + } + + setEmulatedMedia(mediumOverride) { + this.mediumOverride = mediumOverride || ''; + this.updateEmulatedMedia(); + } + + updateEmulatedMedia(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).mediumOverride = this.mediumOverride; + } + + setColorScheme(colorScheme) { + this.colorScheme = fromProtocolColorScheme(colorScheme); + this.updateColorSchemeOverride(); + } + + updateColorSchemeOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).prefersColorSchemeOverride = this.colorScheme || this._browserContext.colorScheme || 'none'; + } + + setReducedMotion(reducedMotion) { + this.reducedMotion = fromProtocolReducedMotion(reducedMotion); + this.updateReducedMotionOverride(); + } + + updateReducedMotionOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).prefersReducedMotionOverride = this.reducedMotion || this._browserContext.reducedMotion || 'none'; + } + + setContrast(contrast) { + this.contrast = fromProtocolContrast(contrast); + this.updateContrastOverride(); + } + + updateContrastOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).prefersContrastOverride = this.contrast || this._browserContext.contrast || 'none'; + } + + setForcedColors(forcedColors) { + this.forcedColors = fromProtocolForcedColors(forcedColors); + this.updateForcedColorsOverride(); + } + + updateForcedColorsOverride(browsingContext = undefined) { + const isActive = this.forcedColors === 'active' || this._browserContext.forcedColors === 'active'; + (browsingContext || this._linkedBrowser.browsingContext).forcedColorsOverride = isActive ? 'active' : 'none'; + } + + async setInterceptFileChooserDialog(enabled) { + this.crossProcessCookie.interceptFileChooserDialog = enabled; + this._updateCrossProcessCookie(); + await this._channel.connect('').send('setInterceptFileChooserDialog', enabled).catch(e => {}); + } + + async setViewportSize(viewportSize) { + this._viewportSize = viewportSize; + await this.updateViewportSize(); + } + + async setZoom(zoom) { + // This is default range from the ZoomManager. + if (zoom < 0.3 || zoom > 5) + throw new Error('Invalid zoom value, must be between 0.3 and 5'); + this._zoom = zoom; + await this.updateZoom(); + } + + close(runBeforeUnload = false) { + this._gBrowser.removeTab(this._tab, { + skipPermitUnload: !runBeforeUnload, + }); + } + + channel() { + return this._channel; + } + + id() { + return this._targetId; + } + + info() { + return { + targetId: this.id(), + type: 'page', + browserContextId: this._browserContext.browserContextId, + openerId: this._openerId, + }; + } + + _onNavigated(aLocation) { + this._url = aLocation.spec; + this._browserContext.grantPermissionsToOrigin(this._url); + } + + _updateCrossProcessCookie() { + Services.ppmm.sharedData.set('juggler:page-cookie-' + this._linkedBrowser.browsingContext.browserId, this.crossProcessCookie); + Services.ppmm.sharedData.flush(); + } + + async ensurePermissions() { + await this._channel.connect('').send('ensurePermissions', {}).catch(e => void e); + } + + async setInitScripts(scripts) { + this.crossProcessCookie.initScripts = scripts; + this._updateCrossProcessCookie(); + await this.pushInitScripts(); + } + + async pushInitScripts() { + await this._channel.connect('').send('setInitScripts', [...this._browserContext.crossProcessCookie.initScripts, ...this.crossProcessCookie.initScripts]).catch(e => void e); + } + + async addBinding(worldName, name, script) { + this.crossProcessCookie.bindings.push({ worldName, name, script }); + this._updateCrossProcessCookie(); + await this._channel.connect('').send('addBinding', { worldName, name, script }).catch(e => void e); + } + + async applyContextSetting(name, value) { + await this._channel.connect('').send('applyContextSetting', { name, value }).catch(e => void e); + } + + async hasFailedToOverrideTimezone() { + return await this._channel.connect('').send('hasFailedToOverrideTimezone').catch(e => true); + } + + async _startVideoRecording({width, height, dir}) { + // On Mac the window may not yet be visible when TargetCreated and its + // NSWindow.windowNumber may be -1, so we wait until the window is known + // to be initialized and visible. + await this.windowReady(); + const file = PathUtils.join(dir, helper.generateId() + '.webm'); + if (width < 10 || width > 10000 || height < 10 || height > 10000) + throw new Error("Invalid size"); + + const docShell = this._gBrowser.ownerGlobal.docShell; + // Exclude address bar and navigation control from the video. + const rect = this.linkedBrowser().getBoundingClientRect(); + const devicePixelRatio = this._window.devicePixelRatio; + let sessionId; + const registry = this._registry; + const screencastClient = { + QueryInterface: ChromeUtils.generateQI([Ci.nsIScreencastServiceClient]), + screencastFrame(data, deviceWidth, deviceHeight) { + }, + screencastStopped() { + registry.emit(TargetRegistry.Events.ScreencastStopped, sessionId); + }, + }; + const viewport = this._viewportSize || this._browserContext.defaultViewportSize || { width: 0, height: 0 }; + sessionId = screencastService.startVideoRecording(screencastClient, docShell, true, file, width, height, 0, viewport.width, viewport.height, devicePixelRatio * rect.top); + this._videoRecordingInfo = { sessionId, file }; + this.emit(PageTarget.Events.ScreencastStarted); + } + + _stopVideoRecording() { + if (!this._videoRecordingInfo) + throw new Error('No video recording in progress'); + const videoRecordingInfo = this._videoRecordingInfo; + this._videoRecordingInfo = undefined; + screencastService.stopVideoRecording(videoRecordingInfo.sessionId); + } + + videoRecordingInfo() { + return this._videoRecordingInfo; + } + + async startScreencast({ width, height, quality }) { + // On Mac the window may not yet be visible when TargetCreated and its + // NSWindow.windowNumber may be -1, so we wait until the window is known + // to be initialized and visible. + await this.windowReady(); + if (width < 10 || width > 10000 || height < 10 || height > 10000) + throw new Error("Invalid size"); + + const docShell = this._gBrowser.ownerGlobal.docShell; + // Exclude address bar and navigation control from the video. + const rect = this.linkedBrowser().getBoundingClientRect(); + const devicePixelRatio = this._window.devicePixelRatio; + + const self = this; + const screencastClient = { + QueryInterface: ChromeUtils.generateQI([Ci.nsIScreencastServiceClient]), + screencastFrame(data, deviceWidth, deviceHeight) { + if (self._screencastRecordingInfo) + self.emit(PageTarget.Events.ScreencastFrame, { data, deviceWidth, deviceHeight }); + }, + screencastStopped() { + }, + }; + const viewport = this._viewportSize || this._browserContext.defaultViewportSize || { width: 0, height: 0 }; + const screencastId = screencastService.startVideoRecording(screencastClient, docShell, false, '', width, height, quality || 90, viewport.width, viewport.height, devicePixelRatio * rect.top); + this._screencastRecordingInfo = { screencastId }; + return { screencastId }; + } + + screencastFrameAck({ screencastId }) { + if (!this._screencastRecordingInfo || this._screencastRecordingInfo.screencastId !== screencastId) + return; + screencastService.screencastFrameAck(screencastId); + } + + stopScreencast() { + if (!this._screencastRecordingInfo) + throw new Error('No screencast in progress'); + const { screencastId } = this._screencastRecordingInfo; + this._screencastRecordingInfo = undefined; + screencastService.stopVideoRecording(screencastId); + } + + ensureContextMenuClosed() { + // Close context menu, if any, since it might capture mouse events on Linux + // and prevent browser shutdown on MacOS. + const doc = this._linkedBrowser.ownerDocument; + const contextMenu = doc.getElementById('contentAreaContextMenu'); + if (contextMenu) + contextMenu.hidePopup(); + const autocompletePopup = doc.getElementById('PopupAutoComplete'); + if (autocompletePopup) + autocompletePopup.hidePopup(); + const selectPopup = doc.getElementById('ContentSelectDropdown')?.menupopup; + if (selectPopup) + selectPopup.hidePopup() + } + + dispose() { + this.ensureContextMenuClosed(); + this._disposed = true; + if (this._videoRecordingInfo) + this._stopVideoRecording(); + if (this._screencastRecordingInfo) + this.stopScreencast(); + this._browserContext.pages.delete(this); + this._registry._browserToTarget.delete(this._linkedBrowser); + this._registry._browserIdToTarget.delete(this._linkedBrowser.browsingContext.browserId); + try { + helper.removeListeners(this._eventListeners); + } catch (e) { + // In some cases, removing listeners from this._linkedBrowser fails + // because it is already half-destroyed. + if (e) + dump(e.message + '\n' + e.stack + '\n'); + } + this._registry.emit(TargetRegistry.Events.TargetDestroyed, this); + } +} + +PageTarget.Events = { + ScreencastStarted: Symbol('PageTarget.ScreencastStarted'), + ScreencastFrame: Symbol('PageTarget.ScreencastFrame'), + Crashed: Symbol('PageTarget.Crashed'), + DialogOpened: Symbol('PageTarget.DialogOpened'), + DialogClosed: Symbol('PageTarget.DialogClosed'), +}; + +function fromProtocolColorScheme(colorScheme) { + if (colorScheme === 'light' || colorScheme === 'dark') + return colorScheme; + if (colorScheme === null || colorScheme === 'no-preference') + return undefined; + throw new Error('Unknown color scheme: ' + colorScheme); +} + +function fromProtocolReducedMotion(reducedMotion) { + if (reducedMotion === 'reduce' || reducedMotion === 'no-preference') + return reducedMotion; + if (reducedMotion === null) + return undefined; + throw new Error('Unknown reduced motion: ' + reducedMotion); +} + +function fromProtocolContrast(contrast) { + if (contrast === 'more' || contrast === 'less' || contrast === 'custom' || contrast === 'no-preference') + return contrast; + if (contrast === null) + return undefined; + throw new Error('Unknown contrast: ' + contrast); +} + +function fromProtocolForcedColors(forcedColors) { + if (forcedColors === 'active' || forcedColors === 'none') + return forcedColors; + if (!forcedColors) + return 'none'; + throw new Error('Unknown forced colors: ' + forcedColors); +} + +class BrowserContext { + constructor(registry, browserContextId, removeOnDetach) { + this._registry = registry; + this.browserContextId = browserContextId; + // Default context has userContextId === 0, but we pass undefined to many APIs just in case. + this.userContextId = 0; + if (browserContextId !== undefined) { + const identity = ContextualIdentityService.create(IDENTITY_NAME + browserContextId); + this.userContextId = identity.userContextId; + } + this._principals = []; + // Maps origins to the permission lists. + this._permissions = new Map(); + this._registry._browserContextIdToBrowserContext.set(this.browserContextId, this); + this._registry._userContextIdToBrowserContext.set(this.userContextId, this); + this._proxy = null; + this.removeOnDetach = removeOnDetach; + this.extraHTTPHeaders = undefined; + this.httpCredentials = undefined; + this.requestInterceptionEnabled = undefined; + this.ignoreHTTPSErrors = undefined; + this.downloadOptions = undefined; + this.defaultViewportSize = undefined; + this.deviceScaleFactor = undefined; + this.defaultUserAgent = null; + this.defaultPlatform = null; + this.touchOverride = false; + this.forceOffline = false; + this.disableCache = false; + this.colorScheme = 'none'; + this.forcedColors = 'none'; + this.reducedMotion = 'none'; + this.contrast = 'none'; + this.videoRecordingOptions = undefined; + this.crossProcessCookie = { + initScripts: [], + bindings: [], + settings: {}, + }; + this.pages = new Set(); + } + + _updateCrossProcessCookie() { + Services.ppmm.sharedData.set('juggler:context-cookie-' + this.userContextId, this.crossProcessCookie); + Services.ppmm.sharedData.flush(); + } + + setColorScheme(colorScheme) { + this.colorScheme = fromProtocolColorScheme(colorScheme); + for (const page of this.pages) + page.updateColorSchemeOverride(); + } + + setReducedMotion(reducedMotion) { + this.reducedMotion = fromProtocolReducedMotion(reducedMotion); + for (const page of this.pages) + page.updateReducedMotionOverride(); + } + + setContrast(contrast) { + this.contrast = fromProtocolContrast(contrast); + for (const page of this.pages) + page.updateContrastOverride(); + } + + setForcedColors(forcedColors) { + this.forcedColors = fromProtocolForcedColors(forcedColors); + for (const page of this.pages) + page.updateForcedColorsOverride(); + } + + async destroy() { + if (this.userContextId !== 0) { + ContextualIdentityService.remove(this.userContextId); + for (const page of this.pages) + page.close(); + if (this.pages.size) { + await new Promise(f => { + const listener = helper.on(this._registry, TargetRegistry.Events.TargetDestroyed, () => { + if (!this.pages.size) { + helper.removeListeners([listener]); + f(); + } + }); + }); + } + } + this._registry._browserContextIdToBrowserContext.delete(this.browserContextId); + this._registry._userContextIdToBrowserContext.delete(this.userContextId); + this._registry._updateProxiesWithSameAuthCacheAndDifferentCredentials(); + } + + setProxy(proxy) { + // Clear AuthCache. + Services.obs.notifyObservers(null, "net:clear-active-logins"); + this._proxy = proxy; + this._registry._updateProxiesWithSameAuthCacheAndDifferentCredentials(); + } + + setIgnoreHTTPSErrors(ignoreHTTPSErrors) { + if (this.ignoreHTTPSErrors === ignoreHTTPSErrors) + return; + this.ignoreHTTPSErrors = ignoreHTTPSErrors; + const certOverrideService = Cc[ + "@mozilla.org/security/certoverride;1" + ].getService(Ci.nsICertOverrideService); + if (ignoreHTTPSErrors) { + Preferences.set("network.stricttransportsecurity.preloadlist", false); + Preferences.set("security.cert_pinning.enforcement_level", 0); + certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(this.userContextId, true); + } else { + certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(this.userContextId, false); + } + } + + setDefaultUserAgent(userAgent) { + this.defaultUserAgent = userAgent; + for (const page of this.pages) + page.updateUserAgent(); + } + + setDefaultPlatform(platform) { + this.defaultPlatform = platform; + for (const page of this.pages) + page.updatePlatform(); + } + + setTouchOverride(touchOverride) { + this.touchOverride = touchOverride; + for (const page of this.pages) + page.updateTouchOverride(); + } + + setForceOffline(forceOffline) { + this.forceOffline = forceOffline; + for (const page of this.pages) + page.updateForceOffline(); + } + + setCacheDisabled(disabled) { + this.disableCache = disabled; + for (const page of this.pages) + page.updateCacheDisabled(); + } + + async setDefaultViewport(viewport) { + this.defaultViewportSize = viewport ? viewport.viewportSize : undefined; + this.deviceScaleFactor = viewport ? viewport.deviceScaleFactor : undefined; + await Promise.all(Array.from(this.pages).map(page => page.updateViewportSize())); + } + + async setInitScripts(scripts) { + this.crossProcessCookie.initScripts = scripts; + this._updateCrossProcessCookie(); + await Promise.all(Array.from(this.pages).map(page => page.pushInitScripts())); + } + + async addBinding(worldName, name, script) { + this.crossProcessCookie.bindings.push({ worldName, name, script }); + this._updateCrossProcessCookie(); + await Promise.all(Array.from(this.pages).map(page => page.addBinding(worldName, name, script))); + } + + async applySetting(name, value) { + this.crossProcessCookie.settings[name] = value; + this._updateCrossProcessCookie(); + await Promise.all(Array.from(this.pages).map(page => page.applyContextSetting(name, value))); + } + + async grantPermissions(origin, permissions) { + this._permissions.set(origin, permissions); + const promises = []; + for (const page of this.pages) { + if (origin === '*' || page._url.startsWith(origin)) { + this.grantPermissionsToOrigin(page._url); + promises.push(page.ensurePermissions()); + } + } + await Promise.all(promises); + } + + resetPermissions() { + for (const principal of this._principals) { + for (const permission of ALL_PERMISSIONS) + Services.perms.removeFromPrincipal(principal, permission); + } + this._principals = []; + this._permissions.clear(); + } + + grantPermissionsToOrigin(url) { + let origin = Array.from(this._permissions.keys()).find(key => url.startsWith(key)); + if (!origin) + origin = '*'; + + const permissions = this._permissions.get(origin); + if (!permissions) + return; + + const attrs = { userContextId: this.userContextId || undefined }; + const principal = Services.scriptSecurityManager.createContentPrincipal(NetUtil.newURI(url), attrs); + this._principals.push(principal); + for (const permission of ALL_PERMISSIONS) { + const action = permissions.includes(permission) ? Ci.nsIPermissionManager.ALLOW_ACTION : Ci.nsIPermissionManager.DENY_ACTION; + Services.perms.addFromPrincipal(principal, permission, action, Ci.nsIPermissionManager.EXPIRE_NEVER, 0 /* expireTime */); + } + } + + setCookies(cookies) { + const protocolToSameSite = { + [undefined]: Ci.nsICookie.SAMESITE_UNSET, + 'None': Ci.nsICookie.SAMESITE_UNSET, + 'Lax': Ci.nsICookie.SAMESITE_LAX, + 'Strict': Ci.nsICookie.SAMESITE_STRICT, + }; + for (const cookie of cookies) { + const uri = cookie.url ? NetUtil.newURI(cookie.url) : null; + let domain = cookie.domain; + if (!domain) { + if (!uri) + throw new Error('At least one of the url and domain needs to be specified'); + domain = uri.host; + } + let path = cookie.path; + if (!path) + path = uri ? dirPath(uri.filePath) : '/'; + let secure = false; + if (cookie.secure !== undefined) + secure = cookie.secure; + else if (uri && uri.scheme === 'https') + secure = true; + Services.cookies.add( + domain, + path, + cookie.name, + cookie.value, + secure, + cookie.httpOnly || false, + cookie.expires === undefined || cookie.expires === -1 /* isSession */, + cookie.expires === undefined ? Date.now() + HUNDRED_YEARS : cookie.expires * 1000, + { userContextId: this.userContextId || undefined } /* originAttributes */, + protocolToSameSite[cookie.sameSite], + Ci.nsICookie.SCHEME_UNSET + ); + } + } + + clearCookies() { + Services.cookies.removeCookiesWithOriginAttributes(JSON.stringify({ userContextId: this.userContextId || undefined })); + } + + getCookies() { + const result = []; + const sameSiteToProtocol = { + [Ci.nsICookie.SAMESITE_UNSET]: 'None', + [Ci.nsICookie.SAMESITE_NONE]: 'None', + [Ci.nsICookie.SAMESITE_LAX]: 'Lax', + [Ci.nsICookie.SAMESITE_STRICT]: 'Strict', + }; + for (let cookie of Services.cookies.cookies) { + if (cookie.originAttributes.userContextId !== this.userContextId) + continue; + if (cookie.host === 'addons.mozilla.org') + continue; + result.push({ + name: cookie.name, + value: cookie.value, + domain: cookie.host, + path: cookie.path, + expires: cookie.isSession ? -1 : cookie.expiry / 1000, + size: cookie.name.length + cookie.value.length, + httpOnly: cookie.isHttpOnly, + secure: cookie.isSecure, + session: cookie.isSession, + sameSite: sameSiteToProtocol[cookie.sameSite], + }); + } + return result; + } + + async setVideoRecordingOptions(options) { + this.videoRecordingOptions = options; + const promises = []; + for (const page of this.pages) { + if (options) + promises.push(page._startVideoRecording(options)); + else if (page._videoRecordingInfo) + promises.push(page._stopVideoRecording()); + } + await Promise.all(promises); + } +} + +class Dialog { + static createIfSupported(prompt) { + const type = prompt.args.promptType; + switch (type) { + case 'alert': + case 'alertCheck': + return new Dialog(prompt, 'alert'); + case 'prompt': + return new Dialog(prompt, 'prompt'); + case 'confirm': + case 'confirmCheck': + return new Dialog(prompt, 'confirm'); + case 'confirmEx': + return new Dialog(prompt, 'beforeunload'); + default: + return null; + }; + } + + constructor(prompt, type) { + this._id = helper.generateId(); + this._type = type; + this._prompt = prompt; + } + + id() { + return this._id; + } + + message() { + return this._prompt.ui.infoBody.textContent; + } + + type() { + return this._type; + } + + prompt() { + return this._prompt; + } + + dismiss() { + if (this._prompt.ui.button1) + this._prompt.ui.button1.click(); + else + this._prompt.ui.button0.click(); + } + + defaultValue() { + return this._prompt.ui.loginTextbox.value; + } + + accept(promptValue) { + if (typeof promptValue === 'string' && this._type === 'prompt') + this._prompt.ui.loginTextbox.value = promptValue; + this._prompt.ui.button0.click(); + } +} + + +function dirPath(path) { + return path.substring(0, path.lastIndexOf('/') + 1); +} + +async function waitForWindowReady(window) { + if (window.delayedStartupPromise) { + await window.delayedStartupPromise; + } else { + await new Promise((resolve => { + Services.obs.addObserver(function observer(aSubject, aTopic) { + if (window == aSubject) { + Services.obs.removeObserver(observer, aTopic); + resolve(); + } + }, "browser-delayed-startup-finished"); + })); + } + if (window.document.readyState !== 'complete') + await helper.awaitEvent(window, 'load'); +} + +TargetRegistry.Events = { + TargetCreated: Symbol('TargetRegistry.Events.TargetCreated'), + TargetDestroyed: Symbol('TargetRegistry.Events.TargetDestroyed'), + DownloadCreated: Symbol('TargetRegistry.Events.DownloadCreated'), + DownloadFinished: Symbol('TargetRegistry.Events.DownloadFinished'), + ScreencastStopped: Symbol('TargetRegistry.ScreencastStopped'), +}; diff --git a/additions/juggler/screencast/HeadlessWindowCapturer.cpp b/additions/juggler/screencast/HeadlessWindowCapturer.cpp index 75200db..8888f14 100644 --- a/additions/juggler/screencast/HeadlessWindowCapturer.cpp +++ b/additions/juggler/screencast/HeadlessWindowCapturer.cpp @@ -40,6 +40,11 @@ void HeadlessWindowCapturer::RegisterCaptureDataCallback(rtc::VideoSinkInterface void HeadlessWindowCapturer::RegisterCaptureDataCallback(webrtc::RawVideoSinkInterface* dataCallback) { } +void HeadlessWindowCapturer::DeRegisterCaptureDataCallback() { + rtc::CritScope lock2(&_callBackCs); + _dataCallBacks.clear(); +} + void HeadlessWindowCapturer::DeRegisterCaptureDataCallback(rtc::VideoSinkInterface* dataCallback) { rtc::CritScope lock2(&_callBackCs); auto it = _dataCallBacks.find(dataCallback); diff --git a/additions/juggler/screencast/HeadlessWindowCapturer.h b/additions/juggler/screencast/HeadlessWindowCapturer.h index cb1bcbb..b131a86 100644 --- a/additions/juggler/screencast/HeadlessWindowCapturer.h +++ b/additions/juggler/screencast/HeadlessWindowCapturer.h @@ -6,12 +6,18 @@ #include #include +#ifdef XP_WIN +typedef int pid_t; // libwebrtc headers reference pid_t which is POSIX-only +#endif #include "api/video/video_frame.h" #include "api/video/video_sink_interface.h" #include "modules/video_capture/video_capture.h" #include "rtc_base/deprecated/recursive_critical_section.h" #include "video_engine/desktop_capture_impl.h" +// Compatibility namespace alias: libwebrtc converted rtc:: to webrtc:: in Fx150 +namespace rtc = webrtc; + class nsIWidget; namespace mozilla { @@ -26,6 +32,7 @@ class HeadlessWindowCapturer : public webrtc::VideoCaptureModuleEx { void RegisterCaptureDataCallback( rtc::VideoSinkInterface* dataCallback) override; + void DeRegisterCaptureDataCallback() override; void DeRegisterCaptureDataCallback( rtc::VideoSinkInterface* dataCallback) override; int32_t StopCaptureIfAllClientsClose() override; diff --git a/additions/juggler/screencast/ScreencastEncoder.h b/additions/juggler/screencast/ScreencastEncoder.h index 883ad01..497268d 100644 --- a/additions/juggler/screencast/ScreencastEncoder.h +++ b/additions/juggler/screencast/ScreencastEncoder.h @@ -16,6 +16,9 @@ namespace webrtc { class VideoFrame; } +// Compatibility namespace alias: libwebrtc converted rtc:: to webrtc:: in Fx150 +namespace rtc = webrtc; + namespace mozilla { class ScreencastEncoder { diff --git a/additions/juggler/screencast/nsScreencastService.cpp b/additions/juggler/screencast/nsScreencastService.cpp index fa9d1a9..a3fc66a 100644 --- a/additions/juggler/screencast/nsScreencastService.cpp +++ b/additions/juggler/screencast/nsScreencastService.cpp @@ -17,9 +17,11 @@ #include "nsIRandomGenerator.h" #include "nsISupportsPrimitives.h" #include "nsThreadManager.h" -#include "nsView.h" -#include "nsViewManager.h" #include "modules/desktop_capture/desktop_capturer.h" + +// Compatibility namespace alias: libwebrtc converted rtc:: to webrtc:: in Fx150 +namespace rtc = webrtc; + #include "modules/desktop_capture/desktop_capture_options.h" #include "modules/desktop_capture/desktop_frame.h" #include "modules/video_capture/video_capture.h" @@ -324,13 +326,9 @@ nsresult nsScreencastService::StartVideoRecording(nsIScreencastServiceClient* aC PresShell* presShell = aDocShell->GetPresShell(); if (!presShell) return NS_ERROR_UNEXPECTED; - nsViewManager* viewManager = presShell->GetViewManager(); - if (!viewManager) + nsIWidget* widget = presShell->GetRootWidget(); + if (!widget) return NS_ERROR_UNEXPECTED; - nsView* view = viewManager->GetRootView(); - if (!view) - return NS_ERROR_UNEXPECTED; - nsIWidget* widget = view->GetWidget(); rtc::scoped_refptr capturer = nullptr; for (auto& it : mIdToSession) { diff --git a/build-tester/scripts/grading.py b/build-tester/scripts/grading.py index aa5a133..31c32e7 100644 --- a/build-tester/scripts/grading.py +++ b/build-tester/scripts/grading.py @@ -8,15 +8,15 @@ import sys # ─── Grading ────────────────────────────────────────────────────────────────── def compute_grade(pass_count: int, total_checks: int) -> str: - fail_count = total_checks - pass_count - if fail_count == 0: + if total_checks == 0: + return "F" + pct = pass_count / total_checks + if pct >= 0.95: return "A" - if fail_count <= 2: + if pct >= 0.85: return "B" - if fail_count <= 5: + if pct >= 0.75: return "C" - if fail_count <= 10: - return "D" return "F" diff --git a/docs/per-context-patches.md b/docs/per-context-patches.md index 3953b18..0585b7c 100644 --- a/docs/per-context-patches.md +++ b/docs/per-context-patches.md @@ -623,6 +623,31 @@ The Camoufox Python package (`pythonlib/`) generates fingerprints for both `NewB | **NewBrowser** (`launch_options()` in `utils.py`) | BrowserForge synthetic | Pass `fingerprint_preset=True` or a preset dict | | **NewContext** (`generate_context_fingerprint()` in `fingerprints.py`) | BrowserForge synthetic | Pass `preset=dict` explicitly | +**Recommended for v149+ binaries:** opt into bundled real fingerprints via +`fingerprint_preset=True`. The library auto-selects the v150 preset bundle +(`fingerprint-presets-v150.json`, 312 real fingerprints scraped from v149–v152 +browsers) for any binary at Firefox ≥ 149, and falls back to the original +bundle (`fingerprint-presets.json`, 123 presets) for older binaries. UA strings +are rewritten to match the active binary's Firefox version, so opting in costs +nothing for compatibility. + +```python +from camoufox.async_api import AsyncCamoufox + +# Use a randomly-sampled real preset matching the binary's Firefox version +async with AsyncCamoufox(fingerprint_preset=True, os='macos') as browser: + page = await browser.new_page() + ... + +# Or pin a specific preset dict +async with AsyncCamoufox(fingerprint_preset=my_preset_dict) as browser: + ... +``` + +Routing logic lives in `fingerprints.py:_select_presets_file()`. The +`PRESETS_V150_MIN_FF` constant (default `149`) controls the cutoff. Both +bundles are shipped in the wheel. + ### What Each Path Sets | Property | Source | Notes | @@ -656,7 +681,9 @@ The Camoufox Python package (`pythonlib/`) generates fingerprints for both `NewB - WebGL sampled via same `sample_webgl()` function - Config validated against `properties.json` before serialization -**`fingerprint-presets.json`** — Bundled real fingerprints organized by OS (macOS, Windows, Linux). Each preset includes navigator properties, screen dimensions, WebGL params, speech voices, and timezone. Font and voice data not used from presets — generated fresh per launch. +**`fingerprint-presets.json`** — Original bundled real fingerprints organized by OS (macOS 30, Windows 75, Linux 18). Each preset includes navigator properties, screen dimensions, WebGL params, and speech voices. Used for Firefox < 149 binaries. Font and voice data not used from presets — generated fresh per launch. + +**`fingerprint-presets-v150.json`** — Newer bundle covering Firefox v149–v152 (macOS 67, Windows 180, Linux 65; 312 total). Same schema as the original. Auto-selected by `load_presets()` when the active binary reports Firefox ≥ 149. **`fonts.json`** — Complete OS-specific font lists for random font subset generation. diff --git a/patches/anti-font-fingerprinting.patch b/patches/anti-font-fingerprinting.patch index 6599d44..465c248 100644 --- a/patches/anti-font-fingerprinting.patch +++ b/patches/anti-font-fingerprinting.patch @@ -1,6 +1,6 @@ diff --git a/dom/base/FontSpacingSeedManager.cpp b/dom/base/FontSpacingSeedManager.cpp new file mode 100644 -index 0000000000..fe74a1f432 +index 0000000000..e07de3e753 --- /dev/null +++ b/dom/base/FontSpacingSeedManager.cpp @@ -0,0 +1,91 @@ @@ -176,7 +176,7 @@ index 0000000000..63d43f3b86 \ No newline at end of file diff --git a/dom/base/RoverfoxStorageManager.cpp b/dom/base/RoverfoxStorageManager.cpp new file mode 100644 -index 0000000000..f38394d39d +index 0000000000..1f8b3a08f6 --- /dev/null +++ b/dom/base/RoverfoxStorageManager.cpp @@ -0,0 +1,184 @@ @@ -366,7 +366,7 @@ index 0000000000..f38394d39d +} // namespace mozilla diff --git a/dom/base/RoverfoxStorageManager.h b/dom/base/RoverfoxStorageManager.h new file mode 100644 -index 0000000000..d5700aea62 +index 0000000000..4a2dac8e8f --- /dev/null +++ b/dom/base/RoverfoxStorageManager.h @@ -0,0 +1,36 @@ @@ -407,23 +407,25 @@ index 0000000000..d5700aea62 + +#endif // mozilla_dom_RoverfoxStorageManager_h diff --git a/dom/base/moz.build b/dom/base/moz.build -index cd9090cda3..609d3b71be 100644 +index 49c8ac12fa..66b3509602 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build -@@ -191,6 +191,7 @@ EXPORTS.mozilla.dom += [ - "EventSourceEventService.h", +@@ -190,6 +190,7 @@ EXPORTS.mozilla.dom += [ "External.h", + "FastFrontRemovableArray.h", "FilteredNodeIterator.h", + "FontSpacingSeedManager.h", "FormData.h", "FragmentDirective.h", "FragmentOrElement.h", -@@ -253,4 +254,5 @@ EXPORTS.mozilla.dom += [ +@@ -255,6 +256,7 @@ EXPORTS.mozilla.dom += [ + "RequestCallbackManager.h", "ResizeObserver.h", "ResponsiveImageSelector.h", + "RoverfoxStorageManager.h", "SameProcessMessageQueue.h", "ScreenLuminance.h", + "ScreenOrientation.h", @@ -369,6 +371,7 @@ UNIFIED_SOURCES += [ "EventSource.cpp", "EventSourceEventService.cpp", @@ -432,17 +434,19 @@ index cd9090cda3..609d3b71be 100644 "FormData.cpp", "FragmentDirective.cpp", "FragmentOrElement.cpp", -@@ -457,4 +461,5 @@ UNIFIED_SOURCES += [ +@@ -459,6 +462,7 @@ UNIFIED_SOURCES += [ + "RemoteOuterWindowProxy.cpp", "ResizeObserver.cpp", "ResponsiveImageSelector.cpp", + "RoverfoxStorageManager.cpp", "SameProcessMessageQueue.cpp", "ScreenLuminance.cpp", + "ScreenOrientation.cpp", diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp -index 330a707789..fb3ba4d3fb 100644 +index 0545014921..5432f702ed 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp -@@ -60,6 +60,7 @@ +@@ -57,6 +57,7 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" #include "mozilla/EventQueue.h" @@ -450,7 +454,7 @@ index 330a707789..fb3ba4d3fb 100644 #include "mozilla/ExtensionPolicyService.h" #include "mozilla/FloatingPoint.h" #include "mozilla/FlushType.h" -@@ -243,6 +244,9 @@ +@@ -242,6 +243,9 @@ #include "nsICookieService.h" #include "nsID.h" #include "nsIDOMStorageManager.h" @@ -460,7 +464,7 @@ index 330a707789..fb3ba4d3fb 100644 #include "nsIDOMXULControlElement.h" #include "nsIDeviceSensors.h" #include "nsIDocShell.h" -@@ -7463,6 +7467,25 @@ IntlUtils* nsGlobalWindowInner::GetIntlUtils(ErrorResult& aError) { +@@ -7707,6 +7711,25 @@ IntlUtils* nsGlobalWindowInner::GetIntlUtils(ErrorResult& aError) { return mIntlUtils; } @@ -487,10 +491,10 @@ index 330a707789..fb3ba4d3fb 100644 MOZ_ASSERT(aSharedWorker); MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker)); diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h -index 648bcda859..46cb7d6f4a 100644 +index 43b3ef9521..b26388188c 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h -@@ -681,6 +681,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, +@@ -678,6 +678,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, mozilla::dom::IntlUtils* GetIntlUtils(mozilla::ErrorResult& aRv); @@ -501,7 +505,7 @@ index 648bcda859..46cb7d6f4a 100644 void ForgetSharedWorker(mozilla::dom::SharedWorker* aSharedWorker); diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp -index 989dba05ca..14f8be6dcd 100644 +index d010d51b43..c1d3f13898 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -57,6 +57,7 @@ @@ -512,7 +516,7 @@ index 989dba05ca..14f8be6dcd 100644 #include "mozilla/dom/FontFaceSet.h" #include "mozilla/dom/FontFaceSetImpl.h" #include "mozilla/dom/GeneratePlaceholderCanvasData.h" -@@ -4719,10 +4720,21 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final +@@ -4784,10 +4785,21 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final } else { flags &= ~gfx::ShapedTextFlags::TEXT_IS_RTL; } @@ -536,10 +540,10 @@ index 989dba05ca..14f8be6dcd 100644 } diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp -index e32eeaeeab..fed027072c 100644 +index a802950043..fa8b4e4490 100644 --- a/dom/canvas/OffscreenCanvas.cpp +++ b/dom/canvas/OffscreenCanvas.cpp -@@ -635,6 +635,15 @@ void OffscreenCanvas::ReportBlockedFontFamily(const nsCString& aMsg) const { +@@ -651,6 +651,15 @@ void OffscreenCanvas::ReportBlockedFontFamily(const nsCString& aMsg) const { } } @@ -556,10 +560,10 @@ index e32eeaeeab..fed027072c 100644 if (NS_IsMainThread()) { nsCOMPtr win = do_QueryInterface(GetOwnerGlobal()); diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl -index 7c509eb87e..7a076768d0 100644 +index ae2d14e105..838aef642d 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl -@@ -892,6 +892,12 @@ partial interface Window { +@@ -930,6 +930,12 @@ partial interface Window { readonly attribute VisualViewport visualViewport; }; @@ -573,10 +577,10 @@ index 7c509eb87e..7a076768d0 100644 // finding on a page. partial interface Window { diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index c5d17c1c0a..216bdace64 100644 +index c34db27680..6fdccc0279 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h -@@ -1103,8 +1103,6 @@ class WorkerPrivate final +@@ -1102,8 +1102,6 @@ class WorkerPrivate final void WorkerScriptLoaded(); @@ -586,10 +590,10 @@ index c5d17c1c0a..216bdace64 100644 void UpdateContextOptions(const JS::ContextOptions& aContextOptions); diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp -index ef081ebe40..a921c49f43 100644 +index a52e3a56d8..3025f57da5 100644 --- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp -@@ -23,9 +23,13 @@ +@@ -22,9 +22,13 @@ #include "nsStyleConsts.h" // for StyleHyphens::None #include "mozilla/Assertions.h" // for MOZ_ASSERT #include "mozilla/UniquePtr.h" // for UniquePtr @@ -603,7 +607,7 @@ index ef081ebe40..a921c49f43 100644 namespace { -@@ -35,17 +39,39 @@ class AutoTextRun { +@@ -34,17 +38,39 @@ class AutoTextRun { AutoTextRun(const nsFontMetrics* aMetrics, DrawTarget* aDrawTarget, const char* aString, uint32_t aLength) { @@ -646,10 +650,10 @@ index ef081ebe40..a921c49f43 100644 gfxTextRun* get() const { return mTextRun.get(); } diff --git a/gfx/src/nsFontMetrics.h b/gfx/src/nsFontMetrics.h -index cc8aec7cc7..e4e51f5000 100644 +index df44559b26..d829aa8ff2 100644 --- a/gfx/src/nsFontMetrics.h +++ b/gfx/src/nsFontMetrics.h -@@ -257,6 +257,10 @@ class nsFontMetrics final { +@@ -299,6 +299,10 @@ class nsFontMetrics final { bool AllowForceGDIClassic() const { return mAllowForceGDIClassic; } #endif @@ -660,7 +664,7 @@ index cc8aec7cc7..e4e51f5000 100644 private: // Private destructor, to discourage deletion outside of Release(): ~nsFontMetrics(); -@@ -264,9 +268,6 @@ class nsFontMetrics final { +@@ -306,9 +310,6 @@ class nsFontMetrics final { const nsFont mFont; RefPtr mFontGroup; RefPtr const mLanguage; @@ -671,10 +675,10 @@ index cc8aec7cc7..e4e51f5000 100644 // The font orientation (horizontal or vertical) for which these metrics diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp -index 6f02e3a566..ca3b60d550 100644 +index a0020a6a65..1f27407e7a 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp -@@ -20,6 +20,7 @@ +@@ -18,6 +18,7 @@ #include "gfxGlyphExtents.h" #include "gfxPlatform.h" @@ -682,15 +686,7 @@ index 6f02e3a566..ca3b60d550 100644 #include "gfxTextRun.h" #include "nsGkAtoms.h" -@@ -47,6 +48,7 @@ - #include "gfxSVGGlyphs.h" - #include "gfx2DGlue.h" - #include "TextDrawTarget.h" -+#include "mozilla/dom/FontSpacingSeedManager.h" - - #include "ThebesRLBox.h" - -@@ -3284,7 +3286,7 @@ bool gfxFont::ProcessShapedWordInternal( +@@ -3284,9 +3285,9 @@ bool gfxFont::ProcessShapedWordInternal( Script aRunScript, nsAtom* aLanguage, bool aVertical, int32_t aAppUnitsPerDevUnit, gfx::ShapedTextFlags aFlags, RoundingFlags aRounding, gfxTextPerfMetrics* aTextPerf GFX_MAYBE_UNUSED, @@ -700,7 +696,9 @@ index 6f02e3a566..ca3b60d550 100644 - aAppUnitsPerDevUnit, aFlags, aRounding); + aAppUnitsPerDevUnit, aFlags, aRounding, aUserContextId); { -@@ -3317,6 +3319,8 @@ bool gfxFont::ProcessShapedWordInternal( + // If we have a word cache, attempt to look up the word in it. + AutoReadLock lock(mLock); +@@ -3317,6 +3318,8 @@ bool gfxFont::ProcessShapedWordInternal( NS_WARNING("failed to create gfxShapedWord - expect missing text"); return false; } @@ -709,7 +707,7 @@ index 6f02e3a566..ca3b60d550 100644 DebugOnly ok = ShapeText(aDrawTarget, aText, 0, aLength, aRunScript, aLanguage, aVertical, aRounding, newShapedWord.get()); -@@ -3383,7 +3387,8 @@ bool gfxFont::WordCacheKey::HashPolicy::match(const Key& aKey, +@@ -3383,7 +3386,8 @@ bool gfxFont::WordCacheKey::HashPolicy::match(const Key& aKey, if (aKey.mLength != aLookup.mLength || aKey.mFlags != aLookup.mFlags || aKey.mRounding != aLookup.mRounding || aKey.mAppUnitsPerDevUnit != aLookup.mAppUnitsPerDevUnit || @@ -718,17 +716,17 @@ index 6f02e3a566..ca3b60d550 100644 + aKey.mUserContextId != aLookup.mUserContextId) { return false; } - -@@ -3420,7 +3425,7 @@ bool gfxFont::ProcessSingleSpaceShapedWord( + +@@ -3420,7 +3424,7 @@ bool gfxFont::ProcessSingleSpaceShapedWord( return ProcessShapedWordInternal( aDrawTarget, &space, 1, gfxShapedWord::HashMix(0, ' '), Script::LATIN, /* aLanguage = */ nullptr, aVertical, aAppUnitsPerDevUnit, aFlags, - aRounding, nullptr, aCallback); + aRounding, nullptr, 0 /* pbid */, aCallback); } - + bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const uint8_t* aText, -@@ -3778,6 +3784,7 @@ bool gfxFont::SplitAndInitTextRun( +@@ -3778,6 +3782,7 @@ bool gfxFont::SplitAndInitTextRun( bool processed = ProcessShapedWordInternal( aDrawTarget, aString + wordStart, length, hash, aRunScript, aLanguage, vertical, appUnitsPerDevUnit, wordFlags, rounding, tp, @@ -745,7 +743,7 @@ index 6f02e3a566..ca3b60d550 100644 aTextRun->CopyGlyphDataFrom(aShapedWord, aRunStart + i); if (boundary == ' ') { diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h -index 4601fc3f17..78c2f1116c 100644 +index 0ae6de8b22..27b0eb3c44 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -737,6 +737,10 @@ class gfxShapedText { @@ -781,7 +779,7 @@ index 4601fc3f17..78c2f1116c 100644 // The mCharGlyphsStorage array is actually a variable-size member; // when the ShapedWord is created, its size will be increased as necessary // to allow the proper number of glyphs to be stored. -@@ -2091,12 +2103,14 @@ class gfxFont { +@@ -2142,12 +2154,14 @@ class gfxFont { // for use in setting up a gfxTextRun. template bool ProcessShapedWordInternal(DrawTarget* aDrawTarget, const T* aText, @@ -799,15 +797,16 @@ index 4601fc3f17..78c2f1116c 100644 + gfxTextPerfMetrics* aTextPerf, + uint32_t aUserContextId, + Func aCallback); - + // whether a given feature is included in feature settings from both the // font and the style. aFeatureOn set if resolved feature value is non-zero -@@ -2127,11 +2141,12 @@ class gfxFont { +@@ -2177,12 +2191,13 @@ class gfxFont { + int32_t mAppUnitsPerDevUnit; PLDHashNumber mHashKey; bool mTextIs8Bit; + uint32_t mUserContextId; RoundingFlags mRounding; - + WordCacheKey(const uint8_t* aText, uint32_t aLength, uint32_t aStringHash, Script aScriptCode, nsAtom* aLanguage, int32_t aAppUnitsPerDevUnit, ShapedTextFlags aFlags, @@ -816,7 +815,7 @@ index 4601fc3f17..78c2f1116c 100644 : mLength(aLength), mFlags(aFlags), mScript(aScriptCode), -@@ -2139,8 +2154,9 @@ class gfxFont { +@@ -2190,8 +2205,9 @@ class gfxFont { mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), mHashKey(aStringHash + static_cast(aScriptCode) + aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 + @@ -827,7 +826,7 @@ index 4601fc3f17..78c2f1116c 100644 mRounding(aRounding) { NS_ASSERTION(aFlags & ShapedTextFlags::TEXT_IS_8BIT, "8-bit flag should have been set"); -@@ -2150,7 +2166,7 @@ class gfxFont { +@@ -2201,7 +2217,7 @@ class gfxFont { WordCacheKey(const char16_t* aText, uint32_t aLength, uint32_t aStringHash, Script aScriptCode, nsAtom* aLanguage, int32_t aAppUnitsPerDevUnit, ShapedTextFlags aFlags, @@ -836,7 +835,7 @@ index 4601fc3f17..78c2f1116c 100644 : mLength(aLength), mFlags(aFlags), mScript(aScriptCode), -@@ -2158,8 +2174,9 @@ class gfxFont { +@@ -2209,8 +2225,9 @@ class gfxFont { mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), mHashKey(aStringHash + static_cast(aScriptCode) + aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 + @@ -848,10 +847,10 @@ index 4601fc3f17..78c2f1116c 100644 // We can NOT assert that TEXT_IS_8BIT is false in aFlags here, // because this might be an 8bit-only word from a 16-bit textrun, diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp -index 1a5bdaba99..46226fc88d 100644 +index 8bd7f6f38c..5282efb7e5 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp -@@ -17,6 +17,10 @@ +@@ -16,6 +16,10 @@ #include "harfbuzz/hb.h" #include "harfbuzz/hb-ot.h" @@ -862,7 +861,7 @@ index 1a5bdaba99..46226fc88d 100644 #include -@@ -1567,6 +1571,36 @@ bool gfxHarfBuzzShaper::ShapeText(DrawTarget* aDrawTarget, +@@ -1466,6 +1470,36 @@ bool gfxHarfBuzzShaper::ShapeText(DrawTarget* aDrawTarget, hb_shape(mHBFont, mBuffer, features.Elements(), features.Length()); @@ -899,16 +898,16 @@ index 1a5bdaba99..46226fc88d 100644 if (isRightToLeft) { hb_buffer_reverse(mBuffer); } -@@ -1872,3 +1905,4 @@ nsresult gfxHarfBuzzShaper::SetGlyphsFromRun(gfxShapedText* aShapedText, +@@ -1771,3 +1805,4 @@ nsresult gfxHarfBuzzShaper::SetGlyphsFromRun(gfxShapedText* aShapedText, return NS_OK; } + diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp -index de9a9661a1..f878bdb36c 100644 +index ea420d13cd..9bd7061f2d 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp -@@ -25,6 +25,7 @@ +@@ -23,6 +23,7 @@ #include "mozilla/Likely.h" #include "mozilla/MruCache.h" #include "mozilla/ServoStyleSet.h" @@ -916,16 +915,17 @@ index de9a9661a1..f878bdb36c 100644 #include "mozilla/Sprintf.h" #include "mozilla/StaticPresData.h" #include "mozilla/UniquePtr.h" -@@ -34,6 +35,8 @@ +@@ -32,6 +33,9 @@ #include "nsUnicodeProperties.h" #include "SharedFontList-impl.h" #include "TextDrawTarget.h" +#include "mozilla/dom/BrowsingContext.h" ++#include "mozilla/dom/Document.h" +#include "nsPIDOMWindow.h" - + #ifdef XP_WIN # include "gfxWindowsPlatform.h" -@@ -145,25 +147,26 @@ void* gfxTextRun::AllocateStorageForTextRun(size_t aSize, uint32_t aLength) { +@@ -143,25 +146,26 @@ void* gfxTextRun::AllocateStorageForTextRun(size_t aSize, uint32_t aLength) { already_AddRefed gfxTextRun::Create( const gfxTextRunFactory::Parameters* aParams, uint32_t aLength, gfxFontGroup* aFontGroup, gfx::ShapedTextFlags aFlags, @@ -955,7 +955,7 @@ index de9a9661a1..f878bdb36c 100644 mReleasedFontGroup(false), mReleasedFontGroupSkippedDrawing(false), mShapingState(eShapingState_Normal) { -@@ -728,7 +731,8 @@ void gfxTextRun::DrawEmphasisMarks( +@@ -726,7 +730,8 @@ void gfxTextRun::DrawEmphasisMarks( gfxContext* aContext, gfxTextRun* aMark, gfxFloat aMarkAdvance, gfx::Point aPt, Range aRange, const PropertyProvider* aProvider, mozilla::gfx::PaletteCache& aPaletteCache) const { @@ -965,7 +965,7 @@ index de9a9661a1..f878bdb36c 100644 EmphasisMarkDrawParams params(aContext, aPaletteCache); params.mark = aMark; -@@ -1870,6 +1874,18 @@ gfxFontGroup::gfxFontGroup(FontVisibilityProvider* aFontVisibilityProvider, +@@ -1868,6 +1873,18 @@ gfxFontGroup::gfxFontGroup(FontVisibilityProvider* aFontVisibilityProvider, mFontVariantEmoji(aVariantEmoji) { // We don't use SetUserFontSet() here, as we want to unconditionally call // EnsureFontList() rather than only do UpdateUserFonts() if it changed. @@ -984,7 +984,7 @@ index de9a9661a1..f878bdb36c 100644 } gfxFontGroup::~gfxFontGroup() { -@@ -2485,12 +2502,12 @@ already_AddRefed gfxFontGroup::MakeHyphenTextRun( +@@ -2474,12 +2491,12 @@ already_AddRefed gfxFontGroup::MakeHyphenTextRun( RefPtr font = GetFirstValidFont(uint32_t(hyphen)); if (font->HasCharacter(hyphen)) { return MakeTextRun(&hyphen, 1, aDrawTarget, aAppUnitsPerDevUnit, aFlags, @@ -999,7 +999,7 @@ index de9a9661a1..f878bdb36c 100644 } gfxFloat gfxFontGroup::GetHyphenWidth( -@@ -2511,7 +2528,7 @@ template +@@ -2500,7 +2517,7 @@ template already_AddRefed gfxFontGroup::MakeTextRun( const T* aString, uint32_t aLength, const Parameters* aParams, gfx::ShapedTextFlags aFlags, nsTextFrameUtils::Flags aFlags2, @@ -1008,7 +1008,7 @@ index de9a9661a1..f878bdb36c 100644 if (aLength == 0) { return MakeEmptyTextRun(aParams, aFlags, aFlags2); } -@@ -2530,8 +2547,16 @@ already_AddRefed gfxFontGroup::MakeTextRun( +@@ -2519,8 +2536,13 @@ already_AddRefed gfxFontGroup::MakeTextRun( return MakeBlankTextRun(aString, aLength, aParams, aFlags, aFlags2); } @@ -1016,9 +1016,6 @@ index de9a9661a1..f878bdb36c 100644 + if (aUserContextId == 0) { + aUserContextId = mUserContextId; + } -+ -+ // Log the user context id used for this text run creation -+ printf("MakeTextRun: userContextId=%u\n", aUserContextId); + RefPtr textRun = - gfxTextRun::Create(aParams, aLength, this, aFlags, aFlags2); @@ -1026,7 +1023,7 @@ index de9a9661a1..f878bdb36c 100644 if (!textRun) { return nullptr; } -@@ -2547,11 +2572,11 @@ already_AddRefed gfxFontGroup::MakeTextRun( +@@ -2536,11 +2561,11 @@ already_AddRefed gfxFontGroup::MakeTextRun( template already_AddRefed gfxFontGroup::MakeTextRun( const uint8_t* aString, uint32_t aLength, const Parameters* aParams, gfx::ShapedTextFlags aFlags, nsTextFrameUtils::Flags aFlags2, @@ -1038,9 +1035,9 @@ index de9a9661a1..f878bdb36c 100644 - gfxMissingFontRecorder* aMFR); + gfxMissingFontRecorder* aMFR, uint32_t aUserContextId); - // Helper to get a hashtable that maps tags to Script codes, created on first - // use. -@@ -2609,8 +2634,9 @@ static Script ResolveScriptForLang(const nsAtom* aLanguage, Script aDefault) { + // ComputeRanges instantiation (used by + // gfxPlatformFontList::ListFontsUsedForString). +@@ -2604,8 +2629,9 @@ static Script ResolveScriptForLang(const nsAtom* aLanguage, Script aDefault) { static LangScriptCache sCache; static RWLock sLock("LangScriptCache lock"); @@ -1052,7 +1049,7 @@ index de9a9661a1..f878bdb36c 100644 { // Try to use a cached value without taking an exclusive lock. -@@ -3045,7 +3071,7 @@ gfxTextRun* gfxFontGroup::GetEllipsisTextRun( +@@ -3040,7 +3066,7 @@ gfxTextRun* gfxFontGroup::GetEllipsisTextRun( nullptr, 0, aAppUnitsPerDevPixel}; mCachedEllipsisTextRun = MakeTextRun(ellipsis.BeginReading(), ellipsis.Length(), ¶ms, aFlags, @@ -1061,7 +1058,7 @@ index de9a9661a1..f878bdb36c 100644 if (!mCachedEllipsisTextRun) { return nullptr; } -@@ -3460,7 +3486,7 @@ already_AddRefed gfxFontGroup::FindFontForChar( +@@ -3455,7 +3481,7 @@ already_AddRefed gfxFontGroup::FindFontForChar( font = FindFallbackFaceForChar(ff, aCh, aNextCh, presentation); if (font) { if (CheckCandidate(font, @@ -1071,10 +1068,10 @@ index de9a9661a1..f878bdb36c 100644 } } diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h -index 06ccaa6082..556ab66718 100644 +index 9e007251ef..e746af411d 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h -@@ -487,13 +487,14 @@ class gfxTextRun : public gfxShapedText { +@@ -485,13 +485,14 @@ class gfxTextRun : public gfxShapedText { void ClearFlagBits(nsTextFrameUtils::Flags aFlags) { mFlags2 &= ~aFlags; } const gfxSkipChars& GetSkipChars() const { return mSkipChars; } gfxFontGroup* GetFontGroup() const { return mFontGroup; } @@ -1090,7 +1087,7 @@ index 06ccaa6082..556ab66718 100644 // The text is divided into GlyphRuns as necessary. (In the vast majority // of cases, a gfxTextRun contains just a single GlyphRun.) -@@ -802,7 +803,7 @@ class gfxTextRun : public gfxShapedText { +@@ -801,7 +802,7 @@ class gfxTextRun : public gfxShapedText { */ gfxTextRun(const gfxTextRunFactory::Parameters* aParams, uint32_t aLength, gfxFontGroup* aFontGroup, mozilla::gfx::ShapedTextFlags aFlags, @@ -1099,7 +1096,7 @@ index 06ccaa6082..556ab66718 100644 // Whether we need to fetch actual glyph extents from the fonts. bool NeedsGlyphExtents() const; -@@ -894,6 +895,8 @@ class gfxTextRun : public gfxShapedText { +@@ -893,6 +894,8 @@ class gfxTextRun : public gfxShapedText { nsTextFrameUtils::Flags mFlags2; // additional flags (see also gfxShapedText::mFlags) @@ -1142,10 +1139,10 @@ index 06ccaa6082..556ab66718 100644 * Textrun creation short-cuts for special cases where we don't need to * call a font shaper to generate glyphs. diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp -index 89ed5fec3e..32920e9b71 100644 +index 41334360e9..e2abf1f5d3 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp -@@ -144,7 +144,8 @@ +@@ -143,6 +143,7 @@ #include "nsIFrameInlines.h" #include "nsIImageLoadingContent.h" #include "nsIInterfaceRequestorUtils.h" @@ -1153,9 +1150,8 @@ index 89ed5fec3e..32920e9b71 100644 #include "nsIWidget.h" #include "nsListControlFrame.h" #include "nsMenuPopupFrame.h" - #include "nsPIDOMWindow.h" -@@ -1210,6 +1211,31 @@ nsIFrame* nsLayoutUtils::GetLastSibling(nsIFrame* aFrame) { - return aFrame; +@@ -1188,6 +1189,31 @@ int32_t nsLayoutUtils::DoCompareTreePosition(const nsIFrame* aFrame1, + nonCommonAncestor ? aCommonAncestor : nullptr); } +/* static */ uint32_t @@ -1184,13 +1180,13 @@ index 89ed5fec3e..32920e9b71 100644 +} + // static - nsView* nsLayoutUtils::FindSiblingViewFor(nsView* aParentView, - nsIFrame* aFrame) { + int32_t nsLayoutUtils::DoCompareTreePosition( + const nsIFrame* aFrame1, const nsIFrame* aFrame2, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h -index 6c7d485e38..da404c0e5c 100644 +index aac8f3cbb2..9079714449 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h -@@ -423,6 +423,11 @@ class nsLayoutUtils { +@@ -433,6 +433,11 @@ class nsLayoutUtils { */ static nsIFrame* GetLastSibling(nsIFrame* aFrame); @@ -1203,10 +1199,10 @@ index 6c7d485e38..da404c0e5c 100644 * FindSiblingViewFor locates the child of aParentView that aFrame's * view should be inserted 'above' (i.e., before in sibling view diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp -index 9bb509ed5f..a5e21d2f57 100644 +index 989e01eefa..fb158fbe99 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp -@@ -425,6 +425,10 @@ bool nsPresContext::IsChrome() const { +@@ -426,6 +426,10 @@ bool nsPresContext::IsChrome() const { return Document()->IsInChromeDocShell(); } @@ -1218,10 +1214,10 @@ index 9bb509ed5f..a5e21d2f57 100644 if (!GetPresShell()) { // No presshell means nothing to do here. We'll do this when we diff --git a/layout/generic/MathMLTextRunFactory.cpp b/layout/generic/MathMLTextRunFactory.cpp -index 13c9cc5c11..b940be8790 100644 +index 22adbaf9bc..e685fd4feb 100644 --- a/layout/generic/MathMLTextRunFactory.cpp +++ b/layout/generic/MathMLTextRunFactory.cpp -@@ -11,6 +11,8 @@ +@@ -9,6 +9,8 @@ #include "mozilla/ComputedStyleInlines.h" #include "mozilla/StaticPrefs_mathml.h" #include "mozilla/intl/UnicodeScriptCodes.h" @@ -1230,7 +1226,7 @@ index 13c9cc5c11..b940be8790 100644 #include "nsDeviceContext.h" #include "nsFontMetrics.h" #include "nsStyleConsts.h" -@@ -637,6 +639,18 @@ void MathMLTextRunFactory::RebuildTextRun( +@@ -635,6 +637,18 @@ void MathMLTextRunFactory::RebuildTextRun( newFontGroup = fontGroup; } @@ -1249,7 +1245,7 @@ index 13c9cc5c11..b940be8790 100644 if (mInnerTransformingTextRunFactory) { transformedChild = mInnerTransformingTextRunFactory->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), &innerParams, -@@ -646,7 +660,7 @@ void MathMLTextRunFactory::RebuildTextRun( +@@ -644,7 +658,7 @@ void MathMLTextRunFactory::RebuildTextRun( } else { cachedChild = newFontGroup->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), &innerParams, @@ -1259,10 +1255,10 @@ index 13c9cc5c11..b940be8790 100644 } if (!child) { diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp -index c84d5cde15..7b0e7f4bdf 100644 +index 67019d714a..0b61323cd7 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp -@@ -2338,10 +2338,11 @@ static already_AddRefed GetHyphenTextRun(nsTextFrame* aTextFrame, +@@ -2348,10 +2348,11 @@ static already_AddRefed GetHyphenTextRun(nsTextFrame* aTextFrame, return fontGroup->MakeHyphenTextRun(dt, flags, appPerDev); } auto* missingFonts = aTextFrame->PresContext()->MissingFontRecorder(); @@ -1275,7 +1271,7 @@ index c84d5cde15..7b0e7f4bdf 100644 } already_AddRefed BuildTextRunsScanner::BuildTextRunForFrames( -@@ -2691,6 +2692,9 @@ already_AddRefed BuildTextRunsScanner::BuildTextRunForFrames( +@@ -2701,6 +2702,9 @@ already_AddRefed BuildTextRunsScanner::BuildTextRunForFrames( "We didn't cover all the characters in the text run!"); } @@ -1285,7 +1281,7 @@ index c84d5cde15..7b0e7f4bdf 100644 RefPtr textRun; gfxTextRunFactory::Parameters params = { mDrawTarget, -@@ -2708,7 +2712,7 @@ already_AddRefed BuildTextRunsScanner::BuildTextRunForFrames( +@@ -2718,7 +2722,7 @@ already_AddRefed BuildTextRunsScanner::BuildTextRunForFrames( std::move(styles), true); } else { textRun = fontGroup->MakeTextRun(text, transformedLength, ¶ms, flags, @@ -1294,7 +1290,7 @@ index c84d5cde15..7b0e7f4bdf 100644 } } else { const uint8_t* text = static_cast(textPtr); -@@ -2719,7 +2723,7 @@ already_AddRefed BuildTextRunsScanner::BuildTextRunForFrames( +@@ -2729,7 +2733,7 @@ already_AddRefed BuildTextRunsScanner::BuildTextRunForFrames( std::move(styles), true); } else { textRun = fontGroup->MakeTextRun(text, transformedLength, ¶ms, flags, @@ -1303,7 +1299,7 @@ index c84d5cde15..7b0e7f4bdf 100644 } } if (!textRun) { -@@ -5561,6 +5565,7 @@ static already_AddRefed GenerateTextRunForEmphasisMarks( +@@ -5590,6 +5594,7 @@ static already_AddRefed GenerateTextRunForEmphasisMarks( RefPtr dt = CreateReferenceDrawTarget(aFrame); auto appUnitsPerDevUnit = aFrame->PresContext()->AppUnitsPerDevPixel(); @@ -1311,7 +1307,7 @@ index c84d5cde15..7b0e7f4bdf 100644 gfx::ShapedTextFlags flags = nsLayoutUtils::GetTextRunOrientFlagsForStyle(aComputedStyle); if (flags == gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_MIXED) { -@@ -5569,7 +5574,8 @@ static already_AddRefed GenerateTextRunForEmphasisMarks( +@@ -5598,7 +5603,8 @@ static already_AddRefed GenerateTextRunForEmphasisMarks( } return aFontGroup->MakeTextRun(string.get(), string.Length(), dt, appUnitsPerDevUnit, flags, @@ -1322,10 +1318,10 @@ index c84d5cde15..7b0e7f4bdf 100644 static nsRubyFrame* FindFurthestInlineRubyAncestor(nsTextFrame* aFrame) { diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp -index 93419af8bb..b524540ec6 100644 +index f950a3ab02..ccc1d61034 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp -@@ -918,6 +918,10 @@ void nsCaseTransformTextRunFactory::RebuildTextRun( +@@ -909,6 +909,10 @@ void nsCaseTransformTextRunFactory::RebuildTextRun( RefPtr cachedChild; gfxTextRun* child; @@ -1336,7 +1332,7 @@ index 93419af8bb..b524540ec6 100644 if (mInnerTransformingTextRunFactory) { transformedChild = mInnerTransformingTextRunFactory->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), &innerParams, -@@ -927,7 +931,7 @@ void nsCaseTransformTextRunFactory::RebuildTextRun( +@@ -918,7 +922,7 @@ void nsCaseTransformTextRunFactory::RebuildTextRun( } else { cachedChild = fontGroup->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), &innerParams, @@ -1346,7 +1342,7 @@ index 93419af8bb..b524540ec6 100644 } if (!child) { diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp -index 58f9670e7f..577fd833ce 100644 +index 58daeb0d22..17cba3f503 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -20,6 +20,8 @@ @@ -1357,17 +1353,17 @@ index 58f9670e7f..577fd833ce 100644 +#include "nsPIDOMWindow.h" #include "mozilla/gfx/2D.h" #include "mozilla/intl/UnicodeScriptCodes.h" - #include "nsCOMPtr.h" -@@ -360,7 +362,7 @@ already_AddRefed nsPropertiesTable::MakeTextRun( - "nsPropertiesTable can only access glyphs by code point"); - return aFontGroup->MakeTextRun(aGlyph.code, aGlyph.Length(), aDrawTarget, - aAppUnitsPerDevPixel, mFlags, + #include "nsCSSRendering.h" +@@ -272,7 +274,7 @@ already_AddRefed nsUnicodeTable::MakeTextRun( + "nsUnicodeTable can only access glyphs by code point"); + return aFontGroup->MakeTextRun(&aGlyph.code, 1, aDrawTarget, + aAppUnitsPerDevPixel, gfx::ShapedTextFlags(), - nsTextFrameUtils::Flags(), nullptr); + nsTextFrameUtils::Flags(), nullptr, 0); // TODO: Extract private browsing ID } // An instance of nsOpenTypeTable is associated with one gfxFontEntry that -@@ -431,7 +433,7 @@ void nsOpenTypeTable::UpdateCache(DrawTarget* aDrawTarget, +@@ -344,7 +346,7 @@ void nsOpenTypeTable::UpdateCache(DrawTarget* aDrawTarget, if (mCharCache != aChar) { RefPtr textRun = aFontGroup->MakeTextRun(&aChar, 1, aDrawTarget, aAppUnitsPerDevPixel, @@ -1376,7 +1372,7 @@ index 58f9670e7f..577fd833ce 100644 const gfxTextRun::CompressedGlyph& data = textRun->GetCharacterGlyphs()[0]; if (data.IsSimpleGlyph()) { mGlyphID = data.GetSimpleGlyph(); -@@ -1396,10 +1398,19 @@ nsresult nsMathMLChar::StretchInternal( +@@ -1220,10 +1222,19 @@ nsresult nsMathMLChar::StretchInternal( flags |= gfx::ShapedTextFlags::TEXT_IS_RTL; } @@ -1396,9 +1392,9 @@ index 58f9670e7f..577fd833ce 100644 + presContext->MissingFontRecorder(), userContextId); aDesiredStretchSize = MeasureTextRun(aDrawTarget, mGlyphs[0].get()); - bool maxWidth = (NS_STRETCH_MAXWIDTH & aStretchHint) != 0; + bool maxWidth = aStretchFlags.contains(MathMLStretchFlag::MaxWidth); diff --git a/toolkit/components/resistfingerprinting/FontVisibilityProvider.h b/toolkit/components/resistfingerprinting/FontVisibilityProvider.h -index 51a754b76e..ea41fde83b 100644 +index 9655c9134d..c21c271060 100644 --- a/toolkit/components/resistfingerprinting/FontVisibilityProvider.h +++ b/toolkit/components/resistfingerprinting/FontVisibilityProvider.h @@ -43,6 +43,7 @@ class FontVisibilityProvider { @@ -1417,3 +1413,14 @@ index 51a754b76e..ea41fde83b 100644 using FontVisibilityProvider::ReportBlockedFontFamily; }; +diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp +--- a/gfx/thebes/gfxPlatformFontList.cpp ++++ b/gfx/thebes/gfxPlatformFontList.cpp +@@ -448,6 +448,7 @@ + return mozilla::Nothing(); + } + void UserFontSetUpdated(gfxUserFontEntry*) override {} ++ mozilla::dom::Document* GetDocument() const override { return nullptr; } + using FontVisibilityProvider::ReportBlockedFontFamily; + + private: diff --git a/patches/audio-fingerprint-manager.patch b/patches/audio-fingerprint-manager.patch index b522aac..13ae584 100644 --- a/patches/audio-fingerprint-manager.patch +++ b/patches/audio-fingerprint-manager.patch @@ -1,6 +1,6 @@ diff --git a/dom/base/AudioFingerprintManager.cpp b/dom/base/AudioFingerprintManager.cpp new file mode 100644 -index 0000000000..f47a35b2e3 +index 0000000000..6ec4dc5265 --- /dev/null +++ b/dom/base/AudioFingerprintManager.cpp @@ -0,0 +1,106 @@ @@ -110,10 +110,9 @@ index 0000000000..f47a35b2e3 + +} // namespace dom +} // namespace mozilla - diff --git a/dom/base/AudioFingerprintManager.h b/dom/base/AudioFingerprintManager.h new file mode 100644 -index 0000000000..535ce3a6f9 +index 0000000000..6848990431 --- /dev/null +++ b/dom/base/AudioFingerprintManager.h @@ -0,0 +1,31 @@ @@ -148,12 +147,11 @@ index 0000000000..535ce3a6f9 +} // namespace mozilla + +#endif // mozilla_dom_AudioFingerprintManager_h - diff --git a/dom/base/moz.build b/dom/base/moz.build -index cd9090cda3..a1b2c3d4e5 100644 +index 49c8ac12fa..b503ecab2b 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build -@@ -144,6 +144,7 @@ EXPORTS.mozilla.dom += [ +@@ -142,6 +142,7 @@ EXPORTS.mozilla.dom += [ "AnimationFrameProvider.h", "AnonymousContent.h", "Attr.h", @@ -161,21 +159,23 @@ index cd9090cda3..a1b2c3d4e5 100644 "AutoPrintEventDispatcher.h", "AutoSuppressEventHandlingAndSuspend.h", "BarProps.h", -@@ -326,4 +326,9 @@ SOURCES += [ - "nsWindowSizes.cpp", +@@ -293,6 +294,11 @@ EXPORTS.mozilla.dom += [ + "WindowProxyHolder.h", ] - + +# AudioFingerprintManager compiled separately to avoid namespace pollution +# in unified builds (it includes RoverfoxStorageManager.h which can affect +# alphabetically-later files like BarProps.cpp) +SOURCES += ["AudioFingerprintManager.cpp"] + - UNIFIED_SOURCES += [ + if CONFIG["FUZZING"]: + EXPORTS.mozilla.dom += [ + "FuzzingFunctions.h", diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp -index 748ae6cf83..b2c3d4e5f6 100644 +index 0545014921..1cc5156ae0 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp -@@ -91,6 +91,7 @@ +@@ -88,6 +88,7 @@ #include "mozilla/TimeStamp.h" #include "mozilla/UniquePtr.h" #include "mozilla/dom/AudioContext.h" @@ -183,10 +183,10 @@ index 748ae6cf83..b2c3d4e5f6 100644 #include "mozilla/dom/AutoEntryScript.h" #include "mozilla/dom/BarProps.h" #include "mozilla/dom/BindingDeclarations.h" -@@ -7477,6 +7478,29 @@ void nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker) { +@@ -7721,6 +7722,29 @@ void nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker) { mSharedWorkers.RemoveElement(aSharedWorker); } - + + +void nsGlobalWindowInner::SetAudioFingerprintSeed(uint32_t seed, + ErrorResult& aRv) { @@ -213,37 +213,151 @@ index 748ae6cf83..b2c3d4e5f6 100644 RefPtr nsGlobalWindowInner::StorageAccessPermissionChanged( bool aGranted) { // Invalidate cached StorageAllowed field so that calls to GetLocalStorage - diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h -index 3183172d29..c4d5e6f7a8 100644 +index 43b3ef9521..a1a0fc5d59 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h -@@ -676,6 +676,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, - +@@ -674,6 +674,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, + mozilla::dom::Worklet* GetPaintWorklet(mozilla::ErrorResult& aRv); - + + // Audio fingerprint seed for per-context audio fingerprinting + void SetAudioFingerprintSeed(uint32_t seed, mozilla::ErrorResult& aRv); + - void GetRegionalPrefsLocales(nsTArray& aLocales); - void GetWebExposedLocales(nsTArray& aLocales); - + + mozilla::dom::IntlUtils* GetIntlUtils(mozilla::ErrorResult& aRv); +diff --git a/dom/media/webaudio/AnalyserNode.cpp b/dom/media/webaudio/AnalyserNode.cpp +index 3c80514a1d..befe6ee2bc 100644 +--- a/dom/media/webaudio/AnalyserNode.cpp ++++ b/dom/media/webaudio/AnalyserNode.cpp +@@ -11,6 +11,11 @@ + #include "mozilla/PodOperations.h" + #include "mozilla/dom/AnalyserNodeBinding.h" + #include "nsMathUtils.h" ++#include "AudioFingerprintManager.h" ++#include "nsPIDOMWindow.h" ++#include "nsIGlobalObject.h" ++#include "mozilla/dom/BrowsingContext.h" ++#include "mozilla/dom/WorkerPrivate.h" + + namespace mozilla { + +@@ -214,6 +219,24 @@ void AnalyserNode::GetFloatFrequencyData(const Float32Array& aArray) { + return; + } + ++ // Apply audio fingerprint transformation to frequency data ++ { ++ uint32_t userContextId = 0; ++ AudioContext* context = GetParentObject(); ++ nsIGlobalObject* globalObj = context ? context->GetParentObject() : nullptr; ++ nsPIDOMWindowInner* global = globalObj ? globalObj->GetAsInnerWindow() : nullptr; ++ if (global) { ++ if (BrowsingContext* bc = global->GetBrowsingContext()) { ++ userContextId = bc->OriginAttributesRef().mUserContextId; ++ } ++ } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { ++ userContextId = wp->GetOriginAttributes().mUserContextId; ++ } ++ uint32_t seed = AudioFingerprintManager::GetSeed(userContextId); ++ if (seed != 0) { ++ AudioFingerprintManager::ApplyTransformation(mOutputBuffer.Elements(), mOutputBuffer.Length(), seed); ++ } ++ } + aArray.ProcessData([&](const Span& aData, JS::AutoCheckCannotGC&&) { + size_t length = std::min(size_t(aData.Length()), mOutputBuffer.Length()); + +@@ -230,6 +253,24 @@ void AnalyserNode::GetByteFrequencyData(const Uint8Array& aArray) { + return; + } + ++ // Apply audio fingerprint transformation to frequency data ++ { ++ uint32_t userContextId = 0; ++ AudioContext* context = GetParentObject(); ++ nsIGlobalObject* globalObj = context ? context->GetParentObject() : nullptr; ++ nsPIDOMWindowInner* global = globalObj ? globalObj->GetAsInnerWindow() : nullptr; ++ if (global) { ++ if (BrowsingContext* bc = global->GetBrowsingContext()) { ++ userContextId = bc->OriginAttributesRef().mUserContextId; ++ } ++ } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { ++ userContextId = wp->GetOriginAttributes().mUserContextId; ++ } ++ uint32_t seed = AudioFingerprintManager::GetSeed(userContextId); ++ if (seed != 0) { ++ AudioFingerprintManager::ApplyTransformation(mOutputBuffer.Elements(), mOutputBuffer.Length(), seed); ++ } ++ } + const double rangeScaleFactor = 1.0 / (mMaxDecibels - mMinDecibels); + + aArray.ProcessData([&](const Span& aData, JS::AutoCheckCannotGC&&) { +@@ -253,6 +294,24 @@ void AnalyserNode::GetFloatTimeDomainData(const Float32Array& aArray) { + size_t length = std::min(aData.Length(), size_t(FftSize())); + + GetTimeDomainData(aData.Elements(), length); ++ // Apply audio fingerprint transformation to time domain data ++ { ++ uint32_t userContextId = 0; ++ AudioContext* context = GetParentObject(); ++ nsIGlobalObject* globalObj = context ? context->GetParentObject() : nullptr; ++ nsPIDOMWindowInner* global = globalObj ? globalObj->GetAsInnerWindow() : nullptr; ++ if (global) { ++ if (BrowsingContext* bc = global->GetBrowsingContext()) { ++ userContextId = bc->OriginAttributesRef().mUserContextId; ++ } ++ } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { ++ userContextId = wp->GetOriginAttributes().mUserContextId; ++ } ++ uint32_t seed = AudioFingerprintManager::GetSeed(userContextId); ++ if (seed != 0) { ++ AudioFingerprintManager::ApplyTransformation(aData.Elements(), length, seed); ++ } ++ } + }); + } + +@@ -267,6 +326,24 @@ void AnalyserNode::GetByteTimeDomainData(const Uint8Array& aArray) { + + GetTimeDomainData(tmpBuffer.Elements(), length); + ++ // Apply audio fingerprint transformation before byte conversion ++ { ++ uint32_t userContextId = 0; ++ AudioContext* context = GetParentObject(); ++ nsIGlobalObject* globalObj = context ? context->GetParentObject() : nullptr; ++ nsPIDOMWindowInner* global = globalObj ? globalObj->GetAsInnerWindow() : nullptr; ++ if (global) { ++ if (BrowsingContext* bc = global->GetBrowsingContext()) { ++ userContextId = bc->OriginAttributesRef().mUserContextId; ++ } ++ } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { ++ userContextId = wp->GetOriginAttributes().mUserContextId; ++ } ++ uint32_t seed = AudioFingerprintManager::GetSeed(userContextId); ++ if (seed != 0) { ++ AudioFingerprintManager::ApplyTransformation(tmpBuffer.Elements(), length, seed); ++ } ++ } + unsigned char* buffer = aData.Elements(); + for (size_t i = 0; i < length; ++i) { + const float value = tmpBuffer[i]; diff --git a/dom/media/webaudio/AudioBuffer.cpp b/dom/media/webaudio/AudioBuffer.cpp -index f59d01944a..d21c86e030 100644 +index 7e684a02e5..5d36f2910d 100644 --- a/dom/media/webaudio/AudioBuffer.cpp +++ b/dom/media/webaudio/AudioBuffer.cpp -@@ -21,6 +21,9 @@ +@@ -19,6 +19,9 @@ #include "mozilla/dom/AudioBufferBinding.h" #include "nsPrintfCString.h" #include "nsTHashSet.h" +#include "AudioFingerprintManager.h" +#include "nsPIDOMWindow.h" +#include "mozilla/dom/BrowsingContext.h" - + namespace mozilla::dom { - -@@ -303,5 +306,26 @@ bool AudioBuffer::RestoreJSChannelData(JSContext* aJSContext) { + +@@ -301,6 +304,27 @@ bool AudioBuffer::RestoreJSChannelData(JSContext* aJSContext) { MOZ_ASSERT(!isShared); // Was created as unshared above CopyChannelDataToFloat(mSharedChannels, i, 0, jsData, Length()); } @@ -270,7 +384,8 @@ index f59d01944a..d21c86e030 100644 + } mJSChannels[i] = array; } -@@ -354,6 +377,24 @@ void AudioBuffer::CopyFromChannel(const Float32Array& aDestination, + +@@ -352,6 +376,24 @@ void AudioBuffer::CopyFromChannel(const Float32Array& aDestination, JS::AutoCheckCannotGC&&) { CopyChannelDataToFloat(mSharedChannels, aChannelNumber, aBufferOffset, aData.Elements(), calculateCount(aData.Length())); @@ -295,138 +410,25 @@ index f59d01944a..d21c86e030 100644 }); return; } - -diff --git a/dom/media/webaudio/AnalyserNode.cpp b/dom/media/webaudio/AnalyserNode.cpp -index 4fd7c8be9a..e5f6a7b8c9 100644 ---- a/dom/media/webaudio/AnalyserNode.cpp -+++ b/dom/media/webaudio/AnalyserNode.cpp -@@ -13,5 +13,10 @@ - #include "mozilla/PodOperations.h" - #include "mozilla/dom/AnalyserNodeBinding.h" - #include "nsMathUtils.h" -+#include "AudioFingerprintManager.h" -+#include "nsPIDOMWindow.h" -+#include "nsIGlobalObject.h" -+#include "mozilla/dom/BrowsingContext.h" -+#include "mozilla/dom/WorkerPrivate.h" - - namespace mozilla { -@@ -216,4 +221,22 @@ void AnalyserNode::GetFloatFrequencyData(const Float32Array& aArray) { - return; - } - -+ // Apply audio fingerprint transformation to frequency data -+ { -+ uint32_t userContextId = 0; -+ AudioContext* context = GetParentObject(); -+ nsIGlobalObject* globalObj = context ? context->GetParentObject() : nullptr; -+ nsPIDOMWindowInner* global = globalObj ? globalObj->GetAsInnerWindow() : nullptr; -+ if (global) { -+ if (BrowsingContext* bc = global->GetBrowsingContext()) { -+ userContextId = bc->OriginAttributesRef().mUserContextId; -+ } -+ } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { -+ userContextId = wp->GetOriginAttributes().mUserContextId; -+ } -+ uint32_t seed = AudioFingerprintManager::GetSeed(userContextId); -+ if (seed != 0) { -+ AudioFingerprintManager::ApplyTransformation(mOutputBuffer.Elements(), mOutputBuffer.Length(), seed); -+ } -+ } - aArray.ProcessData([&](const Span& aData, JS::AutoCheckCannotGC&&) { -@@ -232,4 +254,22 @@ void AnalyserNode::GetByteFrequencyData(const Uint8Array& aArray) { - return; - } - -+ // Apply audio fingerprint transformation to frequency data -+ { -+ uint32_t userContextId = 0; -+ AudioContext* context = GetParentObject(); -+ nsIGlobalObject* globalObj = context ? context->GetParentObject() : nullptr; -+ nsPIDOMWindowInner* global = globalObj ? globalObj->GetAsInnerWindow() : nullptr; -+ if (global) { -+ if (BrowsingContext* bc = global->GetBrowsingContext()) { -+ userContextId = bc->OriginAttributesRef().mUserContextId; -+ } -+ } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { -+ userContextId = wp->GetOriginAttributes().mUserContextId; -+ } -+ uint32_t seed = AudioFingerprintManager::GetSeed(userContextId); -+ if (seed != 0) { -+ AudioFingerprintManager::ApplyTransformation(mOutputBuffer.Elements(), mOutputBuffer.Length(), seed); -+ } -+ } - const double rangeScaleFactor = 1.0 / (mMaxDecibels - mMinDecibels); -@@ -255,5 +295,23 @@ void AnalyserNode::GetFloatTimeDomainData(const Float32Array& aArray) { - size_t length = std::min(aData.Length(), size_t(FftSize())); - - GetTimeDomainData(aData.Elements(), length); -+ // Apply audio fingerprint transformation to time domain data -+ { -+ uint32_t userContextId = 0; -+ AudioContext* context = GetParentObject(); -+ nsIGlobalObject* globalObj = context ? context->GetParentObject() : nullptr; -+ nsPIDOMWindowInner* global = globalObj ? globalObj->GetAsInnerWindow() : nullptr; -+ if (global) { -+ if (BrowsingContext* bc = global->GetBrowsingContext()) { -+ userContextId = bc->OriginAttributesRef().mUserContextId; -+ } -+ } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { -+ userContextId = wp->GetOriginAttributes().mUserContextId; -+ } -+ uint32_t seed = AudioFingerprintManager::GetSeed(userContextId); -+ if (seed != 0) { -+ AudioFingerprintManager::ApplyTransformation(aData.Elements(), length, seed); -+ } -+ } - }); - } -@@ -269,6 +325,24 @@ void AnalyserNode::GetByteTimeDomainData(const Uint8Array& aArray) { - - GetTimeDomainData(tmpBuffer.Elements(), length); - -+ // Apply audio fingerprint transformation before byte conversion -+ { -+ uint32_t userContextId = 0; -+ AudioContext* context = GetParentObject(); -+ nsIGlobalObject* globalObj = context ? context->GetParentObject() : nullptr; -+ nsPIDOMWindowInner* global = globalObj ? globalObj->GetAsInnerWindow() : nullptr; -+ if (global) { -+ if (BrowsingContext* bc = global->GetBrowsingContext()) { -+ userContextId = bc->OriginAttributesRef().mUserContextId; -+ } -+ } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { -+ userContextId = wp->GetOriginAttributes().mUserContextId; -+ } -+ uint32_t seed = AudioFingerprintManager::GetSeed(userContextId); -+ if (seed != 0) { -+ AudioFingerprintManager::ApplyTransformation(tmpBuffer.Elements(), length, seed); -+ } -+ } - unsigned char* buffer = aData.Elements(); - for (size_t i = 0; i < length; ++i) { - const float value = tmpBuffer[i]; diff --git a/dom/media/webaudio/moz.build b/dom/media/webaudio/moz.build -index 3ee8c0aa76..4cf10f3039 100644 +index b962c175f1..0bafa2f0a7 100644 --- a/dom/media/webaudio/moz.build +++ b/dom/media/webaudio/moz.build -@@ -152,5 +152,8 @@ include("/ipc/chromium/chromium-config.mozbuild") - FINAL_LIBRARY = "xul" - LOCAL_INCLUDES += [".."] - +@@ -155,3 +155,6 @@ LOCAL_INCLUDES += [".."] + # DOM Mask LOCAL_INCLUDES += ["/camoucfg"] + +# AudioFingerprintManager in dom/base +LOCAL_INCLUDES += ["/dom/base"] diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl -index 7c509eb87e..7a076768d1 100644 +index ae2d14e105..16afc72899 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl -@@ -892,6 +892,12 @@ partial interface Window { +@@ -930,6 +930,12 @@ partial interface Window { readonly attribute VisualViewport visualViewport; }; - + +// Audio fingerprint seed for per-context audio fingerprinting +partial interface Window { + [Throws, Func="mozilla::dom::AudioFingerprintManager::IsFunctionEnabledForWebIDL"] diff --git a/patches/config.patch b/patches/config.patch index ad004ae..7016514 100644 --- a/patches/config.patch +++ b/patches/config.patch @@ -1,8 +1,8 @@ diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 6bb2e64906..fbdb0b26ea 100644 +index 36eafe3506..1787249b72 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in -@@ -250,6 +250,11 @@ +@@ -255,6 +255,11 @@ #endif #endif @@ -34,13 +34,12 @@ index e69de29bb2..5459e4ac36 100644 + "local-settings.js", +] diff --git a/moz.build b/moz.build -index 4d0f3d6ba9..0f07f37e92 100644 +index fc7ffd9077..41917bd445 100644 --- a/moz.build +++ b/moz.build -@@ -235,3 +235,5 @@ SPHINX_TREES["content-security"] = "docs/content-security" - SPHINX_TREES["jsloader"] = "docs/jsloader" +@@ -247,3 +247,5 @@ SPHINX_TREES["jsloader"] = "docs/jsloader" + SPHINX_TREES["ai-agent-tools"] = "docs/ai-agent-tools" include("build/templates.mozbuild") + +DIRS += ["lw"] -\ No newline at end of file diff --git a/patches/font-hijacker.patch b/patches/font-hijacker.patch index 85d06bc..3706992 100644 --- a/patches/font-hijacker.patch +++ b/patches/font-hijacker.patch @@ -1,5 +1,5 @@ diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp -index bc0e123f85..52ec46f76b 100644 +index d82edfc767..3d16611ebe 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -13,6 +13,7 @@ @@ -8,9 +8,9 @@ index bc0e123f85..52ec46f76b 100644 #include "SharedFontList-impl.h" +#include "MaskConfig.hpp" - #include "GeckoProfiler.h" - #include "nsCRT.h" -@@ -303,6 +304,16 @@ gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames) + #include "FontVisibilityProvider.h" + +@@ -314,6 +315,16 @@ gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames) mFontPrefs = MakeUnique(); @@ -28,22 +28,22 @@ index bc0e123f85..52ec46f76b 100644 mFontFamilyWhitelistActive = !mEnabledFontsList.IsEmpty(); diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build -index 3d99906827..a9d1191688 100644 +index e19da2b985..e4947d70a0 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build -@@ -301,3 +301,6 @@ DEFINES["GRAPHITE2_STATIC"] = True +@@ -299,3 +299,6 @@ DEFINES["GRAPHITE2_STATIC"] = True CXXFLAGS += ["-Werror=switch"] - + include("/tools/fuzzing/libfuzzer-config.mozbuild") + +# DOM Mask +LOCAL_INCLUDES += ["/camoucfg"] \ No newline at end of file diff --git a/layout/style/FontFace.cpp b/layout/style/FontFace.cpp -index f1a90334ea..47d3a881ac 100644 +index 74caa590c0..7627535068 100644 --- a/layout/style/FontFace.cpp +++ b/layout/style/FontFace.cpp -@@ -237,7 +237,16 @@ void FontFace::SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv) { +@@ -239,7 +239,16 @@ void FontFace::SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv) { mImpl->SetSizeAdjust(aValue, aRv); } @@ -61,7 +61,7 @@ index f1a90334ea..47d3a881ac 100644 Promise* FontFace::Load(ErrorResult& aRv) { EnsurePromise(); -@@ -247,7 +256,17 @@ Promise* FontFace::Load(ErrorResult& aRv) { +@@ -249,7 +258,17 @@ Promise* FontFace::Load(ErrorResult& aRv) { return nullptr; } @@ -77,14 +77,14 @@ index f1a90334ea..47d3a881ac 100644 + mLoaded->MaybeReject(NS_ERROR_FAILURE); + } + + mImpl->UpdateOwnerKeepAlive(); return mLoaded; } - diff --git a/layout/style/FontFaceImpl.cpp b/layout/style/FontFaceImpl.cpp -index 9d1f7c8c5b..926315ca2f 100644 +index 6a71b06dab..d1e3f7bbb1 100644 --- a/layout/style/FontFaceImpl.cpp +++ b/layout/style/FontFaceImpl.cpp -@@ -357,22 +357,16 @@ void FontFaceImpl::DoLoad() { +@@ -358,21 +358,15 @@ void FontFaceImpl::DoLoad() { void FontFaceImpl::SetStatus(FontFaceLoadStatus aStatus) { gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked(); @@ -112,20 +112,19 @@ index 9d1f7c8c5b..926315ca2f 100644 if (mInFontFaceSet) { mFontFaceSet->OnFontFaceStatusChanged(this); } - diff --git a/layout/style/FontFaceImpl.h b/layout/style/FontFaceImpl.h -index 70c06609e9..66b2666621 100644 +index ce49ac67dc..0bac123bd4 100644 --- a/layout/style/FontFaceImpl.h +++ b/layout/style/FontFaceImpl.h -@@ -13,6 +13,7 @@ - #include "mozilla/ServoStyleConsts.h" +@@ -8,6 +8,7 @@ + #include "gfxUserFontSet.h" + #include "mozilla/RWLock.h" #include "mozilla/dom/FontFaceBinding.h" +#include "MaskConfig.hpp" #include "nsTHashSet.h" - + class gfxFontFaceBufferSource; - -@@ -33,6 +34,20 @@ +@@ -27,6 +28,20 @@ class UTF8StringOrArrayBufferOrArrayBufferView; namespace mozilla::dom { @@ -147,11 +146,10 @@ index 70c06609e9..66b2666621 100644 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FontFaceImpl) diff --git a/layout/style/moz.build b/layout/style/moz.build -index a14ab6a7ac..6e6a727abf 100644 +index 65874de131..01f29cdcd7 100644 --- a/layout/style/moz.build +++ b/layout/style/moz.build -@@ -378,4 +378,7 @@ - CbindgenHeader( +@@ -368,3 +368,6 @@ if CONFIG["COMPILE_ENVIRONMENT"]: "ServoStyleConsts.h", inputs=["/servo/ports/geckolib", "/servo/components/style"], ) diff --git a/patches/geolocation-spoofing.patch b/patches/geolocation-spoofing.patch index 7aee478..2d656e4 100644 --- a/patches/geolocation-spoofing.patch +++ b/patches/geolocation-spoofing.patch @@ -1,8 +1,8 @@ diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 274cdebc2e..b0183ecc6a 100644 +index 5cc4ca84dc..e657a7fb64 100644 --- a/dom/geolocation/Geolocation.cpp +++ b/dom/geolocation/Geolocation.cpp -@@ -34,6 +34,7 @@ +@@ -35,6 +35,7 @@ #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" #include "nsXULAppAPI.h" @@ -10,9 +10,9 @@ index 274cdebc2e..b0183ecc6a 100644 class nsIPrincipal; -@@ -1267,6 +1268,12 @@ void Geolocation::NotifyAllowedRequest(nsGeolocationRequest* aRequest) { - - bool Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request) { +@@ -1478,6 +1479,12 @@ void Geolocation::NotifyAllowedRequest(nsGeolocationRequest* aRequest) { + /* static */ bool Geolocation::RegisterRequestWithPrompt( + nsGeolocationRequest* request) { nsIEventTarget* target = GetMainThreadSerialEventTarget(); + if (MaskConfig::GetDouble("geolocation:latitude") && + MaskConfig::GetDouble("geolocation:longitude")) { @@ -24,18 +24,18 @@ index 274cdebc2e..b0183ecc6a 100644 if (pr == ContentPermissionRequestBase::PromptResult::Granted) { request->RequestDelayedTask(target, diff --git a/dom/geolocation/GeolocationPosition.cpp b/dom/geolocation/GeolocationPosition.cpp -index 19ca685251..a286a4a784 100644 +index ea9f539aa0..6f0f0b3961 100644 --- a/dom/geolocation/GeolocationPosition.cpp +++ b/dom/geolocation/GeolocationPosition.cpp -@@ -9,6 +9,7 @@ - +@@ -7,6 +7,7 @@ #include "mozilla/FloatingPoint.h" + #include "mozilla/dom/GeolocationCoordinates.h" #include "mozilla/dom/GeolocationPositionBinding.h" +#include "MaskConfig.hpp" using mozilla::EqualOrBothNaN; -@@ -62,13 +63,19 @@ NS_IMPL_RELEASE(nsGeoPositionCoords) +@@ -60,13 +61,19 @@ NS_IMPL_RELEASE(nsGeoPositionCoords) NS_IMETHODIMP nsGeoPositionCoords::GetLatitude(double* aLatitude) { @@ -57,7 +57,7 @@ index 19ca685251..a286a4a784 100644 return NS_OK; } -@@ -80,7 +87,10 @@ nsGeoPositionCoords::GetAltitude(double* aAltitude) { +@@ -78,7 +85,10 @@ nsGeoPositionCoords::GetAltitude(double* aAltitude) { NS_IMETHODIMP nsGeoPositionCoords::GetAccuracy(double* aAccuracy) { @@ -70,11 +70,10 @@ index 19ca685251..a286a4a784 100644 } diff --git a/dom/geolocation/moz.build b/dom/geolocation/moz.build -index 2d6b6b5fab..0c7ed74c6d 100644 +index 25d0eaf307..c60d95e90f 100644 --- a/dom/geolocation/moz.build +++ b/dom/geolocation/moz.build -@@ -84,4 +84,7 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": - BROWSER_CHROME_MANIFESTS += ["test/browser/browser.toml"] +@@ -84,3 +84,6 @@ BROWSER_CHROME_MANIFESTS += ["test/browser/browser.toml"] MOCHITEST_CHROME_MANIFESTS += ["test/chrome/chrome.toml"] MOCHITEST_MANIFESTS += ["test/mochitest/mochitest.toml"] XPCSHELL_TESTS_MANIFESTS += ["test/unit/xpcshell.toml"] @@ -82,12 +81,12 @@ index 2d6b6b5fab..0c7ed74c6d 100644 +# Camoufox: include path for MaskConfig.hpp +LOCAL_INCLUDES += ["/camoucfg"] diff --git a/dom/system/NetworkGeolocationProvider.sys.mjs b/dom/system/NetworkGeolocationProvider.sys.mjs -index 7edc62b4a6..19b77aa6b6 100644 +index f89cf1b1a7..c2fc42998f 100644 --- a/dom/system/NetworkGeolocationProvider.sys.mjs +++ b/dom/system/NetworkGeolocationProvider.sys.mjs -@@ -442,17 +442,53 @@ NetworkGeolocationProvider.prototype = { - let url = Services.urlFormatter.formatURLPref("geo.provider.network.url"); - LOG("Sending request"); +@@ -357,17 +357,52 @@ NetworkGeolocationProvider.prototype = { + Glean.geolocation.geolocationService.network_ip.add(); + } + // Use CAMOU_CONFIG geolocation if configured + let DEFAULT_DEG = -180; @@ -103,8 +102,8 @@ index 7edc62b4a6..19b77aa6b6 100644 + let result; try { -- result = await this.makeRequest(url, wifiData); -- LOG( +- result = await this.fetchLocation(url, wifiData); +- lazy.log.info( - `geo provider reported: ${result.location.lng}:${result.location.lat}` - ); - let newLocation = new NetworkGeoPositionObject( @@ -134,9 +133,8 @@ index 7edc62b4a6..19b77aa6b6 100644 + ); + } else { + // No CAMOU_CONFIG override, use real geolocation -+ result = await this.makeRequest(url, wifiData); -+ -+ LOG( ++ result = await this.fetchLocation(url, wifiData); ++ lazy.log.info( + `geo provider reported: ${result.location.lng}:${result.location.lat}` + ); + newLocation = new NetworkGeoPositionObject( @@ -148,4 +146,3 @@ index 7edc62b4a6..19b77aa6b6 100644 if (this.listener) { this.listener.update(newLocation); - diff --git a/patches/librewolf/mozilla_dirs.patch b/patches/librewolf/mozilla_dirs.patch index a09f49e..ee8917b 100644 --- a/patches/librewolf/mozilla_dirs.patch +++ b/patches/librewolf/mozilla_dirs.patch @@ -1,8 +1,8 @@ diff --git a/toolkit/components/extensions/NativeManifests.sys.mjs b/toolkit/components/extensions/NativeManifests.sys.mjs -index 59313e821f..f3a7caa057 100644 +index 5c9cee1b70..a00955446e 100644 --- a/toolkit/components/extensions/NativeManifests.sys.mjs +++ b/toolkit/components/extensions/NativeManifests.sys.mjs -@@ -40,6 +40,8 @@ +@@ -39,6 +39,8 @@ export var NativeManifests = { let dirs = [ Services.dirsvc.get("XREUserNativeManifests", Ci.nsIFile).path, Services.dirsvc.get("XRESysNativeManifests", Ci.nsIFile).path, @@ -12,10 +12,10 @@ index 59313e821f..f3a7caa057 100644 this._lookup = (type, name, context) => this._tryPaths(type, name, dirs, context); diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp -index 9c94cb8808..af2dbdbf3f 100644 +index 7615c2c7cf..b41b027f95 100644 --- a/toolkit/xre/nsXREDirProvider.cpp +++ b/toolkit/xre/nsXREDirProvider.cpp -@@ -278,23 +278,25 @@ +@@ -336,23 +336,25 @@ nsresult nsXREDirProvider::GetBackgroundTasksProfilesRootDir( * On Linux this is /usr/{lib,lib64}/mozilla * (for 32- and 64-bit systems respsectively) */ @@ -47,28 +47,30 @@ index 9c94cb8808..af2dbdbf3f 100644 # endif ; rv = NS_NewNativeLocalFile(dirname, getter_AddRefs(localDir)); -@@ -362,10 +364,20 @@ +@@ -420,11 +422,22 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent, #if defined(XP_UNIX) || defined(XP_MACOSX) else if (!strcmp(aProperty, XRE_SYS_NATIVE_MANIFESTS)) { rv = ::GetSystemParentDirectory(getter_AddRefs(file)); + } else if (!strcmp(aProperty, XRE_MOZ_SYS_NATIVE_MANIFESTS)) { + rv = ::GetSystemParentDirectory(getter_AddRefs(file), "Mozilla"_ns); } else if (!strcmp(aProperty, XRE_USER_NATIVE_MANIFESTS)) { - rv = GetUserDataDirectoryHome(getter_AddRefs(file), false); + // Keep forcing the legacy path for compatibility + rv = GetUserDataDirectoryHome(getter_AddRefs(file), /* aLocal */ false, + /* aForceLegacy */ true); NS_ENSURE_SUCCESS(rv, rv); - # if defined(XP_MACOSX) ++# if defined(XP_MACOSX) + rv = file->AppendNative("LibreWolf"_ns); +# else // defined(XP_MACOSX) + rv = file->AppendNative(".librewolf"_ns); +# endif // defined(XP_MACOSX) + } else if (!strcmp(aProperty, XRE_MOZ_USER_NATIVE_MANIFESTS)) { -+ rv = GetUserDataDirectoryHome(getter_AddRefs(file), false); ++ rv = GetUserDataDirectoryHome(getter_AddRefs(file), /* aLocal */ false, ++ /* aForceLegacy */ true); + NS_ENSURE_SUCCESS(rv, rv); -+# if defined(XP_MACOSX) + # if defined(XP_MACOSX) rv = file->AppendNative("Mozilla"_ns); # else // defined(XP_MACOSX) - rv = file->AppendNative(".mozilla"_ns); -@@ -398,9 +410,10 @@ +@@ -458,9 +471,10 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent, else if (!strcmp(aProperty, XRE_SYS_SHARE_EXTENSION_PARENT_DIR)) { # ifdef ENABLE_SYSTEM_EXTENSION_DIRS # if defined(__OpenBSD__) || defined(__FreeBSD__) @@ -81,7 +83,7 @@ index 9c94cb8808..af2dbdbf3f 100644 # endif rv = NS_NewNativeLocalFile(nsDependentCString(sysLExtDir), getter_AddRefs(file)); -@@ -926,13 +939,7 @@ +@@ -987,13 +1001,7 @@ nsresult nsXREDirProvider::GetUpdateRootDir(nsIFile** aResult, } appDirPath = Substring(appDirPath, 1, dotIndex - 1); @@ -96,7 +98,7 @@ index 9c94cb8808..af2dbdbf3f 100644 return NS_ERROR_FAILURE; } -@@ -1192,7 +1199,7 @@ +@@ -1291,7 +1299,7 @@ nsresult nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile) { #if defined(XP_MACOSX) || defined(XP_WIN) @@ -105,7 +107,7 @@ index 9c94cb8808..af2dbdbf3f 100644 rv = aFile->AppendNative(nsDependentCString(sXR)); NS_ENSURE_SUCCESS(rv, rv); -@@ -1202,7 +1209,7 @@ +@@ -1301,7 +1309,7 @@ nsresult nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile) { #elif defined(XP_UNIX) @@ -114,7 +116,7 @@ index 9c94cb8808..af2dbdbf3f 100644 rv = aFile->AppendNative(nsDependentCString(sXR)); NS_ENSURE_SUCCESS(rv, rv); -@@ -1253,10 +1260,6 @@ +@@ -1587,10 +1595,6 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) { if (!profile.IsEmpty()) { rv = AppendProfileString(aFile, profile.get()); } else { @@ -125,9 +127,9 @@ index 9c94cb8808..af2dbdbf3f 100644 rv = aFile->AppendNative(appName); } NS_ENSURE_SUCCESS(rv, rv); -@@ -1288,16 +1291,6 @@ +@@ -1628,16 +1632,6 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) { - rv = AppendProfileString(aFile, folder.BeginReading()); + rv = AppendProfileString(aFile, folder.get()); } else { - if (!vendor.IsEmpty()) { - folder.Append(vendor); @@ -143,10 +145,10 @@ index 9c94cb8808..af2dbdbf3f 100644 if (!appName.IsEmpty()) { folder.Append(appName); diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h -index 28a2a68c63..b0917fb9b8 100644 +index 8a09115312..f8c623b611 100644 --- a/xpcom/build/nsXULAppAPI.h +++ b/xpcom/build/nsXULAppAPI.h -@@ -116,6 +116,8 @@ +@@ -113,6 +113,8 @@ struct BootstrapConfig; */ # define XRE_SYS_NATIVE_MANIFESTS "XRESysNativeManifests" # define XRE_USER_NATIVE_MANIFESTS "XREUserNativeManifests" diff --git a/patches/librewolf/ui-patches/hide-default-browser.patch b/patches/librewolf/ui-patches/hide-default-browser.patch index d099069..eb1f290 100644 --- a/patches/librewolf/ui-patches/hide-default-browser.patch +++ b/patches/librewolf/ui-patches/hide-default-browser.patch @@ -1,8 +1,8 @@ diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js -index 46283d3..9e14d59 100644 +index 8f8da3c4ca..83e9ccce59 100644 --- a/browser/components/preferences/main.js +++ b/browser/components/preferences/main.js -@@ -1000,65 +1000,6 @@ const DefaultBrowserHelper = { +@@ -1660,65 +1660,6 @@ const DefaultBrowserHelper = { }, }; @@ -22,7 +22,7 @@ index 46283d3..9e14d59 100644 - * browser is already the default browser. - */ - visible: () => DefaultBrowserHelper.canCheck, -- disabled: (deps, setting) => +- disabled: (_, setting) => - !DefaultBrowserHelper.canCheck || - setting.locked || - DefaultBrowserHelper.isBrowserDefault, @@ -65,10 +65,10 @@ index 46283d3..9e14d59 100644 - }, -}); - - // Performance settings + // Firefox support settings Preferences.addSetting({ - id: "contentProcessCount", -@@ -1141,31 +1082,6 @@ let SETTINGS_CONFIG = { + id: "supportLinksGroup", +@@ -2688,10 +2629,6 @@ function createStartupConfig(hidden = false) { control: "moz-message-bar", l10nId: "startup-windows-launch-on-login-profile-disabled", }, @@ -76,27 +76,26 @@ index 46283d3..9e14d59 100644 - id: "alwaysCheckDefault", - l10nId: "always-check-default", - }, -- { -- id: "isDefaultPane", -- l10nId: "is-default-browser", -- control: "moz-promo", -- }, -- { -- id: "isNotDefaultPane", -- l10nId: "is-not-default-browser", -- control: "moz-promo", -- options: [ -- { -- control: "moz-button", -- l10nId: "set-as-my-default-browser", -- id: "setDefaultButton", -- controlAttrs: { -- slot: "actions", -- type: "primary", -- }, -- }, -- ], -- }, + ], + }; + } +@@ -2753,7 +2690,6 @@ SettingGroupManager.registerGroups({ + }, ], }, - zoom: { +- defaultBrowser: createDefaultBrowserConfig(), + startup: createStartupConfig( + Services.prefs.getBoolPref("browser.settings-redesign.enabled", false) + ), +@@ -4639,11 +4575,6 @@ SettingGroupManager.registerGroups({ + }, + ], + }, +- defaultBrowserSync: createDefaultBrowserConfig({ +- includeIsDefaultPane: false, +- inProgress: true, +- hiddenFromSearch: true, +- }), + sync: { + inProgress: true, + l10nId: "sync-group-label", diff --git a/patches/locale-spoofing.patch b/patches/locale-spoofing.patch index fa83ae9..c5cf69a 100644 --- a/patches/locale-spoofing.patch +++ b/patches/locale-spoofing.patch @@ -1,20 +1,10 @@ -diff --git a/intl/components/moz.build b/intl/components/moz.build -index xxxxxxxxxx..yyyyyyyyyy 100644 ---- a/intl/components/moz.build -+++ b/intl/components/moz.build -@@ -1,3 +1,5 @@ -+LOCAL_INCLUDES += ["/camoucfg"] -+ - # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- - # vim: set filetype=python: - # This Source Code Form is subject to the terms of the Mozilla Public diff --git a/browser/base/content/browser-init.js b/browser/base/content/browser-init.js -index 2456c5b4c6..826404b1b7 100644 +index b64d2f52ed..543bb50593 100644 --- a/browser/base/content/browser-init.js +++ b/browser/base/content/browser-init.js -@@ -109,6 +109,22 @@ var gBrowserInit = { +@@ -183,6 +183,22 @@ var gBrowserInit = { window.TabBarVisibility.update(); - TabsInTitlebar.init(); + CustomTitlebar.init(); + // If a list of languages were passed, use them. + let camouLocale = ChromeUtils.camouGetString("locale:all") @@ -35,11 +25,21 @@ index 2456c5b4c6..826404b1b7 100644 new LightweightThemeConsumer(document); if ( +diff --git a/intl/components/moz.build b/intl/components/moz.build +index eb6673cb34..e7456492ee 100644 +--- a/intl/components/moz.build ++++ b/intl/components/moz.build +@@ -1,3 +1,5 @@ ++LOCAL_INCLUDES += ["/camoucfg"] ++ + # 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/. diff --git a/intl/components/src/Locale.cpp b/intl/components/src/Locale.cpp -index 9a043518cf..a8d3733212 100644 +index 718d8814d8..068d042bc7 100644 --- a/intl/components/src/Locale.cpp +++ b/intl/components/src/Locale.cpp -@@ -24,11 +24,56 @@ +@@ -20,11 +20,56 @@ #include "unicode/uloc.h" #include "unicode/utypes.h" @@ -97,12 +97,12 @@ index 9a043518cf..a8d3733212 100644 bool IsStructurallyValidLanguageTag(Span aLanguage) { // unicode_language_subtag = alpha{2,3} | alpha{5,8}; diff --git a/intl/components/src/Locale.h b/intl/components/src/Locale.h -index 1f4e06f543..448486a479 100644 +index afc065bc80..77269cea1a 100644 --- a/intl/components/src/Locale.h +++ b/intl/components/src/Locale.h -@@ -190,8 +190,11 @@ using UniqueChars = UniquePtr; - */ - class MOZ_STACK_CLASS Locale final { +@@ -209,8 +209,11 @@ class MOZ_STACK_CLASS Locale final { + + private: LanguageSubtag mLanguage = {}; + mutable LanguageSubtag mCamouLanguage = {}; ScriptSubtag mScript = {}; @@ -110,9 +110,9 @@ index 1f4e06f543..448486a479 100644 RegionSubtag mRegion = {}; + mutable RegionSubtag mCamouRegion = {}; - using VariantsVector = Vector; - using ExtensionsVector = Vector; -@@ -314,9 +317,28 @@ class MOZ_STACK_CLASS Locale final { + VariantsVector mVariants; + ExtensionsVector mExtensions; +@@ -339,9 +342,28 @@ class MOZ_STACK_CLASS Locale final { } }; @@ -144,7 +144,7 @@ index 1f4e06f543..448486a479 100644 auto Variants() const { return SubtagEnumeration(mVariants); } auto Extensions() const { return SubtagEnumeration(mExtensions); } Maybe> PrivateUse() const { -@@ -483,7 +505,15 @@ class MOZ_STACK_CLASS Locale final { +@@ -519,7 +541,15 @@ class MOZ_STACK_CLASS Locale final { * * Also see . */ @@ -162,10 +162,10 @@ index 1f4e06f543..448486a479 100644 /** * Returns an iterator over all supported locales. diff --git a/intl/locale/OSPreferences.cpp b/intl/locale/OSPreferences.cpp -index b87924b61a..2eaa960c04 100644 +index b922e3890e..a856788d48 100644 --- a/intl/locale/OSPreferences.cpp +++ b/intl/locale/OSPreferences.cpp -@@ -406,6 +406,10 @@ bool OSPreferences::GetDateTimeConnectorPattern(const nsACString& aLocale, +@@ -410,6 +410,10 @@ bool OSPreferences::GetDateTimeConnectorPattern(const nsACString& aLocale, */ NS_IMETHODIMP OSPreferences::GetSystemLocales(nsTArray& aRetVal) { @@ -176,7 +176,7 @@ index b87924b61a..2eaa960c04 100644 if (!mSystemLocales.IsEmpty()) { aRetVal = mSystemLocales.Clone(); return NS_OK; -@@ -425,7 +429,10 @@ OSPreferences::GetSystemLocales(nsTArray& aRetVal) { +@@ -429,7 +433,10 @@ OSPreferences::GetSystemLocales(nsTArray& aRetVal) { NS_IMETHODIMP OSPreferences::GetSystemLocale(nsACString& aRetVal) { @@ -188,7 +188,7 @@ index b87924b61a..2eaa960c04 100644 aRetVal = mSystemLocales[0]; } else { AutoTArray locales; -@@ -439,6 +446,10 @@ OSPreferences::GetSystemLocale(nsACString& aRetVal) { +@@ -443,6 +450,10 @@ OSPreferences::GetSystemLocale(nsACString& aRetVal) { NS_IMETHODIMP OSPreferences::GetRegionalPrefsLocales(nsTArray& aRetVal) { diff --git a/patches/playwright/0-playwright.patch b/patches/playwright/0-playwright.patch index fece1c2..b7dfed5 100644 --- a/patches/playwright/0-playwright.patch +++ b/patches/playwright/0-playwright.patch @@ -1,8 +1,28 @@ +diff --git a/third_party/libwebrtc/api/location.h b/third_party/libwebrtc/api/location.h +new file mode 100644 +index 0000000000..040cbc972b +--- /dev/null ++++ b/third_party/libwebrtc/api/location.h +@@ -0,0 +1,14 @@ ++#ifndef API_LOCATION_H_ ++#define API_LOCATION_H_ ++ ++namespace webrtc { ++class Location { ++ public: ++ static constexpr Location Current() { return Location(); } ++ constexpr Location() = default; ++ constexpr Location(const Location&) = default; ++ constexpr Location& operator=(const Location&) = default; ++}; ++} // namespace webrtc ++ ++#endif // API_LOCATION_H_ diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl -index 6c932c14a0..6312131c94 100644 +index 2ee93b3834..cdc5972aa1 100644 --- a/accessible/interfaces/nsIAccessibleDocument.idl +++ b/accessible/interfaces/nsIAccessibleDocument.idl -@@ -73,4 +73,9 @@ interface nsIAccessibleDocument : nsISupports +@@ -72,4 +72,9 @@ interface nsIAccessibleDocument : nsISupports * The BrowsingContext of this document. */ readonly attribute BrowsingContext browsingContext; @@ -13,10 +33,10 @@ index 6c932c14a0..6312131c94 100644 + readonly attribute boolean isUpdatePendingForJugglerAccessibility; }; diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp -index 3229ee415b..c2cc38ded2 100644 +index 30c6427da3..166a6837ec 100644 --- a/accessible/xpcom/xpcAccessibleDocument.cpp +++ b/accessible/xpcom/xpcAccessibleDocument.cpp -@@ -151,6 +151,13 @@ xpcAccessibleDocument::GetBrowsingContext( +@@ -149,6 +149,13 @@ xpcAccessibleDocument::GetBrowsingContext( return NS_OK; } @@ -31,10 +51,10 @@ index 3229ee415b..c2cc38ded2 100644 // xpcAccessibleDocument diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h -index 9b6effc38f..939ff9615b 100644 +index 9eea79a25c..a9e21f5207 100644 --- a/accessible/xpcom/xpcAccessibleDocument.h +++ b/accessible/xpcom/xpcAccessibleDocument.h -@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText, +@@ -46,6 +46,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText, nsIAccessibleDocument** aDocument) final; NS_IMETHOD GetBrowsingContext(dom::BrowsingContext** aBrowsingContext) final; @@ -44,18 +64,18 @@ index 9b6effc38f..939ff9615b 100644 * Return XPCOM wrapper for the internal accessible. */ diff --git a/browser/app/winlauncher/LauncherProcessWin.cpp b/browser/app/winlauncher/LauncherProcessWin.cpp -index 6766615d29..a70473d9f4 100644 +index c63afe6dc5..19d27fac99 100644 --- a/browser/app/winlauncher/LauncherProcessWin.cpp +++ b/browser/app/winlauncher/LauncherProcessWin.cpp -@@ -22,6 +22,7 @@ +@@ -20,6 +20,7 @@ #include "mozilla/WinHeaderOnlyUtils.h" #include "nsWindowsHelpers.h" +#include #include #include - -@@ -413,8 +414,18 @@ Maybe LauncherMain(int& argc, wchar_t* argv[]) { + #include +@@ -492,8 +493,18 @@ Maybe LauncherMain(int& argc, wchar_t* argv[]) { HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE), ::GetStdHandle(STD_OUTPUT_HANDLE), ::GetStdHandle(STD_ERROR_HANDLE)}; @@ -76,10 +96,10 @@ index 6766615d29..a70473d9f4 100644 DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn -index 0e195e47d9..d7ecbe4648 100644 +index a826f3afb8..d70d2794b2 100644 --- a/browser/installer/allowed-dupes.mn +++ b/browser/installer/allowed-dupes.mn -@@ -61,6 +61,12 @@ browser/chrome/browser/builtin-addons/webcompat/shims/empty-shim.txt +@@ -66,6 +66,12 @@ browser/chrome/browser/builtin-addons/webcompat/shims/empty-shim.txt removed-files #endif @@ -93,10 +113,10 @@ index 0e195e47d9..d7ecbe4648 100644 browser/chrome/browser/content/activity-stream/data/content/tippytop/favicons/allegro-pl.ico browser/defaults/settings/main/search-config-icons/96327a73-c433-5eb4-a16d-b090cadfb80b diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 6bb2e64906..8bf50addfb 100644 +index 36eafe3506..33fe25fc50 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in -@@ -195,6 +195,9 @@ +@@ -200,6 +200,9 @@ @RESPATH@/chrome/remote.manifest #endif @@ -107,10 +127,10 @@ index 6bb2e64906..8bf50addfb 100644 @RESPATH@/browser/modules/* @RESPATH@/modules/* diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js -index d49c6fbf1b..7ea3540947 100644 +index 257e87fe0c..8c13f02010 100644 --- a/devtools/server/socket/websocket-server.js +++ b/devtools/server/socket/websocket-server.js -@@ -134,13 +134,12 @@ function writeHttpResponse(output, response) { +@@ -135,13 +135,12 @@ function writeHttpResponse(output, response) { * Process the WebSocket handshake headers and return the key to be sent in * Sec-WebSocket-Accept response header. */ @@ -126,7 +146,7 @@ index d49c6fbf1b..7ea3540947 100644 throw new Error("The handshake request has unknown path"); } -@@ -190,13 +189,13 @@ function computeKey(key) { +@@ -191,13 +190,13 @@ function computeKey(key) { /** * Perform the server part of a WebSocket opening handshake on an incoming connection. */ @@ -142,7 +162,7 @@ index d49c6fbf1b..7ea3540947 100644 // Send response headers await writeHttpResponse(output, [ -@@ -218,8 +217,8 @@ const serverHandshake = async function (input, output) { +@@ -219,8 +218,8 @@ const serverHandshake = async function (input, output) { * Performs the WebSocket handshake and waits for the WebSocket to open. * Returns Promise with a WebSocket ready to send and receive messages. */ @@ -154,7 +174,7 @@ index d49c6fbf1b..7ea3540947 100644 const transportProvider = { setListener(upgradeListener) { diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp -index 81896a2c74..86f3d642b7 100644 +index 2d667bf000..b69acde96c 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp @@ -116,8 +116,15 @@ struct ParamTraits @@ -175,7 +195,7 @@ index 81896a2c74..86f3d642b7 100644 template <> struct ParamTraits -@@ -3342,6 +3349,32 @@ void BrowsingContext::DidSet(FieldIndex, +@@ -3544,6 +3551,32 @@ void BrowsingContext::DidSet(FieldIndex, }); } @@ -208,7 +228,7 @@ index 81896a2c74..86f3d642b7 100644 void BrowsingContext::DidSet(FieldIndex, nsString&& aOldValue) { MOZ_ASSERT(IsTop()); -@@ -3689,7 +3722,7 @@ void BrowsingContext::SetGeolocationServiceOverride( +@@ -3824,7 +3857,7 @@ void BrowsingContext::SetGeolocationServiceOverride( if (aGeolocationOverride.WasPassed()) { if (!mGeolocationServiceOverride) { mGeolocationServiceOverride = new nsGeolocationService(); @@ -218,11 +238,11 @@ index 81896a2c74..86f3d642b7 100644 mGeolocationServiceOverride->Update(aGeolocationOverride.Value()); } else if (RefPtr serviceOverride = diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index 724326453f..ffa90c3247 100644 +index dc64d5c136..fe99703ac2 100644 --- a/docshell/base/BrowsingContext.h +++ b/docshell/base/BrowsingContext.h -@@ -209,11 +209,11 @@ struct EmbedderColorSchemes { - FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ +@@ -211,11 +211,11 @@ struct EmbedderColorSchemes { + FIELD(HasScreenAreaOverride, bool) \ /* ScreenOrientation-related APIs */ \ FIELD(CurrentOrientationAngle, float) \ - FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ @@ -235,7 +255,7 @@ index 724326453f..ffa90c3247 100644 FIELD(EmbedderElementType, Maybe) \ FIELD(MessageManagerGroup, nsString) \ FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -254,6 +254,9 @@ struct EmbedderColorSchemes { +@@ -258,6 +258,9 @@ struct EmbedderColorSchemes { * embedder element. */ \ FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ FIELD(DisplayMode, dom::DisplayMode) \ @@ -245,8 +265,8 @@ index 724326453f..ffa90c3247 100644 /* The number of entries added to the session history because of this \ * browsing context. */ \ FIELD(HistoryEntryCount, uint32_t) \ -@@ -1050,6 +1053,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetForcedColorsOverride(); +@@ -1117,6 +1120,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { + return Top()->GetAnimationsPlayBackRateMultiplier(); } + dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { @@ -258,9 +278,9 @@ index 724326453f..ffa90c3247 100644 + } + bool IsInBFCache() const; - - bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1230,6 +1241,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { + bool IsEnteringBFCache() const { return mIsEnteringBFCache; } + void DeactivateDocuments(); +@@ -1319,6 +1330,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { return IsTop(); } @@ -272,9 +292,9 @@ index 724326453f..ffa90c3247 100644 bool CanSet(FieldIndex, dom::ForcedColorsOverride, ContentParent*) { return IsTop(); -@@ -1249,12 +1265,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - void DidSet(FieldIndex, - dom::ForcedColorsOverride aOldValue); +@@ -1347,12 +1363,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { + void DidSet(FieldIndex, + double aOldValue); + void DidSet(FieldIndex, + dom::PrefersContrastOverride aOldValue); @@ -297,19 +317,19 @@ index 724326453f..ffa90c3247 100644 void DidSet(FieldIndex, nsString&& aOldValue); diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp -index 6109e20259..9ccc289e8a 100644 +index 8bce434c60..6daddee486 100644 --- a/docshell/base/CanonicalBrowsingContext.cpp +++ b/docshell/base/CanonicalBrowsingContext.cpp -@@ -274,6 +274,8 @@ void CanonicalBrowsingContext::ReplacedBy( +@@ -278,6 +278,8 @@ void CanonicalBrowsingContext::ReplacedBy( txn.SetForceOffline(GetForceOffline()); - txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP()); + txn.SetInnerSizeSpoofedForRFP(GetInnerSizeSpoofedForRFP()); txn.SetIPAddressSpace(GetIPAddressSpace()); + txn.SetPrefersReducedMotionOverride(GetPrefersReducedMotionOverride()); + txn.SetForcedColorsOverride(GetForcedColorsOverride()); txn.SetParentalControlsEnabled(GetParentalControlsEnabled()); if (!GetLanguageOverride().IsEmpty()) { -@@ -1905,6 +1907,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, +@@ -1926,6 +1928,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, (void)SetIsCaptivePortalTab(true); } @@ -323,10 +343,10 @@ index 6109e20259..9ccc289e8a 100644 } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index cee178c29e..8aeaed0336 100644 +index fe34e34edd..74ee7906c9 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp -@@ -16,6 +16,12 @@ +@@ -15,6 +15,12 @@ # include // for getpid() #endif @@ -336,9 +356,9 @@ index cee178c29e..8aeaed0336 100644 + +#include "js/LocaleSensitive.h" + + #include "nsDeviceContext.h" #include "mozilla/Attributes.h" #include "mozilla/AutoRestore.h" - #include "mozilla/BasePrincipal.h" @@ -63,6 +69,7 @@ #include "mozilla/dom/DocGroup.h" #include "mozilla/dom/Element.h" @@ -371,7 +391,7 @@ index cee178c29e..8aeaed0336 100644 #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsObjectLoadingContent.h" -@@ -355,6 +365,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, +@@ -353,6 +363,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, mAllowDNSPrefetch(true), mAllowWindowControl(true), mCSSErrorReportingEnabled(false), @@ -386,7 +406,7 @@ index cee178c29e..8aeaed0336 100644 mAllowAuth(mItemType == typeContent), mAllowKeywordFixup(false), mDisableMetaRefreshWhenInactive(false), -@@ -3042,6 +3060,232 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { +@@ -2957,6 +2975,232 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { return NS_OK; } @@ -619,7 +639,7 @@ index cee178c29e..8aeaed0336 100644 NS_IMETHODIMP nsDocShell::GetIsNavigating(bool* aOut) { *aOut = mIsNavigating; -@@ -4803,7 +5047,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { +@@ -4616,7 +4860,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { } void nsDocShell::ActivenessMaybeChanged() { @@ -628,18 +648,7 @@ index cee178c29e..8aeaed0336 100644 if (RefPtr presShell = GetPresShell()) { presShell->ActivenessMaybeChanged(); } -@@ -6874,6 +7118,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, - return false; // no entry to save into - } - -+ if (mDisallowBFCache) { -+ return false; -+ } -+ - MOZ_ASSERT(!mozilla::SessionHistoryInParent(), - "mOSHE cannot be non-null with SHIP"); - nsCOMPtr viewer = mOSHE->GetDocumentViewer(); -@@ -8630,6 +8878,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { +@@ -7628,6 +7872,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { true, // aForceNoOpener getter_AddRefs(newBC)); MOZ_ASSERT(!newBC); @@ -652,8 +661,18 @@ index cee178c29e..8aeaed0336 100644 return rv; } -@@ -10016,6 +10270,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, - nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); +@@ -8782,6 +9032,9 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, + // before calling Stop() below. + Document* document = GetDocument(); + uint32_t flags = 0; ++ if (mDisallowBFCache && document) { ++ document->DisallowBFCaching(flags); ++ } + if (document && !document->CanSavePresentation(nullptr, flags, true)) { + // This forces some flags into the WindowGlobalParent's mBFCacheStatus, + // which we'll then use in CanonicalBrowsingContext::AllowedInBFCache, +@@ -8857,6 +9110,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, + attrs.SetFirstPartyDomain(isTopLevelDoc, aLoadState->URI()); nsCOMPtr req; + @@ -669,7 +688,7 @@ index cee178c29e..8aeaed0336 100644 rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); if (NS_SUCCEEDED(rv)) { -@@ -13431,6 +13695,9 @@ class OnLinkClickEvent : public Runnable { +@@ -12016,6 +12279,9 @@ class OnLinkClickEvent : public Runnable { mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, mTriggeringPrincipal); } @@ -679,7 +698,7 @@ index cee178c29e..8aeaed0336 100644 return NS_OK; } -@@ -13548,6 +13815,8 @@ nsresult nsDocShell::OnLinkClick( +@@ -12133,6 +12399,8 @@ nsresult nsDocShell::OnLinkClick( nsCOMPtr ev = new OnLinkClickEvent( this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal); @@ -689,18 +708,18 @@ index cee178c29e..8aeaed0336 100644 } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 4cc4ebb096..ec270518b3 100644 +index 1d82b0d770..d57ac67172 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h -@@ -16,6 +16,7 @@ +@@ -14,6 +14,7 @@ #include "mozilla/WeakPtr.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/dom/NavigationBinding.h" +#include "mozilla/dom/Element.h" + #include "mozilla/dom/SessionHistoryEntry.h" #include "mozilla/dom/WindowProxyHolder.h" #include "nsCOMPtr.h" - #include "nsCharsetSource.h" -@@ -82,6 +83,7 @@ class nsCommandManager; +@@ -84,6 +85,7 @@ class nsCommandManager; class nsDocShellEditorData; class nsDOMNavigationTiming; class nsDSURIContentListener; @@ -708,7 +727,7 @@ index 4cc4ebb096..ec270518b3 100644 class nsGlobalWindowOuter; class FramingChecker; -@@ -414,6 +416,15 @@ class nsDocShell final : public nsDocLoader, +@@ -396,6 +398,15 @@ class nsDocShell final : public nsDocLoader, void SetWillChangeProcess() { mWillChangeProcess = true; } bool WillChangeProcess() { return mWillChangeProcess; } @@ -721,10 +740,10 @@ index 4cc4ebb096..ec270518b3 100644 + + RefPtr GetGeolocationServiceOverride(); + - // Create a content viewer within this nsDocShell for the given - // `WindowGlobalChild` actor. - nsresult CreateDocumentViewerForActor( -@@ -1058,6 +1069,8 @@ class nsDocShell final : public nsDocLoader, + // Creates a real network channel (not a DocumentChannel) using the specified + // parameters. + // Used by nsDocShell when not using DocumentChannel, by DocumentLoadListener +@@ -988,6 +999,8 @@ class nsDocShell final : public nsDocLoader, bool CSSErrorReportingEnabled() const { return mCSSErrorReportingEnabled; } @@ -733,7 +752,7 @@ index 4cc4ebb096..ec270518b3 100644 // Handles retrieval of subframe session history for nsDocShell::LoadURI. If a // load is requested in a subframe of the current DocShell, the subframe // loadType may need to reflect the loadType of the parent document, or in -@@ -1389,6 +1402,17 @@ class nsDocShell final : public nsDocLoader, +@@ -1299,6 +1312,17 @@ class nsDocShell final : public nsDocLoader, bool mAllowDNSPrefetch : 1; bool mAllowWindowControl : 1; bool mCSSErrorReportingEnabled : 1; @@ -752,10 +771,10 @@ index 4cc4ebb096..ec270518b3 100644 bool mAllowKeywordFixup : 1; bool mDisableMetaRefreshWhenInactive : 1; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index 888d99bae8..7e03f9c504 100644 +index cc1b0d3c15..5b8107ddbb 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl -@@ -44,6 +44,7 @@ interface nsIURI; +@@ -43,6 +43,7 @@ interface nsIURI; interface nsIChannel; interface nsIPolicyContainer; interface nsIDocumentViewer; @@ -763,7 +782,7 @@ index 888d99bae8..7e03f9c504 100644 interface nsIEditor; interface nsIEditingSession; interface nsIInputStream; -@@ -719,6 +720,45 @@ interface nsIDocShell : nsIDocShellTreeItem +@@ -691,6 +692,45 @@ interface nsIDocShell : nsIDocShellTreeItem */ void synchronizeLayoutHistoryState(); @@ -810,10 +829,10 @@ index 888d99bae8..7e03f9c504 100644 * This attempts to save any applicable layout history state (like * scroll position) in the nsISHEntry. This is normally done diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp -index 5a890d76ef..c4f24f7170 100644 +index 178078c084..eccc3b9cab 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp -@@ -3937,6 +3937,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { +@@ -3776,6 +3776,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { } void Document::ApplySettingsFromCSP(bool aSpeculative) { @@ -823,7 +842,7 @@ index 5a890d76ef..c4f24f7170 100644 nsresult rv = NS_OK; if (!aSpeculative) { nsIContentSecurityPolicy* csp = PolicyContainer::GetCSP(mPolicyContainer); -@@ -4025,6 +4028,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { +@@ -3864,6 +3867,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { MOZ_ASSERT(mPolicyContainer, "Policy container must be initialized before CSP!"); @@ -835,7 +854,7 @@ index 5a890d76ef..c4f24f7170 100644 // If this is a data document - no need to set CSP. if (mLoadedAsData) { return NS_OK; -@@ -4897,6 +4905,10 @@ bool Document::HasFocus(ErrorResult& rv) const { +@@ -4819,6 +4827,10 @@ bool Document::HasFocus(ErrorResult& rv) const { return false; } @@ -846,7 +865,7 @@ index 5a890d76ef..c4f24f7170 100644 if (!fm->IsInActiveWindow(bc)) { return false; } -@@ -20483,6 +20495,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { +@@ -20590,6 +20602,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { return PreferenceSheet::PrefsFor(*this).mColorScheme; } @@ -883,10 +902,10 @@ index 5a890d76ef..c4f24f7170 100644 if (!sLoadingForegroundTopLevelContentDocument) { return false; diff --git a/dom/base/Document.h b/dom/base/Document.h -index 5e25b19fb9..e7bfd1e29d 100644 +index 83678711a2..f73f6141a1 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h -@@ -4317,6 +4317,8 @@ class Document : public nsINode, +@@ -4409,6 +4409,8 @@ class Document : public nsINode, // color-scheme meta tag. ColorScheme DefaultColorScheme() const; @@ -896,10 +915,10 @@ index 5e25b19fb9..e7bfd1e29d 100644 static bool AutomaticStorageAccessPermissionCanBeGranted( diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index 51d8331345..9880047350 100644 +index 23e8de1e55..c100a8e35d 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp -@@ -338,16 +338,15 @@ void Navigator::GetAppName(nsAString& aAppName) const { +@@ -340,16 +340,15 @@ void Navigator::GetAppName(nsAString& aAppName) const { * for more detail. */ /* static */ @@ -919,7 +938,7 @@ index 51d8331345..9880047350 100644 } else { intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLang); } -@@ -407,13 +406,14 @@ void Navigator::GetLanguages(nsTArray& aLanguages) { +@@ -409,13 +408,14 @@ void Navigator::GetLanguages(nsTArray& aLanguages) { const nsCString& languageOverride = bc->Top()->GetLanguageOverride(); if (!languageOverride.IsEmpty()) { @@ -936,7 +955,7 @@ index 51d8331345..9880047350 100644 // The returned value is cached by the binding code. The window listens to the // accept languages change and will clear the cache when needed. It has to -@@ -2336,7 +2336,8 @@ bool Navigator::Webdriver() { +@@ -2349,7 +2349,8 @@ bool Navigator::Webdriver() { } #endif @@ -947,7 +966,7 @@ index 51d8331345..9880047350 100644 AutoplayPolicy Navigator::GetAutoplayPolicy(AutoplayPolicyMediaType aType) { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h -index ebbf1b34c3..2d972742c3 100644 +index ff891b977d..6e88d98f22 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -225,8 +225,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { @@ -961,10 +980,10 @@ index ebbf1b34c3..2d972742c3 100644 dom::MediaCapabilities* MediaCapabilities(); dom::MediaSession* MediaSession(); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index 60e805446a..eb6216e7af 100644 +index 2b4726cb70..ca042528c9 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp -@@ -9529,6 +9529,8 @@ Result nsContentUtils::SynthesizeMouseEvent( +@@ -9814,6 +9814,8 @@ Result nsContentUtils::SynthesizeMouseEvent( EventMessage msg; Maybe exitFrom; bool contextMenuKey = false; @@ -973,7 +992,7 @@ index 60e805446a..eb6216e7af 100644 if (aType.EqualsLiteral("mousedown")) { msg = eMouseDown; } else if (aType.EqualsLiteral("mouseup")) { -@@ -9555,13 +9557,26 @@ Result nsContentUtils::SynthesizeMouseEvent( +@@ -9840,13 +9842,26 @@ Result nsContentUtils::SynthesizeMouseEvent( msg = eMouseHitTest; } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { msg = eMouseExploreByTouch; @@ -1001,7 +1020,7 @@ index 60e805446a..eb6216e7af 100644 if (MOZ_UNLIKELY(aOptions.mIsWidgetEventSynthesized)) { MOZ_ASSERT_UNREACHABLE( "The event shouldn't be dispatched as a synthesized event"); -@@ -9589,6 +9604,7 @@ Result nsContentUtils::SynthesizeMouseEvent( +@@ -9874,6 +9889,7 @@ Result nsContentUtils::SynthesizeMouseEvent( mozilla::widget::AutoSynthesizedEventCallbackNotifier notifier(callback); WidgetMouseEvent& mouseOrPointerEvent = @@ -1009,20 +1028,20 @@ index 60e805446a..eb6216e7af 100644 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref(); mouseOrPointerEvent.pointerId = aMouseEventData.mIdentifier; mouseOrPointerEvent.mModifiers = -@@ -9609,6 +9625,8 @@ Result nsContentUtils::SynthesizeMouseEvent( +@@ -9898,6 +9914,8 @@ Result nsContentUtils::SynthesizeMouseEvent( mouseOrPointerEvent.mFlags.mIsSynthesizedForTests = aOptions.mIsDOMEventSynthesized; - mouseOrPointerEvent.mExitFrom = exitFrom; + mouseOrPointerEvent.mExitFrom = std::move(exitFrom); + mouseOrPointerEvent.mJugglerEventId = aMouseEventData.mJugglerEventId; + mouseOrPointerEvent.convertToPointer = aOptions.mConvertToPointer; mouseOrPointerEvent.mCallbackId = notifier.SaveCallback(); nsPresContext* presContext = aPresShell->GetPresContext(); diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index d27975b2a3..d48f4c2285 100644 +index c73fbaf596..4b03ebacd3 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp -@@ -710,6 +710,55 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { +@@ -705,6 +705,55 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { return NS_ERROR_FAILURE; } @@ -1057,7 +1076,7 @@ index d27975b2a3..d48f4c2285 100644 + mouseEventData.mButton = aButton; + mouseEventData.mButtons.Construct(aButtons); + mouseEventData.mClickCount.Construct(aClickCount); -+ mouseEventData.mPressure = aPressure; ++ mouseEventData.mPressure.Construct(aPressure); + mouseEventData.mInputSource = aInputSourceArg; + mouseEventData.mModifiers = aModifiers; + mouseEventData.mJugglerEventId = *aJugglerEventId; @@ -1079,10 +1098,10 @@ index d27975b2a3..d48f4c2285 100644 nsDOMWindowUtils::IsCORSSafelistedRequestHeader(const nsACString& aName, const nsACString& aValue, diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index fa2125fa66..6bb0c72796 100644 +index e3d8521bab..44c4dbc3a2 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp -@@ -1840,6 +1840,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, +@@ -1842,6 +1842,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, (GetActiveBrowsingContext() == newRootBrowsingContext); } @@ -1093,7 +1112,7 @@ index fa2125fa66..6bb0c72796 100644 // Exit fullscreen if a website focuses another window if (StaticPrefs::full_screen_api_exit_on_windowRaise() && !isElementInActiveWindow && (aFlags & FLAG_RAISE)) { -@@ -2427,6 +2431,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, +@@ -2403,6 +2407,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, bool aIsLeavingDocument, bool aAdjustWidget, bool aRemainActive, Element* aElementToFocus, uint64_t aActionId) { @@ -1101,7 +1120,7 @@ index fa2125fa66..6bb0c72796 100644 LOGFOCUS(("<>", aActionId)); // hold a reference to the focused content, which may be null -@@ -2470,6 +2475,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, +@@ -2446,6 +2451,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, return true; } @@ -1113,7 +1132,7 @@ index fa2125fa66..6bb0c72796 100644 // Keep a ref to presShell since dispatching the DOM event may cause // the document to be destroyed. RefPtr presShell = docShell->GetPresShell(); -@@ -3169,7 +3179,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, +@@ -3144,7 +3154,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, } } @@ -1125,13 +1144,22 @@ index fa2125fa66..6bb0c72796 100644 // care of lowering the present active window. This happens in // a separate runnable to avoid touching multiple windows in diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp -index ae3b72b612..8f6e62f41a 100644 +index 3de5de2402..7aab4d6f92 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2515,10 +2515,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, +@@ -2522,7 +2522,7 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, + &nsGlobalWindowInner::FireOnNewGlobalObject)); + } + +- if (!newInnerWindow->mHasNotifiedGlobalCreated && mDoc) { ++ if (mDoc) { + // We should probably notify, except if we have the initial about:blank + // in a chrome docshell, defer notification until the first non-initial + // document. +@@ -2540,10 +2540,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, }(); - if (!isContentAboutBlankInChromeDocshell) { + if (!isAboutBlankInChromeDocshell) { - newInnerWindow->mHasNotifiedGlobalCreated = true; - nsContentUtils::AddScriptRunner(NewRunnableMethod( - "nsGlobalWindowOuter::DispatchDOMWindowCreated", this, @@ -1149,7 +1177,7 @@ index ae3b72b612..8f6e62f41a 100644 } } -@@ -2638,6 +2644,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { +@@ -2663,6 +2669,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { } } @@ -1170,10 +1198,10 @@ index ae3b72b612..8f6e62f41a 100644 void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index b6226ff10f..87fae2cff5 100644 +index ce97e3c308..a2f3342c80 100644 --- a/dom/base/nsGlobalWindowOuter.h +++ b/dom/base/nsGlobalWindowOuter.h -@@ -315,6 +315,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, +@@ -306,6 +306,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, // Outer windows only. void DispatchDOMWindowCreated(); @@ -1182,10 +1210,10 @@ index b6226ff10f..87fae2cff5 100644 // Outer windows only. virtual void EnsureSizeAndPositionUpToDate() override; diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp -index 9bed2cad8b..64355630dd 100644 +index c76d946e3b..3d9b486da6 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp -@@ -1507,6 +1507,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, +@@ -1503,6 +1503,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); } @@ -1248,10 +1276,10 @@ index 9bed2cad8b..64355630dd 100644 DOMQuad& aQuad, const GeometryNode& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h -index 1611ea9eb2..6511777068 100644 +index 319fd55c5d..84cbb7b8f7 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h -@@ -2499,6 +2499,10 @@ class nsINode : public mozilla::dom::EventTarget { +@@ -2505,6 +2505,10 @@ class nsINode : public mozilla::dom::EventTarget { nsTArray>& aResult, ErrorResult& aRv); @@ -1263,10 +1291,10 @@ index 1611ea9eb2..6511777068 100644 DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index 25b261cb57..9f1bc7626e 100644 +index 59b306ffb0..8486e23714 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp -@@ -151,6 +151,11 @@ bool nsJSUtils::GetEnvironmentChainForElement(JSContext* aCx, Element* aElement, +@@ -149,6 +149,11 @@ bool nsJSUtils::GetEnvironmentChainForElement(JSContext* aCx, Element* aElement, return true; } @@ -1279,10 +1307,10 @@ index 25b261cb57..9f1bc7626e 100644 void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h -index b6ea43886d..f0abb08931 100644 +index 841cab0c7f..418f5cc276 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h -@@ -74,6 +74,7 @@ class nsJSUtils { +@@ -72,6 +72,7 @@ class nsJSUtils { mozilla::dom::Element* aElement, JS::EnvironmentChain& aEnvChain); @@ -1291,10 +1319,10 @@ index b6ea43886d..f0abb08931 100644 static bool DumpEnabled(); diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl -index 9730cea647..79da6984a4 100644 +index 87cdd7c3c4..10a522f712 100644 --- a/dom/chrome-webidl/BrowsingContext.webidl +++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -62,6 +62,26 @@ enum ForcedColorsOverride { +@@ -63,6 +63,26 @@ enum ForcedColorsOverride { "active", }; @@ -1321,9 +1349,9 @@ index 9730cea647..79da6984a4 100644 /** * Allowed overrides of platform/pref default behaviour for touch events. */ -@@ -235,6 +255,12 @@ interface BrowsingContext { - // Forced-colors simulation, for DevTools - [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; +@@ -246,6 +266,12 @@ interface BrowsingContext { + // Animation playbackRate multiplier, for Devtools + [SetterThrows] attribute double animationsPlayBackRateMultiplier; + // Reduced-Motion simulation, for DevTools. + [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; @@ -1335,12 +1363,12 @@ index 9730cea647..79da6984a4 100644 * A unique identifier for the browser element that is hosting this * BrowsingContext tree. Every BrowsingContext in the element's tree will diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp -index 84965f7b23..31e5c1343e 100644 +index 5c4bf5d794..2c4ad91822 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp -@@ -699,6 +699,12 @@ already_AddRefed FetchRequest(nsIGlobalObject* aGlobal, - ipcArgs.hasCSPEventListener() = false; - ipcArgs.isWorkerRequest() = false; +@@ -721,6 +721,12 @@ already_AddRefed FetchRequest(nsIGlobalObject* aGlobal, + actor->SetOriginStack(std::move(stack)); + } + /* --> Playwright: associate keep-alive fetch with the window */ + BrowsingContext* bc = window ? window->GetBrowsingContext() : nullptr; @@ -1352,7 +1380,7 @@ index 84965f7b23..31e5c1343e 100644 return p.forget(); diff --git a/dom/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp -index 421a3ce2be..095d003d33 100644 +index bc43c14771..851fb12eb1 100644 --- a/dom/fetch/FetchService.cpp +++ b/dom/fetch/FetchService.cpp @@ -267,6 +267,14 @@ RefPtr FetchService::FetchInstance::Fetch() { @@ -1371,10 +1399,10 @@ index 421a3ce2be..095d003d33 100644 auto& args = mArgs.as(); mFetchDriver->SetWorkerScript(args.mWorkerScript); diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 33832d190f..f0d776bb3d 100644 +index 5cc4ca84dc..513657245d 100644 --- a/dom/geolocation/Geolocation.cpp +++ b/dom/geolocation/Geolocation.cpp -@@ -393,7 +393,10 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { +@@ -398,7 +398,10 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { return NS_OK; } @@ -1386,7 +1414,7 @@ index 33832d190f..f0d776bb3d 100644 // Asynchronously present the system dialog or open system preferences // (RequestGeolocationPermissionFromUser will know which to do), and wait // for the permission to change or the request to be canceled. If the -@@ -425,8 +428,6 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { +@@ -430,8 +433,6 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { return NS_OK; } @@ -1395,7 +1423,7 @@ index 33832d190f..f0d776bb3d 100644 bool canUseCache = false; CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); if (lastPosition.position) { -@@ -709,11 +710,16 @@ NS_INTERFACE_MAP_END +@@ -718,11 +719,16 @@ NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsGeolocationService) NS_IMPL_RELEASE(nsGeolocationService) @@ -1413,7 +1441,7 @@ index 33832d190f..f0d776bb3d 100644 if (XRE_IsContentProcess()) { return NS_OK; } -@@ -792,6 +798,10 @@ nsresult nsGeolocationService::Init() { +@@ -801,6 +807,10 @@ nsresult nsGeolocationService::Init() { return NS_OK; } @@ -1424,7 +1452,7 @@ index 33832d190f..f0d776bb3d 100644 nsGeolocationService::~nsGeolocationService() = default; NS_IMETHODIMP -@@ -935,6 +945,10 @@ bool nsGeolocationService::HighAccuracyRequested() { +@@ -944,6 +954,10 @@ bool nsGeolocationService::HighAccuracyRequested() { } void nsGeolocationService::UpdateAccuracy(bool aForceHigh) { @@ -1436,10 +1464,10 @@ index 33832d190f..f0d776bb3d 100644 if (XRE_IsContentProcess()) { diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index d46e2e88b1..e69d62ffb4 100644 +index 51c26cb8bd..c4568d18f2 100644 --- a/dom/geolocation/Geolocation.h +++ b/dom/geolocation/Geolocation.h -@@ -64,7 +64,7 @@ class nsGeolocationService final : public nsIGeolocationUpdate, +@@ -62,7 +62,7 @@ class nsGeolocationService final : public nsIGeolocationUpdate, nsGeolocationService() = default; @@ -1448,7 +1476,7 @@ index d46e2e88b1..e69d62ffb4 100644 // Management of the Geolocation objects void AddLocator(mozilla::dom::Geolocation* aLocator); -@@ -89,6 +89,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, +@@ -87,6 +87,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, void UpdateAccuracy(bool aForceHigh = false); bool HighAccuracyRequested(); @@ -1457,7 +1485,7 @@ index d46e2e88b1..e69d62ffb4 100644 private: ~nsGeolocationService(); -@@ -115,6 +117,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, +@@ -113,6 +115,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, // Nothing() if not being started, or a boolean reflecting the requested // accuracy. mozilla::Maybe mStarting; @@ -1467,10 +1495,10 @@ index d46e2e88b1..e69d62ffb4 100644 namespace mozilla::dom { diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index 31b29ac946..f8c6335c0a 100644 +index 6e31658fba..20ca8b511d 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp -@@ -45,6 +45,7 @@ +@@ -46,6 +46,7 @@ #include "mozilla/dom/HTMLDataListElement.h" #include "mozilla/dom/HTMLOptionElement.h" #include "mozilla/dom/InputType.h" @@ -1478,7 +1506,7 @@ index 31b29ac946..f8c6335c0a 100644 #include "mozilla/dom/MouseEvent.h" #include "mozilla/dom/NumericInputTypes.h" #include "mozilla/dom/ProgressEvent.h" -@@ -799,6 +800,13 @@ nsresult HTMLInputElement::InitColorPicker() { +@@ -870,6 +871,13 @@ nsresult HTMLInputElement::InitColorPicker() { return NS_ERROR_FAILURE; } @@ -1493,12 +1521,12 @@ index 31b29ac946..f8c6335c0a 100644 return NS_OK; } diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index ce7c11966e..4079c43d9d 100644 +index 1d90478329..8b7b9eecfe 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl -@@ -327,6 +327,26 @@ cenum AsyncEnabledOption : 8 { - ASYNC_ENABLED = 1 - }; +@@ -325,6 +325,26 @@ interface nsIDOMWindowUtils : nsISupports { + ASYNC_ENABLED = 1 + }; + /** + * Playwright: a separate method to dispatch mouse event with a @@ -1520,14 +1548,14 @@ index ce7c11966e..4079c43d9d 100644 + in unsigned long aIdentifier, + in boolean aDisablePointerEvent); + - /** Synthesize a touch event. The event types supported are: - * touchstart, touchend, touchmove, and touchcancel + /** Synthesize a wheel event for a window. The event types supported is only + * wheel. * diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp -index 80158ce3a0..4e7fc3c95d 100644 +index 2f7f261445..c5fc28182c 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp -@@ -1813,6 +1813,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, +@@ -1822,6 +1822,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, if (postLayerization) { postLayerization->Register(); } @@ -1550,10 +1578,10 @@ index 80158ce3a0..4e7fc3c95d 100644 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent( diff --git a/dom/ipc/CoalescedMouseData.cpp b/dom/ipc/CoalescedMouseData.cpp -index a4ccc0049d..36b4c59369 100644 +index f71812b8e0..6286e45533 100644 --- a/dom/ipc/CoalescedMouseData.cpp +++ b/dom/ipc/CoalescedMouseData.cpp -@@ -73,6 +73,9 @@ bool CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent, +@@ -71,6 +71,9 @@ bool CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent, mCoalescedInputEvent->pointerId != aEvent.pointerId || mCoalescedInputEvent->mButton != aEvent.mButton || mCoalescedInputEvent->mButtons != aEvent.mButtons || mGuid != aGuid || @@ -1564,23 +1592,23 @@ index a4ccc0049d..36b4c59369 100644 return false; } diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index ad5f871cf6..41ff4f49ac 100644 +index 9e1086527c..4357efe79a 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -53,9 +53,10 @@ namespace webrtc { +@@ -52,9 +52,10 @@ namespace webrtc { - DesktopCaptureImpl* DesktopCaptureImpl::Create(const int32_t aModuleId, + DesktopCaptureImpl* DesktopCaptureImpl::Create(int32_t aCaptureId, const char* aUniqueId, - const CaptureDeviceType aType) { + const CaptureDeviceType aType, + bool aCaptureCursor) { - return new webrtc::RefCountedObject(aModuleId, aUniqueId, + return new webrtc::RefCountedObject(aCaptureId, aUniqueId, - aType); + aType, aCaptureCursor); } static DesktopCaptureOptions CreateDesktopCaptureOptions() { -@@ -156,8 +157,10 @@ static std::unique_ptr CreateTabCapturer( +@@ -154,8 +155,10 @@ static std::unique_ptr CreateTabCapturer( static std::unique_ptr CreateDesktopCapturerAndThread( CaptureDeviceType aDeviceType, DesktopCapturer::SourceId aSourceId, @@ -1592,28 +1620,36 @@ index ad5f871cf6..41ff4f49ac 100644 auto ensureThread = [&]() { if (*aOutThread) { return *aOutThread; -@@ -254,7 +257,8 @@ static std::unique_ptr CreateDesktopCapturerAndThread( - } +@@ -253,7 +256,8 @@ static std::unique_ptr CreateDesktopCapturerAndThread( - DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, + DesktopCaptureImpl::DesktopCaptureImpl(int32_t aCaptureId, + const char* aUniqueId, - const CaptureDeviceType aType) + const CaptureDeviceType aType, + bool aCaptureCursor) - : mModuleId(aId), - mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { + : mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { switch (aType) { -@@ -271,6 +275,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, - aId)), + case CaptureDeviceType::Screen: +@@ -269,6 +273,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(int32_t aCaptureId, + aCaptureId)), mDeviceUniqueId(aUniqueId), mDeviceType(aType), + capture_cursor_(aCaptureCursor), mControlThread(mozilla::GetCurrentSerialEventTarget()), mNextFrameMinimumTime(Timestamp::Zero()), - mCallbacks("DesktopCaptureImpl::mCallbacks") {} -@@ -295,6 +300,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( - } + mCallback("DesktopCaptureImpl::mCallback"), +@@ -290,6 +295,35 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback() { + *callback = nullptr; } ++void DesktopCaptureImpl::DeRegisterCaptureDataCallback( ++ webrtc::VideoSinkInterface* aCallback) { ++ auto callback = mCallback.Lock(); ++ if (*callback == aCallback) { ++ *callback = nullptr; ++ } ++} ++ +void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { + webrtc::CritScope lock(&mApiCs); + _rawFrameCallbacks.insert(rawFrameCallback); @@ -1627,10 +1663,18 @@ index ad5f871cf6..41ff4f49ac 100644 + } +} + - int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { - { - auto callbacks = mCallbacks.Lock(); -@@ -326,7 +344,7 @@ int32_t DesktopCaptureImpl::StartCapture( ++int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { ++ auto callback = mCallback.Lock(); ++ if (*callback == nullptr) { ++ return StopCapture(); ++ } ++ return 0; ++} ++ + int32_t DesktopCaptureImpl::SetCaptureRotation(VideoRotation aRotation) { + MOZ_ASSERT_UNREACHABLE("Unused"); + return -1; +@@ -311,7 +345,7 @@ int32_t DesktopCaptureImpl::StartCapture( mRequestedCapability = mozilla::Some(aCapability); MOZ_ALWAYS_SUCCEEDS(mCaptureThread->Dispatch( NS_NewRunnableFunction("DesktopCaptureImpl::UpdateOnThread", @@ -1639,7 +1683,7 @@ index ad5f871cf6..41ff4f49ac 100644 UpdateOnThread(maxFps); }))); return 0; -@@ -350,7 +368,7 @@ int32_t DesktopCaptureImpl::StartCapture( +@@ -335,7 +369,7 @@ int32_t DesktopCaptureImpl::StartCapture( return -1; } std::unique_ptr capturer = CreateDesktopCapturerAndThread( @@ -1648,7 +1692,7 @@ index ad5f871cf6..41ff4f49ac 100644 MOZ_ASSERT(!capturer == !mCaptureThread); if (!capturer) { -@@ -362,7 +380,7 @@ int32_t DesktopCaptureImpl::StartCapture( +@@ -347,7 +381,7 @@ int32_t DesktopCaptureImpl::StartCapture( MOZ_ALWAYS_SUCCEEDS(mCaptureThread->Dispatch(NS_NewRunnableFunction( "DesktopCaptureImpl::InitOnThread", @@ -1657,7 +1701,7 @@ index ad5f871cf6..41ff4f49ac 100644 maxFps]() mutable { InitOnThread(std::move(capturer), maxFps); }))); return 0; -@@ -458,6 +476,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, +@@ -445,6 +479,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, frameInfo.height = aFrame->size().height(); frameInfo.videoType = VideoType::kARGB; @@ -1674,18 +1718,18 @@ index ad5f871cf6..41ff4f49ac 100644 frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index 498de96bf6..967cc4d8dc 100644 +index 7f3e2e0360..44df1ff0a9 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.h +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h @@ -26,6 +26,7 @@ - #include "api/video/video_sink_interface.h" + #include "common_video/include/video_frame_buffer_pool.h" #include "modules/desktop_capture/desktop_capturer.h" #include "modules/video_capture/video_capture.h" +#include "rtc_base/deprecated/recursive_critical_section.h" #include "mozilla/DataMutex.h" #include "mozilla/Maybe.h" #include "mozilla/TimeStamp.h" -@@ -42,17 +43,44 @@ namespace webrtc { +@@ -43,18 +44,53 @@ namespace webrtc { class VideoCaptureEncodeInterface; @@ -1702,6 +1746,10 @@ index 498de96bf6..967cc4d8dc 100644 + + virtual void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0; + virtual void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0; ++ virtual void DeRegisterCaptureDataCallback( ++ VideoSinkInterface* aCallback) = 0; ++ using VideoCaptureModule::DeRegisterCaptureDataCallback; ++ virtual int32_t StopCaptureIfAllClientsClose() = 0; + int32_t StartCaptureCounted(const VideoCaptureCapability& aCapability) { + ++capture_counter_; + return capture_counter_ == 1 ? StartCapture(aCapability) : 0; @@ -1719,39 +1767,44 @@ index 498de96bf6..967cc4d8dc 100644 // Reuses the video engine pipeline for screen sharing. // As with video, DesktopCaptureImpl is a proxy for screen sharing // and follows the video pipeline design - class DesktopCaptureImpl : public DesktopCapturer::Callback, + class DesktopCaptureImpl : public mozilla::DesktopCaptureInterface, + public DesktopCapturer::Callback, - public VideoCaptureModule { + public VideoCaptureModuleEx { public: /* Create a screen capture modules object */ static DesktopCaptureImpl* Create( - const int32_t aModuleId, const char* aUniqueId, + int32_t aCaptureId, const char* aUniqueId, - const mozilla::camera::CaptureDeviceType aType); + const mozilla::camera::CaptureDeviceType aType, bool aCaptureCursor = true); - - [[nodiscard]] static std::shared_ptr - CreateDeviceInfo(const int32_t aId, -@@ -66,6 +94,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void DeRegisterCaptureDataCallback( - webrtc::VideoSinkInterface* aCallback) override; - int32_t StopCaptureIfAllClientsClose() override; ++ + void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; + void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; ++ int32_t StopCaptureIfAllClientsClose() override; + + [[nodiscard]] static std::shared_ptr + CreateDeviceInfo(const mozilla::camera::CaptureDeviceType aType); +@@ -65,6 +101,8 @@ class DesktopCaptureImpl : public mozilla::DesktopCaptureInterface, + void RegisterCaptureDataCallback( + RawVideoSinkInterface* dataCallback) override {} + void DeRegisterCaptureDataCallback() override; ++ void DeRegisterCaptureDataCallback( ++ webrtc::VideoSinkInterface* aCallback) override; int32_t SetCaptureRotation(VideoRotation aRotation) override; bool SetApplyRotation(bool aEnable) override; -@@ -89,7 +119,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, +@@ -87,7 +125,8 @@ class DesktopCaptureImpl : public mozilla::DesktopCaptureInterface, protected: - DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, + DesktopCaptureImpl(const int32_t aCaptureId, const char* aUniqueId, - const mozilla::camera::CaptureDeviceType aType); + const mozilla::camera::CaptureDeviceType aType, -+ bool aCaptureCusor); ++ bool aCaptureCursor = true); virtual ~DesktopCaptureImpl(); private: -@@ -98,6 +129,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, +@@ -96,6 +135,9 @@ class DesktopCaptureImpl : public mozilla::DesktopCaptureInterface, void InitOnThread(std::unique_ptr aCapturer, int aFramerate); void UpdateOnThread(int aFramerate); void ShutdownOnThread(); @@ -1761,7 +1814,7 @@ index 498de96bf6..967cc4d8dc 100644 // DesktopCapturer::Callback interface. void OnCaptureResult(DesktopCapturer::Result aResult, std::unique_ptr aFrame) override; -@@ -105,6 +139,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, +@@ -103,6 +145,8 @@ class DesktopCaptureImpl : public mozilla::DesktopCaptureInterface, // Notifies all mCallbacks of OnFrame(). mCaptureThread only. void NotifyOnFrame(const VideoFrame& aFrame); @@ -1771,10 +1824,10 @@ index 498de96bf6..967cc4d8dc 100644 const nsCOMPtr mControlThread; // Set in StartCapture. diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp -index 9444fad192..cc526e1ac8 100644 +index 9cdecc7f34..e3aae194a3 100644 --- a/dom/script/ScriptSettings.cpp +++ b/dom/script/ScriptSettings.cpp -@@ -150,6 +150,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() { +@@ -146,6 +146,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() { MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->HasJSGlobal()); } @@ -1805,7 +1858,7 @@ index 9444fad192..cc526e1ac8 100644 // If the entry or incumbent global ends up being something that the subject // principal doesn't subsume, we don't want to use it. This never happens on // the web, but can happen with asymmetric privilege relationships (i.e. -@@ -177,7 +201,7 @@ static nsIGlobalObject* ClampToSubject(nsIGlobalObject* aGlobalOrNull) { +@@ -173,7 +197,7 @@ static nsIGlobalObject* ClampToSubject(nsIGlobalObject* aGlobalOrNull) { NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal()); if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller() ->SubsumesConsideringDomain(globalPrin)) { @@ -1815,10 +1868,10 @@ index 9444fad192..cc526e1ac8 100644 return aGlobalOrNull; diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp -index fb7533f064..420383cefa 100644 +index 73c6d16359..ce844dcf83 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp -@@ -33,6 +33,7 @@ +@@ -31,6 +31,7 @@ #include "nsSandboxFlags.h" #include "nsServiceManagerUtils.h" #include "nsWhitespaceTokenizer.h" @@ -1826,7 +1879,7 @@ index fb7533f064..420383cefa 100644 using namespace mozilla; using mozilla::dom::SRIMetadata; -@@ -136,6 +137,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, +@@ -134,6 +135,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, return; } @@ -1839,10 +1892,10 @@ index fb7533f064..420383cefa 100644 nsContentUtils::TrimWhitespace( aPolicyStr)); diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index aee376e971..1701311534 100644 +index 584d39da5f..65eb701435 100644 --- a/dom/webidl/GeometryUtils.webidl +++ b/dom/webidl/GeometryUtils.webidl -@@ -17,6 +17,8 @@ dictionary GeometryUtilsOptions { +@@ -16,6 +16,8 @@ dictionary GeometryUtilsOptions { boolean createFramesForSuppressedWhitespace = true; [ChromeOnly] boolean flush = true; @@ -1851,7 +1904,7 @@ index aee376e971..1701311534 100644 }; dictionary BoxQuadOptions : GeometryUtilsOptions { -@@ -35,6 +37,9 @@ interface mixin GeometryUtils { +@@ -34,6 +36,9 @@ interface mixin GeometryUtils { [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] sequence getBoxQuads(optional BoxQuadOptions options = {}); @@ -1862,10 +1915,10 @@ index aee376e971..1701311534 100644 * returned quads are further translated relative to the window * origin -- which is not the layout origin. Further translation diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl -index 7c509eb87e..632652dace 100644 +index ae2d14e105..77f35801a0 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl -@@ -408,6 +408,8 @@ dictionary SynthesizeMouseEventData { +@@ -394,6 +394,8 @@ dictionary SynthesizeMouseEventData : SynthesizeEventData { short inputSource = 1; // Modifiers pressed, using constants defined as MODIFIER_* in nsIDOMWindowUtils. long modifiers = 0; @@ -1874,20 +1927,20 @@ index 7c509eb87e..632652dace 100644 }; // Mozilla-specific stuff -@@ -424,6 +426,8 @@ dictionary SynthesizeMouseEventOptions { +@@ -432,6 +434,8 @@ dictionary SynthesizeEventOptions { // Set this to true to ensure that the event is dispatched to this DOM window // or one of its children. boolean toWindow = false; + // Controls whether the mouse event should be converted to a pointer event. + boolean convertToPointer = true; + // Controls Event.isSynthesized value that helps identifying test related events. + boolean isDOMEventSynthesized = true; }; - - // Mozilla-specific stuff diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp -index 5b30b4117b..f53955c06d 100644 +index 6c0c284f52..8f1bb51fca 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp -@@ -1117,7 +1117,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { +@@ -1113,7 +1113,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { AssertIsOnMainThread(); nsTArray languages; @@ -1896,7 +1949,7 @@ index 5b30b4117b..f53955c06d 100644 RuntimeService* runtime = RuntimeService::GetService(); if (runtime) { -@@ -1307,8 +1307,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) { +@@ -1305,8 +1305,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) { } // The navigator overridden properties should have already been read. @@ -1906,7 +1959,7 @@ index 5b30b4117b..f53955c06d 100644 mNavigatorPropertiesLoaded = true; } -@@ -1936,6 +1935,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( +@@ -1939,6 +1938,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( } } @@ -1920,7 +1973,7 @@ index 5b30b4117b..f53955c06d 100644 template void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { AssertIsOnMainThread(); -@@ -2497,6 +2503,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( +@@ -2505,6 +2511,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( } } @@ -1936,23 +1989,23 @@ index 5b30b4117b..f53955c06d 100644 MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(aCx); diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h -index bb7167d639..6d5bef88d9 100644 +index f024885058..fcaf831426 100644 --- a/dom/workers/RuntimeService.h +++ b/dom/workers/RuntimeService.h -@@ -112,6 +112,8 @@ class RuntimeService final : public nsIObserver { +@@ -111,6 +111,8 @@ class RuntimeService final : public nsIObserver { void PropagateStorageAccessPermissionGranted( const nsPIDOMWindowInner& aWindow); + void ResetDefaultLocaleInAllWorkers(); + - const NavigatorProperties& GetNavigatorProperties() const { + NavigatorProperties GetNavigatorProperties() const { + MutexAutoLock lock(mMutex); return mNavigatorProperties; - } diff --git a/dom/workers/WorkerCommon.h b/dom/workers/WorkerCommon.h -index af8d36c0d7..6b3a967c9a 100644 +index b5a06c2300..b8bae691b5 100644 --- a/dom/workers/WorkerCommon.h +++ b/dom/workers/WorkerCommon.h -@@ -50,6 +50,8 @@ void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow); +@@ -49,6 +49,8 @@ void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow); void PropagateStorageAccessPermissionGrantedToWorkers( const nsPIDOMWindowInner& aWindow); @@ -1962,7 +2015,7 @@ index af8d36c0d7..6b3a967c9a 100644 bool IsWorkerGlobal(JSObject* global); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp -index c8e44687b7..382b67f1c4 100644 +index c89a73b30e..95e5ca1574 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -742,6 +742,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { @@ -1984,7 +2037,7 @@ index c8e44687b7..382b67f1c4 100644 class UpdateLanguagesRunnable final : public WorkerThreadRunnable { nsTArray mLanguages; -@@ -2350,6 +2362,16 @@ void WorkerPrivate::UpdateContextOptions( +@@ -2358,6 +2370,16 @@ void WorkerPrivate::UpdateContextOptions( } } @@ -2001,7 +2054,7 @@ index c8e44687b7..382b67f1c4 100644 void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { AssertIsOnParentThread(); -@@ -6019,6 +6041,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( +@@ -6067,6 +6089,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( } } @@ -2018,10 +2071,10 @@ index c8e44687b7..382b67f1c4 100644 const nsTArray& aLanguages) { WorkerGlobalScope* globalScope = GlobalScope(); diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index c5d17c1c0a..f8790fa5b0 100644 +index c34db27680..487b0311ad 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h -@@ -462,6 +462,8 @@ class WorkerPrivate final +@@ -460,6 +460,8 @@ class WorkerPrivate final void UpdateContextOptionsInternal(JSContext* aCx, const JS::ContextOptions& aContextOptions); @@ -2030,7 +2083,7 @@ index c5d17c1c0a..f8790fa5b0 100644 void UpdateLanguagesInternal(const nsTArray& aLanguages); void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -1109,6 +1111,8 @@ class WorkerPrivate final +@@ -1108,6 +1110,8 @@ class WorkerPrivate final void UpdateContextOptions(const JS::ContextOptions& aContextOptions); @@ -2092,10 +2145,10 @@ index 523e84c8c9..98d5b1176e 100644 inline ClippedTime TimeClip(double time); diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp -index 2d177b5aad..28af5d41eb 100644 +index bf14a6125a..22f712123f 100644 --- a/js/src/debugger/Object.cpp +++ b/js/src/debugger/Object.cpp -@@ -2516,7 +2516,11 @@ Maybe DebuggerObject::call(JSContext* cx, +@@ -2521,7 +2521,11 @@ Maybe DebuggerObject::call(JSContext* cx, invokeArgs[i].set(args2[i]); } @@ -2108,10 +2161,10 @@ index 2d177b5aad..28af5d41eb 100644 } diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp -index 5f329ff0f6..709cd2b90d 100644 +index 12cf8713d2..96ed101921 100644 --- a/js/src/vm/DateTime.cpp +++ b/js/src/vm/DateTime.cpp -@@ -167,7 +167,7 @@ static int32_t UTCToLocalStandardOffsetSeconds() { +@@ -166,7 +166,7 @@ static int32_t UTCToLocalStandardOffsetSeconds() { void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { #if JS_HAS_INTL_API @@ -2120,7 +2173,7 @@ index 5f329ff0f6..709cd2b90d 100644 #endif // Nothing to do when an update request is already enqueued. -@@ -207,28 +207,16 @@ void js::DateTimeInfo::resetState() { +@@ -206,28 +206,16 @@ void js::DateTimeInfo::resetState() { #endif /* JS_HAS_INTL_API */ } @@ -2153,7 +2206,7 @@ index 5f329ff0f6..709cd2b90d 100644 #endif bool updateIfChanged = timeZoneStatus_ == TimeZoneStatus::UpdateIfChanged; -@@ -266,21 +254,6 @@ js::DateTimeInfo::DateTimeInfo() { +@@ -265,21 +253,6 @@ js::DateTimeInfo::DateTimeInfo() { timeZoneStatus_ = TimeZoneStatus::NeedsUpdate; } @@ -2175,7 +2228,7 @@ index 5f329ff0f6..709cd2b90d 100644 js::DateTimeInfo::~DateTimeInfo() = default; -@@ -549,9 +522,9 @@ bool js::DateTimeInfo::internalTimeZoneId(TimeZoneIdentifierVector& result) { +@@ -548,9 +521,9 @@ bool js::DateTimeInfo::internalTimeZoneId(TimeZoneIdentifierVector& result) { mozilla::intl::TimeZone* js::DateTimeInfo::timeZone() { if (!timeZone_) { mozilla::Maybe> timeZoneOverride; @@ -2187,7 +2240,7 @@ index 5f329ff0f6..709cd2b90d 100644 } auto timeZone = mozilla::intl::TimeZone::TryCreate(timeZoneOverride); -@@ -559,7 +532,7 @@ mozilla::intl::TimeZone* js::DateTimeInfo::timeZone() { +@@ -558,7 +531,7 @@ mozilla::intl::TimeZone* js::DateTimeInfo::timeZone() { // If a time zone override was specified, but couldn't be resolved to a // valid time zone, then we ignore the override request and instead use the // system default time zone. @@ -2196,7 +2249,7 @@ index 5f329ff0f6..709cd2b90d 100644 timeZone = mozilla::intl::TimeZone::TryCreate(); } -@@ -596,10 +569,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { +@@ -595,10 +568,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { js::DateTimeInfo::resetTimeZone(mode); } @@ -2221,7 +2274,7 @@ index 5f329ff0f6..709cd2b90d 100644 #if JS_HAS_INTL_API # if defined(XP_WIN) static bool IsOlsonCompatibleWindowsTimeZoneId(std::string_view tz) { -@@ -813,9 +800,17 @@ static bool ReadTimeZoneLink(std::string_view tz, +@@ -812,9 +799,17 @@ static bool ReadTimeZoneLink(std::string_view tz, void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { #if JS_HAS_INTL_API @@ -2309,10 +2362,10 @@ index 30b172e197..110824439c 100644 void internalResyncICUDefaultTimeZone(); diff --git a/js/src/vm/Realm.cpp b/js/src/vm/Realm.cpp -index cebc5d1eb1..81b4d13cdb 100644 +index 8ab093044d..3ed5fc6e2d 100644 --- a/js/src/vm/Realm.cpp +++ b/js/src/vm/Realm.cpp -@@ -545,22 +545,10 @@ void Realm::setLocaleOverride(const char* locale) { +@@ -568,22 +568,10 @@ void Realm::setLocaleOverride(const char* locale) { } js::DateTimeInfo* Realm::getDateTimeInfo() { @@ -2339,61 +2392,11 @@ index cebc5d1eb1..81b4d13cdb 100644 return nullptr; } -diff --git a/juggler/screencast/HeadlessWindowCapturer.h b/juggler/screencast/HeadlessWindowCapturer.h -index cb1bcbbfd7..6b39dfbea0 100644 ---- a/juggler/screencast/HeadlessWindowCapturer.h -+++ b/juggler/screencast/HeadlessWindowCapturer.h -@@ -6,12 +6,17 @@ - - #include - #include -+#include "api/scoped_refptr.h" - #include "api/video/video_frame.h" - #include "api/video/video_sink_interface.h" - #include "modules/video_capture/video_capture.h" - #include "rtc_base/deprecated/recursive_critical_section.h" -+#include "rtc_base/ref_counted_object.h" - #include "video_engine/desktop_capture_impl.h" - -+// Compatibility namespace aliases for WebRTC types -+namespace rtc = webrtc; -+ - class nsIWidget; - - namespace mozilla { -diff --git a/juggler/screencast/ScreencastEncoder.cpp b/juggler/screencast/ScreencastEncoder.cpp -index 701361add0..08e4fb9667 100644 ---- a/juggler/screencast/ScreencastEncoder.cpp -+++ b/juggler/screencast/ScreencastEncoder.cpp -@@ -41,6 +41,10 @@ - #include "WebMFileWriter.h" - #include "api/video/video_frame.h" - -+ -+// Compatibility namespace aliases for WebRTC types -+namespace rtc = webrtc; -+ - namespace mozilla { - - namespace { -diff --git a/juggler/screencast/nsScreencastService.cpp b/juggler/screencast/nsScreencastService.cpp -index 062a851429..953d973a3b 100644 ---- a/juggler/screencast/nsScreencastService.cpp -+++ b/juggler/screencast/nsScreencastService.cpp -@@ -25,6 +25,8 @@ - #include "mozilla/widget/PlatformWidgetTypes.h" - #include "video_engine/desktop_capture_impl.h" - #include "VideoEngine.h" -+#include "gfxPlatform.h" -+ - - extern "C" { - #include "jpeglib.h" diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp -index 67673c5c30..fe4a278dad 100644 +index 1f5759ad1a..c7d2924c27 100644 --- a/layout/base/GeometryUtils.cpp +++ b/layout/base/GeometryUtils.cpp -@@ -23,6 +23,7 @@ +@@ -21,6 +21,7 @@ #include "nsContentUtils.h" #include "nsIFrame.h" #include "nsLayoutUtils.h" @@ -2401,7 +2404,7 @@ index 67673c5c30..fe4a278dad 100644 using namespace mozilla; using namespace mozilla::dom; -@@ -265,10 +266,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, +@@ -263,10 +264,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, return false; } @@ -2430,7 +2433,7 @@ index 67673c5c30..fe4a278dad 100644 if (!frame) { // No boxes to return return; -@@ -281,7 +299,8 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, +@@ -279,7 +297,8 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, // EnsureFrameForTextNode call. We need to get the first frame again // when that happens and re-check it. if (!weakFrame.IsAlive()) { @@ -2441,10 +2444,10 @@ index 67673c5c30..fe4a278dad 100644 // No boxes to return return; diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 8e488bb954..d9510c00b9 100644 +index c81cc6bd30..bca5f8cf90 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp -@@ -12044,7 +12044,9 @@ bool PresShell::ComputeActiveness() const { +@@ -11674,7 +11674,9 @@ bool PresShell::ComputeActiveness() const { if (!browserChild->IsVisible()) { MOZ_LOG(gLog, LogLevel::Debug, (" > BrowserChild %p is not visible", browserChild)); @@ -2456,10 +2459,10 @@ index 8e488bb954..d9510c00b9 100644 // If the browser is visible but just due to be preserving layers diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp -index 89ed5fec3e..6f8cc2ccf6 100644 +index 41334360e9..0764a61948 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp -@@ -704,6 +704,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( +@@ -701,6 +701,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( !aDocument->GetPresShell()->AsyncPanZoomEnabled()) { return false; } @@ -2470,7 +2473,7 @@ index 89ed5fec3e..6f8cc2ccf6 100644 // True if we allow zooming for all documents on this platform, or if we are // in RDM. BrowsingContext* bc = aDocument->GetBrowsingContext(); -@@ -9736,6 +9740,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, +@@ -9789,6 +9793,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, /* static */ bool nsLayoutUtils::ShouldHandleMetaViewport(const Document* aDocument) { @@ -2481,10 +2484,10 @@ index 89ed5fec3e..6f8cc2ccf6 100644 return StaticPrefs::dom_meta_viewport_enabled() || (bc && bc->InRDMPane()); } diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index 79a93cb336..124390898b 100644 +index cd6f670479..0e5652a49d 100644 --- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h -@@ -591,6 +591,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); +@@ -609,6 +609,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); bool Gecko_MediaFeatures_PrefersReducedTransparency( const mozilla::dom::Document*); @@ -2493,10 +2496,10 @@ index 79a93cb336..124390898b 100644 mozilla::StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( const mozilla::dom::Document*); diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp -index 3182e94281..6f4ca1847a 100644 +index 93eafd4b98..800bd0c502 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp -@@ -264,11 +264,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { +@@ -274,11 +274,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { } bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { @@ -2509,7 +2512,7 @@ index 3182e94281..6f4ca1847a 100644 } bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { -@@ -298,6 +294,20 @@ bool Gecko_MediaFeatures_MacRTL(const Document* aDocument) { +@@ -308,6 +304,20 @@ bool Gecko_MediaFeatures_MacRTL(const Document* aDocument) { // as a signal. StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( const Document* aDocument) { @@ -2531,10 +2534,10 @@ index 3182e94281..6f4ca1847a 100644 return StylePrefersContrast::NoPreference; } diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp -index c80e36383b..169cce6ea2 100644 +index 4b2d68f47f..bedb15b2c6 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp -@@ -2094,4 +2094,16 @@ void LoadInfo::UpdateParentAddressSpaceInfo() { +@@ -2089,4 +2089,16 @@ void LoadInfo::UpdateParentAddressSpaceInfo() { } } @@ -2552,10 +2555,10 @@ index c80e36383b..169cce6ea2 100644 + } // namespace mozilla::net diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h -index 383d6f1f80..a51107be81 100644 +index 50052f1af1..8d0ff2c495 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h -@@ -540,6 +540,8 @@ class LoadInfo final : public nsILoadInfo { +@@ -551,6 +551,8 @@ class LoadInfo final : public nsILoadInfo { dom::UserNavigationInvolvement::None; bool mSkipHTTPSUpgrade = false; @@ -2565,10 +2568,10 @@ index 383d6f1f80..a51107be81 100644 // This is exposed solely for testing purposes and should not be used outside of // LoadInfo diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp -index be0f8bcb6f..00f0771453 100644 +index debfc6aa22..c39faf3b45 100644 --- a/netwerk/base/TRRLoadInfo.cpp +++ b/netwerk/base/TRRLoadInfo.cpp -@@ -562,5 +562,15 @@ TRRLoadInfo::GetFetchDestination(nsACString& aDestination) { +@@ -549,5 +549,15 @@ TRRLoadInfo::GetFetchDestination(nsACString& aDestination) { return NS_ERROR_NOT_IMPLEMENTED; } @@ -2585,10 +2588,10 @@ index be0f8bcb6f..00f0771453 100644 } // namespace net } // namespace mozilla diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl -index 4f4673f41b..dbc045c153 100644 +index 7e529645af..379759ed11 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl -@@ -1714,4 +1714,6 @@ interface nsILoadInfo : nsISupports +@@ -1719,4 +1719,6 @@ interface nsILoadInfo : nsISupports return static_cast(userNavigationInvolvement); } %} @@ -2596,10 +2599,10 @@ index 4f4673f41b..dbc045c153 100644 + [infallible] attribute unsigned long long jugglerLoadIdentifier; }; diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl -index 7f91d2df6f..aaa5541a17 100644 +index 3654f3ed20..f685e7668a 100644 --- a/netwerk/base/nsINetworkInterceptController.idl +++ b/netwerk/base/nsINetworkInterceptController.idl -@@ -60,6 +60,16 @@ interface nsIInterceptedChannel : nsISupports +@@ -59,6 +59,16 @@ interface nsIInterceptedChannel : nsISupports */ void resetInterception(in boolean bypass); @@ -2617,22 +2620,22 @@ index 7f91d2df6f..aaa5541a17 100644 * Set the status and reason for the forthcoming synthesized response. * Multiple calls overwrite existing values. diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp -index 634865583e..91585bddb7 100644 +index 25fa5efcae..7c028400f4 100644 --- a/netwerk/ipc/DocumentLoadListener.cpp +++ b/netwerk/ipc/DocumentLoadListener.cpp -@@ -190,6 +190,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, - loadInfo->SetTextDirectiveUserActivation( - aLoadState->GetTextDirectiveUserActivation()); +@@ -195,6 +195,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, + aLoadState->GetTextDirectiveUserActivation() || + aLoadState->HasLoadFlags(nsIWebNavigation::LOAD_FLAGS_FROM_EXTERNAL)); loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh()); + loadInfo->SetJugglerLoadIdentifier(aLoadState->GetLoadIdentifier()); return loadInfo.forget(); } diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index 9a7f39489d..56ee9beaee 100644 +index fe8db1c68a..f8c49580b7 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.cpp +++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -724,10 +724,33 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) +@@ -720,10 +720,33 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) } // anonymous namespace @@ -2666,7 +2669,7 @@ index 9a7f39489d..56ee9beaee 100644 if (mCanceled) { return mStatus; } -@@ -1142,11 +1165,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { +@@ -1137,11 +1160,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { GetCallback(mProgressSink); } @@ -2686,10 +2689,10 @@ index 9a7f39489d..56ee9beaee 100644 if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { mPump->PeekStream(CallTypeSniffers, static_cast(this)); diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h -index 7a2a4f2910..a416e1357a 100644 +index 74a4d086e0..445b4ec3b3 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.h +++ b/netwerk/protocol/http/InterceptedHttpChannel.h -@@ -90,6 +90,11 @@ class InterceptedHttpChannel final +@@ -89,6 +89,11 @@ class InterceptedHttpChannel final Atomic mCallingStatusAndProgress; bool mInterceptionReset{false}; @@ -2702,10 +2705,10 @@ index 7a2a4f2910..a416e1357a 100644 * InterceptionTimeStamps is used to record the time stamps of the * interception. diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp -index 1a76f06043..61f7cab9c1 100644 +index 5041de0a9e..05951a5945 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp -@@ -922,11 +922,9 @@ nsresult nsHttpChannel::OnBeforeConnect() { +@@ -916,11 +916,9 @@ nsresult nsHttpChannel::OnBeforeConnect() { // SecurityInfo.sys.mjs mLoadInfo->SetHstsStatus(isSecureURI); @@ -2718,7 +2721,7 @@ index 1a76f06043..61f7cab9c1 100644 BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { return NS_ERROR_OFFLINE; } -@@ -1039,9 +1037,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, +@@ -1033,9 +1031,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, return aStatus; } @@ -2729,7 +2732,7 @@ index 1a76f06043..61f7cab9c1 100644 if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC() || forceOffline) { -@@ -1518,15 +1514,14 @@ nsresult nsHttpChannel::ContinueConnect() { +@@ -1516,15 +1512,14 @@ nsresult nsHttpChannel::ContinueConnect() { "CORS preflight must have been finished by the time we " "do the rest of ContinueConnect"); @@ -2747,7 +2750,7 @@ index 1a76f06043..61f7cab9c1 100644 BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { return NS_ERROR_OFFLINE; } -@@ -1568,7 +1563,7 @@ nsresult nsHttpChannel::ContinueConnect() { +@@ -1566,7 +1561,7 @@ nsresult nsHttpChannel::ContinueConnect() { } // We're about to hit the network. Don't if we're forced offline. @@ -2756,7 +2759,7 @@ index 1a76f06043..61f7cab9c1 100644 return NS_ERROR_OFFLINE; } -@@ -1676,12 +1671,9 @@ void nsHttpChannel::SpeculativeConnect() { +@@ -1674,12 +1669,9 @@ void nsHttpChannel::SpeculativeConnect() { // don't speculate if we are offline, when doing http upgrade (i.e. // websockets bootstrap), or if we can't do keep-alive (because then we // couldn't reuse the speculative connection anyhow). @@ -2770,7 +2773,7 @@ index 1a76f06043..61f7cab9c1 100644 return; } -@@ -4674,9 +4666,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { +@@ -5011,9 +5003,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { uint32_t cacheEntryOpenFlags; bool offline = gIOService->IsOffline(); @@ -2780,7 +2783,7 @@ index 1a76f06043..61f7cab9c1 100644 bool maybeRCWN = false; nsAutoCString cacheControlRequestHeader; -@@ -4687,7 +4676,7 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { +@@ -5024,7 +5013,7 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { return NS_OK; } @@ -2789,7 +2792,7 @@ index 1a76f06043..61f7cab9c1 100644 if (offline || (mLoadFlags & INHIBIT_CACHING) || forceOffline) { if (BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass()) && !offline && !forceOffline) { -@@ -7975,6 +7964,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() { +@@ -8401,6 +8390,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() { } } @@ -2800,7 +2803,7 @@ index 1a76f06043..61f7cab9c1 100644 + return true; + + RefPtr wbc; -+ mLoadInfo->GetWorkerAssociatedBrowsingContext(getter_AddRefs(wbc)); ++ mLoadInfo->GetAssociatedBrowsingContext(getter_AddRefs(wbc)); + if (wbc && wbc->Top()->GetForceOffline()) + return true; + @@ -2811,7 +2814,7 @@ index 1a76f06043..61f7cab9c1 100644 nsHttpChannel::GetEncodedBodySize(uint64_t* aEncodedBodySize) { if (mCacheEntry && !LoadCacheEntryIsWriteOnly()) { diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h -index f455ad5874..f2e8f43543 100644 +index 2a30ef2905..3320a66050 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -312,6 +312,10 @@ class nsHttpChannel final : public HttpBaseChannel, @@ -2826,10 +2829,10 @@ index f455ad5874..f2e8f43543 100644 // end server host name. ProxyDNSStrategy GetProxyDNSStrategy(); diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index 72523ca8c1..465aac80a7 100644 +index 9d085e0a5f..928862ea76 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1367,6 +1367,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( +@@ -1448,6 +1448,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -2841,10 +2844,10 @@ index 72523ca8c1..465aac80a7 100644 nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); if (!preloadCsp) { diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp -index 9d262dbf33..495afbbe2b 100644 +index 068d9702fd..9ff49d6de9 100644 --- a/security/manager/ssl/nsCertOverrideService.cpp +++ b/security/manager/ssl/nsCertOverrideService.cpp -@@ -626,6 +626,8 @@ void nsCertOverrideService::CountPermanentOverrideTelemetry( +@@ -624,6 +624,8 @@ void nsCertOverrideService::CountPermanentOverrideTelemetry( } static bool IsDebugger() { @@ -2854,19 +2857,19 @@ index 9d262dbf33..495afbbe2b 100644 nsCOMPtr marionette = do_GetService(NS_MARIONETTE_CONTRACTID); if (marionette) { diff --git a/services/settings/Utils.sys.mjs b/services/settings/Utils.sys.mjs -index 8cd4afc313..60f5eb6e52 100644 +index da12049e14..24621137e2 100644 --- a/services/settings/Utils.sys.mjs +++ b/services/settings/Utils.sys.mjs -@@ -97,7 +97,7 @@ const _cdnURLs = {}; +@@ -99,7 +99,7 @@ const _cdnURLs = {}; export var Utils = { get SERVER_URL() { -- return lazy.allowServerURLOverride -+ return true || lazy.allowServerURLOverride - ? lazy.gServerURL - : AppConstants.REMOTE_SETTINGS_SERVER_URL; - }, -@@ -110,6 +110,9 @@ export var Utils = { +- return lazy.allowServerURL ++ return true || lazy.allowServerURL + ? // eslint-disable-next-line mozilla/valid-lazy + lazy.gServerURL + : AppConstants.REMOTE_SETTINGS_SERVER_URLS[0]; +@@ -113,6 +113,9 @@ export var Utils = { log, get shouldSkipRemoteActivityDueToTests() { @@ -2876,33 +2879,13 @@ index 8cd4afc313..60f5eb6e52 100644 return ( (lazy.isRunningTests || Cu.isInAutomation) && this.SERVER_URL == "data:,#remote-settings-dummy/v1" -diff --git a/third_party/libwebrtc/api/location.h b/third_party/libwebrtc/api/location.h -new file mode 100644 -index 0000000000..040cbc972b ---- /dev/null -+++ b/third_party/libwebrtc/api/location.h -@@ -0,0 +1,14 @@ -+#ifndef API_LOCATION_H_ -+#define API_LOCATION_H_ -+ -+namespace webrtc { -+class Location { -+ public: -+ static constexpr Location Current() { return Location(); } -+ constexpr Location() = default; -+ constexpr Location(const Location&) = default; -+ constexpr Location& operator=(const Location&) = default; -+}; -+} // namespace webrtc -+ -+#endif // API_LOCATION_H_ diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 75555352b8..72855a404e 100644 +index e2b69d51df..9f79494c20 100644 --- a/toolkit/components/browser/nsIWebBrowserChrome.idl +++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -74,6 +74,9 @@ interface nsIWebBrowserChrome : nsISupports - // Whether this window should use out-of-process cross-origin subframes. - const unsigned long CHROME_FISSION_WINDOW = 1 << 21; +@@ -88,6 +88,9 @@ interface nsIWebBrowserChrome : nsISupports + // Whether this is a Document Picture-in-Picture window + const unsigned long CHROME_DOCUMENT_PIP = 1 << 22; + // Whether this window has "width" or "height" defined in features + const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE = 0x00400000; @@ -2911,10 +2894,10 @@ index 75555352b8..72855a404e 100644 // ignored for Linux. const unsigned long CHROME_SUPPRESS_ANIMATION = 1 << 24; diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -index bb451a2795..cf5ae51466 100644 +index d7f1cafba2..d87e67ec71 100644 --- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs +++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -@@ -106,7 +106,9 @@ EnterprisePoliciesManager.prototype = { +@@ -107,7 +107,9 @@ EnterprisePoliciesManager.prototype = { Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); } @@ -2925,7 +2908,7 @@ index bb451a2795..cf5ae51466 100644 if (provider.failed) { this.status = Ci.nsIEnterprisePolicies.FAILED; -@@ -619,6 +621,19 @@ class JSONPoliciesProvider { +@@ -644,6 +646,19 @@ class JSONPoliciesProvider { } } @@ -2946,10 +2929,10 @@ index bb451a2795..cf5ae51466 100644 constructor() { this._policies = null; diff --git a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -index 091aafb624..a82d8a79de 100644 +index f4143be013..8e0a5b28b2 100644 --- a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp +++ b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -@@ -589,7 +589,7 @@ void PopulateLanguages() { +@@ -793,7 +793,7 @@ void PopulateLanguages() { // sufficient to only collect this information as the other properties are // just reformats of Navigator::GetAcceptLanguages. nsTArray languages; @@ -2959,7 +2942,7 @@ index 091aafb624..a82d8a79de 100644 for (const auto& language : languages) { diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index 5175a8a3ef..4c6b3137f7 100644 +index c5eddf7f3f..43e2d7c71b 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -360,7 +360,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { @@ -2987,10 +2970,10 @@ index 36fe2d427e..593795dfb2 100644 int32_t aMaxSelfProgress, int32_t aCurTotalProgress, diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -index 942cb7c400..864cf804b6 100644 +index 9cf52bffca..f142df4ece 100644 --- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp +++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1880,7 +1880,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( +@@ -1918,7 +1918,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( // Open a minimal popup. *aIsPopupRequested = true; @@ -3004,10 +2987,10 @@ index 942cb7c400..864cf804b6 100644 /** diff --git a/toolkit/mozapps/update/UpdateService.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs -index 61a7a589cf..fccf2fbefa 100644 +index 2a02e58652..d8ae08c71a 100644 --- a/toolkit/mozapps/update/UpdateService.sys.mjs +++ b/toolkit/mozapps/update/UpdateService.sys.mjs -@@ -3990,6 +3990,8 @@ export class UpdateService { +@@ -4026,6 +4026,8 @@ export class UpdateService { } get disabledForTesting() { @@ -3017,10 +3000,10 @@ index 61a7a589cf..fccf2fbefa 100644 } diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index 0ab59fb09f..f115a6f7bb 100644 +index 24f86c7c54..580d38caec 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild -@@ -156,6 +156,7 @@ if CONFIG["ENABLE_WEBDRIVER"]: +@@ -155,6 +155,7 @@ if CONFIG["ENABLE_WEBDRIVER"]: "/remote", "/testing/firefox-ui", "/testing/marionette", @@ -3064,10 +3047,10 @@ index b7c376eadc..4438577634 100644 // Only run this code if LauncherProcessWin.h was included beforehand, thus // signalling that the hosting process should support launcher mode. diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp -index ef95040ffc..f62a103de6 100644 +index 059ef152a4..772c7428af 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp -@@ -897,6 +897,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, +@@ -884,6 +884,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, mIsLoadingJavascriptURI ? "javascript URI" : "document.open")); @@ -3081,10 +3064,10 @@ index ef95040ffc..f62a103de6 100644 // nsDocumentViewer::LoadComplete that doesn't do various things // that are not relevant here because this wasn't an actual diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp -index 04c46fda68..21b2fcf861 100644 +index 614089c280..6e9d1a3262 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -111,6 +111,8 @@ +@@ -110,6 +110,8 @@ #include "mozilla/Components.h" #include "mozilla/ClearOnShutdown.h" @@ -3093,7 +3076,7 @@ index 04c46fda68..21b2fcf861 100644 #include "mozilla/Preferences.h" #include "mozilla/ipc/URIUtils.h" -@@ -866,6 +868,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( +@@ -865,6 +867,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( return NS_OK; } @@ -3106,7 +3089,7 @@ index 04c46fda68..21b2fcf861 100644 nsresult nsExternalHelperAppService::GetFileTokenForPath( const char16_t* aPlatformAppPath, nsIFile** aFile) { nsDependentString platformAppPath(aPlatformAppPath); -@@ -1497,7 +1505,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { +@@ -1496,7 +1504,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { // Strip off the ".part" from mTempLeafName mTempLeafName.Truncate(mTempLeafName.Length() - std::size(".part") + 1); @@ -3119,7 +3102,7 @@ index 04c46fda68..21b2fcf861 100644 mSaver = do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); -@@ -1681,7 +1694,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { +@@ -1680,7 +1693,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { return NS_OK; } @@ -3157,7 +3140,7 @@ index 04c46fda68..21b2fcf861 100644 if (NS_FAILED(rv)) { nsresult transferError = rv; -@@ -1742,6 +1784,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { +@@ -1741,6 +1783,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { bool alwaysAsk = true; mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); @@ -3167,7 +3150,7 @@ index 04c46fda68..21b2fcf861 100644 if (alwaysAsk) { // But we *don't* ask if this mimeInfo didn't come from // our user configuration datastore and the user has said -@@ -2258,6 +2303,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, +@@ -2257,6 +2302,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, NotifyTransfer(aStatus); } @@ -3184,7 +3167,7 @@ index 04c46fda68..21b2fcf861 100644 return NS_OK; } -@@ -2741,6 +2796,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { +@@ -2740,6 +2795,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { } } @@ -3201,10 +3184,10 @@ index 04c46fda68..21b2fcf861 100644 // OnStartRequest) mDialog = nullptr; diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h -index f2e7d379f3..a5932f2986 100644 +index e28e6a7451..85c5e87a0f 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h -@@ -270,6 +270,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, +@@ -269,6 +269,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, nsIInterfaceRequestor* aWindowContext, nsIStreamListener** aStreamListener); @@ -3213,7 +3196,7 @@ index f2e7d379f3..a5932f2986 100644 }; /** -@@ -467,6 +469,9 @@ class nsExternalAppHandler final : public nsIStreamListener, +@@ -466,6 +468,9 @@ class nsExternalAppHandler final : public nsIStreamListener, * Upon successful return, both mTempFile and mSaver will be valid. */ nsresult SetUpTempFile(nsIChannel* aChannel); @@ -3224,10 +3207,10 @@ index f2e7d379f3..a5932f2986 100644 * When we download a helper app, we are going to retarget all load * notifications into our own docloader and load group instead of diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl -index e6490ebb08..2792373dcb 100644 +index f5c40986ad..99708fe18d 100644 --- a/uriloader/exthandler/nsIExternalHelperAppService.idl +++ b/uriloader/exthandler/nsIExternalHelperAppService.idl -@@ -6,8 +6,11 @@ +@@ -5,8 +5,11 @@ #include "nsICancelable.idl" @@ -3239,7 +3222,7 @@ index e6490ebb08..2792373dcb 100644 interface nsIStreamListener; interface nsIFile; interface nsIMIMEInfo; -@@ -15,6 +18,17 @@ interface nsIWebProgressListener2; +@@ -14,6 +17,17 @@ interface nsIWebProgressListener2; interface nsIInterfaceRequestor; webidl BrowsingContext; @@ -3257,7 +3240,7 @@ index e6490ebb08..2792373dcb 100644 /** * The external helper app service is used for finding and launching * platform specific external applications for a given mime content type. -@@ -87,6 +101,8 @@ interface nsIExternalHelperAppService : nsISupports +@@ -86,6 +100,8 @@ interface nsIExternalHelperAppService : nsISupports * `DownloadIntegration.sys.mjs`, which is implemented on all platforms. */ nsIFile getPreferredDownloadsDirectory(); @@ -3295,10 +3278,10 @@ index 777157e17e..50cf4bfffc 100644 } #endif diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h -index 76fd0e0ff6..ee6cb6d354 100644 +index 7c6d850fde..2f4c7b5867 100644 --- a/widget/MouseEvents.h +++ b/widget/MouseEvents.h -@@ -386,6 +386,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, +@@ -425,6 +425,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, // Otherwise, this must be 0. uint32_t mClickCount = 0; @@ -3308,7 +3291,7 @@ index 76fd0e0ff6..ee6cb6d354 100644 // Whether the event should ignore scroll frame bounds during dispatch. bool mIgnoreRootScrollFrame = false; -@@ -425,6 +428,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, +@@ -465,6 +468,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, mContextMenuTrigger = aEvent.mContextMenuTrigger; mExitFrom = aEvent.mExitFrom; mClickCount = aEvent.mClickCount; @@ -3317,38 +3300,10 @@ index 76fd0e0ff6..ee6cb6d354 100644 mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent; mClickEventPrevented = aEvent.mClickEventPrevented; diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm -index 24b70173c2..75ac367a1c 100644 +index d77173551c..8f40613aed 100644 --- a/widget/cocoa/NativeKeyBindings.mm +++ b/widget/cocoa/NativeKeyBindings.mm -@@ -549,6 +549,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - break; - case KEY_NAME_INDEX_ArrowLeft: - if (aEvent.IsAlt()) { -+ if (aEvent.IsMeta() || aEvent.IsControl()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ !aEvent.IsShift() -+ ? ToObjcSelectorPtr(@selector(moveWordLeft:)) -+ : ToObjcSelectorPtr(@selector(moveWordLeftAndModifySelection:)), -+ aCommands); - break; - } - if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { -@@ -571,6 +578,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - break; - case KEY_NAME_INDEX_ArrowRight: - if (aEvent.IsAlt()) { -+ if (aEvent.IsMeta() || aEvent.IsControl()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ !aEvent.IsShift() -+ ? ToObjcSelectorPtr(@selector(moveWordRight:)) -+ : ToObjcSelectorPtr(@selector(moveWordRightAndModifySelection:)), -+ aCommands); - break; - } - if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { -@@ -593,6 +607,10 @@ void NativeKeyBindings::GetEditCommandsForTests( +@@ -620,6 +620,10 @@ void NativeKeyBindings::GetEditCommandsForTests( break; case KEY_NAME_INDEX_ArrowUp: if (aEvent.IsControl()) { @@ -3359,16 +3314,7 @@ index 24b70173c2..75ac367a1c 100644 break; } if (aEvent.IsMeta()) { -@@ -603,7 +621,7 @@ void NativeKeyBindings::GetEditCommandsForTests( - !aEvent.IsShift() - ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) - : ToObjcSelectorPtr( -- @selector(moveToBegginingOfDocumentAndModifySelection:)), -+ @selector(moveToBeginningOfDocumentAndModifySelection:)), - aCommands); - break; - } -@@ -630,6 +648,10 @@ void NativeKeyBindings::GetEditCommandsForTests( +@@ -657,6 +661,10 @@ void NativeKeyBindings::GetEditCommandsForTests( break; case KEY_NAME_INDEX_ArrowDown: if (aEvent.IsControl()) { @@ -3380,10 +3326,10 @@ index 24b70173c2..75ac367a1c 100644 } if (aEvent.IsMeta()) { diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp -index 20fac05df3..ff9f1c79e6 100644 +index bfe6b88ec0..fce0e99a08 100644 --- a/widget/gtk/nsFilePicker.cpp +++ b/widget/gtk/nsFilePicker.cpp -@@ -22,6 +22,7 @@ +@@ -21,6 +21,7 @@ #include "mozilla/Preferences.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/Document.h" @@ -3392,10 +3338,10 @@ index 20fac05df3..ff9f1c79e6 100644 #include "nsArrayEnumerator.h" #include "nsEnumeratorUtils.h" diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp -index bb4ee9175e..6814ae8503 100644 +index cbaa021c9d..6cf72e6006 100644 --- a/widget/headless/HeadlessCompositorWidget.cpp +++ b/widget/headless/HeadlessCompositorWidget.cpp -@@ -3,6 +3,8 @@ +@@ -2,6 +2,8 @@ * 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/. */ @@ -3404,7 +3350,7 @@ index bb4ee9175e..6814ae8503 100644 #include "mozilla/widget/PlatformWidgetTypes.h" #include "HeadlessCompositorWidget.h" #include "VsyncDispatcher.h" -@@ -15,9 +17,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget( +@@ -14,9 +16,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget( const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) : CompositorWidget(aOptions), mWidget(aWindow), @@ -3435,7 +3381,7 @@ index bb4ee9175e..6814ae8503 100644 void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { if (RefPtr cvd = mWidget->GetCompositorVsyncDispatcher()) { -@@ -31,6 +54,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged( +@@ -30,6 +53,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged( const LayoutDeviceIntSize& aClientSize) { auto size = mClientSize.Lock(); *size = aClientSize; @@ -3496,10 +3442,10 @@ index bb4ee9175e..6814ae8503 100644 LayoutDeviceIntSize HeadlessCompositorWidget::GetClientSize() { diff --git a/widget/headless/HeadlessCompositorWidget.h b/widget/headless/HeadlessCompositorWidget.h -index facd2bc65a..3c5751ad1b 100644 +index 8374cd0094..0345d19d1d 100644 --- a/widget/headless/HeadlessCompositorWidget.h +++ b/widget/headless/HeadlessCompositorWidget.h -@@ -6,6 +6,7 @@ +@@ -5,6 +5,7 @@ #ifndef widget_headless_HeadlessCompositorWidget_h #define widget_headless_HeadlessCompositorWidget_h @@ -3507,7 +3453,7 @@ index facd2bc65a..3c5751ad1b 100644 #include "mozilla/widget/CompositorWidget.h" #include "HeadlessWidget.h" -@@ -23,8 +24,11 @@ class HeadlessCompositorWidget final : public CompositorWidget, +@@ -22,8 +23,11 @@ class HeadlessCompositorWidget final : public CompositorWidget, HeadlessWidget* aWindow); void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); @@ -3519,7 +3465,7 @@ index facd2bc65a..3c5751ad1b 100644 uintptr_t GetWidgetKey() override; -@@ -42,10 +46,18 @@ class HeadlessCompositorWidget final : public CompositorWidget, +@@ -41,10 +45,18 @@ class HeadlessCompositorWidget final : public CompositorWidget, } private: @@ -3539,10 +3485,10 @@ index facd2bc65a..3c5751ad1b 100644 } // namespace widget diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index 9ca469064e..adf0f885f8 100644 +index 867b4a9fd9..0d239412f9 100644 --- a/widget/headless/HeadlessWidget.cpp +++ b/widget/headless/HeadlessWidget.cpp -@@ -113,6 +113,8 @@ void HeadlessWidget::Destroy() { +@@ -112,6 +112,8 @@ void HeadlessWidget::Destroy() { } } @@ -3551,7 +3497,7 @@ index 9ca469064e..adf0f885f8 100644 nsIWidget::OnDestroy(); nsIWidget::Destroy(); -@@ -590,5 +592,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( +@@ -572,5 +574,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( return NS_OK; } @@ -3567,10 +3513,10 @@ index 9ca469064e..adf0f885f8 100644 } // namespace widget } // namespace mozilla diff --git a/widget/headless/HeadlessWidget.h b/widget/headless/HeadlessWidget.h -index ba4da76d76..027c55167d 100644 +index ca31e584b7..1dff8fd40c 100644 --- a/widget/headless/HeadlessWidget.h +++ b/widget/headless/HeadlessWidget.h -@@ -131,6 +131,9 @@ class HeadlessWidget final : public nsIWidget { +@@ -127,6 +127,9 @@ class HeadlessWidget final : public nsIWidget { double aDeltaX, double aDeltaY, int32_t aModifierFlags, nsISynthesizedEventCallback* aCallback) override; @@ -3581,30 +3527,30 @@ index ba4da76d76..027c55167d 100644 ~HeadlessWidget(); bool mEnabled; diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h -index ef6b603bdb..6cc82fa4a6 100644 +index 908a3d8a4a..9b6fbdb9ae 100644 --- a/widget/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h -@@ -250,6 +250,7 @@ struct ParamTraits { - aParam.mExitFrom.value())); - } +@@ -297,6 +297,7 @@ struct ParamTraits { + WriteParam(aWriter, aParam.mContextMenuTrigger); + WriteParam(aWriter, aParam.mExitFrom); WriteParam(aWriter, aParam.mClickCount); + WriteParam(aWriter, aParam.mJugglerEventId); WriteParam(aWriter, aParam.mCallbackId); // Mark the event as stopped to notify callback. -@@ -278,6 +279,7 @@ struct ParamTraits { - aResult->mExitFrom = Some(static_cast(exitFrom)); - } - rv = rv && ReadParam(aReader, &aResult->mClickCount) && -+ ReadParam(aReader, &aResult->mJugglerEventId) && - ReadParam(aReader, &aResult->mCallbackId); - return rv; +@@ -314,6 +315,7 @@ struct ParamTraits { + ReadParam(aReader, &aResult->mContextMenuTrigger) && + ReadParam(aReader, &aResult->mExitFrom) && + ReadParam(aReader, &aResult->mClickCount) && ++ ReadParam(aReader, &aResult->mJugglerEventId) && + ReadParam(aReader, &aResult->mCallbackId); } + }; diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h -index 1c0aff31b9..bbac5fa58a 100644 +index 2888ffaf43..cd4cce73f6 100644 --- a/xpcom/reflect/xptinfo/xptinfo.h +++ b/xpcom/reflect/xptinfo/xptinfo.h -@@ -505,7 +505,7 @@ static_assert(sizeof(nsXPTMethodInfo) == 8, "wrong size"); +@@ -503,7 +503,7 @@ static_assert(sizeof(nsXPTMethodInfo) == 8, "wrong size"); #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) # define PARAM_BUFFER_COUNT 18 #else diff --git a/patches/screen-spoofing.patch b/patches/screen-spoofing.patch index 550b103..5c46e94 100644 --- a/patches/screen-spoofing.patch +++ b/patches/screen-spoofing.patch @@ -1,6 +1,6 @@ diff --git a/dom/base/ScreenDimensionManager.cpp b/dom/base/ScreenDimensionManager.cpp new file mode 100644 -index 0000000000..1a2b3c4d5e +index 0000000000..f5d2c23df5 --- /dev/null +++ b/dom/base/ScreenDimensionManager.cpp @@ -0,0 +1,104 @@ @@ -108,10 +108,9 @@ index 0000000000..1a2b3c4d5e + +} // namespace dom +} // namespace mozilla - diff --git a/dom/base/ScreenDimensionManager.h b/dom/base/ScreenDimensionManager.h new file mode 100644 -index 0000000000..2b3c4d5e6f +index 0000000000..329f709a60 --- /dev/null +++ b/dom/base/ScreenDimensionManager.h @@ -0,0 +1,47 @@ @@ -162,33 +161,31 @@ index 0000000000..2b3c4d5e6f +} // namespace mozilla + +#endif // mozilla_dom_ScreenDimensionManager_h - diff --git a/dom/base/moz.build b/dom/base/moz.build -index cd9090cda3..b2c3d4e5f6 100644 +index 39952f9af8..c471c97936 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build -@@ -256,6 +256,7 @@ EXPORTS.mozilla.dom += [ - "ResizeObserver.h", +@@ -260,6 +260,7 @@ EXPORTS.mozilla.dom += [ "ResponsiveImageSelector.h", + "RoverfoxStorageManager.h", "SameProcessMessageQueue.h", + "ScreenDimensionManager.h", "ScreenLuminance.h", "ScreenOrientation.h", "Selection.h", -@@ -460,6 +461,7 @@ UNIFIED_SOURCES += [ - "ResizeObserver.cpp", +@@ -471,6 +472,7 @@ UNIFIED_SOURCES += [ "ResponsiveImageSelector.cpp", + "RoverfoxStorageManager.cpp", "SameProcessMessageQueue.cpp", + "ScreenDimensionManager.cpp", "ScreenLuminance.cpp", "ScreenOrientation.cpp", "ScriptableContentIterator.cpp", - diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp -index 748ae6cf83..c3d4e5f6a7 100644 +index a72b2b478a..babefb850c 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp -@@ -277,6 +277,7 @@ +@@ -286,6 +286,7 @@ #include "nsISizeOfEventTarget.h" #include "nsISlowScriptDebug.h" #include "nsISupportsUtils.h" @@ -196,10 +193,10 @@ index 748ae6cf83..c3d4e5f6a7 100644 #include "nsIThread.h" #include "nsITimedChannel.h" #include "nsIURI.h" -@@ -7420,7 +7421,53 @@ nsGlobalWindowInner::GetAudioWorklet(ErrorResult& aRv) { - return mAudioWorklet; +@@ -7706,6 +7707,52 @@ nsISerialEventTarget* nsGlobalWindowInner::SerialEventTarget() const { + return GetMainThreadSerialEventTarget(); } - + +void nsGlobalWindowInner::SetScreenDimensions(int32_t aWidth, int32_t aHeight, + ErrorResult& aRv) { + uint32_t userContextId = ScreenDimensionManager::GetUserContextIdFromWindow(this); @@ -249,62 +246,35 @@ index 748ae6cf83..c3d4e5f6a7 100644 Worklet* nsGlobalWindowInner::GetPaintWorklet(ErrorResult& aRv) { if (!mPaintWorklet) { nsIPrincipal* principal = GetPrincipal(); - diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h -index 3183172d29..d4e5f6a7b8 100644 +index 9f1ce33fdc..42584898fa 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h -@@ -750,6 +750,10 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, - - Worklet* GetPaintWorklet(mozilla::ErrorResult& aRv); - +@@ -677,6 +677,10 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, + // Audio fingerprint seed for per-context audio fingerprinting + void SetAudioFingerprintSeed(uint32_t seed, mozilla::ErrorResult& aRv); + + // Screen dimension methods for per-context screen spoofing + void SetScreenDimensions(int32_t aWidth, int32_t aHeight, mozilla::ErrorResult& aRv); + void SetScreenColorDepth(int32_t aColorDepth, mozilla::ErrorResult& aRv); + - void GetRegionalPrefsLocales(nsTArray& aLocales); - void GetWebExposedLocales(nsTArray& aLocales); - -diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl -index a6f0d96a36..b1c2d3e4f5 100644 ---- a/dom/webidl/Window.webidl -+++ b/dom/webidl/Window.webidl -@@ -886,6 +886,18 @@ partial interface Window { - [Throws, Func="IsChromeOrUAWidget"] - readonly attribute IntlUtils intlUtils; - }; - -+// Screen dimension for per-context screen spoofing -+partial interface Window { -+ [Throws, Func="mozilla::dom::ScreenDimensionManager::IsFunctionEnabledForWebIDL"] -+ undefined setScreenDimensions(long width, long height); -+}; -+ -+// Screen color depth for per-context screen spoofing -+partial interface Window { -+ [Throws, Func="mozilla::dom::ScreenDimensionManager::IsFunctionEnabledForWebIDL"] -+ undefined setScreenColorDepth(long colorDepth); -+}; -+ - partial interface Window { - [SameObject, Replaceable] - readonly attribute VisualViewport visualViewport; - }; - + + mozilla::dom::IntlUtils* GetIntlUtils(mozilla::ErrorResult& aRv); diff --git a/dom/base/nsScreen.cpp b/dom/base/nsScreen.cpp -index 7f7728a6cc..a1b2c3d4e5 100644 +index 8ebb3e575a..f157ff7da8 100644 --- a/dom/base/nsScreen.cpp +++ b/dom/base/nsScreen.cpp -@@ -14,6 +14,7 @@ +@@ -12,6 +12,8 @@ #include "mozilla/dom/DocumentInlines.h" #include "mozilla/widget/ScreenManager.h" #include "nsCOMPtr.h" +#include "ScreenDimensionManager.h" - #include "nsContentUtils.h" ++#include "nsContentUtils.h" #include "nsDeviceContext.h" #include "nsGlobalWindowInner.h" -@@ -67,6 +68,26 @@ nsDeviceContext* nsScreen::GetDeviceContext() const { + #include "nsGlobalWindowOuter.h" +@@ -73,6 +75,26 @@ nsDeviceContext* nsScreen::GetDeviceContext() const { } CSSIntRect nsScreen::GetRect() { @@ -331,7 +301,7 @@ index 7f7728a6cc..a1b2c3d4e5 100644 // Return window inner rect to prevent fingerprinting. if (ShouldResistFingerprinting(RFPTarget::ScreenRect)) { return GetTopWindowInnerRectForRFP(); -@@ -95,6 +116,24 @@ +@@ -105,6 +127,24 @@ CSSIntRect nsScreen::GetRect() { } CSSIntRect nsScreen::GetAvailRect() { @@ -356,34 +326,55 @@ index 7f7728a6cc..a1b2c3d4e5 100644 auto rect = MaskConfig::GetRect("screen.availLeft", "screen.availTop", "screen.availWidth", "screen.availHeight"); if (rect.has_value()) { - +diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl +index 1aa2baa931..4f5479fc2e 100644 +--- a/dom/webidl/Window.webidl ++++ b/dom/webidl/Window.webidl +@@ -929,6 +929,18 @@ partial interface Window { + readonly attribute IntlUtils intlUtils; + }; + ++// Screen dimension for per-context screen spoofing ++partial interface Window { ++ [Throws, Func="mozilla::dom::ScreenDimensionManager::IsFunctionEnabledForWebIDL"] ++ undefined setScreenDimensions(long width, long height); ++}; ++ ++// Screen color depth for per-context screen spoofing ++partial interface Window { ++ [Throws, Func="mozilla::dom::ScreenDimensionManager::IsFunctionEnabledForWebIDL"] ++ undefined setScreenColorDepth(long colorDepth); ++}; ++ + partial interface Window { + [SameObject, Replaceable] + readonly attribute VisualViewport visualViewport; diff --git a/gfx/src/moz.build b/gfx/src/moz.build -index a2b3e60fe5..faa0c113bc 100644 +index d1e1cdf387..54fbb8ad08 100644 --- a/gfx/src/moz.build +++ b/gfx/src/moz.build -@@ -95,3 +95,6 @@ FINAL_LIBRARY = "xul" +@@ -93,3 +93,6 @@ FINAL_LIBRARY = "xul" if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"] CXXFLAGS += CONFIG["MOZ_PANGO_CFLAGS"] + +# DOM Mask +LOCAL_INCLUDES += ["/camoucfg"] - diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp -index 7a4fa8d48f..408b754d92 100644 +index 06b86c6c75..9641c8457c 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp -@@ -5,6 +5,7 @@ +@@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - + #include "nsDeviceContext.h" +#include "MaskConfig.hpp" #include // for max #include "gfxContext.h" #include "gfxPoint.h" // for gfxSize -@@ -177,6 +178,13 @@ bool nsDeviceContext::GetScreenIsHDR() { +@@ -193,6 +194,13 @@ bool nsDeviceContext::GetScreenIsHDR() { } - + nsSize nsDeviceContext::GetDeviceSurfaceDimensions() { + // Check for height and width overrides from MaskConfig + if (auto height = MaskConfig::GetInt32("screen.height"), @@ -394,30 +385,24 @@ index 7a4fa8d48f..408b754d92 100644 + } return GetRect().Size(); } - + diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp -index f83e2c21ca..5362dd77d4 100644 +index 07564ab15b..ae6b70f3b6 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp -@@ -26,4 +26,6 @@ +@@ -22,6 +22,8 @@ + #include "nsDeviceContext.h" + #include "nsGkAtoms.h" #include "nsGlobalWindowOuter.h" +#include "nsGlobalWindowInner.h" +#include "mozilla/dom/ScreenDimensionManager.h" #include "nsIBaseWindow.h" #include "nsIDocShell.h" #include "nsIPrintSettings.h" -@@ -66,14 +68,18 @@ static nsSize GetDeviceSize(const Document& aDocument) { +@@ -62,6 +64,18 @@ static nsSize GetDeviceSize(const Document& aDocument) { return GetSize(aDocument); } - -- // Media queries in documents in an RDM pane should use the simulated -- // device size. -- Maybe deviceSize = -- nsGlobalWindowOuter::GetRDMDeviceSize(aDocument); -- if (deviceSize.isSome()) { -- return CSSPixel::ToAppUnits(deviceSize.value()); -- } -- + + // Camoufox: per-context screen dimensions for CSS device-width/height queries + if (nsPIDOMWindowInner* inner = aDocument.GetInnerWindow()) { + nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(inner); @@ -430,6 +415,6 @@ index f83e2c21ca..5362dd77d4 100644 + } + } + - nsPresContext* pc = aDocument.GetPresContext(); - // NOTE(emilio): We should probably figure out how to return an appropriate - // device size here, though in a multi-screen world that makes no sense + // Media queries in documents in an RDM pane should use the simulated + // device size. + Maybe deviceSize = diff --git a/patches/system-ui-font-spoofing.patch b/patches/system-ui-font-spoofing.patch index 4603203..80b432d 100644 --- a/patches/system-ui-font-spoofing.patch +++ b/patches/system-ui-font-spoofing.patch @@ -1,8 +1,8 @@ diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp -index xxxxxxxxxx..yyyyyyyyyy 100644 +index d82edfc767..2e05cedcb3 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp -@@ -2132,6 +2132,16 @@ +@@ -2246,6 +2246,18 @@ void gfxPlatformFontList::MaybeRemoveCmap(gfxCharacterMap* aCharMap, static void GetSystemUIFontFamilies( FontVisibilityProvider* aFontVisibilityProvider, [[maybe_unused]] nsAtom* aLangGroup, nsTArray& aFamilies) { diff --git a/patches/timezone-spoofing.patch b/patches/timezone-spoofing.patch index 63fa308..8a8cccf 100644 --- a/patches/timezone-spoofing.patch +++ b/patches/timezone-spoofing.patch @@ -1,9 +1,9 @@ diff --git a/dom/base/TimezoneManager.cpp b/dom/base/TimezoneManager.cpp new file mode 100644 -index 0000000000..7ec236d160 +index 0000000000..ffbc624040 --- /dev/null +++ b/dom/base/TimezoneManager.cpp -@@ -0,0 +1,72 @@ +@@ -0,0 +1,71 @@ +#include "TimezoneManager.h" +#include "RoverfoxStorageManager.h" +#include "MaskConfig.hpp" @@ -77,10 +77,10 @@ index 0000000000..7ec236d160 +} // namespace mozilla diff --git a/dom/base/TimezoneManager.h b/dom/base/TimezoneManager.h new file mode 100644 -index 0000000000..a7f5735e53 +index 0000000000..7cc942e7c9 --- /dev/null +++ b/dom/base/TimezoneManager.h -@@ -0,0 +1,28 @@ +@@ -0,0 +1,27 @@ +#ifndef mozilla_dom_TimezoneManager_h +#define mozilla_dom_TimezoneManager_h + @@ -109,10 +109,10 @@ index 0000000000..a7f5735e53 + +#endif // mozilla_dom_TimezoneManager_h diff --git a/dom/base/moz.build b/dom/base/moz.build -index 617d0152bd..dc13a2b4ac 100644 +index 66b3509602..2b5e125904 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build -@@ -285,6 +285,7 @@ EXPORTS.mozilla.dom += [ +@@ -280,6 +280,7 @@ EXPORTS.mozilla.dom += [ "TimeoutBudgetManager.h", "TimeoutHandler.h", "TimeoutManager.h", @@ -120,7 +120,7 @@ index 617d0152bd..dc13a2b4ac 100644 "TreeIterator.h", "TreeOrderedArray.h", "TreeOrderedArrayInlines.h", -@@ -499,6 +500,7 @@ UNIFIED_SOURCES += [ +@@ -493,6 +494,7 @@ UNIFIED_SOURCES += [ "TimeoutExecutor.cpp", "TimeoutHandler.cpp", "TimeoutManager.cpp", @@ -129,10 +129,10 @@ index 617d0152bd..dc13a2b4ac 100644 "UIDirectionManager.cpp", "UserActivation.cpp", diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp -index ea66d28e53..2abb83c3a6 100644 +index 5432f702ed..10568ed4f7 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp -@@ -246,6 +246,8 @@ +@@ -244,6 +244,8 @@ #include "nsID.h" #include "nsIDOMStorageManager.h" #include "FontSpacingSeedManager.h" @@ -141,7 +141,7 @@ index ea66d28e53..2abb83c3a6 100644 #include "nsDocShell.h" #include "mozilla/OriginAttributes.h" #include "nsIDOMXULControlElement.h" -@@ -7525,6 +7527,48 @@ void nsGlobalWindowInner::SetFontSpacingSeed(uint32_t seed, ErrorResult& aRv) { +@@ -7730,6 +7732,48 @@ void nsGlobalWindowInner::SetFontSpacingSeed(uint32_t seed, ErrorResult& aRv) { } } @@ -191,25 +191,61 @@ index ea66d28e53..2abb83c3a6 100644 MOZ_ASSERT(aSharedWorker); MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker)); diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h -index 5f9a11b0d3..3183172d29 100644 +index b26388188c..e7c3c14a3f 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h -@@ -683,6 +683,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, - +@@ -680,6 +680,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, + // Font spacing seed for privacy-preserving font fingerprinting void SetFontSpacingSeed(uint32_t seed, mozilla::ErrorResult& aRv); + void SetTimezone(const nsAString& timezone, mozilla::ErrorResult& aRv); - + void StoreSharedWorker(mozilla::dom::SharedWorker* aSharedWorker); - + +diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp +index 7aab4d6f92..81caaa8f31 100644 +--- a/dom/base/nsGlobalWindowOuter.cpp ++++ b/dom/base/nsGlobalWindowOuter.cpp +@@ -87,6 +87,8 @@ + #include "js/friend/WindowProxy.h" // js::IsWindowProxy, js::SetWindowProxy + #include "jsapi.h" + #include "jsfriendapi.h" ++#include "TimezoneManager.h" ++#include "js/Date.h" + #include "mozilla/Likely.h" + #include "mozilla/Preferences.h" + #include "mozilla/SchedulerGroup.h" +@@ -2507,6 +2509,22 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, + MOZ_ALWAYS_SUCCEEDS(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID())); + } + ++ // Camoufox: Auto-apply stored timezone when navigating to new document ++ // This ensures timezone persists across page navigations within same context ++ { ++ uint32_t userContextId = 0; ++ if (bc) { ++ userContextId = bc->OriginAttributesRef().mUserContextId; ++ } ++ nsAutoString storedTimezone; ++ if (mozilla::dom::TimezoneManager::GetTimezone(userContextId, storedTimezone)) { ++ if (JSContext* cx = nsContentUtils::GetCurrentJSContext()) { ++ NS_LossyConvertUTF16toASCII timezoneASCII(storedTimezone); ++ JS::SetRealmTimeZoneOverride(cx, timezoneASCII.get()); ++ } ++ } ++ } ++ + // We no longer need the old inner window. Start its destruction if + // its not being reused and clear our reference. + if (doomCurrentInner) { diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl -index 7a076768d0..a6f0d96a36 100644 +index 454ef6f4e7..b96e76edb7 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl -@@ -892,6 +892,12 @@ partial interface Window { - readonly attribute VisualViewport visualViewport; +@@ -940,6 +940,12 @@ partial interface Window { + undefined setFontSpacingSeed(unsigned long seed); }; - + +// Timezone interface for per-context timezone spoofing +partial interface Window { + [Throws, Func="mozilla::dom::TimezoneManager::IsFunctionEnabledForWebIDL"] @@ -219,36 +255,69 @@ index 7a076768d0..a6f0d96a36 100644 // Used to assign marks to appear on the scrollbar when // finding on a page. partial interface Window { +diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp +index 95e5ca1574..16ec178d9e 100644 +--- a/dom/workers/WorkerPrivate.cpp ++++ b/dom/workers/WorkerPrivate.cpp +@@ -21,6 +21,8 @@ + #include "js/CallAndConstruct.h" // JS_CallFunctionValue + #include "js/CompilationAndEvaluation.h" + #include "js/ContextOptions.h" ++#include "js/Date.h" ++#include "TimezoneManager.h" + #include "js/Exception.h" + #include "js/LocaleSensitive.h" + #include "js/MemoryMetrics.h" +@@ -6429,6 +6431,19 @@ WorkerGlobalScope* WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx) { + data->mScope->DisconnectGlobalTeardownObservers(); + } + ++ // Camoufox: Apply per-context timezone override to this worker's JS realm. ++ // All worker types (dedicated, shared, service) inherit userContextId from ++ // the parent BrowserContext via OriginAttributes. Firefox creates separate ++ // worker instances per userContextId, so per-context lookup always works. ++ { ++ uint32_t ucid = GetOriginAttributes().mUserContextId; ++ nsAutoString tz; ++ if (mozilla::dom::TimezoneManager::GetTimezone(ucid, tz) && !tz.IsEmpty()) { ++ NS_LossyConvertUTF16toASCII tzASCII(tz); ++ JS::SetRealmTimeZoneOverride(aCx, tzASCII.get()); ++ } ++ } ++ + JS_FireOnNewGlobalObject(aCx, global); + + return data->mScope; diff --git a/js/public/Date.h b/js/public/Date.h index 98d5b1176e..89c2942a68 100644 --- a/js/public/Date.h +++ b/js/public/Date.h @@ -56,6 +56,9 @@ namespace JS { extern JS_PUBLIC_API void ResetTimeZone(); - + extern JS_PUBLIC_API bool SetTimeZoneOverride(const char* timezoneId); +// Camoufox: per-context timezone override +extern JS_PUBLIC_API bool SetRealmTimeZoneOverride(JSContext* cx, const char* timezoneId); + - + class ClippedTime; inline ClippedTime TimeClip(double time); diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp -index 709cd2b90d..af5abb38be 100644 +index 96ed101921..aa78f0fe26 100644 --- a/js/src/vm/DateTime.cpp +++ b/js/src/vm/DateTime.cpp -@@ -39,6 +39,7 @@ +@@ -38,6 +38,7 @@ #include "util/Text.h" #include "vm/MutexIDs.h" #include "vm/Realm.h" +#include "jspubtd.h" - + static bool ComputeLocalTime(time_t local, struct tm* ptm) { // Neither localtime_s nor localtime_r are required to act as if tzset has -@@ -257,6 +258,12 @@ js::DateTimeInfo::DateTimeInfo() { - +@@ -256,6 +257,12 @@ js::DateTimeInfo::DateTimeInfo() { + js::DateTimeInfo::~DateTimeInfo() = default; - + +js::DateTimeInfo::DateTimeInfo(const char* timezone) : DateTimeInfo() { +#if JS_HAS_INTL_API + timeZoneOverride_ = timezone ? std::string(timezone) : std::string(); @@ -258,10 +327,10 @@ index 709cd2b90d..af5abb38be 100644 int64_t js::DateTimeInfo::toClampedSeconds(int64_t milliseconds) { int64_t seconds = milliseconds / msPerSecond; int64_t millis = milliseconds % msPerSecond; -@@ -587,6 +594,18 @@ JS_PUBLIC_API bool JS::SetTimeZoneOverride(const char* timeZoneId) { +@@ -586,6 +593,18 @@ JS_PUBLIC_API bool JS::SetTimeZoneOverride(const char* timeZoneId) { return true; } - + +JS_PUBLIC_API bool JS::SetRealmTimeZoneOverride(JSContext* cx, const char* timeZoneId) { + if (!timeZoneId || !mozilla::intl::TimeZone::IsValidTimeZoneId(timeZoneId)) { + return false; @@ -282,56 +351,20 @@ index 110824439c..dfc88898f5 100644 --- a/js/src/vm/DateTime.h +++ b/js/src/vm/DateTime.h @@ -154,6 +154,7 @@ class DateTimeInfo { - + public: ~DateTimeInfo(); + explicit DateTimeInfo(const char* timezone); - + // The spec implicitly assumes DST and time zone adjustment information // never change in the course of a function -- sometimes even across -diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp -index a1b2c3d4e5..f6g7h8i9j0 100644 ---- a/dom/base/nsGlobalWindowOuter.cpp -+++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -86,6 +86,8 @@ - #include "js/friend/WindowProxy.h" // js::IsWindowProxy, js::SetWindowProxy - #include "jsapi.h" - #include "jsfriendapi.h" -+#include "TimezoneManager.h" -+#include "js/Date.h" - #include "mozilla/Likely.h" - #include "mozilla/Preferences.h" - #include "mozilla/SchedulerGroup.h" -@@ -2480,6 +2482,22 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, - if (bc->IsOwnedByProcess()) { - MOZ_ALWAYS_SUCCEEDS(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID())); - } -+ -+ // Camoufox: Auto-apply stored timezone when navigating to new document -+ // This ensures timezone persists across page navigations within same context -+ { -+ uint32_t userContextId = 0; -+ if (bc) { -+ userContextId = bc->OriginAttributesRef().mUserContextId; -+ } -+ nsAutoString storedTimezone; -+ if (mozilla::dom::TimezoneManager::GetTimezone(userContextId, storedTimezone)) { -+ if (JSContext* cx = nsContentUtils::GetCurrentJSContext()) { -+ NS_LossyConvertUTF16toASCII timezoneASCII(storedTimezone); -+ JS::SetRealmTimeZoneOverride(cx, timezoneASCII.get()); -+ } -+ } -+ } - - // We no longer need the old inner window. Start its destruction if - // its not being reused and clear our reference. diff --git a/js/src/vm/Realm.cpp b/js/src/vm/Realm.cpp -index 81b4d13cdb..ca04167603 100644 +index 3ed5fc6e2d..6df86a6059 100644 --- a/js/src/vm/Realm.cpp +++ b/js/src/vm/Realm.cpp -@@ -545,10 +545,15 @@ void Realm::setLocaleOverride(const char* locale) { +@@ -568,10 +568,15 @@ void Realm::setLocaleOverride(const char* locale) { } - + js::DateTimeInfo* Realm::getDateTimeInfo() { - // Playwright patch: Per-realm timezone overrides are disabled in favor of - // global timezone overrides via JS::SetTimeZoneOverride(). @@ -348,37 +381,4 @@ index 81b4d13cdb..ca04167603 100644 +#endif return nullptr; } - -diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp -index c8e44687b7..9a2bae61e7 100644 ---- a/dom/workers/WorkerPrivate.cpp -+++ b/dom/workers/WorkerPrivate.cpp -@@ -23,6 +23,8 @@ - #include "js/CallAndConstruct.h" // JS_CallFunctionValue - #include "js/CompilationAndEvaluation.h" - #include "js/ContextOptions.h" -+#include "js/Date.h" -+#include "TimezoneManager.h" - #include "js/Exception.h" - #include "js/LocaleSensitive.h" - #include "js/MemoryMetrics.h" -@@ -6350,6 +6352,19 @@ WorkerGlobalScope* WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx) { - data->mScope->DisconnectGlobalTeardownObservers(); - } - -+ // Camoufox: Apply per-context timezone override to this worker's JS realm. -+ // All worker types (dedicated, shared, service) inherit userContextId from -+ // the parent BrowserContext via OriginAttributes. Firefox creates separate -+ // worker instances per userContextId, so per-context lookup always works. -+ { -+ uint32_t ucid = GetOriginAttributes().mUserContextId; -+ nsAutoString tz; -+ if (mozilla::dom::TimezoneManager::GetTimezone(ucid, tz) && !tz.IsEmpty()) { -+ NS_LossyConvertUTF16toASCII tzASCII(tz); -+ JS::SetRealmTimeZoneOverride(aCx, tzASCII.get()); -+ } -+ } -+ - JS_FireOnNewGlobalObject(aCx, global); - - return data->mScope; + diff --git a/patches/webgl-spoofing.patch b/patches/webgl-spoofing.patch index b8013c0..c15ed5a 100644 --- a/patches/webgl-spoofing.patch +++ b/patches/webgl-spoofing.patch @@ -1,6 +1,6 @@ diff --git a/dom/base/WebGLParamsManager.cpp b/dom/base/WebGLParamsManager.cpp new file mode 100644 -index 0000000000..abcdef1234 +index 0000000000..4f1ff23af4 --- /dev/null +++ b/dom/base/WebGLParamsManager.cpp @@ -0,0 +1,82 @@ @@ -88,7 +88,7 @@ index 0000000000..abcdef1234 +} // namespace mozilla diff --git a/dom/base/WebGLParamsManager.h b/dom/base/WebGLParamsManager.h new file mode 100644 -index 0000000000..bcdef12345 +index 0000000000..72df27b6e5 --- /dev/null +++ b/dom/base/WebGLParamsManager.h @@ -0,0 +1,32 @@ @@ -125,13 +125,13 @@ index 0000000000..bcdef12345 + +#endif // mozilla_dom_WebGLParamsManager_h diff --git a/dom/base/moz.build b/dom/base/moz.build -index xxxxxxxxxx..yyyyyyyyyy 100644 +index 49c8ac12fa..aaf888c706 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build -@@ -534,5 +534,13 @@ +@@ -534,6 +534,14 @@ SOURCES += [ "nsPluginArray.cpp", ] - + +# WebGLParamsManager compiled separately to avoid unified build scope issues +# (includes RoverfoxStorageManager.h which can affect compilation units) +SOURCES += ["WebGLParamsManager.cpp"] @@ -142,11 +142,12 @@ index xxxxxxxxxx..yyyyyyyyyy 100644 + # Are we targeting x86-32 or x86-64? If so, we want to include SSE2 code for # CharacterDataBuffer.cpp + if CONFIG["INTEL_ARCHITECTURE"]: diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp -index xxxxxxxxxx..yyyyyyyyyy 100644 +index 0545014921..37bc0fe6c9 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp -@@ -25,6 +25,7 @@ +@@ -22,6 +22,7 @@ #include "SessionStorageCache.h" #include "Units.h" #include "VRManagerChild.h" @@ -154,10 +155,10 @@ index xxxxxxxxxx..yyyyyyyyyy 100644 #include "WindowDestroyedEvent.h" #include "WindowNamedPropertiesHandler.h" #include "js/ComparisonOperators.h" -@@ -7477,6 +7478,51 @@ void nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker) { +@@ -7721,6 +7722,51 @@ void nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker) { mSharedWorkers.RemoveElement(aSharedWorker); } - + + +void nsGlobalWindowInner::SetWebGLVendor(const nsAString& vendor, + ErrorResult& aRv) { @@ -207,13 +208,13 @@ index xxxxxxxxxx..yyyyyyyyyy 100644 bool aGranted) { // Invalidate cached StorageAllowed field so that calls to GetLocalStorage diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h -index xxxxxxxxxx..yyyyyyyyyy 100644 +index 43b3ef9521..c3b17c91e2 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h -@@ -685,6 +685,10 @@ - +@@ -682,6 +682,10 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, + void ForgetSharedWorker(mozilla::dom::SharedWorker* aSharedWorker); - + + // Per-context WebGL parameter spoofing + void SetWebGLVendor(const nsAString& vendor, mozilla::ErrorResult& aRv); + void SetWebGLRenderer(const nsAString& renderer, mozilla::ErrorResult& aRv); @@ -221,29 +222,13 @@ index xxxxxxxxxx..yyyyyyyyyy 100644 public: void Alert(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void Alert(const nsAString& aMessage, nsIPrincipal& aSubjectPrincipal, -diff --git a/dom/canvas/ClientWebGLContext.h b/dom/canvas/ClientWebGLContext.h -index xxxxxxxxxx..yyyyyyyyyy 100644 ---- a/dom/canvas/ClientWebGLContext.h -+++ b/dom/canvas/ClientWebGLContext.h -@@ -1083,6 +1083,11 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, - void GetContextAttributes(dom::Nullable& retval); - - private: -+ // Helper for mask config values -+ bool MBoolVal(const std::string& key, bool defaultValue); -+ // Per-context WebGL parameter support -+ uint32_t GetUserContextId() const; -+ - webgl::SwapChainOptions PrepareAsyncSwapChainOptions( - WebGLFramebufferJS* fb, bool webvr, - const webgl::SwapChainOptions& options = webgl::SwapChainOptions()); diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp -index 11578f425f..6c77acd7f3 100644 +index c7721c36a8..f439a8cbe6 100644 --- a/dom/canvas/ClientWebGLContext.cpp +++ b/dom/canvas/ClientWebGLContext.cpp -@@ -4,6 +4,14 @@ +@@ -3,6 +3,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - + #include "ClientWebGLContext.h" +#include "MaskConfig.hpp" +#include "WebGLParamsManager.h" @@ -253,13 +238,13 @@ index 11578f425f..6c77acd7f3 100644 +#include "nsPIDOMWindow.h" +#include +#include - + #include - -@@ -754,6 +761,35 @@ void ClientWebGLContext::SetUnpackColorSpace( + +@@ -767,6 +775,35 @@ void ClientWebGLContext::SetUnpackColorSpace( Run(*mUnpackColorSpace); } - + +bool ClientWebGLContext::MBoolVal(const std::string& key, bool defaultValue) { + if (auto value = MaskConfig::GetAttribute(key, mIsWebGL2); + value.has_value()) @@ -292,10 +277,10 @@ index 11578f425f..6c77acd7f3 100644 void ClientWebGLContext::GetContextAttributes( dom::Nullable& retval) { retval.SetNull(); -@@ -764,15 +787,40 @@ void ClientWebGLContext::GetContextAttributes( - +@@ -777,15 +814,40 @@ void ClientWebGLContext::GetContextAttributes( + const auto& options = mNotLost->info.options; - + - result.mAlpha.Construct(options.alpha); - result.mDepth = options.depth; - result.mStencil = options.stencil; @@ -340,12 +325,12 @@ index 11578f425f..6c77acd7f3 100644 + result.mForceSoftwareRendering = MBoolVal( + "forceSoftwareRendering", options.forceSoftwareRendering); } - + // ----------------------- -@@ -991,18 +1039,28 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) { +@@ -1015,18 +1077,28 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) { std::unordered_map webgl::MakeIsEnabledMap(const bool webgl2) { auto ret = std::unordered_map{}; - + - ret[LOCAL_GL_BLEND] = false; - ret[LOCAL_GL_CULL_FACE] = false; - ret[LOCAL_GL_DEPTH_TEST] = false; @@ -373,17 +358,17 @@ index 11578f425f..6c77acd7f3 100644 + MaskConfig::MParamGL(LOCAL_GL_SCISSOR_TEST, false, webgl2); + ret[LOCAL_GL_STENCIL_TEST] = + MaskConfig::MParamGL(LOCAL_GL_STENCIL_TEST, false, webgl2); - + if (webgl2) { - ret[LOCAL_GL_RASTERIZER_DISCARD] = false; + ret[LOCAL_GL_RASTERIZER_DISCARD] = + MaskConfig::MParamGL(LOCAL_GL_RASTERIZER_DISCARD, false, webgl2); } - + return ret; -@@ -2114,6 +2172,57 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, +@@ -2140,6 +2212,57 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, const auto& state = State(); - + // - + std::optional< + std::variant> @@ -436,11 +421,11 @@ index 11578f425f..6c77acd7f3 100644 + return; + } + } - + const auto fnSetRetval_Buffer = [&](const GLenum target) { const auto buffer = *MaybeFind(state.mBoundBufferByTarget, target); -@@ -2219,49 +2328,84 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, - +@@ -2245,49 +2368,84 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, + // 2 floats case LOCAL_GL_DEPTH_RANGE: - retval.set(Create(cx, this, state.mDepthRange, rv)); @@ -450,7 +435,7 @@ index 11578f425f..6c77acd7f3 100644 + mIsWebGL2), + rv)); return; - + case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: - retval.set( - Create(cx, this, limits.pointSizeRange, rv)); @@ -460,7 +445,7 @@ index 11578f425f..6c77acd7f3 100644 + pname, limits.pointSizeRange, mIsWebGL2), + rv)); return; - + case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: - retval.set( - Create(cx, this, limits.lineWidthRange, rv)); @@ -470,7 +455,7 @@ index 11578f425f..6c77acd7f3 100644 + pname, limits.lineWidthRange, mIsWebGL2), + rv)); return; - + // 4 floats case LOCAL_GL_COLOR_CLEAR_VALUE: - retval.set(Create(cx, this, state.mClearColor, rv)); @@ -480,7 +465,7 @@ index 11578f425f..6c77acd7f3 100644 + mIsWebGL2), + rv)); return; - + case LOCAL_GL_BLEND_COLOR: - retval.set(Create(cx, this, state.mBlendColor, rv)); + retval.set(Create( @@ -489,7 +474,7 @@ index 11578f425f..6c77acd7f3 100644 + mIsWebGL2), + rv)); return; - + // 2 ints case LOCAL_GL_MAX_VIEWPORT_DIMS: { auto maxViewportDim = BitwiseCast(limits.maxViewportDim); @@ -502,7 +487,7 @@ index 11578f425f..6c77acd7f3 100644 + rv)); return; } - + // 4 ints case LOCAL_GL_SCISSOR_BOX: - retval.set(Create(cx, this, state.mScissor, rv)); @@ -512,7 +497,7 @@ index 11578f425f..6c77acd7f3 100644 + mIsWebGL2), + rv)); return; - + case LOCAL_GL_VIEWPORT: - retval.set(Create(cx, this, state.mViewport, rv)); + retval.set(Create( @@ -521,7 +506,7 @@ index 11578f425f..6c77acd7f3 100644 + mIsWebGL2), + rv)); return; - + - // any case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: - retval.set(Create(cx, this, @@ -536,9 +521,9 @@ index 11578f425f..6c77acd7f3 100644 + rv)); return; } - -@@ -2441,6 +2585,17 @@ - + +@@ -2468,6 +2626,17 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, + switch (pname) { case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_RENDERER_WEBGL: + { @@ -552,12 +537,12 @@ index 11578f425f..6c77acd7f3 100644 + ret = Some(value.value()); + break; + } - if (ShouldResistFingerprinting(RFPTarget::WebGLRenderInfo)) { + if (ShouldResistFingerprinting(RFPTarget::WebGLRenderInfo) || + ShouldResistFingerprinting(RFPTarget::WebGLRendererConstant)) { ret = Some("Mozilla"_ns); - } else { -@@ -2452,6 +2607,17 @@ +@@ -2480,6 +2649,17 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, break; - + case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_VENDOR_WEBGL: + { + nsAutoString stored; @@ -570,10 +555,10 @@ index 11578f425f..6c77acd7f3 100644 + ret = Some(value.value()); + break; + } - ret = ShouldResistFingerprinting(RFPTarget::WebGLRenderInfo) - ? Some("Mozilla"_ns) - : GetUnmaskedVendor(); -@@ -2545,7 +2711,9 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, + if (ShouldResistFingerprinting(RFPTarget::WebGLRenderInfo)) { + ret = Some("Mozilla"_ns); + } else if (ShouldResistFingerprinting( +@@ -2600,7 +2780,9 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, case LOCAL_GL_COLOR_WRITEMASK: { const auto mask = uint8_t(*maybe); const auto bs = std::bitset<4>(mask); @@ -584,10 +569,10 @@ index 11578f425f..6c77acd7f3 100644 JS::Rooted arr(cx); if (!dom::ToJSValue(cx, src.data(), src.size(), &arr)) { rv = NS_ERROR_OUT_OF_MEMORY; -@@ -2960,6 +3128,24 @@ ClientWebGLContext::GetShaderPrecisionFormat(const GLenum shadertype, +@@ -3015,6 +3197,24 @@ ClientWebGLContext::GetShaderPrecisionFormat(const GLenum shadertype, const FuncScope funcScope(*this, "getShaderPrecisionFormat"); if (IsContextLost()) return nullptr; - + + // Check for spoofed value + if (auto value = + MaskConfig::MShaderData(shadertype, precisiontype, mIsWebGL2)) { @@ -609,10 +594,10 @@ index 11578f425f..6c77acd7f3 100644 const auto& shaderPrecisions = *notLost->info.shaderPrecisions; const auto args = webgl::GetShaderPrecisionFormatArgs{shadertype, precisiontype}; -@@ -6101,6 +6287,17 @@ bool ClientWebGLContext::IsSupported(const WebGLExtensionID ext, +@@ -6168,6 +6368,17 @@ bool ClientWebGLContext::IsSupported(const WebGLExtensionID ext, return false; } - + + if (std::vector maskValues = + MaskConfig::GetStringList(mIsWebGL2 ? "webGl2:supportedExtensions" + : "webGl:supportedExtensions"); @@ -627,9 +612,9 @@ index 11578f425f..6c77acd7f3 100644 const auto& limits = Limits(); return limits.supportedExtensions[ext]; } -@@ -6112,6 +6309,18 @@ void ClientWebGLContext::GetSupportedExtensions( +@@ -6179,6 +6390,18 @@ void ClientWebGLContext::GetSupportedExtensions( if (IsContextLost()) return; - + auto& retarr = retval.SetValue(); + + // Implement separately to prevent O(n^2) timing @@ -645,15 +630,31 @@ index 11578f425f..6c77acd7f3 100644 + for (const auto i : MakeEnumeratedRange(WebGLExtensionID::Max)) { if (!IsSupported(i, callerType)) continue; - + +diff --git a/dom/canvas/ClientWebGLContext.h b/dom/canvas/ClientWebGLContext.h +index 828fe63283..c87a5dced7 100644 +--- a/dom/canvas/ClientWebGLContext.h ++++ b/dom/canvas/ClientWebGLContext.h +@@ -1082,6 +1082,11 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, + void GetContextAttributes(dom::Nullable& retval); + + private: ++ // Helper for mask config values ++ bool MBoolVal(const std::string& key, bool defaultValue); ++ // Per-context WebGL parameter support ++ uint32_t GetUserContextId() const; ++ + webgl::SwapChainOptions PrepareAsyncSwapChainOptions( + WebGLFramebufferJS* fb, bool webvr, + const webgl::SwapChainOptions& options = webgl::SwapChainOptions()); diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build -index xxxxxxxxxx..yyyyyyyyyy 100644 +index f61ba653ae..f8448afaa6 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build -@@ -188,6 +188,10 @@ SOURCES += [ +@@ -186,6 +186,10 @@ TEST_DIRS += [ # Suppress warnings from third-party code. SOURCES["MurmurHash3.cpp"].flags += ["-Wno-implicit-fallthrough"] - + +LOCAL_INCLUDES += ["/camoucfg"] +LOCAL_INCLUDES += ["/dom/base"] +LOCAL_INCLUDES += ["/dom/workers"] @@ -662,14 +663,13 @@ index xxxxxxxxxx..yyyyyyyyyy 100644 "/js/xpconnect/wrappers", ] diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl -index xxxxxxxxxx..yyyyyyyyyy 100644 +index ae2d14e105..c8ffa297fd 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl -@@ -900,6 +900,18 @@ - undefined setScrollMarks(sequence marks, +@@ -939,6 +939,18 @@ partial interface Window { optional boolean onHorizontalScrollbar = false); }; - + +// Per-context WebGL vendor spoofing +partial interface Window { + [Throws, Func="mozilla::dom::WebGLParamsManager::IsVendorFunctionEnabledForWebIDL"] diff --git a/patches/windows-theming-bug-modified.patch b/patches/windows-theming-bug-modified.patch index f4266ac..720e374 100644 --- a/patches/windows-theming-bug-modified.patch +++ b/patches/windows-theming-bug-modified.patch @@ -1,17 +1,8 @@ diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in -index d11c35ff9d..0aa4b9058b 100644 +index a615f68a6f..f950c876fa 100644 --- a/browser/app/Makefile.in +++ b/browser/app/Makefile.in -@@ -23,7 +23,7 @@ ifeq ($(OS_ARCH),WINNT) - # (this dependency should really be just for firefox.exe, not other targets) - # Note the manifest file exists in the tree, so we use the explicit filename - # here. --EXTRA_DEPS += $(srcdir)/firefox.exe.manifest -+EXTRA_DEPS += $(srcdir)/camoufox.exe.manifest - endif - - PROGRAMS_DEST = $(DIST)/bin -@@ -92,7 +92,7 @@ tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME) $(objdir)/macbuild/Contents/MacOS- +@@ -84,7 +84,7 @@ tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME) $(objdir)/macbuild/Contents/MacOS- rsync -aL $(DIST)/bin/$(MOZ_APP_NAME) '$(dist_dest)/Contents/MacOS' cp -RL $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/firefox.icns '$(dist_dest)/Contents/Resources/firefox.icns' cp -RL $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/document.icns '$(dist_dest)/Contents/Resources/document.icns' diff --git a/pythonlib/camoufox/fingerprint-presets-v150.json b/pythonlib/camoufox/fingerprint-presets-v150.json new file mode 100644 index 0000000..4660ea5 --- /dev/null +++ b/pythonlib/camoufox/fingerprint-presets-v150.json @@ -0,0 +1,16513 @@ +{ + "version": 1, + "generated_at": "2026-05-11T18:23:31.169717Z", + "source": "roverfox_fingerprints", + "min_firefox_version": 149, + "presets": { + "macos": [ + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0", + "platform": "MacIntel", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 720, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 800, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2240, + "height": 1260, + "colorDepth": 30, + "availWidth": 2240, + "availHeight": 1230, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 30, + "availWidth": 1849, + "availHeight": 1050, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3200, + "height": 1800, + "colorDepth": 30, + "availWidth": 3200, + "availHeight": 1680, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 832, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 726, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 736, + "height": 414, + "colorDepth": 30, + "availWidth": 736, + "availHeight": 414, + "devicePixelRatio": 2.60869565217391 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2056, + "height": 1329, + "colorDepth": 30, + "availWidth": 2056, + "availHeight": 1253, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 30, + "availWidth": 2560, + "availHeight": 1410, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 30, + "availWidth": 1440, + "availHeight": 900, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + }, + "speechVoices": [ + "Alex:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amelie:fr-CA:local", + "Anna:de-DE:local", + "Carmit:he-IL:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Diego:es-AR:local", + "Ellen:nl-BE:local", + "Fiona:en-scotland:local", + "Fred:en-US:local", + "Ioana:ro-RO:local", + "Joana:pt-PT:local", + "Jorge:es-ES:local", + "Juan:es-MX:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kyoko:ja-JP:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Luca:it-IT:local", + "Luciana:pt-BR:local", + "Maged:ar-SA:local", + "Mariska:hu-HU:local", + "Mei-Jia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Monica:es-ES:local", + "Nora:nb-NO:local", + "Paulina:es-MX:local", + "Rishi:en-IN:local", + "Samantha:en-US:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Sin-ji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Ting-Ting:zh-CN:local", + "Veena:en-IN:local", + "Victoria:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Yuri:ru-RU:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3360, + "height": 1890, + "colorDepth": 30, + "availWidth": 3360, + "availHeight": 1865, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1728, + "height": 1117, + "colorDepth": 30, + "availWidth": 1728, + "availHeight": 1010, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1440, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1344, + "height": 840, + "colorDepth": 30, + "availWidth": 1344, + "availHeight": 764, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 900, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 30, + "availWidth": 1920, + "availHeight": 1170, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1152, + "colorDepth": 30, + "availWidth": 2048, + "availHeight": 1122, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3440, + "height": 1440, + "colorDepth": 30, + "availWidth": 3440, + "availHeight": 1364, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1360, + "height": 768, + "colorDepth": 30, + "availWidth": 1360, + "availHeight": 676, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 18, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3840, + "height": 2160, + "colorDepth": 30, + "availWidth": 3840, + "availHeight": 2052, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1710, + "height": 1107, + "colorDepth": 30, + "availWidth": 1710, + "availHeight": 1031, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 715, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1710, + "height": 1107, + "colorDepth": 30, + "availWidth": 1710, + "availHeight": 1074, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 730, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 2560, + "colorDepth": 30, + "availWidth": 1440, + "availHeight": 2484, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Brutte notizie:en-US:local", + "Bahh:en-US:local", + "Campane:en-US:local", + "Boing:en-US:local", + "Bollicine:en-US:local", + "Carmit:he-IL:local", + "Violoncelli:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Tremolio:en-US:local", + "Eddy (Tedesco (Germania)):de-DE:local", + "Eddy (Inglese (UK)):en-GB:local", + "Eddy (Inglese (USA)):en-US:local", + "Eddy (Spagnolo (Spagna)):es-ES:local", + "Eddy (Spagnolo (Messico)):es-MX:local", + "Eddy (Finlandese (Finlandia)):fi-FI:local", + "Eddy (Francese (Canada)):fr-CA:local", + "Eddy (Francese (Francia)):fr-FR:local", + "Eddy (Italiano (Italia)):it-IT:local", + "Eddy (Giapponese (Giappone)):ja-JP:local", + "Eddy (Coreano (Corea del Sud)):ko-KR:local", + "Eddy (Portoghese (Brasile)):pt-BR:local", + "Eddy (Cinese (Cina continentale)):zh-CN:local", + "Eddy (Cinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (Tedesco (Germania)):de-DE:local", + "Flo (Inglese (UK)):en-GB:local", + "Flo (Inglese (USA)):en-US:local", + "Flo (Spagnolo (Spagna)):es-ES:local", + "Flo (Spagnolo (Messico)):es-MX:local", + "Flo (Finlandese (Finlandia)):fi-FI:local", + "Flo (Francese (Canada)):fr-CA:local", + "Flo (Francese (Francia)):fr-FR:local", + "Flo (Italiano (Italia)):it-IT:local", + "Flo (Giapponese (Giappone)):ja-JP:local", + "Flo (Coreano (Corea del Sud)):ko-KR:local", + "Flo (Portoghese (Brasile)):pt-BR:local", + "Flo (Cinese (Cina continentale)):zh-CN:local", + "Flo (Cinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Buone notizie:en-US:local", + "Grandma (Tedesco (Germania)):de-DE:local", + "Grandma (Inglese (UK)):en-GB:local", + "Grandma (Inglese (USA)):en-US:local", + "Grandma (Spagnolo (Spagna)):es-ES:local", + "Grandma (Spagnolo (Messico)):es-MX:local", + "Grandma (Finlandese (Finlandia)):fi-FI:local", + "Grandma (Francese (Canada)):fr-CA:local", + "Grandma (Francese (Francia)):fr-FR:local", + "Grandma (Italiano (Italia)):it-IT:local", + "Grandma (Giapponese (Giappone)):ja-JP:local", + "Grandma (Coreano (Corea del Sud)):ko-KR:local", + "Grandma (Portoghese (Brasile)):pt-BR:local", + "Grandma (Cinese (Cina continentale)):zh-CN:local", + "Grandma (Cinese (Taiwan)):zh-TW:local", + "Grandpa (Tedesco (Germania)):de-DE:local", + "Grandpa (Inglese (UK)):en-GB:local", + "Grandpa (Inglese (USA)):en-US:local", + "Grandpa (Spagnolo (Spagna)):es-ES:local", + "Grandpa (Spagnolo (Messico)):es-MX:local", + "Grandpa (Finlandese (Finlandia)):fi-FI:local", + "Grandpa (Francese (Canada)):fr-CA:local", + "Grandpa (Francese (Francia)):fr-FR:local", + "Grandpa (Italiano (Italia)):it-IT:local", + "Grandpa (Giapponese (Giappone)):ja-JP:local", + "Grandpa (Coreano (Corea del Sud)):ko-KR:local", + "Grandpa (Portoghese (Brasile)):pt-BR:local", + "Grandpa (Cinese (Cina continentale)):zh-CN:local", + "Grandpa (Cinese (Taiwan)):zh-TW:local", + "Giullare:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organo:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (Tedesco (Germania)):de-DE:local", + "Reed (Inglese (UK)):en-GB:local", + "Reed (Inglese (USA)):en-US:local", + "Reed (Spagnolo (Spagna)):es-ES:local", + "Reed (Spagnolo (Messico)):es-MX:local", + "Reed (Finlandese (Finlandia)):fi-FI:local", + "Reed (Francese (Canada)):fr-CA:local", + "Reed (Italiano (Italia)):it-IT:local", + "Reed (Giapponese (Giappone)):ja-JP:local", + "Reed (Coreano (Corea del Sud)):ko-KR:local", + "Reed (Portoghese (Brasile)):pt-BR:local", + "Reed (Cinese (Cina continentale)):zh-CN:local", + "Reed (Cinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (Tedesco (Germania)):de-DE:local", + "Rocko (Inglese (UK)):en-GB:local", + "Rocko (Inglese (USA)):en-US:local", + "Rocko (Spagnolo (Spagna)):es-ES:local", + "Rocko (Spagnolo (Messico)):es-MX:local", + "Rocko (Finlandese (Finlandia)):fi-FI:local", + "Rocko (Francese (Canada)):fr-CA:local", + "Rocko (Francese (Francia)):fr-FR:local", + "Rocko (Italiano (Italia)):it-IT:local", + "Rocko (Giapponese (Giappone)):ja-JP:local", + "Rocko (Coreano (Corea del Sud)):ko-KR:local", + "Rocko (Portoghese (Brasile)):pt-BR:local", + "Rocko (Cinese (Cina continentale)):zh-CN:local", + "Rocko (Cinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (Tedesco (Germania)):de-DE:local", + "Sandy (Inglese (UK)):en-GB:local", + "Sandy (Inglese (USA)):en-US:local", + "Sandy (Spagnolo (Spagna)):es-ES:local", + "Sandy (Spagnolo (Messico)):es-MX:local", + "Sandy (Finlandese (Finlandia)):fi-FI:local", + "Sandy (Francese (Canada)):fr-CA:local", + "Sandy (Francese (Francia)):fr-FR:local", + "Sandy (Italiano (Italia)):it-IT:local", + "Sandy (Giapponese (Giappone)):ja-JP:local", + "Sandy (Coreano (Corea del Sud)):ko-KR:local", + "Sandy (Portoghese (Brasile)):pt-BR:local", + "Sandy (Cinese (Cina continentale)):zh-CN:local", + "Sandy (Cinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (Tedesco (Germania)):de-DE:local", + "Shelley (Inglese (UK)):en-GB:local", + "Shelley (Inglese (USA)):en-US:local", + "Shelley (Spagnolo (Spagna)):es-ES:local", + "Shelley (Spagnolo (Messico)):es-MX:local", + "Shelley (Finlandese (Finlandia)):fi-FI:local", + "Shelley (Francese (Canada)):fr-CA:local", + "Shelley (Francese (Francia)):fr-FR:local", + "Shelley (Italiano (Italia)):it-IT:local", + "Shelley (Giapponese (Giappone)):ja-JP:local", + "Shelley (Coreano (Corea del Sud)):ko-KR:local", + "Shelley (Portoghese (Brasile)):pt-BR:local", + "Shelley (Cinese (Cina continentale)):zh-CN:local", + "Shelley (Cinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Ting-Ting:zh-CN:local", + "Trinoid:en-US:local", + "Vani:ta-IN:local", + "Sussurro:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 30, + "availWidth": 1440, + "availHeight": 870, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1792, + "height": 1120, + "colorDepth": 30, + "availWidth": 1792, + "availHeight": 1010, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 960, + "height": 540, + "colorDepth": 30, + "availWidth": 960, + "availHeight": 528, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1152, + "colorDepth": 30, + "availWidth": 2048, + "availHeight": 1033, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 800, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel 945GM, or similar" + }, + "speechVoices": [ + "Alex:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amelie:fr-CA:local", + "Anna:de-DE:local", + "Carmit:he-IL:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Diego:es-AR:local", + "Ellen:nl-BE:local", + "Fiona:en-scotland:local", + "Fred:en-US:local", + "Ioana:ro-RO:local", + "Joana:pt-PT:local", + "Jorge:es-ES:local", + "Juan:es-MX:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kyoko:ja-JP:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Luca:it-IT:local", + "Luciana:pt-BR:local", + "Maged:ar-SA:local", + "Mariska:hu-HU:local", + "Mei-Jia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Monica:es-ES:local", + "Nora:nb-NO:local", + "Paulina:es-MX:local", + "Rishi:en-IN:local", + "Samantha:en-US:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Sin-ji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Ting-Ting:zh-CN:local", + "Veena:en-IN:local", + "Victoria:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Yuri:ru-RU:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1080, + "colorDepth": 24, + "availWidth": 2048, + "availHeight": 1080, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1512, + "height": 982, + "colorDepth": 30, + "availWidth": 1512, + "availHeight": 893, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1470, + "height": 956, + "colorDepth": 30, + "availWidth": 1470, + "availHeight": 880, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 18, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 30, + "availWidth": 2560, + "availHeight": 1410, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Ellen:nl-BE:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Rishi:en-IN:local", + "Samantha:en-US:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 30, + "availWidth": 1920, + "availHeight": 1055, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Malas noticias:en-US:local", + "Bahh:en-US:local", + "Campanas:en-US:local", + "Boing:en-US:local", + "Burbujas:en-US:local", + "Carmit:he-IL:local", + "Violonchelos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (Alemán (Alemania)):de-DE:local", + "Eddy (Inglés (RU)):en-GB:local", + "Eddy (Inglés (EE. UU.)):en-US:local", + "Eddy (Español (España)):es-ES:local", + "Eddy (Español (México)):es-MX:local", + "Eddy (Finés (Finlandia)):fi-FI:local", + "Eddy (Francés (Canadá)):fr-CA:local", + "Eddy (Francés (Francia)):fr-FR:local", + "Eddy (Italiano (Italia)):it-IT:local", + "Eddy (Portugués (Brasil)):pt-BR:local", + "Ellen:nl-BE:local", + "Flo (Alemán (Alemania)):de-DE:local", + "Flo (Inglés (RU)):en-GB:local", + "Flo (Inglés (EE. UU.)):en-US:local", + "Flo (Español (España)):es-ES:local", + "Flo (Español (México)):es-MX:local", + "Flo (Finés (Finlandia)):fi-FI:local", + "Flo (Francés (Canadá)):fr-CA:local", + "Flo (Francés (Francia)):fr-FR:local", + "Flo (Italiano (Italia)):it-IT:local", + "Flo (Portugués (Brasil)):pt-BR:local", + "Fred:en-US:local", + "Buenas noticias:en-US:local", + "Grandma (Alemán (Alemania)):de-DE:local", + "Grandma (Inglés (RU)):en-GB:local", + "Grandma (Inglés (EE. UU.)):en-US:local", + "Grandma (Español (España)):es-ES:local", + "Grandma (Español (México)):es-MX:local", + "Grandma (Finés (Finlandia)):fi-FI:local", + "Grandma (Francés (Canadá)):fr-CA:local", + "Grandma (Francés (Francia)):fr-FR:local", + "Grandma (Italiano (Italia)):it-IT:local", + "Grandma (Portugués (Brasil)):pt-BR:local", + "Grandpa (Alemán (Alemania)):de-DE:local", + "Grandpa (Inglés (RU)):en-GB:local", + "Grandpa (Inglés (EE. UU.)):en-US:local", + "Grandpa (Español (España)):es-ES:local", + "Grandpa (Español (México)):es-MX:local", + "Grandpa (Finés (Finlandia)):fi-FI:local", + "Grandpa (Francés (Canadá)):fr-CA:local", + "Grandpa (Francés (Francia)):fr-FR:local", + "Grandpa (Italiano (Italia)):it-IT:local", + "Grandpa (Portugués (Brasil)):pt-BR:local", + "Bufón:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Órgano:en-US:local", + "Paulina:es-MX:local", + "Superestrella:en-US:local", + "Ralph:en-US:local", + "Reed (Alemán (Alemania)):de-DE:local", + "Reed (Inglés (RU)):en-GB:local", + "Reed (Inglés (EE. UU.)):en-US:local", + "Reed (Español (España)):es-ES:local", + "Reed (Español (México)):es-MX:local", + "Reed (Finés (Finlandia)):fi-FI:local", + "Reed (Francés (Canadá)):fr-CA:local", + "Reed (Italiano (Italia)):it-IT:local", + "Reed (Portugués (Brasil)):pt-BR:local", + "Rishi:en-IN:local", + "Rocko (Alemán (Alemania)):de-DE:local", + "Rocko (Inglés (RU)):en-GB:local", + "Rocko (Inglés (EE. UU.)):en-US:local", + "Rocko (Español (España)):es-ES:local", + "Rocko (Español (México)):es-MX:local", + "Rocko (Finés (Finlandia)):fi-FI:local", + "Rocko (Francés (Canadá)):fr-CA:local", + "Rocko (Francés (Francia)):fr-FR:local", + "Rocko (Italiano (Italia)):it-IT:local", + "Rocko (Portugués (Brasil)):pt-BR:local", + "Samantha:en-US:local", + "Sandy (Alemán (Alemania)):de-DE:local", + "Sandy (Inglés (RU)):en-GB:local", + "Sandy (Inglés (EE. UU.)):en-US:local", + "Sandy (Español (España)):es-ES:local", + "Sandy (Español (México)):es-MX:local", + "Sandy (Finés (Finlandia)):fi-FI:local", + "Sandy (Francés (Canadá)):fr-CA:local", + "Sandy (Francés (Francia)):fr-FR:local", + "Sandy (Italiano (Italia)):it-IT:local", + "Sandy (Portugués (Brasil)):pt-BR:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (Alemán (Alemania)):de-DE:local", + "Shelley (Inglés (RU)):en-GB:local", + "Shelley (Inglés (EE. UU.)):en-US:local", + "Shelley (Español (España)):es-ES:local", + "Shelley (Español (México)):es-MX:local", + "Shelley (Finés (Finlandia)):fi-FI:local", + "Shelley (Francés (Canadá)):fr-CA:local", + "Shelley (Francés (Francia)):fr-FR:local", + "Shelley (Italiano (Italia)):it-IT:local", + "Shelley (Portugués (Brasil)):pt-BR:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Susurro:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 30, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1600, + "colorDepth": 30, + "availWidth": 2560, + "availHeight": 1480, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1728, + "height": 1117, + "colorDepth": 30, + "availWidth": 1728, + "availHeight": 1083, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 832, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 803, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Malas noticias:en-US:local", + "Bahh:en-US:local", + "Campanas:en-US:local", + "Boing:en-US:local", + "Burbujas:en-US:local", + "Carmit:he-IL:local", + "Violonchelos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (Alemán (Alemania)):de-DE:local", + "Eddy (Inglés (RU)):en-GB:local", + "Eddy (Inglés (EE. UU.)):en-US:local", + "Eddy (Español (España)):es-ES:local", + "Eddy (Español (México)):es-MX:local", + "Eddy (Finés (Finlandia)):fi-FI:local", + "Eddy (Francés (Canadá)):fr-CA:local", + "Eddy (Francés (Francia)):fr-FR:local", + "Eddy (Italiano (Italia)):it-IT:local", + "Eddy (Japonés (Japón)):ja-JP:local", + "Eddy (Coreano (Corea del Sur)):ko-KR:local", + "Eddy (Portugués (Brasil)):pt-BR:local", + "Eddy (Chino (China continental)):zh-CN:local", + "Eddy (Chino (Taiwán)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (Alemán (Alemania)):de-DE:local", + "Flo (Inglés (RU)):en-GB:local", + "Flo (Inglés (EE. UU.)):en-US:local", + "Flo (Español (España)):es-ES:local", + "Flo (Español (México)):es-MX:local", + "Flo (Finés (Finlandia)):fi-FI:local", + "Flo (Francés (Canadá)):fr-CA:local", + "Flo (Francés (Francia)):fr-FR:local", + "Flo (Italiano (Italia)):it-IT:local", + "Flo (Japonés (Japón)):ja-JP:local", + "Flo (Coreano (Corea del Sur)):ko-KR:local", + "Flo (Portugués (Brasil)):pt-BR:local", + "Flo (Chino (China continental)):zh-CN:local", + "Flo (Chino (Taiwán)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Buenas noticias:en-US:local", + "Grandma (Alemán (Alemania)):de-DE:local", + "Grandma (Inglés (RU)):en-GB:local", + "Grandma (Inglés (EE. UU.)):en-US:local", + "Grandma (Español (España)):es-ES:local", + "Grandma (Español (México)):es-MX:local", + "Grandma (Finés (Finlandia)):fi-FI:local", + "Grandma (Francés (Canadá)):fr-CA:local", + "Grandma (Francés (Francia)):fr-FR:local", + "Grandma (Italiano (Italia)):it-IT:local", + "Grandma (Japonés (Japón)):ja-JP:local", + "Grandma (Coreano (Corea del Sur)):ko-KR:local", + "Grandma (Portugués (Brasil)):pt-BR:local", + "Grandma (Chino (China continental)):zh-CN:local", + "Grandma (Chino (Taiwán)):zh-TW:local", + "Grandpa (Alemán (Alemania)):de-DE:local", + "Grandpa (Inglés (RU)):en-GB:local", + "Grandpa (Inglés (EE. UU.)):en-US:local", + "Grandpa (Español (España)):es-ES:local", + "Grandpa (Español (México)):es-MX:local", + "Grandpa (Finés (Finlandia)):fi-FI:local", + "Grandpa (Francés (Canadá)):fr-CA:local", + "Grandpa (Francés (Francia)):fr-FR:local", + "Grandpa (Italiano (Italia)):it-IT:local", + "Grandpa (Japonés (Japón)):ja-JP:local", + "Grandpa (Coreano (Corea del Sur)):ko-KR:local", + "Grandpa (Portugués (Brasil)):pt-BR:local", + "Grandpa (Chino (China continental)):zh-CN:local", + "Grandpa (Chino (Taiwán)):zh-TW:local", + "Bufón:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Órgano:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superestrella:en-US:local", + "Ralph:en-US:local", + "Reed (Alemán (Alemania)):de-DE:local", + "Reed (Inglés (RU)):en-GB:local", + "Reed (Inglés (EE. UU.)):en-US:local", + "Reed (Español (España)):es-ES:local", + "Reed (Español (México)):es-MX:local", + "Reed (Finés (Finlandia)):fi-FI:local", + "Reed (Francés (Canadá)):fr-CA:local", + "Reed (Italiano (Italia)):it-IT:local", + "Reed (Japonés (Japón)):ja-JP:local", + "Reed (Coreano (Corea del Sur)):ko-KR:local", + "Reed (Portugués (Brasil)):pt-BR:local", + "Reed (Chino (China continental)):zh-CN:local", + "Reed (Chino (Taiwán)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (Alemán (Alemania)):de-DE:local", + "Rocko (Inglés (RU)):en-GB:local", + "Rocko (Inglés (EE. UU.)):en-US:local", + "Rocko (Español (España)):es-ES:local", + "Rocko (Español (México)):es-MX:local", + "Rocko (Finés (Finlandia)):fi-FI:local", + "Rocko (Francés (Canadá)):fr-CA:local", + "Rocko (Francés (Francia)):fr-FR:local", + "Rocko (Italiano (Italia)):it-IT:local", + "Rocko (Japonés (Japón)):ja-JP:local", + "Rocko (Coreano (Corea del Sur)):ko-KR:local", + "Rocko (Portugués (Brasil)):pt-BR:local", + "Rocko (Chino (China continental)):zh-CN:local", + "Rocko (Chino (Taiwán)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (Alemán (Alemania)):de-DE:local", + "Sandy (Inglés (RU)):en-GB:local", + "Sandy (Inglés (EE. UU.)):en-US:local", + "Sandy (Español (España)):es-ES:local", + "Sandy (Español (México)):es-MX:local", + "Sandy (Finés (Finlandia)):fi-FI:local", + "Sandy (Francés (Canadá)):fr-CA:local", + "Sandy (Francés (Francia)):fr-FR:local", + "Sandy (Italiano (Italia)):it-IT:local", + "Sandy (Japonés (Japón)):ja-JP:local", + "Sandy (Coreano (Corea del Sur)):ko-KR:local", + "Sandy (Portugués (Brasil)):pt-BR:local", + "Sandy (Chino (China continental)):zh-CN:local", + "Sandy (Chino (Taiwán)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (Alemán (Alemania)):de-DE:local", + "Shelley (Inglés (RU)):en-GB:local", + "Shelley (Inglés (EE. UU.)):en-US:local", + "Shelley (Español (España)):es-ES:local", + "Shelley (Español (México)):es-MX:local", + "Shelley (Finés (Finlandia)):fi-FI:local", + "Shelley (Francés (Canadá)):fr-CA:local", + "Shelley (Francés (Francia)):fr-FR:local", + "Shelley (Italiano (Italia)):it-IT:local", + "Shelley (Japonés (Japón)):ja-JP:local", + "Shelley (Coreano (Corea del Sur)):ko-KR:local", + "Shelley (Portugués (Brasil)):pt-BR:local", + "Shelley (Chino (China continental)):zh-CN:local", + "Shelley (Chino (Taiwán)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Susurro:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1680, + "height": 1050, + "colorDepth": 30, + "availWidth": 1680, + "availHeight": 934, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:152.0) Gecko/20100101 Firefox/152.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 30, + "availWidth": 1920, + "availHeight": 1004, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 719, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + }, + "speechVoices": [ + "Alex:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amelie:fr-CA:local", + "Anna:de-DE:local", + "Carmit:he-IL:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Diego:es-AR:local", + "Ellen:nl-BE:local", + "Fiona:en-scotland:local", + "Fred:en-US:local", + "Ioana:ro-RO:local", + "Joana:pt-PT:local", + "Jorge:es-ES:local", + "Juan:es-MX:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kyoko:ja-JP:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Luca:it-IT:local", + "Luciana:pt-BR:local", + "Maged:ar-SA:local", + "Mariska:hu-HU:local", + "Mei-Jia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Monica:es-ES:local", + "Nora:nb-NO:local", + "Paulina:es-MX:local", + "Rishi:en-IN:local", + "Samantha:en-US:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Sin-ji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Ting-Ting:zh-CN:local", + "Veena:en-IN:local", + "Victoria:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Yuri:ru-RU:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 30, + "availWidth": 1920, + "availHeight": 984, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1710, + "height": 1112, + "colorDepth": 30, + "availWidth": 1710, + "availHeight": 1073, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman (English (India)):en-IN:local", + "Aman (English (India)):en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Yelda:tr-TR:local", + "Ioana:ro-RO:local", + "Yuna:ko-KR:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Krzysztof (Enhanced):pl-PL:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona ((null)):lt-LT:local", + "Ona ((null)):lt-LT:local", + "Organ:en-US:local", + "Piya:bn-IN:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 30, + "availWidth": 1440, + "availHeight": 824, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1680, + "height": 1050, + "colorDepth": 30, + "availWidth": 1680, + "availHeight": 974, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1080, + "colorDepth": 30, + "availWidth": 2048, + "availHeight": 1080, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "MacIntel", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1080, + "colorDepth": 30, + "availWidth": 2560, + "availHeight": 957, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + }, + "speechVoices": [ + "Alex:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amelie:fr-CA:local", + "Anna:de-DE:local", + "Carmit:he-IL:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Diego:es-AR:local", + "Ellen:nl-BE:local", + "Fiona:en-scotland:local", + "Fred:en-US:local", + "Ioana:ro-RO:local", + "Joana:pt-PT:local", + "Jorge:es-ES:local", + "Juan:es-MX:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kyoko:ja-JP:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Luca:it-IT:local", + "Luciana:pt-BR:local", + "Maged:ar-SA:local", + "Mariska:hu-HU:local", + "Mei-Jia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Monica:es-ES:local", + "Nora:nb-NO:local", + "Paulina:es-MX:local", + "Rishi:en-IN:local", + "Samantha:en-US:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Sin-ji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Ting-Ting:zh-CN:local", + "Veena:en-IN:local", + "Victoria:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Yuri:ru-RU:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 30, + "availWidth": 1440, + "availHeight": 900, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + }, + "speechVoices": [ + "Alex:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amelie:fr-CA:local", + "Anna:de-DE:local", + "Carmit:he-IL:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Diego:es-AR:local", + "Ellen:nl-BE:local", + "Fiona:en-scotland:local", + "Fred:en-US:local", + "Ioana:ro-RO:local", + "Joana:pt-PT:local", + "Jorge:es-ES:local", + "Juan:es-MX:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kyoko:ja-JP:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Luca:it-IT:local", + "Luciana:pt-BR:local", + "Maged:ar-SA:local", + "Mariska:hu-HU:local", + "Mei-Jia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Monica:es-ES:local", + "Nora:nb-NO:local", + "Paulina:es-MX:local", + "Rishi:en-IN:local", + "Samantha:en-US:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Sin-ji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Ting-Ting:zh-CN:local", + "Veena:en-IN:local", + "Victoria:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Yuri:ru-RU:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1024, + "height": 768, + "colorDepth": 30, + "availWidth": 1024, + "availHeight": 768, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2304, + "height": 1296, + "colorDepth": 30, + "availWidth": 2304, + "availHeight": 1266, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1512, + "height": 982, + "colorDepth": 30, + "availWidth": 1512, + "availHeight": 860, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1935, + "height": 1251, + "colorDepth": 30, + "availWidth": 1935, + "availHeight": 1160, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1710, + "height": 1112, + "colorDepth": 30, + "availWidth": 1710, + "availHeight": 1112, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1470, + "height": 956, + "colorDepth": 30, + "availWidth": 1470, + "availHeight": 849, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 30, + "availWidth": 1440, + "availHeight": 824, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2056, + "height": 1329, + "colorDepth": 30, + "availWidth": 2056, + "availHeight": 1285, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 30, + "availWidth": 1280, + "availHeight": 720, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel (English (UK)):en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 5120, + "height": 1440, + "colorDepth": 30, + "availWidth": 5120, + "availHeight": 1364, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Soumya:kn-IN:local", + "Alva:sv-SE:local", + "Aman:en-IN:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Aru:kk-KZ:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Geeta:te-IN:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Ona:lt-LT:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Piya:bn-IN:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tara:en-IN:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 960, + "colorDepth": 30, + "availWidth": 1536, + "availHeight": 935, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1800, + "height": 1169, + "colorDepth": 30, + "availWidth": 1800, + "availHeight": 1061, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 30, + "availWidth": 2560, + "availHeight": 1415, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2133, + "height": 1200, + "colorDepth": 30, + "availWidth": 2133, + "availHeight": 1179, + "devicePixelRatio": 2.4 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 30, + "availWidth": 1920, + "availHeight": 984, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel 945GM, or similar" + }, + "speechVoices": [ + "Alex:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amelie:fr-CA:local", + "Anna:de-DE:local", + "Carmit:he-IL:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Diego:es-AR:local", + "Ellen:nl-BE:local", + "Fiona:en-scotland:local", + "Fred:en-US:local", + "Ioana:ro-RO:local", + "Joana:pt-PT:local", + "Jorge:es-ES:local", + "Juan:es-MX:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kyoko:ja-JP:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Luca:it-IT:local", + "Luciana:pt-BR:local", + "Maged:ar-SA:local", + "Mariska:hu-HU:local", + "Mei-Jia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Monica:es-ES:local", + "Nora:nb-NO:local", + "Paulina:es-MX:local", + "Rishi:en-IN:local", + "Samantha:en-US:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Sin-ji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Ting-Ting:zh-CN:local", + "Veena:en-IN:local", + "Victoria:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Yuri:ru-RU:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1152, + "colorDepth": 30, + "availWidth": 2048, + "availHeight": 1026, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "ATI Technologies Inc.", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Vani:ta-IN:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 30, + "availWidth": 1366, + "availHeight": 670, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Inc.", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "MacIntel", + "hardwareConcurrency": 10, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1225, + "height": 797, + "colorDepth": 30, + "availWidth": 1225, + "availHeight": 765, + "devicePixelRatio": 2.4 + }, + "webgl": { + "unmaskedVendor": "Apple", + "unmaskedRenderer": "Apple M1, or similar" + }, + "speechVoices": [ + "Albert:en-US:local", + "Alice:it-IT:local", + "Alva:sv-SE:local", + "Amélie:fr-CA:local", + "Amira:ms-MY:local", + "Anna:de-DE:local", + "Bad News:en-US:local", + "Bahh:en-US:local", + "Bells:en-US:local", + "Boing:en-US:local", + "Bubbles:en-US:local", + "Carmit:he-IL:local", + "Cellos:en-US:local", + "Damayanti:id-ID:local", + "Daniel:en-GB:local", + "Daria:bg-BG:local", + "Wobble:en-US:local", + "Eddy (German (Germany)):de-DE:local", + "Eddy (English (UK)):en-GB:local", + "Eddy (English (US)):en-US:local", + "Eddy (Spanish (Spain)):es-ES:local", + "Eddy (Spanish (Mexico)):es-MX:local", + "Eddy (Finnish (Finland)):fi-FI:local", + "Eddy (French (Canada)):fr-CA:local", + "Eddy (French (France)):fr-FR:local", + "Eddy (Italian (Italy)):it-IT:local", + "Eddy (Japanese (Japan)):ja-JP:local", + "Eddy (Korean (South Korea)):ko-KR:local", + "Eddy (Portuguese (Brazil)):pt-BR:local", + "Eddy (Chinese (China mainland)):zh-CN:local", + "Eddy (Chinese (Taiwan)):zh-TW:local", + "Ellen:nl-BE:local", + "Flo (German (Germany)):de-DE:local", + "Flo (English (UK)):en-GB:local", + "Flo (English (US)):en-US:local", + "Flo (Spanish (Spain)):es-ES:local", + "Flo (Spanish (Mexico)):es-MX:local", + "Flo (Finnish (Finland)):fi-FI:local", + "Flo (French (Canada)):fr-CA:local", + "Flo (French (France)):fr-FR:local", + "Flo (Italian (Italy)):it-IT:local", + "Flo (Japanese (Japan)):ja-JP:local", + "Flo (Korean (South Korea)):ko-KR:local", + "Flo (Portuguese (Brazil)):pt-BR:local", + "Flo (Chinese (China mainland)):zh-CN:local", + "Flo (Chinese (Taiwan)):zh-TW:local", + "Fred:en-US:local", + "Good News:en-US:local", + "Grandma (German (Germany)):de-DE:local", + "Grandma (English (UK)):en-GB:local", + "Grandma (English (US)):en-US:local", + "Grandma (Spanish (Spain)):es-ES:local", + "Grandma (Spanish (Mexico)):es-MX:local", + "Grandma (Finnish (Finland)):fi-FI:local", + "Grandma (French (Canada)):fr-CA:local", + "Grandma (French (France)):fr-FR:local", + "Grandma (Italian (Italy)):it-IT:local", + "Grandma (Japanese (Japan)):ja-JP:local", + "Grandma (Korean (South Korea)):ko-KR:local", + "Grandma (Portuguese (Brazil)):pt-BR:local", + "Grandma (Chinese (China mainland)):zh-CN:local", + "Grandma (Chinese (Taiwan)):zh-TW:local", + "Grandpa (German (Germany)):de-DE:local", + "Grandpa (English (UK)):en-GB:local", + "Grandpa (English (US)):en-US:local", + "Grandpa (Spanish (Spain)):es-ES:local", + "Grandpa (Spanish (Mexico)):es-MX:local", + "Grandpa (Finnish (Finland)):fi-FI:local", + "Grandpa (French (Canada)):fr-CA:local", + "Grandpa (French (France)):fr-FR:local", + "Grandpa (Italian (Italy)):it-IT:local", + "Grandpa (Japanese (Japan)):ja-JP:local", + "Grandpa (Korean (South Korea)):ko-KR:local", + "Grandpa (Portuguese (Brazil)):pt-BR:local", + "Grandpa (Chinese (China mainland)):zh-CN:local", + "Grandpa (Chinese (Taiwan)):zh-TW:local", + "Jester:en-US:local", + "Ioana:ro-RO:local", + "Jacques:fr-FR:local", + "Joana:pt-PT:local", + "Junior:en-US:local", + "Kanya:th-TH:local", + "Karen:en-AU:local", + "Kathy:en-US:local", + "Kyoko:ja-JP:local", + "Lana:hr-HR:local", + "Laura:sk-SK:local", + "Lekha:hi-IN:local", + "Lesya:uk-UA:local", + "Linh:vi-VN:local", + "Luciana:pt-BR:local", + "Majed:ar-001:local", + "Tünde:hu-HU:local", + "Meijia:zh-TW:local", + "Melina:el-GR:local", + "Milena:ru-RU:local", + "Moira:en-IE:local", + "Mónica:es-ES:local", + "Montse:ca-ES:local", + "Nora:nb-NO:local", + "Organ:en-US:local", + "Paulina:es-MX:local", + "Superstar:en-US:local", + "Ralph:en-US:local", + "Reed (German (Germany)):de-DE:local", + "Reed (English (UK)):en-GB:local", + "Reed (English (US)):en-US:local", + "Reed (Spanish (Spain)):es-ES:local", + "Reed (Spanish (Mexico)):es-MX:local", + "Reed (Finnish (Finland)):fi-FI:local", + "Reed (French (Canada)):fr-CA:local", + "Reed (Italian (Italy)):it-IT:local", + "Reed (Japanese (Japan)):ja-JP:local", + "Reed (Korean (South Korea)):ko-KR:local", + "Reed (Portuguese (Brazil)):pt-BR:local", + "Reed (Chinese (China mainland)):zh-CN:local", + "Reed (Chinese (Taiwan)):zh-TW:local", + "Rishi:en-IN:local", + "Rocko (German (Germany)):de-DE:local", + "Rocko (English (UK)):en-GB:local", + "Rocko (English (US)):en-US:local", + "Rocko (Spanish (Spain)):es-ES:local", + "Rocko (Spanish (Mexico)):es-MX:local", + "Rocko (Finnish (Finland)):fi-FI:local", + "Rocko (French (Canada)):fr-CA:local", + "Rocko (French (France)):fr-FR:local", + "Rocko (Italian (Italy)):it-IT:local", + "Rocko (Japanese (Japan)):ja-JP:local", + "Rocko (Korean (South Korea)):ko-KR:local", + "Rocko (Portuguese (Brazil)):pt-BR:local", + "Rocko (Chinese (China mainland)):zh-CN:local", + "Rocko (Chinese (Taiwan)):zh-TW:local", + "Samantha:en-US:local", + "Sandy (German (Germany)):de-DE:local", + "Sandy (English (UK)):en-GB:local", + "Sandy (English (US)):en-US:local", + "Sandy (Spanish (Spain)):es-ES:local", + "Sandy (Spanish (Mexico)):es-MX:local", + "Sandy (Finnish (Finland)):fi-FI:local", + "Sandy (French (Canada)):fr-CA:local", + "Sandy (French (France)):fr-FR:local", + "Sandy (Italian (Italy)):it-IT:local", + "Sandy (Japanese (Japan)):ja-JP:local", + "Sandy (Korean (South Korea)):ko-KR:local", + "Sandy (Portuguese (Brazil)):pt-BR:local", + "Sandy (Chinese (China mainland)):zh-CN:local", + "Sandy (Chinese (Taiwan)):zh-TW:local", + "Sara:da-DK:local", + "Satu:fi-FI:local", + "Shelley (German (Germany)):de-DE:local", + "Shelley (English (UK)):en-GB:local", + "Shelley (English (US)):en-US:local", + "Shelley (Spanish (Spain)):es-ES:local", + "Shelley (Spanish (Mexico)):es-MX:local", + "Shelley (Finnish (Finland)):fi-FI:local", + "Shelley (French (Canada)):fr-CA:local", + "Shelley (French (France)):fr-FR:local", + "Shelley (Italian (Italy)):it-IT:local", + "Shelley (Japanese (Japan)):ja-JP:local", + "Shelley (Korean (South Korea)):ko-KR:local", + "Shelley (Portuguese (Brazil)):pt-BR:local", + "Shelley (Chinese (China mainland)):zh-CN:local", + "Shelley (Chinese (Taiwan)):zh-TW:local", + "Sinji:zh-HK:local", + "Tessa:en-ZA:local", + "Thomas:fr-FR:local", + "Tina:sl-SI:local", + "Tingting:zh-CN:local", + "Trinoids:en-US:local", + "Whisper:en-US:local", + "Xander:nl-NL:local", + "Yelda:tr-TR:local", + "Yuna:ko-KR:local", + "Zarvox:en-US:local", + "Zosia:pl-PL:local", + "Zuzana:cs-CZ:local" + ] + } + ], + "windows": [ + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 2 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1632, + "height": 918, + "colorDepth": 24, + "availWidth": 1632, + "availHeight": 918, + "devicePixelRatio": 1.17647058823529 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 864, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 768, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Tolga - Turkish (Turkey):tr-TR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1707, + "height": 1067, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 1019, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Naayf - Arabic (Saudi):ar-SA:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Irina - Russian (Russia):ru-RU:local", + "Microsoft Pavel - Russian (Russia):ru-RU:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Irina Desktop - Russian:ru-RU:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Hortense Desktop - French:fr-FR:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 1067, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 1027, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 5 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Jakub - Czech (Czech Republic):cs-CZ:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1040, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1152, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 20, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3840, + "height": 1080, + "colorDepth": 24, + "availWidth": 3840, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 5 + }, + "screen": { + "width": 1280, + "height": 853, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 805, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Caroline - French (Canada):fr-CA:local", + "Microsoft Claude - French (Canada):fr-CA:local", + "Microsoft Nathalie - French (Canada):fr-CA:local", + "Microsoft Daniel - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria - Portuguese (Brazil):pt-BR:local", + "Microsoft Irina - Russian (Russia):ru-RU:local", + "Microsoft Pavel - Russian (Russia):ru-RU:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local", + "Microsoft Maria Desktop - Portuguese(Brazil):pt-BR:local", + "Microsoft Irina Desktop - Russian:ru-RU:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1408, + "height": 792, + "colorDepth": 24, + "availWidth": 1408, + "availHeight": 748, + "devicePixelRatio": 1.36363636363636 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1728, + "height": 972, + "colorDepth": 24, + "availWidth": 1728, + "availHeight": 921, + "devicePixelRatio": 1.11111111111111 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 960, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 920, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Heami - Korean (Korean):ko-KR:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Heami Desktop - Korean:ko-KR:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1718, + "height": 1277, + "colorDepth": 24, + "availWidth": 1718, + "availHeight": 1277, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Mozilla", + "unmaskedRenderer": "Mozilla" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1472, + "height": 828, + "colorDepth": 24, + "availWidth": 1472, + "availHeight": 791, + "devicePixelRatio": 1.30434782608696 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Daniel - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria Desktop - Portuguese(Brazil):pt-BR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 1024, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 984, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1680, + "height": 1050, + "colorDepth": 24, + "availWidth": 1680, + "availHeight": 1002, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 1 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 852, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Hoda - Arabic (Egypt):ar-EG:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Cosimo - Italian (Italy):it-IT:local", + "Microsoft Elsa - Italian (Italy):it-IT:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Hortense Desktop - French:fr-FR:local", + "Microsoft Elsa Desktop - Italian (Italy):it-IT:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1392, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 960, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 912, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Microsoft)", + "unmaskedRenderer": "ANGLE (Microsoft, Microsoft Basic Render Driver Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1451, + "height": 907, + "colorDepth": 24, + "availWidth": 1451, + "availHeight": 907, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1600, + "height": 900, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 840, + "devicePixelRatio": 1.2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1600, + "height": 900, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 900, + "devicePixelRatio": 1.2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 1 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1392, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 800, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1600, + "height": 1000, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 940, + "devicePixelRatio": 1.2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 24, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2293, + "height": 960, + "colorDepth": 24, + "availWidth": 2293, + "availHeight": 912, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Ivan - Bulgarian (Bulgaria):bg-BG:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 720, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Daniel - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria Desktop - Portuguese(Brazil):pt-BR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 752, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1664, + "height": 936, + "colorDepth": 24, + "availWidth": 1664, + "availHeight": 894, + "devicePixelRatio": 1.15384615384615 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_4_0 ps_4_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1360, + "height": 768, + "colorDepth": 24, + "availWidth": 1360, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Microsoft)", + "unmaskedRenderer": "ANGLE (Microsoft, Microsoft Basic Render Driver Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:151.0) Gecko/20100101 Firefox/151.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 720, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 860, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Richard - English (Canada):en-CA:local", + "Microsoft Linda - English (Canada):en-CA:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1344, + "height": 756, + "colorDepth": 24, + "availWidth": 1344, + "availHeight": 714, + "devicePixelRatio": 1.42857142857143 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Ravi - English (India):en-IN:local", + "Microsoft Heera - English (India):en-IN:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1504, + "height": 846, + "colorDepth": 24, + "availWidth": 1504, + "availHeight": 846, + "devicePixelRatio": 1.27659574468085 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3456, + "height": 1440, + "colorDepth": 24, + "availWidth": 3456, + "availHeight": 1392, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Microsoft)", + "unmaskedRenderer": "ANGLE (Microsoft, Microsoft Basic Render Driver Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 960, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 960, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Heera - English (India):en-IN:local", + "Microsoft Ravi - English (India):en-IN:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1040, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_1 ps_4_1), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 960, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 912, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 900, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1278, + "height": 852, + "colorDepth": 24, + "availWidth": 1278, + "availHeight": 805, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Hortense Desktop - French:fr-FR:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 22, + "maxTouchPoints": 10 + }, + "screen": { + "width": 2293, + "height": 960, + "colorDepth": 24, + "availWidth": 2293, + "availHeight": 912, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1792, + "height": 1008, + "colorDepth": 24, + "availWidth": 1792, + "availHeight": 1008, + "devicePixelRatio": 2.14285714285714 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Irina - Russian (Russia):ru-RU:local", + "Microsoft Pavel - Russian (Russia):ru-RU:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Irina Desktop - Russian:ru-RU:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 1 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1600, + "height": 1000, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 952, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Adam - Polish (Poland):pl-PL:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Paulina - Polish (Poland):pl-PL:local", + "Microsoft Paulina Desktop - Polish:pl-PL:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1160, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1216, + "height": 684, + "colorDepth": 24, + "availWidth": 1216, + "availHeight": 646, + "devicePixelRatio": 1.57894736842105 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helia - Portuguese (Portugal):pt-PT:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 20, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3440, + "height": 1440, + "colorDepth": 24, + "availWidth": 3440, + "availHeight": 1392, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0 AtContent/93.5.6604.5", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 834, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 752, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1451, + "height": 907, + "colorDepth": 24, + "availWidth": 1451, + "availHeight": 859, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Hortense Desktop - French:fr-FR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1536, + "height": 1024, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 984, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1440, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 20, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1080, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1088, + "height": 614, + "colorDepth": 24, + "availWidth": 1088, + "availHeight": 566, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 40 + }, + "screen": { + "width": 1360, + "height": 768, + "colorDepth": 24, + "availWidth": 1360, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Ravi - English (India):en-IN:local", + "Microsoft Heera - English (India):en-IN:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2176, + "height": 1224, + "colorDepth": 24, + "availWidth": 2176, + "availHeight": 1176, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Daniel - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria - Portuguese (Brazil):pt-BR:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Maria Desktop - Portuguese(Brazil):pt-BR:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 20, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 960, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 912, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1500, + "height": 1000, + "colorDepth": 24, + "availWidth": 1500, + "availHeight": 952, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2112, + "height": 1320, + "colorDepth": 24, + "availWidth": 2112, + "availHeight": 1320, + "devicePixelRatio": 1.36363636363636 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Stefanos - Greek (Greece):el-GR:local", + "Microsoft Tolga - Turkish (Turkey):tr-TR:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1824, + "height": 1026, + "colorDepth": 24, + "availWidth": 1824, + "availHeight": 980, + "devicePixelRatio": 1.05263157894737 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Heera - English (India):en-IN:local", + "Microsoft Ravi - English (India):en-IN:local", + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Hortense Desktop - French:fr-FR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 5120, + "height": 1440, + "colorDepth": 24, + "availWidth": 5120, + "availHeight": 1440, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 1067, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 1019, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1440, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1392, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 1 + }, + "screen": { + "width": 1600, + "height": 900, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 900, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 24, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1392, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 22, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1296, + "height": 810, + "colorDepth": 24, + "availWidth": 1296, + "availHeight": 810, + "devicePixelRatio": 2.22222222222222 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Richard - English (Canada):en-CA:local", + "Microsoft Linda - English (Canada):en-CA:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 852, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 20, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1360, + "height": 768, + "colorDepth": 24, + "availWidth": 1360, + "availHeight": 720, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 852, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 852, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1299, + "availHeight": 768, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_1 ps_4_1), or similar" + }, + "speechVoices": [ + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1088, + "height": 612, + "colorDepth": 24, + "availWidth": 1088, + "availHeight": 564, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Heami - Korean (Korean):ko-KR:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Heami Desktop - Korean:ko-KR:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 10 + }, + "screen": { + "width": 2560, + "height": 1080, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1152, + "colorDepth": 24, + "availWidth": 2048, + "availHeight": 1112, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1707, + "height": 1067, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 1019, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:151.0) Gecko/20100101 Firefox/151.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 720, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 5 + }, + "screen": { + "width": 2731, + "height": 768, + "colorDepth": 24, + "availWidth": 2731, + "availHeight": 730, + "devicePixelRatio": 1.875 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Jakub - Czech (Czech Republic):cs-CZ:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1680, + "height": 1050, + "colorDepth": 24, + "availWidth": 1680, + "availHeight": 1010, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_4_0 ps_4_0), or similar" + }, + "speechVoices": [ + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3840, + "height": 1600, + "colorDepth": 24, + "availWidth": 3840, + "availHeight": 1552, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1152, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 720, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_1 ps_4_1), or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2176, + "height": 1224, + "colorDepth": 24, + "availWidth": 2176, + "availHeight": 1224, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Irina - Russian (Russia):ru-RU:local", + "Microsoft Pavel - Russian (Russia):ru-RU:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Irina Desktop - Russian:ru-RU:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Cosimo - Italian (Italy):it-IT:local", + "Microsoft Elsa - Italian (Italy):it-IT:local", + "Microsoft Elsa Desktop - Italian (Italy):it-IT:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 22, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 752, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1093, + "height": 614, + "colorDepth": 24, + "availWidth": 1093, + "availHeight": 566, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 768, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 5850 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 720, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1184, + "height": 666, + "colorDepth": 24, + "availWidth": 1184, + "availHeight": 629, + "devicePixelRatio": 1.62162162162162 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 22, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 1067, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 1019, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 864, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 24, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 960, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 920, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 1 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 1 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Guillaume - French (Switzerland):fr-CH:local", + "Microsoft Karsten - German (Switzerland):de-CH:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Hortense Desktop - French:fr-FR:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1152, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1760, + "height": 990, + "colorDepth": 24, + "availWidth": 1760, + "availHeight": 953, + "devicePixelRatio": 1.09090909090909 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Hedda Desktop - German:de-DE:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1696, + "height": 954, + "colorDepth": 24, + "availWidth": 1696, + "availHeight": 901, + "devicePixelRatio": 1.13207547169811 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 5 + }, + "screen": { + "width": 1536, + "height": 960, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 912, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 5 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Irina - Russian (Russia):ru-RU:local", + "Microsoft Pavel - Russian (Russia):ru-RU:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Irina Desktop - Russian:ru-RU:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 1 + }, + "screen": { + "width": 1728, + "height": 972, + "colorDepth": 24, + "availWidth": 1728, + "availHeight": 929, + "devicePixelRatio": 1.11111111111111 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Hortense Desktop - French:fr-FR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1696, + "height": 954, + "colorDepth": 24, + "availWidth": 1696, + "availHeight": 954, + "devicePixelRatio": 1.13207547169811 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1504, + "height": 846, + "colorDepth": 24, + "availWidth": 1504, + "availHeight": 846, + "devicePixelRatio": 1.27659574468085 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 28, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1200, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 22, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1440, + "height": 900, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 852, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft David Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Richard - English (Canada):en-CA:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Linda - English (Canada):en-CA:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Caroline - French (Canada):fr-CA:local", + "Microsoft Claude - French (Canada):fr-CA:local", + "Microsoft Nathalie - French (Canada):fr-CA:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1343, + "height": 755, + "colorDepth": 24, + "availWidth": 1343, + "availHeight": 726, + "devicePixelRatio": 1.01694915254237 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 1024, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 984, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1152, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3440, + "height": 1440, + "colorDepth": 24, + "availWidth": 3440, + "availHeight": 1392, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1152, + "colorDepth": 24, + "availWidth": 2048, + "availHeight": 1122, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena Mobile - Spanish (Spain):es-ES:local", + "Microsoft Laura Mobile - Spanish (Spain):es-ES:local", + "Microsoft Pablo Mobile - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1138, + "height": 640, + "colorDepth": 24, + "availWidth": 1138, + "availHeight": 600, + "devicePixelRatio": 1.2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1184, + "height": 666, + "colorDepth": 24, + "availWidth": 1184, + "availHeight": 666, + "devicePixelRatio": 1.62162162162162 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Stefanos - Greek (Greece):el-GR:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 752, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Unknown)", + "unmaskedRenderer": "ANGLE (Unknown, Generic Renderer Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Hortense Desktop - French:fr-FR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 752, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Karsten - German (Switzerland):de-CH:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Guillaume - French (Switzerland):fr-CH:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1680, + "height": 1050, + "colorDepth": 24, + "availWidth": 1680, + "availHeight": 1010, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 720, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Unknown)", + "unmaskedRenderer": "ANGLE (Unknown, Adreno (TM) 650 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 752, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Jon - Norwegian (Bokmål):nb-NO:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1040, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Microsoft)", + "unmaskedRenderer": "ANGLE (Microsoft, Microsoft Basic Render Driver Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Hortense Desktop - French:fr-FR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 5120, + "height": 1440, + "colorDepth": 24, + "availWidth": 5120, + "availHeight": 1392, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2049, + "height": 1152, + "colorDepth": 24, + "availWidth": 2049, + "availHeight": 1092, + "devicePixelRatio": 0.666666666666667 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1600, + "height": 900, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 860, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 1 + }, + "screen": { + "width": 1707, + "height": 1067, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 1019, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 14, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1408, + "height": 880, + "colorDepth": 24, + "availWidth": 1408, + "availHeight": 827, + "devicePixelRatio": 1.36363636363636 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1680, + "height": 1050, + "colorDepth": 24, + "availWidth": 1680, + "availHeight": 1010, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3440, + "height": 1440, + "colorDepth": 24, + "availWidth": 3440, + "availHeight": 1400, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 22, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1600, + "height": 1000, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 952, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3840, + "height": 1080, + "colorDepth": 24, + "availWidth": 3840, + "availHeight": 1032, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Karsten - German (Switzerland):de-CH:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Guillaume - French (Switzerland):fr-CH:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 720, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Microsoft)", + "unmaskedRenderer": "ANGLE (Microsoft, Microsoft Basic Render Driver Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 960, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 912, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1152, + "colorDepth": 24, + "availWidth": 2048, + "availHeight": 1112, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Szabolcs - Hungarian (Hungary):hu-HU:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Andika - Indonesian (Indonesia):id-ID:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1504, + "height": 1003, + "colorDepth": 24, + "availWidth": 1504, + "availHeight": 1003, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1440, + "height": 960, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 912, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Unknown)", + "unmaskedRenderer": "ANGLE (Unknown, Generic Renderer Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_0 ps_4_0), or similar" + }, + "speechVoices": [ + "Microsoft Raul - Spanish (Mexico):es-MX:local", + "Microsoft Sabina - Spanish (Mexico):es-MX:local", + "Microsoft Sabina Desktop - Spanish (Mexico):es-MX:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 816, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Unknown)", + "unmaskedRenderer": "ANGLE (Unknown, Adreno (TM) 650 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Daniel - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria Desktop - Portuguese(Brazil):pt-BR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 752, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) Arc(TM) A750 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Hortense Desktop - French:fr-FR:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1536, + "height": 960, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 912, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 20, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3096, + "height": 1296, + "colorDepth": 24, + "availWidth": 3096, + "availHeight": 1248, + "devicePixelRatio": 1.11111111111111 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 1 + }, + "screen": { + "width": 2859, + "height": 1608, + "colorDepth": 24, + "availWidth": 2859, + "availHeight": 1608, + "devicePixelRatio": 0.895522388059702 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Michael - German (Austria):de-AT:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1275, + "height": 717, + "colorDepth": 24, + "availWidth": 1275, + "availHeight": 672, + "devicePixelRatio": 1.07142857142857 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1392, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1525, + "height": 858, + "colorDepth": 24, + "availWidth": 1525, + "availHeight": 858, + "devicePixelRatio": 0.895522388059702 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1088, + "height": 612, + "colorDepth": 24, + "availWidth": 1088, + "availHeight": 578, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Cosimo - Italian (Italy):it-IT:local", + "Microsoft Stefanos - Greek (Greece):el-GR:local", + "Microsoft Elsa - Italian (Italy):it-IT:local", + "Microsoft Elsa Desktop - Italian (Italy):it-IT:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 672, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 960, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 920, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Hedda - German (Germany):de-DE:local", + "Microsoft Naayf - Arabic (Saudi):ar-SA:local", + "Microsoft Katja - German (Germany):de-DE:local", + "Microsoft Stefan - German (Germany):de-DE:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Hortense - French (France):fr-FR:local", + "Microsoft Julie - French (France):fr-FR:local", + "Microsoft Paul - French (France):fr-FR:local", + "Microsoft Adam - Polish (Poland):pl-PL:local", + "Microsoft Paulina - Polish (Poland):pl-PL:local", + "Microsoft Irina - Russian (Russia):ru-RU:local", + "Microsoft Pavel - Russian (Russia):ru-RU:local", + "Microsoft Tolga - Turkish (Turkey):tr-TR:local", + "Microsoft Hedda Desktop - German:de-DE:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Hortense Desktop - French:fr-FR:local", + "Microsoft Paulina Desktop - Polish:pl-PL:local", + "Microsoft Irina Desktop - Russian:ru-RU:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 10 + }, + "screen": { + "width": 2144, + "height": 1340, + "colorDepth": 24, + "availWidth": 2144, + "availHeight": 1307, + "devicePixelRatio": 0.895522388059702 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft James - English (Australia):en-AU:local", + "Microsoft Catherine - English (Australia):en-AU:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1248, + "height": 702, + "colorDepth": 24, + "availWidth": 1248, + "availHeight": 663, + "devicePixelRatio": 1.53846153846154 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3440, + "height": 1440, + "colorDepth": 24, + "availWidth": 3440, + "availHeight": 1392, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1400, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Daniel - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria - Portuguese (Brazil):pt-BR:local", + "Microsoft Maria Desktop - Portuguese(Brazil):pt-BR:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 800, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 752, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (AMD)", + "unmaskedRenderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Hoda - Arabic (Egypt):ar-EG:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 2, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1504, + "height": 1003, + "colorDepth": 24, + "availWidth": 1504, + "availHeight": 1003, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Karsten - German (Switzerland):de-CH:local", + "Microsoft George - English (United Kingdom):en-GB:local", + "Microsoft Hazel - English (United Kingdom):en-GB:local", + "Microsoft Susan - English (United Kingdom):en-GB:local", + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Hazel Desktop - English (Great Britain):en-GB:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 28, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1600, + "height": 1200, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 1152, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Richard - English (Canada):en-CA:local", + "Microsoft Linda - English (Canada):en-CA:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1040, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (NVIDIA)", + "unmaskedRenderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Helena - Spanish (Spain):es-ES:local", + "Microsoft Laura - Spanish (Spain):es-ES:local", + "Microsoft Pablo - Spanish (Spain):es-ES:local", + "Microsoft Helena Desktop - Spanish (Spain):es-ES:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1408, + "height": 792, + "colorDepth": 24, + "availWidth": 1408, + "availHeight": 748, + "devicePixelRatio": 1.36363636363636 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 14, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1152, + "colorDepth": 24, + "availWidth": 2048, + "availHeight": 1104, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft David - English (United States):en-US:local", + "Microsoft Mark - English (United States):en-US:local", + "Microsoft Zira - English (United States):en-US:local", + "Microsoft David Desktop - English (United States):en-US:local", + "Microsoft Zira Desktop - English (United States):en-US:local" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Win32", + "hardwareConcurrency": 8, + "maxTouchPoints": 10 + }, + "screen": { + "width": 1088, + "height": 612, + "colorDepth": 24, + "availWidth": 1088, + "availHeight": 571, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Google Inc. (Intel)", + "unmaskedRenderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar" + }, + "speechVoices": [ + "Microsoft Szabolcs - Hungarian (Hungary):hu-HU:local", + "Microsoft Irina - Russian (Russia):ru-RU:local", + "Microsoft Pavel - Russian (Russia):ru-RU:local", + "Microsoft Zira Desktop - English (United States):en-US:local", + "Microsoft Irina Desktop - Russian:ru-RU:local" + ] + } + ], + "linux": [ + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce 8800 GTX, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1200, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 864, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1600, + "height": 900, + "colorDepth": 24, + "availWidth": 1575, + "availHeight": 880, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 768, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:152.0) Gecko/20100101 Firefox/152.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1440, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1760, + "height": 990, + "colorDepth": 24, + "availWidth": 1760, + "availHeight": 990, + "devicePixelRatio": 1.09090909090909 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1400, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 768, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 32, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3840, + "height": 2160, + "colorDepth": 24, + "availWidth": 3840, + "availHeight": 2160, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce GTX 980, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 712, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 864, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 864, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 864, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 6, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 5120, + "height": 1440, + "colorDepth": 24, + "availWidth": 5120, + "availHeight": 1408, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce GTX 980, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1368, + "height": 768, + "colorDepth": 24, + "availWidth": 1368, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Mesa", + "unmaskedRenderer": "GeForce 8800 GTX, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1408, + "height": 792, + "colorDepth": 24, + "availWidth": 1408, + "availHeight": 792, + "devicePixelRatio": 1.36363636363636 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 717, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Open Source Technology Center", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + }, + "speechVoices": [ + "Catalan:ca:remote", + "Bishnupriya Manipuri:bpy:remote", + "Nahuatl (Classical):nci:remote", + "Dutch:nl:remote", + "Azerbaijani:az:remote", + "Kyrgyz:ky:remote", + "English (Great Britain):en:remote", + "Chinese (Cantonese):yue:remote", + "English (Lancaster):en:remote", + "Vietnamese (Northern):vi:remote", + "Amharic:am:remote", + "Gaelic (Irish):ga:remote", + "Latvian:lv:remote", + "Swahili:sw:remote", + "Afrikaans:af:remote", + "Malay:ms:remote", + "Tatar:tt:remote", + "Nepali:ne:remote", + "Serbian:sr:remote", + "Oriya:or:remote", + "Arabic:ar:remote", + "Interlingua:ia:remote", + "Italian:it:remote", + "Aragonese:an:remote", + "German:de:remote", + "Assamese:as:remote", + "Bengali:bn:remote", + "Georgian:ka:remote", + "Lithuanian:lt:remote", + "Danish:da:remote", + "English (Caribbean):en:remote", + "Papiamento:pap:remote", + "Chinese (Mandarin):cmn:remote", + "Bosnian:bs:remote", + "Guarani:gn:remote", + "Marathi:mr:remote", + "Persian:fa:remote", + "Hindi:hi:remote", + "Bulgarian:bg:remote", + "Lingua Franca Nova:lfn:remote", + "Hungarian:hu:remote", + "Icelandic:is:remote", + "Burmese:my:remote", + "Maltese:mt:remote", + "Esperanto:eo:remote", + "Portuguese (Portugal):pt:remote", + "Spanish (Spain):es:remote", + "Kurdish:ku:remote", + "Lojban:jbo:remote", + "Czech:cs:remote", + "Turkish:tr:remote", + "Tamil:ta:remote", + "Spanish (Latin America):es:remote", + "Indonesian:id:remote", + "Armenian (West Armenia):hy:remote", + "Kannada:kn:remote", + "Greek (Ancient):grc:remote", + "Armenian (East Armenia):hy:remote", + "Greenlandic:kl:remote", + "French (Switzerland):fr:remote", + "Norwegian Bokmål:nb:remote", + "Portuguese (Brazil):pt:remote", + "Urdu:ur:remote", + "Punjabi:pa:remote", + "Japanese:ja:remote", + "Romanian:ro:remote", + "Gujarati:gu:remote", + "Latin:la:remote", + "Polish:pl:remote", + "French (France):fr:remote", + "Slovenian:sl:remote", + "Malayalam:ml:remote", + "Russian:ru:remote", + "Croatian:hr:remote", + "Korean:ko:remote", + "Welsh:cy:remote", + "Slovak:sk:remote", + "poz/mi:mi:remote", + "English (Scotland):en:remote", + "Vietnamese (Southern):vi:remote", + "English (West Midlands):en:remote", + "Persian (Pinglish):fa:remote", + "Albanian:sq:remote", + "Finnish:fi:remote", + "English (Received Pronunciation):en:remote", + "Greek:el:remote", + "French (Belgium):fr:remote", + "Gaelic (Scottish):gd:remote", + "Telugu:te:remote", + "Konkani:kok:remote", + "Sindhi:sd:remote", + "Estonian:et:remote", + "Basque:eu:remote", + "Oromo:om:remote", + "English (America):en:remote", + "Swedish:sv:remote", + "Macedonian:mk:remote", + "Setswana:tn:remote", + "Sinhala:si:remote", + "Vietnamese (Central):vi:remote" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1760, + "height": 990, + "colorDepth": 24, + "availWidth": 1760, + "availHeight": 990, + "devicePixelRatio": 1.09090909090909 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 728, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1440, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1664, + "height": 936, + "colorDepth": 24, + "availWidth": 1664, + "availHeight": 936, + "devicePixelRatio": 1.15384615384615 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 768, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 718, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel Open Source Technology Center", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 24, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3072, + "height": 1728, + "colorDepth": 24, + "availWidth": 3072, + "availHeight": 1728, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce 8800 GTX, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 768, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 24, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2048, + "height": 1152, + "colorDepth": 24, + "availWidth": 2048, + "availHeight": 1152, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 2 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3440, + "height": 1440, + "colorDepth": 24, + "availWidth": 3440, + "availHeight": 1440, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Mesa", + "unmaskedRenderer": "llvmpipe, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 28, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3840, + "height": 1080, + "colorDepth": 24, + "availWidth": 3840, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce GTX 980, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1600, + "height": 900, + "colorDepth": 24, + "availWidth": 1600, + "availHeight": 900, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + }, + "speechVoices": [ + "en_US-ryan-high:en-US:remote" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce GTX 980, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1200, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1680, + "height": 1050, + "colorDepth": 24, + "availWidth": 1680, + "availHeight": 1050, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1200, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1200, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1620, + "height": 1080, + "colorDepth": 24, + "availWidth": 1620, + "availHeight": 1080, + "devicePixelRatio": 1.33333333333333 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 720, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 22, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1088, + "height": 612, + "colorDepth": 24, + "availWidth": 1088, + "availHeight": 612, + "devicePixelRatio": 1.76470588235294 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3840, + "height": 1080, + "colorDepth": 24, + "availWidth": 3840, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Mesa", + "unmaskedRenderer": "llvmpipe, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1280, + "height": 720, + "colorDepth": 24, + "availWidth": 1280, + "availHeight": 720, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1440, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce GTX 980, or similar" + }, + "speechVoices": [ + "virginie:fr-FR:remote", + "isabel:es-ES:remote", + "serena:en-GB:remote", + "samantha:en-US:remote", + "sabrina:de-DE:remote", + "silvia:it-IT:remote" + ] + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 22, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 960, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 960, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 712, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1760, + "height": 990, + "colorDepth": 24, + "availWidth": 1760, + "availHeight": 953, + "devicePixelRatio": 1.09090909090909 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce GTX 980, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1536, + "availHeight": 864, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 3200, + "height": 1800, + "colorDepth": 24, + "availWidth": 3200, + "availHeight": 1800, + "devicePixelRatio": 1.2 + }, + "webgl": { + "unmaskedVendor": "NVIDIA Corporation", + "unmaskedRenderer": "NVIDIA GeForce GTX 980, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 12, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1862, + "availHeight": 1048, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon R9 200 Series, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1707, + "height": 960, + "colorDepth": 24, + "availWidth": 1707, + "availHeight": 960, + "devicePixelRatio": 1.5 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1440, + "height": 810, + "colorDepth": 24, + "availWidth": 1440, + "availHeight": 810, + "devicePixelRatio": 1.33333333333333 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 2, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1366, + "availHeight": 735, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Mesa", + "unmaskedRenderer": "Radeon HD 5850, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 2560, + "height": 1440, + "colorDepth": 24, + "availWidth": 2560, + "availHeight": 1413, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 4, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1525, + "height": 858, + "colorDepth": 24, + "availWidth": 1525, + "availHeight": 813, + "devicePixelRatio": 0.895522388059702 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1536, + "height": 864, + "colorDepth": 24, + "availWidth": 1483, + "availHeight": 832, + "devicePixelRatio": 1.25 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 8, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1366, + "height": 768, + "colorDepth": 24, + "availWidth": 1296, + "availHeight": 741, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "Intel", + "unmaskedRenderer": "Intel(R) HD Graphics 400, or similar" + } + }, + { + "navigator": { + "userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0", + "platform": "Linux x86_64", + "hardwareConcurrency": 16, + "maxTouchPoints": 0 + }, + "screen": { + "width": 1920, + "height": 1080, + "colorDepth": 24, + "availWidth": 1920, + "availHeight": 1080, + "devicePixelRatio": 1 + }, + "webgl": { + "unmaskedVendor": "AMD", + "unmaskedRenderer": "Radeon HD 3200 Graphics, or similar" + } + } + ] + } +} \ No newline at end of file diff --git a/pythonlib/camoufox/fingerprints.py b/pythonlib/camoufox/fingerprints.py index 716d37f..9a138ad 100644 --- a/pythonlib/camoufox/fingerprints.py +++ b/pythonlib/camoufox/fingerprints.py @@ -22,7 +22,10 @@ FP_GENERATOR = FingerprintGenerator(browser='firefox', os=('linux', 'macos', 'wi # Bundled real fingerprint presets PRESETS_FILE = Path(__file__).parent / 'fingerprint-presets.json' -_PRESETS_CACHE: Optional[Dict] = None +PRESETS_V150_FILE = Path(__file__).parent / 'fingerprint-presets-v150.json' +# Firefox major version at which the v150 preset bundle becomes preferred. +PRESETS_V150_MIN_FF = 149 +_PRESETS_CACHE: Dict[Path, Dict] = {} # CreepJS OS marker fonts used for OS detection _MACOS_MARKER_FONTS = [ @@ -184,16 +187,32 @@ def _generate_random_voice_subset(target_os: str) -> List[str]: return result -def load_presets() -> Optional[Dict]: +def _select_presets_file(ff_version: Optional[Any] = None) -> Path: + """Pick the bundled-presets file appropriate for a given Firefox version. + + For Firefox >= PRESETS_V150_MIN_FF, prefer the v150 bundle (real + fingerprints scraped from contemporary browsers); otherwise fall back to + the original bundle. + """ + try: + major = int(str(ff_version).split('.', 1)[0]) if ff_version else 0 + except (ValueError, TypeError): + major = 0 + if major >= PRESETS_V150_MIN_FF and PRESETS_V150_FILE.exists(): + return PRESETS_V150_FILE + return PRESETS_FILE + + +def load_presets(ff_version: Optional[Any] = None) -> Optional[Dict]: """Load bundled fingerprint presets from JSON file.""" - global _PRESETS_CACHE - if _PRESETS_CACHE is not None: - return _PRESETS_CACHE - if not PRESETS_FILE.exists(): + path = _select_presets_file(ff_version) + if path in _PRESETS_CACHE: + return _PRESETS_CACHE[path] + if not path.exists(): return None - with open(PRESETS_FILE) as f: - _PRESETS_CACHE = json.load(f) - return _PRESETS_CACHE + with open(path) as f: + _PRESETS_CACHE[path] = json.load(f) + return _PRESETS_CACHE[path] # Map OS names to preset keys @@ -209,12 +228,13 @@ _OS_TO_PRESET_KEY = { def get_random_preset( os: Optional[str] = None, + ff_version: Optional[Any] = None, ) -> Optional[Dict]: """ Get a random preset for the given OS. Returns None if no presets are available. """ - presets = load_presets() + presets = load_presets(ff_version) if not presets: return None diff --git a/pythonlib/camoufox/utils.py b/pythonlib/camoufox/utils.py index 2dab6d5..f95fbdb 100644 --- a/pythonlib/camoufox/utils.py +++ b/pythonlib/camoufox/utils.py @@ -591,7 +591,7 @@ def launch_options( if isinstance(fingerprint_preset, dict): preset = fingerprint_preset else: - preset = get_random_preset(os=os) + preset = get_random_preset(os=os, ff_version=ff_version_str) if preset: merge_into(config, from_preset(preset, ff_version_str)) _used_preset = True diff --git a/scripts/_mixin.py b/scripts/_mixin.py index a4eab56..456da3d 100644 --- a/scripts/_mixin.py +++ b/scripts/_mixin.py @@ -58,7 +58,7 @@ def get_moz_target(target, arch): if target == "linux": return "aarch64-unknown-linux-gnu" if arch == "arm64" else f"{arch}-pc-linux-gnu" if target == "windows": - return f"{arch}-pc-mingw32" + return f"{arch}-pc-windows-msvc" if target == "macos": return "aarch64-apple-darwin" if arch == "arm64" else f"{arch}-apple-darwin" raise ValueError(f"Unsupported target: {target}") diff --git a/service-tester/README.md b/service-tester/README.md index 1566717..fddf1ea 100644 --- a/service-tester/README.md +++ b/service-tester/README.md @@ -19,9 +19,18 @@ End-to-end antibot-detection tests that verify a pip-installed camoufox release `run_tests.sh` will: 1. Install npm deps in `../build-tester/` (for `esbuild`, first run only) 2. Create a `.venv` virtualenv (first run only) -3. Install `camoufox` from the local `../pythonlib` source -4. Download the camoufox browser binary -5. Run the full test suite +3. Build a wheel from `../pythonlib` and install it (tests the actual packaged artifact) +4. **Phase 1** — run the suite against the locally compiled binary, auto-detected from: + - macOS: `../camoufox-*/obj-*-apple-darwin/dist/Camoufox.app/Contents/MacOS/camoufox` + - Linux: `../camoufox-*/obj-*-linux-*/dist/bin/camoufox-bin` + + Skipped (with a notice) if no local build is found. On macOS, the script also copies `properties.json` from `Camoufox.app/Contents/Resources/` into `MacOS/` so pythonlib can locate it next to the binary. +5. **Phase 2** — download the official binary (`--browser-version`, default `official/stable`) and run the suite against it +6. Exit `0` only if both phases pass + +Use `--binary local` or `--binary fetched` to run only one phase. + +> **Heads-up on Phase 2:** if the latest `official/stable` is much older than the local pythonlib (e.g. v135 binary vs pythonlib targeting v149+), the binary may not understand newer fingerprint patches and the test page can fail to produce results. Pin a newer binary with `--browser-version` to avoid this. ## Proxies @@ -43,6 +52,7 @@ alice:secret123@proxy1.example.com:10001 - Blank lines and lines starting with `#` are ignored - Proxies are assigned round-robin across the 6 test profiles - Fewer proxies than profiles is fine — they cycle +- `127.0.0.1` and `localhost` are bypassed automatically so the local test-page server stays reachable ## Manual Setup @@ -56,8 +66,10 @@ cd ../build-tester && npm install && cd ../service-tester python3 -m venv .venv source .venv/bin/activate -# Install camoufox from local source -pip install -e ../pythonlib +# Build wheel from local source and install it +pip install build +(cd ../pythonlib && rm -rf dist && python -m build --wheel -o dist) +pip install --force-reinstall ../pythonlib/dist/*.whl # Download the browser binary python -m camoufox fetch @@ -80,6 +92,10 @@ python run_tests.py [options] --no-cert Skip certificate generation --save-cert PATH Save certificate text to a file --secret KEY HMAC signing key for the certificate + --binary MODE Which binary to test: local | fetched | both (default: both) + (run_tests.sh only — orchestrates the two phases) + --executable-path PATH Run against a specific binary path + (run_tests.py only — used internally by phase 1) ``` ## What It Tests diff --git a/service-tester/_proxies.py b/service-tester/_proxies.py index 26d7ad0..92d1913 100644 --- a/service-tester/_proxies.py +++ b/service-tester/_proxies.py @@ -28,7 +28,12 @@ def load_proxies(path: Path) -> list: except ValueError: print(f"ERROR: proxies.txt line {lineno}: expected user:pass@domain:port, got: {line!r}", file=sys.stderr) sys.exit(1) - proxies.append({"server": f"http://{domain}:{port}", "username": user, "password": password}) + proxies.append({ + "server": f"http://{domain}:{port}", + "username": user, + "password": password, + "bypass": "127.0.0.1,localhost", + }) if not proxies: print("ERROR: proxies.txt contains no valid proxy entries.", file=sys.stderr) diff --git a/service-tester/run_tests.py b/service-tester/run_tests.py index ea4aad2..5b7794e 100644 --- a/service-tester/run_tests.py +++ b/service-tester/run_tests.py @@ -48,6 +48,7 @@ async def run_tests( secret: str, save_cert: Optional[str], no_cert: bool, + executable_path: Optional[str] = None, ) -> int: # 1. Ensure checks bundle is built ensure_bundle() @@ -103,7 +104,10 @@ async def run_tests( print("Launching browser...") launch_kwargs = {"headless": not headful} - if ff_version: + if executable_path: + launch_kwargs["executable_path"] = executable_path + print(f"Using local binary: {executable_path}") + elif ff_version: launch_kwargs["ff_version"] = ff_version try: @@ -233,6 +237,8 @@ def main(): help="Save certificate to this file path") parser.add_argument("--no-cert", action="store_true", help="Skip certificate generation") + parser.add_argument("--executable-path", default=None, + help="Use a specific Camoufox binary (skips fetched-version selection)") args = parser.parse_args() sys.exit(asyncio.run(run_tests( @@ -243,6 +249,7 @@ def main(): secret=args.secret, save_cert=args.save_cert, no_cert=args.no_cert, + executable_path=args.executable_path, ))) diff --git a/service-tester/run_tests.sh b/service-tester/run_tests.sh index 878e6be..66e44f3 100755 --- a/service-tester/run_tests.sh +++ b/service-tester/run_tests.sh @@ -11,6 +11,7 @@ HEADFUL="" PROFILE_COUNT=6 PROXIES="$SCRIPT_DIR/proxies.txt" EXTRA_ARGS="" +BINARY_MODE="both" # local | fetched | both # Parse args while [[ $# -gt 0 ]]; do @@ -39,17 +40,27 @@ while [[ $# -gt 0 ]]; do EXTRA_ARGS="$EXTRA_ARGS --save-cert $2" shift 2 ;; + --binary) + BINARY_MODE="$2" + shift 2 + ;; *) echo "Unknown argument: $1" - echo "Usage: $0 [--browser-version ] [--profile-count N] [--proxies PATH] [--headful] [--no-cert] [--save-cert PATH]" + echo "Usage: $0 [--browser-version ] [--profile-count N] [--proxies PATH] [--headful] [--no-cert] [--save-cert PATH] [--binary local|fetched|both]" echo " e.g. $0 --browser-version official/prerelease/146.0.1-beta.50 --headful" exit 1 ;; esac done +if [[ "$BINARY_MODE" != "local" && "$BINARY_MODE" != "fetched" && "$BINARY_MODE" != "both" ]]; then + echo "ERROR: --binary must be 'local', 'fetched', or 'both' (got: $BINARY_MODE)" >&2 + exit 1 +fi + echo "==> Browser version: $VERSION" echo "==> Profile count: $PROFILE_COUNT" +echo "==> Binary mode: $BINARY_MODE" # Install npm deps in build-tester (for esbuild — needed to build TypeScript bundle) if [ ! -d "$BUILD_TESTER_DIR/node_modules" ]; then @@ -66,20 +77,98 @@ fi PYTHON=".venv/bin/python" PIP=".venv/bin/pip" -echo "==> Installing camoufox from local source..." -$PIP uninstall -y cloverlabs-camoufox >/dev/null 2>&1 || true -$PIP install -q -e ../pythonlib +echo "==> Building camoufox wheel from ../pythonlib..." +$PIP install -q build +rm -rf ../pythonlib/dist +(cd ../pythonlib && "$SCRIPT_DIR/.venv/bin/python" -m build --wheel -o dist >/dev/null) -echo "==> Setting browser version: $VERSION" -$PYTHON -m camoufox set "$VERSION" +echo "==> Installing camoufox from local wheel..." +$PIP uninstall -y camoufox cloverlabs-camoufox >/dev/null 2>&1 || true +$PIP install -q --force-reinstall ../pythonlib/dist/*.whl -echo "==> Fetching browser..." -$PYTHON -m camoufox fetch +# Locate locally compiled binary +# - macOS: Camoufox.app/Contents/MacOS/camoufox (bare bin/camoufox-bin can't find dylibs) +# - Linux: bin/camoufox-bin +LOCAL_BIN="" +if [[ "$BINARY_MODE" != "fetched" ]]; then + if [[ "$(uname -s)" == "Darwin" ]]; then + LOCAL_GLOB=(../camoufox-*/obj-*-apple-darwin/dist/Camoufox.app/Contents/MacOS/camoufox) + else + LOCAL_GLOB=(../camoufox-*/obj-*-linux-*/dist/bin/camoufox-bin) + fi + # shellcheck disable=SC2012 + LOCAL_BIN=$(ls -1t "${LOCAL_GLOB[@]}" 2>/dev/null | head -1 || true) + if [[ -z "$LOCAL_BIN" || ! -f "$LOCAL_BIN" ]]; then + if [[ "$BINARY_MODE" == "local" ]]; then + echo "ERROR: --binary local requested but no local build found at ${LOCAL_GLOB[0]}" >&2 + exit 1 + fi + echo "==> No local build found — skipping local-binary phase" + LOCAL_BIN="" + else + LOCAL_BIN=$(cd "$(dirname "$LOCAL_BIN")" && pwd)/$(basename "$LOCAL_BIN") + # macOS .app: pythonlib reads properties.json from the executable's parent dir, + # but the bundle stores it in Contents/Resources/. Copy it into MacOS/ if missing. + if [[ "$(uname -s)" == "Darwin" ]]; then + MACOS_DIR=$(dirname "$LOCAL_BIN") + RESOURCES_PROPS="${MACOS_DIR%/MacOS}/Resources/properties.json" + if [[ ! -f "$MACOS_DIR/properties.json" && -f "$RESOURCES_PROPS" ]]; then + cp "$RESOURCES_PROPS" "$MACOS_DIR/properties.json" + echo "==> Copied properties.json into $MACOS_DIR/" + fi + fi + fi +fi -echo "==> Running service tests..." -$PYTHON run_tests.py \ - --browser-version "$VERSION" \ - --profile-count "$PROFILE_COUNT" \ - --proxies "$PROXIES" \ - $HEADFUL \ - $EXTRA_ARGS +LOCAL_RC=0 +FETCHED_RC=0 + +# ── Phase 1: locally compiled binary ───────────────────────────────────────── +if [[ -n "$LOCAL_BIN" ]]; then + echo + echo "════════════════════════════════════════════════════════════" + echo " PHASE 1/2 — Local binary: $LOCAL_BIN" + echo "════════════════════════════════════════════════════════════" + set +e + $PYTHON run_tests.py \ + --executable-path "$LOCAL_BIN" \ + --profile-count "$PROFILE_COUNT" \ + --proxies "$PROXIES" \ + $HEADFUL \ + $EXTRA_ARGS + LOCAL_RC=$? + set -e +fi + +# ── Phase 2: fetched binary (--browser-version) ────────────────────────────── +if [[ "$BINARY_MODE" != "local" ]]; then + echo + echo "════════════════════════════════════════════════════════════" + echo " PHASE 2/2 — Fetched binary: $VERSION" + echo "════════════════════════════════════════════════════════════" + echo "==> Setting browser version: $VERSION" + $PYTHON -m camoufox set "$VERSION" + echo "==> Fetching browser..." + $PYTHON -m camoufox fetch + set +e + $PYTHON run_tests.py \ + --browser-version "$VERSION" \ + --profile-count "$PROFILE_COUNT" \ + --proxies "$PROXIES" \ + $HEADFUL \ + $EXTRA_ARGS + FETCHED_RC=$? + set -e +fi + +echo +echo "════════════════════════════════════════════════════════════" +echo " COMBINED RESULT" +echo "════════════════════════════════════════════════════════════" +[[ -n "$LOCAL_BIN" ]] && echo " Local binary: exit $LOCAL_RC" +[[ "$BINARY_MODE" != "local" ]] && echo " Fetched binary: exit $FETCHED_RC" + +if (( LOCAL_RC != 0 || FETCHED_RC != 0 )); then + exit 1 +fi +exit 0 diff --git a/upstream.sh b/upstream.sh index f05af71..702a4a2 100644 --- a/upstream.sh +++ b/upstream.sh @@ -1,3 +1,3 @@ -version=146.0.1 +version=150.0.2 release=beta.25 closedsrc_rev=1.0.0