diff --git a/pyproject.toml b/pyproject.toml index c045edb..a79a4e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "invisible-playwright" -version = "0.2.0" +version = "0.3.0" description = "Playwright wrapper for a patched Firefox with deterministic stealth profile." readme = "README.md" requires-python = ">=3.11" @@ -20,13 +20,11 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] dependencies = [ + # Pure config (seed -> fingerprint -> prefs, binary download, proxy, geo) lives + # in invisible-core since the 2026-07-03 split; it pulls platformdirs/requests/ + # maxminddb/tzdata/tqdm/pywin32 transitively. The wrapper only adds Playwright. + "invisible-core @ git+https://github.com/feder-cr/invisible_core.git", "playwright>=1.40,<1.61", - "platformdirs>=4", - "requests[socks]>=2.31", - "maxminddb>=2.2", - "tzdata>=2024.1", - "tqdm>=4.66", - "pywin32>=306; sys_platform == 'win32'", ] [project.optional-dependencies] @@ -57,6 +55,7 @@ Issues = "https://github.com/feder-cr/invisible_playwright/issues" [tool.hatch.build.targets.wheel] packages = ["src/invisible_playwright"] +exclude = ["*.bak", "*-bak"] [tool.hatch.build.targets.sdist] include = ["src/invisible_playwright", "tests", "README.md", "LICENSE", "pyproject.toml"] diff --git a/src/invisible_playwright/_fpforge/__init__.py b/src/invisible_playwright/_fpforge/__init__.py index 830dcf6..937b411 100644 --- a/src/invisible_playwright/_fpforge/__init__.py +++ b/src/invisible_playwright/_fpforge/__init__.py @@ -1,26 +1,17 @@ -"""Internal Bayesian fingerprint generator used by invisible_playwright. +"""Backward-compat shim — spostato in invisible_core._fpforge (alias completo). -Private module — do not import from user code. Use -invisible_playwright.InvisiblePlaywright(seed=..., pin=...) instead. +Aliasa il package E i suoi submodule agli stessi oggetti del core, cosi' +``from invisible_playwright._fpforge.profile import Profile`` e +``from invisible_core._fpforge.profile import Profile`` sono la STESSA classe +(isinstance funziona) e i nomi privati restano accessibili. """ -from .profile import ( - AudioProfile, - CodecProfile, - GPUProfile, - HardwareProfile, - Profile, - ScreenProfile, - WebGLProfile, - generate_profile, -) +import sys as _sys +import invisible_core._fpforge as _pkg +from invisible_core._fpforge import profile as _profile +from invisible_core._fpforge import _sampler as _sampler_mod +from invisible_core._fpforge import _network as _network_mod -__all__ = [ - "generate_profile", - "Profile", - "GPUProfile", - "ScreenProfile", - "HardwareProfile", - "AudioProfile", - "CodecProfile", - "WebGLProfile", -] +_sys.modules[__name__] = _pkg +_sys.modules[__name__ + ".profile"] = _profile +_sys.modules[__name__ + "._sampler"] = _sampler_mod +_sys.modules[__name__ + "._network"] = _network_mod diff --git a/src/invisible_playwright/_fpforge/_network.py b/src/invisible_playwright/_fpforge/_network.py deleted file mode 100644 index 930df91..0000000 --- a/src/invisible_playwright/_fpforge/_network.py +++ /dev/null @@ -1,144 +0,0 @@ -# -*- coding: utf-8 -*- -"""Generic Bayesian network for fingerprint sampling. - -A Node has: - - name - - parents (list of parent node names) - - CPT: either - * marginal (no parents): flat [{value, prob}, ...] - * conditional: {parent_tuple: [{value, prob}, ...]} - - OR deterministic: a classifier function `(context) -> value` (no CPT) - -Sampling: - - Nodes are topologically sorted - - For each node, look up the conditional distribution given parent values - already sampled in `context`, then weighted-pick - - Deterministic nodes apply their classifier directly - -Values can be ANY JSON-serializable type (int, str, dict, list, bool). -Complex values (e.g. screen joint {w, h, dpr}) are stored as dicts in the -CPT and returned as-is in the context. -""" -import json -import random -from typing import Any, Callable, Dict, List, Optional, Tuple - - -class Node: - """Single Bayesian node.""" - - __slots__ = ("name", "parents", "cpt", "classifier", "_marginal") - - def __init__( - self, - name: str, - parents: Optional[List[str]] = None, - cpt: Optional[Any] = None, - classifier: Optional[Callable[[Dict[str, Any]], Any]] = None, - ): - self.name = name - self.parents = list(parents or []) - self.cpt = cpt - self.classifier = classifier - # Precompute: for no-parent nodes, cpt is the marginal list - self._marginal = cpt if not self.parents and classifier is None else None - - def sample(self, context: Dict[str, Any], rng: random.Random) -> Any: - # Deterministic nodes don't sample - if self.classifier is not None: - return self.classifier(context) - - if not self.parents: - # Marginal root - return _weighted_pick(self._marginal, rng) - - # Conditional node: build the key from parent values - key = _parent_key(self.parents, context) - if key not in self.cpt: - # Fallback: concatenate all parents' tables (uniform over union) - # Keeps sampler from crashing if data doesn't cover some combo. - pool = [] - for v in self.cpt.values(): - pool.extend(v) - if not pool: - raise ValueError( - f"Node {self.name!r}: no CPT entries for {self.parents}={key}" - ) - return _weighted_pick(pool, rng) - return _weighted_pick(self.cpt[key], rng) - - -class Network: - """Collection of nodes with topological sampling.""" - - def __init__(self, nodes: List[Node]): - self.nodes = _topsort(nodes) - self.by_name = {n.name: n for n in self.nodes} - - def sample( - self, - rng: random.Random, - evidence: Optional[Dict[str, Any]] = None, - ) -> Dict[str, Any]: - """Sample the network. ``evidence`` fixes named nodes BEFORE their children - sample, so the children RE-CONDITION on the fixed value (not relabel after). - Used to pin ``gpu_class`` to the validated WebGL persona's class so the whole - bundle (cores/screen/fonts) stays coherent with the GPU we expose. Earlier - nodes still sample (RNG stream preserved → per-seed determinism).""" - evidence = evidence or {} - context: Dict[str, Any] = {} - for node in self.nodes: - if node.name in evidence: - context[node.name] = evidence[node.name] - else: - context[node.name] = node.sample(context, rng) - return context - - -# ── Helpers ───────────────────────────────────────────────────────────── - -def _weighted_pick(table: List[Dict[str, Any]], rng: random.Random) -> Any: - """`table` is a list of {value, prob} dicts. Returns one value.""" - values = [e["value"] for e in table] - probs = [float(e["prob"]) for e in table] - if not values: - raise ValueError("Empty CPT entry") - total = sum(probs) - if total <= 0: - return rng.choice(values) - # Normalize to be safe (CPTs can be unnormalized) - probs = [p / total for p in probs] - return rng.choices(values, weights=probs, k=1)[0] - - -def _parent_key(parents: List[str], context: Dict[str, Any]) -> str: - """Build a JSON-stable key from parent values in declared order.""" - if len(parents) == 1: - v = context[parents[0]] - return v if isinstance(v, str) else json.dumps(v, sort_keys=True) - return json.dumps([context[p] for p in parents], sort_keys=True) - - -def _topsort(nodes: List[Node]) -> List[Node]: - """Topological sort by parent-before-child.""" - by_name = {n.name: n for n in nodes} - visited: set = set() - order: List[Node] = [] - - def visit(n: Node, path: set): - if n.name in visited: - return - if n.name in path: - raise ValueError(f"Cycle at {n.name}") - path.add(n.name) - for p in n.parents: - if p not in by_name: - raise ValueError(f"Node {n.name} has unknown parent {p}") - visit(by_name[p], path) - path.discard(n.name) - visited.add(n.name) - order.append(n) - - for n in nodes: - visit(n, set()) - return order diff --git a/src/invisible_playwright/_fpforge/_sampler.py b/src/invisible_playwright/_fpforge/_sampler.py deleted file mode 100644 index b977ba5..0000000 --- a/src/invisible_playwright/_fpforge/_sampler.py +++ /dev/null @@ -1,445 +0,0 @@ -# -*- coding: utf-8 -*- -"""stealth_forge — Bayesian fingerprint generator for Firefox 150 Windows. - -Everything the Firefox build exposes to JS (screen, hardwareConcurrency, -WebGL, audio, MSAA, theme, media codecs) is sampled from a Bayesian network -with coherent cross-field dependencies. Identity (userAgent, platform, -oscpu, webdriver=false, maxTouchPoints=0) is locked by the compiled build. - -Graph: - - gpu (root, 474 real Windows ANGLE renderers) - │ - └─> gpu_class (deterministic classifier, 6 classes) - ├─> hw_concurrency (CPT per class) - ├─> screen (w/h/dpr/av) (CPT per class) - └─> msaa_samples (CPT per class) - - audio (root, joint rate+latency+channels — marginal) - dark_theme (marginal) - av1_enabled (marginal) - webm_encoder_enabled (marginal) - - font_exclude ← deterministic hash of stealth_seed (seed-derived) - -CPTs live in `data/*.json` (easy to tune without code changes). -Sampling is deterministic per stealth_seed via a private random.Random. -""" -import json -import os -import re -from typing import Any, Dict, Optional - -from ._network import Network, Node - -_HERE = os.path.dirname(os.path.abspath(__file__)) - - -def _load(filename: str) -> Any: - with open(os.path.join(_HERE, "data", filename), "r", encoding="utf-8") as f: - return json.load(f) - - -# ═══════════════════════════════════════════════════════════════════════ -# LOCKED IDENTITY (compiled into our Firefox 150 build — never varies) -# ═══════════════════════════════════════════════════════════════════════ -_LOCKED: Dict[str, Any] = { - "user_agent": ( - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) " - "Gecko/20100101 Firefox/150.0.1" - ), - "platform": "Win32", - "oscpu": "Windows NT 10.0; Win64; x64", - "app_code_name": "Mozilla", - "app_version": "5.0 (Windows)", - "product_sub": "20100101", - "webdriver": False, - "max_touch_points": 0, -} - - -# ═══════════════════════════════════════════════════════════════════════ -# DATA -# ═══════════════════════════════════════════════════════════════════════ -_GPU_POOL = _load("webgl_renderer_pool.json")["entries"] -# hwc/screen/storage now keyed on (gpu_class, intra_tier) for triangulation -_CPT_HWC = _load("cpt_hwc_given_class_tier.json")["table"] -_CPT_SCREEN = _load("cpt_screen_given_class_tier.json")["table"] -_CPT_STORAGE = _load("cpt_storage_given_class_tier.json")["table"] -# Hidden tier variable that makes hwc/screen/storage jointly coherent -_CPT_INTRA_TIER = _load("cpt_intra_tier_given_class.json")["table"] -# MSAA depends on (gpu_class, screen_tier) — 4K gaming → MSAA=0, 1080p+GPU → MSAA=4 -_CPT_MSAA = _load("cpt_msaa_given_class_screen.json")["table"] -# Codec unchanged -_CPT_CODEC = _load("cpt_codec_given_class.json")["table"] -# Audio now conditional on gpu_class (workstation → pro audio, old → 44.1kHz onboard) -_CPT_AUDIO = _load("cpt_audio_given_class.json")["table"] -_INDEP = _load("priors_independent.json") -_FONT_POOL = _load("font_pool.json") -# hardwareConcurrency: grounded in the REAL Windows marginal (browserforge Windows UAs). -# cores are OS-level, ~independent of GPU given the OS (browserforge confirms), so this is a -# root marginal — NOT conditioned on gpu_class/intra_tier. Fixes the old CPT over-representing -# 6 cores (~28% vs real ~2%). NB: screen size + dpr are intentionally LEFT on their existing -# nodes (user 2026-06-18: "non modificare dpr e le size degli screen, rompono sempre"). -_CORES_MARGINAL = [ - {"value": int(e["value"]), "prob": e["prob"]} - for e in _load("win_hw_marginals.json")["cores"] - if 2 <= int(e["value"]) <= 64 and e["prob"] >= 0.004 -] -# Each entry is a dict {"name": "", "factor": float}. -# - name: the font family advertised to the page. -# - factor: per-family width scale used by the consumer to make the family -# detectable by width-diff probes. -# Core = always-included; Optional = sampled with P(font | gpu_class). -_FONT_CORE: list = _FONT_POOL["core"] -_FONT_OPTIONAL: list = _FONT_POOL["optional"] -_CPT_FONTS_OPT = _load("cpt_fonts_optional_given_class.json")["table"] # legacy (per-font sampling, superseded by profiles) -# Realistic Windows font PROFILES (2026-06-18): each = a real machine's optional-font set -# (validated to NOT over-claim on FP Pro). Profile-level variation (machines differ in -# Office/extra fonts) instead of per-font random sampling, which produced unrealistic -# combinations (exotic fonts -> FP Pro over-detection -> tampering_ml tell). -_FONT_PROFILES: list = _FONT_POOL.get("profiles", []) -_OPT_BY_NAME = {e["name"]: e for e in _FONT_OPTIONAL} -# Browsing-history pool + CPT (per-class probabilities for visited sites). -# Drives _recaptcha_seed's cookie pre-seed: each persona ends up with a -# coherent list of ~15-30 visited sites whose categories correlate with -# gpu_class (workstation → dev-heavy, integrated_old → shop+news-heavy). -_BROWSING_POOL: list = _load("browsing_pool.json")["entries"] -_CPT_BROWSING = _load("cpt_browsing_given_class.json")["table"] - - -# ═══════════════════════════════════════════════════════════════════════ -# GPU CLASSIFIER (deterministic function of gpu → gpu_class) -# ═══════════════════════════════════════════════════════════════════════ -_GPU_CLASSES = ( - "integrated_old", "integrated_modern", "low_end", - "mid_range", "high_end", "workstation", -) - - -def classify_gpu(gpu_value: Dict[str, str]) -> str: - """Deterministic: maps (renderer, vendor) dict to one of 6 classes. - - See data/cpt_*.json — each CPT table has an entry for every class. - """ - r = gpu_value.get("renderer", "") - - if re.search(r"Intel.*HD Graphics (3000|4000|2500)", r): - return "integrated_old" - # Discrete Intel Arc DESKTOP/dGPU cards (A-series / B-series, e.g. A750, - # A770, B580) are discrete GPUs (~RTX 3060 tier for A7xx), NOT the - # integrated "Arc 130T/140T/Graphics" iGPUs in Core Ultra chips. Route the - # discrete SKUs to a coherent discrete-GPU class so the conditioned bundle - # (cores, screen, storage) matches a real discrete-GPU machine; A3xx are - # entry discrete -> low_end, A5xx/A7xx/Bxxx -> mid_range. Bare "Arc 1x0(T/V)" - # integrated names do NOT match and fall through to integrated_modern below. - m = re.search(r"Intel.*\bArc(?:\(TM\))?\s+([AB])(\d)\d\d\b", r) - if m: - return "low_end" if m.group(2) == "3" else "mid_range" - if re.search( - r"Intel.*(HD Graphics (4[56]|5\d\d|6\d\d)|UHD Graphics|Graphics Family|Iris|Arc)", - r, - ): - return "integrated_modern" - if re.search( - r"AMD.*(Radeon(\(TM\))? (Graphics|6\d\dM|7\d\dM|8\d\dM)|Vega [0-9]|" - r"Renoir|Rembrandt|TM Graphics)", - r, re.IGNORECASE, - ): - return "integrated_modern" - - # NVIDIA: Firefox SanitizeRenderer.cpp collapses every GeForce into one of - # 3 vintage buckets (8800 GTX / GTX 480 / GTX 980). The renderer string - # exposed to JS is therefore vintage; pairing it with modern cores/screen - # creates an internal mismatch that FP Pro's tampering_ml flags. We pick - # `low_end` for all 3 buckets so cores stay 4-12 and screen 1080-1440p, - # consistent with what a real user with each of those (vintage) cards - # would have. Workstation overrides keep their high-tier classification. - if re.search( - r"(GeForce (8\d\d\d?|9\d\d\d?|GTX 980|GTX 480|GT 1030|GT 710|GT 730|" - r"GT 220|GT 240|210|310)|Quadro K\d|Radeon HD [1234]\d\d\d)", r, - ): - return "low_end" - - # NVIDIA discrete (any other GeForce — should be rare after the pool was - # collapsed to the 3 sanitize buckets, but kept as a safety net). - m = re.search(r"GeForce\s+(?:GTX\s+|RTX\s+)?(\d{3,4})", r) - if m: - if "Quadro" in r or "Workstation" in r: - return "workstation" - # Anything that survives the sanitize collapse stays low_end to avoid - # the modern-cores/vintage-renderer pairing. - return "low_end" - - # AMD discrete - m = re.search(r"Radeon[^0-9]*(\d{3,4})", r) - if m: - n = int(m.group(1)) - if "FirePro" in r or "Radeon Pro" in r: - return "workstation" - if n >= 5700: - return "high_end" - if 5500 <= n <= 5600 or 580 <= n <= 590: - return "mid_range" - return "low_end" - - # Fallback - return "mid_range" - - -# ═══════════════════════════════════════════════════════════════════════ -# NETWORK CONSTRUCTION -# ═══════════════════════════════════════════════════════════════════════ -# Build once at import — the network is stateless, only the RNG varies. - -def _gpu_marginal(): - """Build marginal distribution over GPU pool (uniform for now).""" - n = len(_GPU_POOL) - p = 1.0 / n - return [{"value": g, "prob": p} for g in _GPU_POOL] - - -def _cpt_from_table(table: Dict[str, Any]) -> Dict[str, list]: - """CPT for conditional nodes: `{class_name: [{value, prob}, ...]}`.""" - return dict(table) - - -def _screen_tier(ctx): - """Classify screen width into tier for (gpu_class, screen_tier) CPTs.""" - s = ctx.get("screen", {}) or {} - w = int(s.get("w", 1920)) - h = int(s.get("h", 1080)) - # Ultrawide: aspect ratio > 2.1 (e.g. 3440x1440, 5120x1440) - if h > 0 and (w / h) > 2.1: - return "ultrawide" - if w <= 1920: - return "1080p" - if w <= 2560: - return "1440p" - if w <= 3840: - return "2160p" - return "ultrawide" - - -_NETWORK = Network([ - Node("gpu", parents=[], cpt=_gpu_marginal()), - Node("gpu_class", parents=["gpu"], classifier=lambda ctx: classify_gpu(ctx["gpu"])), - # Hidden variable: within a gpu_class, user's OTHER components (RAM, SSD, - # cores, screen) correlate — a 'premium' mid_range user has more cores, - # larger SSD, higher-res screen than a 'budget' mid_range user. Without - # this, hwc/screen/storage would be independent given gpu_class (noisy). - Node("intra_tier", parents=["gpu_class"], cpt=_cpt_from_table(_CPT_INTRA_TIER)), - # hw_concurrency: REAL Windows marginal (root, OS-level, not GPU-conditioned). screen + - # storage stay jointly coherent via (gpu_class, intra_tier) — screen size deliberately - # unchanged (user: dpr + screen sizes break things; leave them). - Node("hw_concurrency", parents=[], cpt=_CORES_MARGINAL), - Node("screen", parents=["gpu_class", "intra_tier"], - cpt=_cpt_from_table(_CPT_SCREEN)), - # Derive screen_tier from screen for msaa parent lookup. - Node("screen_tier", parents=["screen"], classifier=_screen_tier), - # MSAA: realistic combo (4K + high_end GPU → MSAA=0 due to perf cost; - # 1080p + high_end → MSAA=4 common; 1080p + integrated → MSAA=0). - Node("msaa_samples", parents=["gpu_class", "screen_tier"], - cpt=_cpt_from_table(_CPT_MSAA)), - # Joint codec distribution (gpu_class only). - Node("codec", parents=["gpu_class"], cpt=_cpt_from_table(_CPT_CODEC)), - # Storage quota: coherent within gpu_class × intra_tier (premium workstation - # user → 2-3TB SSD; budget workstation user → 512GB; budget integrated_old - # → 128GB). - Node("storage_quota_mb", parents=["gpu_class", "intra_tier"], - cpt=_cpt_from_table(_CPT_STORAGE)), - # Audio: pro users (workstation) → 48/96kHz 6-8ch; old onboard → 44.1kHz - # 2ch high latency. Workstation GPU + 44.1kHz mono was previously - # implausible; now blocked by the CPT. - Node("audio", parents=["gpu_class"], cpt=_cpt_from_table(_CPT_AUDIO)), - Node("dark_theme", parents=[], cpt=_INDEP["dark_theme"]["table"]), -]) - - -# ═══════════════════════════════════════════════════════════════════════ -# FONT LIST (Bayesian: core ∪ sampled_optional | gpu_class) -# ═══════════════════════════════════════════════════════════════════════ -# The browser sees ONLY these families (everything else hidden) and renders -# them from the REAL Windows font files the binary bundles in /fonts -# (MOZ_BUNDLED_FONTS). No fabricated widths: per-session metric uniqueness -# comes from the HarfBuzz per-glyph jitter (shared fpp.hw_seed), not here. -# Core (~112): always included — fresh Win11 + Office 2021 English. -# Optional (~40): one realistic Windows profile sampled per seed (weighted, -# deterministic) → ~3-8 optional families differ per session while staying -# centered on 'typical Windows user'. - - -def derive_font_prefs(gpu_class: str, rng) -> Dict[str, str]: - """Build the session's font family list. - - Profile-based (not per-font random): - - Core families always included (OS defaults + CSS-generic backers). - - Optional families come from ONE realistic Windows profile picked per - seed (weighted, deterministic). - - Returns ``{"whitelist": "arial,calibri,marlett,..."}`` — the comma-joined - family list to advertise. The binary applies it to the native system font - allow-list AT CONSTRUCTION and renders each family from the bundled real - Windows file, so glyphs and widths are genuine. To add a family, just add - an entry to font_pool.json:core/optional — no special-case code needed. - """ - # Profile-based (2026-06-18): pick ONE realistic Windows font profile (weighted, - # deterministic per seed). Per-font random sampling is superseded — it produced - # unrealistic optional combinations (exotic fonts) that FP Pro over-detected - # (detected-set 26 vs real 20 -> tampering_ml ~0.72). Profiles are validated subsets - # of a real machine's set, so the detected-set matches a genuine Windows install. - included: list = list(_FONT_CORE) # core: always present (OS defaults + generic backers) - profile = None - if _FONT_PROFILES: - total = sum(p.get("weight", 1) for p in _FONT_PROFILES) - anchor = rng.random() * total - cum = 0.0 - for p in _FONT_PROFILES: - cum += p.get("weight", 1) - if anchor < cum: - profile = p - break - if profile is None: - profile = _FONT_PROFILES[-1] - if profile is not None: - for name in profile.get("optional", []): - entry = _OPT_BY_NAME.get(name) - if entry is not None: - included.append(entry) - else: - included.extend(_FONT_OPTIONAL) # fallback (no profiles defined): all optional - # Dedup by name (a profile may list a font that is also in core, e.g. after a - # standard font is promoted core→always-present) so the list never carries a - # duplicate family. - _seen: set = set() - _uniq: list = [] - for e in included: - if e["name"] not in _seen: - _seen.add(e["name"]) - _uniq.append(e) - included = _uniq - # Deterministic ordering: sort by name - included.sort(key=lambda e: e["name"]) - whitelist = ",".join(e["name"] for e in included) - return {"whitelist": whitelist} - - -# Back-compat shim: legacy callers still import derive_font_whitelist. -def derive_font_whitelist(gpu_class: str, rng) -> str: - return derive_font_prefs(gpu_class, rng)["whitelist"] - - -# ═══════════════════════════════════════════════════════════════════════ -# BROWSING HISTORY (Bayesian: per-site P(visited|gpu_class)) -# ═══════════════════════════════════════════════════════════════════════ -def derive_browsing_history(gpu_class: str, rng) -> list: - """Sample which sites this persona has visited recently. - - Each site in the pool has a per-class probability (CPT). We sample - independently per-site, producing a list of dicts: - [{"name": "github.com", "category": "dev", "cookie_profile": "ga_cf"}, ...] - - Sum of CPT probabilities per class is tuned to land ~15-30 visited sites - on average — an established-user signature. Sorted by name for stable - output across runs of the same seed. - """ - cpt = _CPT_BROWSING.get(gpu_class) - if cpt is None: - cpt = _CPT_BROWSING["mid_range"] - visited: list = [] - for entry in _BROWSING_POOL: - name = entry["name"] - p = cpt.get(name, 0.3) # default 0.3 for missing CPT row - if rng.random() < p: - visited.append(dict(entry)) # copy to avoid mutating pool - visited.sort(key=lambda e: e["name"]) - return visited - - -# ═══════════════════════════════════════════════════════════════════════ -# PUBLIC API: Forge -# ═══════════════════════════════════════════════════════════════════════ -import random - - -class Forge: - """Fingerprint forge — single seed → coherent bundle.""" - - def __init__(self, seed: int): - self.seed = int(seed) - self._rng = random.Random(self.seed) - - def sample(self, fixed_gpu_class: Optional[str] = None) -> Dict[str, Any]: - # fixed_gpu_class pins gpu_class so the WHOLE bundle (cores/screen/fonts) is - # drawn coherently for the WebGL persona's class we expose on Windows/mac. - # The default (no fix) path calls _NETWORK.sample(rng) with one arg so existing - # monkeypatches/tests keep working. - if fixed_gpu_class: - bundle = _NETWORK.sample(self._rng, evidence={"gpu_class": fixed_gpu_class}) - else: - bundle = _NETWORK.sample(self._rng) - gpu = bundle["gpu"] - screen = bundle["screen"] - audio = bundle["audio"] - codec = bundle["codec"] - return { - # Seed tracking - "stealth_seed": self.seed, - # Locked identity - **_LOCKED, - # GPU (coherent pair from 474 pool) - "webgl_renderer": gpu["renderer"], - "webgl_vendor": gpu["vendor"], - "gpu_class": bundle["gpu_class"], - # Hidden-variable debug metadata (not a Firefox pref, just for - # analysis / test result correlation tracking) - "intra_tier": bundle["intra_tier"], - "screen_tier": bundle["screen_tier"], - # Screen (coherent with GPU class) - "screen_w": int(screen["w"]), - "screen_h": int(screen["h"]), - "screen_avail_w": int(screen.get("aw", screen["w"])), - "screen_avail_h": int(screen.get("ah", screen["h"] - 40)), - "dpr": float(screen["dpr"]), - # Hardware (coherent with GPU class) - "hw_concurrency": int(bundle["hw_concurrency"]), - # WebGL MSAA (coherent with GPU class) - "msaa_samples": int(bundle["msaa_samples"]), - # Audio (independent joint) - "audio_sample_rate": int(audio["rate"]), - "audio_output_latency_ms": int(audio["latency"]), - "audio_max_channel_count": int(audio["channels"]), - # Codec prefs (joint, coherent with GPU class). All 5 are - # JS-visible: av1/webm_encoder via canPlayType/MediaRecorder, - # mediasource_* via MediaSource.isTypeSupported, webspeech_synth - # via 'speechSynthesis' in window (CreepJS voices probe). - "av1_enabled": bool(codec["av1_enabled"]), - "webm_encoder_enabled": bool(codec["webm_encoder_enabled"]), - "mediasource_webm": bool(codec["mediasource_webm"]), - "mediasource_mp4": bool(codec["mediasource_mp4"]), - "webspeech_synth": bool(codec["webspeech_synth"]), - # Storage quota MB (coherent with GPU class — workstation larger SSDs). - "storage_quota_mb": int(bundle["storage_quota_mb"]), - # Independent marginals - "dark_theme": int(bundle["dark_theme"]), - # Bayesian font prefs (coherent pair: whitelist + per-family - # width scale metrics, both sampled from the same font_pool.json - # and conditioned on gpu_class). - **{ - f"font_{k}": v - for k, v in derive_font_prefs( - bundle["gpu_class"], self._rng - ).items() - }, - # Bayesian browsing history (per-class P(visited|gpu_class)). - # Consumed by _recaptcha_seed.py to seed coherent cookie history - # when invisible_playwright is launched with prep_recaptcha=True. - "browsing_history": derive_browsing_history( - bundle["gpu_class"], self._rng - ), - } - - -def sample(seed: int, fixed_gpu_class: Optional[str] = None) -> Dict[str, Any]: - """Convenience: `Forge(seed).sample(fixed_gpu_class)`.""" - return Forge(seed).sample(fixed_gpu_class) diff --git a/src/invisible_playwright/_fpforge/data/browsing_pool.json b/src/invisible_playwright/_fpforge/data/browsing_pool.json deleted file mode 100644 index 6e98cd9..0000000 --- a/src/invisible_playwright/_fpforge/data/browsing_pool.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "_comment": [ - "Pool of everyday websites used by the browsing_history node.", - "Each entry: { name, category, cookie_profile }.", - "- name: bare domain (no scheme, no leading dot).", - "- category: dev / shop / news / reference / media / community / misc.", - "- cookie_profile: short tag pointing to a cookie-template recipe used by", - " _recaptcha_seed.py to generate concrete cookies (so heavy-analytics sites", - " get _ga+_gid+OneTrust, simple sites get just _ga, dev tools get GH-style).", - "Add new entries here + add per-class probabilities in cpt_browsing_given_class.json." - ], - "entries": [ - {"name": "youtube.com", "category": "media", "cookie_profile": "ga_only"}, - {"name": "wikipedia.org", "category": "reference", "cookie_profile": "minimal"}, - {"name": "mozilla.org", "category": "reference", "cookie_profile": "ga_consent"}, - {"name": "w3schools.com", "category": "dev", "cookie_profile": "ga_consent_clarity"}, - {"name": "mdn.io", "category": "dev", "cookie_profile": "minimal"}, - {"name": "duckduckgo.com", "category": "reference", "cookie_profile": "minimal"}, - {"name": "github.com", "category": "dev", "cookie_profile": "ga_cf"}, - {"name": "stackoverflow.com", "category": "dev", "cookie_profile": "ga_consent_clarity"}, - {"name": "npmjs.com", "category": "dev", "cookie_profile": "ga_consent"}, - {"name": "gitlab.com", "category": "dev", "cookie_profile": "ga_cf"}, - {"name": "pypi.org", "category": "dev", "cookie_profile": "minimal"}, - {"name": "docs.python.org", "category": "dev", "cookie_profile": "minimal"}, - {"name": "rust-lang.org", "category": "dev", "cookie_profile": "ga_consent"}, - {"name": "go.dev", "category": "dev", "cookie_profile": "ga_consent"}, - {"name": "amazon.com", "category": "shop", "cookie_profile": "ga_consent_clarity"}, - {"name": "ebay.com", "category": "shop", "cookie_profile": "ga_consent"}, - {"name": "etsy.com", "category": "shop", "cookie_profile": "ga_consent_clarity"}, - {"name": "bestbuy.com", "category": "shop", "cookie_profile": "ga_consent_clarity"}, - {"name": "target.com", "category": "shop", "cookie_profile": "ga_consent_clarity"}, - {"name": "nytimes.com", "category": "news", "cookie_profile": "ga_consent_clarity"}, - {"name": "cnn.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "bbc.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "theguardian.com", "category": "news", "cookie_profile": "ga_consent_clarity"}, - {"name": "reuters.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "apnews.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "washingtonpost.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "techcrunch.com", "category": "news", "cookie_profile": "ga_consent_clarity"}, - {"name": "theverge.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "arstechnica.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "wired.com", "category": "news", "cookie_profile": "ga_consent_clarity"}, - {"name": "engadget.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "9to5mac.com", "category": "news", "cookie_profile": "ga_consent"}, - {"name": "medium.com", "category": "community", "cookie_profile": "ga_consent"}, - {"name": "dev.to", "category": "community", "cookie_profile": "ga_consent"}, - {"name": "reddit.com", "category": "community", "cookie_profile": "ga_cf"}, - {"name": "news.ycombinator.com", "category": "community", "cookie_profile": "minimal"}, - {"name": "quora.com", "category": "community", "cookie_profile": "ga_consent_clarity"}, - {"name": "stackexchange.com", "category": "community", "cookie_profile": "ga_consent_clarity"}, - {"name": "imdb.com", "category": "media", "cookie_profile": "ga_consent_clarity"}, - {"name": "rottentomatoes.com", "category": "media", "cookie_profile": "ga_consent"}, - {"name": "metacritic.com", "category": "media", "cookie_profile": "ga_consent"}, - {"name": "allrecipes.com", "category": "misc", "cookie_profile": "ga_consent_clarity"}, - {"name": "epicurious.com", "category": "misc", "cookie_profile": "ga_consent"}, - {"name": "tripadvisor.com", "category": "misc", "cookie_profile": "ga_consent_clarity"}, - {"name": "weather.com", "category": "reference", "cookie_profile": "ga_consent"}, - {"name": "timeanddate.com", "category": "reference", "cookie_profile": "ga_consent"}, - {"name": "thesaurus.com", "category": "reference", "cookie_profile": "ga_consent_clarity"}, - {"name": "kayak.com", "category": "shop", "cookie_profile": "ga_consent_clarity"}, - {"name": "booking.com", "category": "shop", "cookie_profile": "ga_consent_clarity"}, - {"name": "airbnb.com", "category": "shop", "cookie_profile": "ga_consent"} - ] -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_audio_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_audio_given_class.json deleted file mode 100644 index fe6a075..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_audio_given_class.json +++ /dev/null @@ -1,217 +0,0 @@ -{ - "_meta": "audio (rate/latency/channels) given gpu_class. NOTE 2026-06-14: maxChannelCount reflects the OS DEFAULT OUTPUT DEVICE (stereo for the vast majority of users), NOT the GPU — so channels=2 dominates every class (~78-92%) with only a small 6/8 surround tail. The previous tables emitted 45-100% surround on mid/high/workstation, which is unrealistic and lifted FP Pro tampering_ml (surround on a typical consumer profile reads as a coherence anomaly). Rate/latency tuples are unchanged.", - "table": { - "integrated_old": [ - { - "value": { - "rate": 44100, - "latency": 50, - "channels": 2 - }, - "prob": 0.7 - }, - { - "value": { - "rate": 48000, - "latency": 50, - "channels": 2 - }, - "prob": 0.3 - } - ], - "integrated_modern": [ - { - "value": { - "rate": 48000, - "latency": 30, - "channels": 2 - }, - "prob": 0.62 - }, - { - "value": { - "rate": 44100, - "latency": 40, - "channels": 2 - }, - "prob": 0.3 - }, - { - "value": { - "rate": 48000, - "latency": 25, - "channels": 6 - }, - "prob": 0.08 - } - ], - "low_end": [ - { - "value": { - "rate": 48000, - "latency": 40, - "channels": 2 - }, - "prob": 0.6 - }, - { - "value": { - "rate": 44100, - "latency": 50, - "channels": 2 - }, - "prob": 0.32 - }, - { - "value": { - "rate": 48000, - "latency": 30, - "channels": 6 - }, - "prob": 0.08 - } - ], - "mid_range": [ - { - "value": { - "rate": 48000, - "latency": 25, - "channels": 2 - }, - "prob": 0.5 - }, - { - "value": { - "rate": 48000, - "latency": 20, - "channels": 2 - }, - "prob": 0.3 - }, - { - "value": { - "rate": 44100, - "latency": 30, - "channels": 2 - }, - "prob": 0.12 - }, - { - "value": { - "rate": 48000, - "latency": 20, - "channels": 6 - }, - "prob": 0.06 - }, - { - "value": { - "rate": 48000, - "latency": 20, - "channels": 8 - }, - "prob": 0.02 - } - ], - "high_end": [ - { - "value": { - "rate": 48000, - "latency": 15, - "channels": 2 - }, - "prob": 0.6 - }, - { - "value": { - "rate": 96000, - "latency": 15, - "channels": 2 - }, - "prob": 0.18 - }, - { - "value": { - "rate": 48000, - "latency": 15, - "channels": 6 - }, - "prob": 0.1 - }, - { - "value": { - "rate": 48000, - "latency": 15, - "channels": 8 - }, - "prob": 0.05 - }, - { - "value": { - "rate": 96000, - "latency": 15, - "channels": 6 - }, - "prob": 0.05 - }, - { - "value": { - "rate": 96000, - "latency": 15, - "channels": 8 - }, - "prob": 0.02 - } - ], - "workstation": [ - { - "value": { - "rate": 48000, - "latency": 10, - "channels": 2 - }, - "prob": 0.45 - }, - { - "value": { - "rate": 96000, - "latency": 10, - "channels": 2 - }, - "prob": 0.2 - }, - { - "value": { - "rate": 48000, - "latency": 10, - "channels": 8 - }, - "prob": 0.12 - }, - { - "value": { - "rate": 96000, - "latency": 10, - "channels": 8 - }, - "prob": 0.1 - }, - { - "value": { - "rate": 96000, - "latency": 10, - "channels": 6 - }, - "prob": 0.08 - }, - { - "value": { - "rate": 192000, - "latency": 10, - "channels": 8 - }, - "prob": 0.05 - } - ] - } -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_browsing_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_browsing_given_class.json deleted file mode 100644 index b2e3b1a..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_browsing_given_class.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "_comment": [ - "Per-class probability that a persona of a given gpu_class has visited each", - "site in the pool. Used by the browsing_history node to derive a coherent", - "visited-domain list per persona.", - "", - "Probabilities are tuned so each class samples ~15-30 sites on average", - "(sum across all 50 entries falls in that range), giving an established-user", - "look. Categories are biased by class:", - " - workstation/high_end: higher P(dev) + high P(news/media)", - " - mid_range: balanced", - " - low_end/integrated_*: lower P(dev), higher P(shop/news/reference)", - "", - "Missing class falls back to mid_range via Node CPT pool fallback." - ], - "table": { - "workstation": { - "youtube.com": 0.80, "wikipedia.org": 0.85, "mozilla.org": 0.70, - "w3schools.com": 0.40, "mdn.io": 0.55, "duckduckgo.com": 0.45, - "github.com": 0.95, "stackoverflow.com": 0.90, "npmjs.com": 0.65, - "gitlab.com": 0.50, "pypi.org": 0.55, "docs.python.org": 0.60, - "rust-lang.org": 0.35, "go.dev": 0.30, - "amazon.com": 0.70, "ebay.com": 0.25, "etsy.com": 0.15, - "bestbuy.com": 0.45, "target.com": 0.30, - "nytimes.com": 0.55, "cnn.com": 0.40, "bbc.com": 0.55, - "theguardian.com": 0.45, "reuters.com": 0.40, "apnews.com": 0.30, - "washingtonpost.com": 0.40, - "techcrunch.com": 0.65, "theverge.com": 0.60, "arstechnica.com": 0.65, - "wired.com": 0.50, "engadget.com": 0.35, "9to5mac.com": 0.30, - "medium.com": 0.55, "dev.to": 0.40, "reddit.com": 0.70, - "news.ycombinator.com": 0.65, "quora.com": 0.20, "stackexchange.com": 0.60, - "imdb.com": 0.45, "rottentomatoes.com": 0.25, "metacritic.com": 0.20, - "allrecipes.com": 0.20, "epicurious.com": 0.15, "tripadvisor.com": 0.30, - "weather.com": 0.55, "timeanddate.com": 0.30, "thesaurus.com": 0.25, - "kayak.com": 0.30, "booking.com": 0.35, "airbnb.com": 0.30 - }, - "high_end": { - "youtube.com": 0.85, "wikipedia.org": 0.80, "mozilla.org": 0.60, - "w3schools.com": 0.45, "mdn.io": 0.45, "duckduckgo.com": 0.40, - "github.com": 0.85, "stackoverflow.com": 0.80, "npmjs.com": 0.50, - "gitlab.com": 0.40, "pypi.org": 0.45, "docs.python.org": 0.50, - "rust-lang.org": 0.30, "go.dev": 0.25, - "amazon.com": 0.75, "ebay.com": 0.30, "etsy.com": 0.20, - "bestbuy.com": 0.50, "target.com": 0.35, - "nytimes.com": 0.50, "cnn.com": 0.50, "bbc.com": 0.50, - "theguardian.com": 0.40, "reuters.com": 0.35, "apnews.com": 0.30, - "washingtonpost.com": 0.35, - "techcrunch.com": 0.60, "theverge.com": 0.65, "arstechnica.com": 0.60, - "wired.com": 0.50, "engadget.com": 0.40, "9to5mac.com": 0.35, - "medium.com": 0.50, "dev.to": 0.35, "reddit.com": 0.75, - "news.ycombinator.com": 0.55, "quora.com": 0.25, "stackexchange.com": 0.55, - "imdb.com": 0.55, "rottentomatoes.com": 0.35, "metacritic.com": 0.30, - "allrecipes.com": 0.25, "epicurious.com": 0.20, "tripadvisor.com": 0.30, - "weather.com": 0.55, "timeanddate.com": 0.30, "thesaurus.com": 0.25, - "kayak.com": 0.30, "booking.com": 0.40, "airbnb.com": 0.30 - }, - "mid_range": { - "youtube.com": 0.85, "wikipedia.org": 0.75, "mozilla.org": 0.45, - "w3schools.com": 0.40, "mdn.io": 0.30, "duckduckgo.com": 0.35, - "github.com": 0.55, "stackoverflow.com": 0.55, "npmjs.com": 0.30, - "gitlab.com": 0.25, "pypi.org": 0.25, "docs.python.org": 0.30, - "rust-lang.org": 0.15, "go.dev": 0.15, - "amazon.com": 0.80, "ebay.com": 0.40, "etsy.com": 0.30, - "bestbuy.com": 0.55, "target.com": 0.40, - "nytimes.com": 0.45, "cnn.com": 0.55, "bbc.com": 0.45, - "theguardian.com": 0.35, "reuters.com": 0.30, "apnews.com": 0.30, - "washingtonpost.com": 0.30, - "techcrunch.com": 0.45, "theverge.com": 0.50, "arstechnica.com": 0.40, - "wired.com": 0.45, "engadget.com": 0.35, "9to5mac.com": 0.30, - "medium.com": 0.45, "dev.to": 0.25, "reddit.com": 0.70, - "news.ycombinator.com": 0.30, "quora.com": 0.35, "stackexchange.com": 0.40, - "imdb.com": 0.60, "rottentomatoes.com": 0.40, "metacritic.com": 0.35, - "allrecipes.com": 0.35, "epicurious.com": 0.25, "tripadvisor.com": 0.40, - "weather.com": 0.60, "timeanddate.com": 0.25, "thesaurus.com": 0.30, - "kayak.com": 0.35, "booking.com": 0.45, "airbnb.com": 0.40 - }, - "low_end": { - "youtube.com": 0.85, "wikipedia.org": 0.70, "mozilla.org": 0.35, - "w3schools.com": 0.30, "mdn.io": 0.20, "duckduckgo.com": 0.30, - "github.com": 0.30, "stackoverflow.com": 0.30, "npmjs.com": 0.15, - "gitlab.com": 0.10, "pypi.org": 0.10, "docs.python.org": 0.15, - "rust-lang.org": 0.05, "go.dev": 0.05, - "amazon.com": 0.85, "ebay.com": 0.50, "etsy.com": 0.40, - "bestbuy.com": 0.55, "target.com": 0.45, - "nytimes.com": 0.40, "cnn.com": 0.60, "bbc.com": 0.40, - "theguardian.com": 0.30, "reuters.com": 0.25, "apnews.com": 0.30, - "washingtonpost.com": 0.25, - "techcrunch.com": 0.30, "theverge.com": 0.35, "arstechnica.com": 0.25, - "wired.com": 0.40, "engadget.com": 0.30, "9to5mac.com": 0.25, - "medium.com": 0.35, "dev.to": 0.15, "reddit.com": 0.65, - "news.ycombinator.com": 0.15, "quora.com": 0.45, "stackexchange.com": 0.25, - "imdb.com": 0.65, "rottentomatoes.com": 0.45, "metacritic.com": 0.35, - "allrecipes.com": 0.45, "epicurious.com": 0.30, "tripadvisor.com": 0.45, - "weather.com": 0.65, "timeanddate.com": 0.25, "thesaurus.com": 0.35, - "kayak.com": 0.35, "booking.com": 0.50, "airbnb.com": 0.40 - }, - "integrated_modern": { - "youtube.com": 0.85, "wikipedia.org": 0.70, "mozilla.org": 0.40, - "w3schools.com": 0.35, "mdn.io": 0.25, "duckduckgo.com": 0.35, - "github.com": 0.40, "stackoverflow.com": 0.40, "npmjs.com": 0.20, - "gitlab.com": 0.15, "pypi.org": 0.20, "docs.python.org": 0.20, - "rust-lang.org": 0.10, "go.dev": 0.10, - "amazon.com": 0.80, "ebay.com": 0.40, "etsy.com": 0.30, - "bestbuy.com": 0.50, "target.com": 0.40, - "nytimes.com": 0.40, "cnn.com": 0.55, "bbc.com": 0.45, - "theguardian.com": 0.35, "reuters.com": 0.30, "apnews.com": 0.30, - "washingtonpost.com": 0.30, - "techcrunch.com": 0.40, "theverge.com": 0.45, "arstechnica.com": 0.30, - "wired.com": 0.40, "engadget.com": 0.30, "9to5mac.com": 0.25, - "medium.com": 0.40, "dev.to": 0.20, "reddit.com": 0.65, - "news.ycombinator.com": 0.25, "quora.com": 0.40, "stackexchange.com": 0.35, - "imdb.com": 0.60, "rottentomatoes.com": 0.40, "metacritic.com": 0.30, - "allrecipes.com": 0.40, "epicurious.com": 0.25, "tripadvisor.com": 0.40, - "weather.com": 0.60, "timeanddate.com": 0.25, "thesaurus.com": 0.30, - "kayak.com": 0.35, "booking.com": 0.45, "airbnb.com": 0.40 - }, - "integrated_old": { - "youtube.com": 0.75, "wikipedia.org": 0.65, "mozilla.org": 0.30, - "w3schools.com": 0.20, "mdn.io": 0.10, "duckduckgo.com": 0.25, - "github.com": 0.15, "stackoverflow.com": 0.20, "npmjs.com": 0.05, - "gitlab.com": 0.05, "pypi.org": 0.05, "docs.python.org": 0.10, - "rust-lang.org": 0.02, "go.dev": 0.02, - "amazon.com": 0.85, "ebay.com": 0.55, "etsy.com": 0.45, - "bestbuy.com": 0.55, "target.com": 0.50, - "nytimes.com": 0.45, "cnn.com": 0.65, "bbc.com": 0.40, - "theguardian.com": 0.30, "reuters.com": 0.25, "apnews.com": 0.35, - "washingtonpost.com": 0.30, - "techcrunch.com": 0.20, "theverge.com": 0.25, "arstechnica.com": 0.15, - "wired.com": 0.30, "engadget.com": 0.20, "9to5mac.com": 0.20, - "medium.com": 0.30, "dev.to": 0.05, "reddit.com": 0.55, - "news.ycombinator.com": 0.05, "quora.com": 0.55, "stackexchange.com": 0.15, - "imdb.com": 0.70, "rottentomatoes.com": 0.50, "metacritic.com": 0.35, - "allrecipes.com": 0.55, "epicurious.com": 0.35, "tripadvisor.com": 0.50, - "weather.com": 0.70, "timeanddate.com": 0.30, "thesaurus.com": 0.40, - "kayak.com": 0.40, "booking.com": 0.55, "airbnb.com": 0.40 - } - } -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_codec_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_codec_given_class.json deleted file mode 100644 index e5a3d05..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_codec_given_class.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "_meta": "codec given gpu_class", - "table": { - "integrated_old": [ - { - "value": { - "av1_enabled": false, - "webm_encoder_enabled": false, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": true - }, - "prob": 1.0 - } - ], - "integrated_modern": [ - { - "value": { - "av1_enabled": true, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": true - }, - "prob": 0.55 - }, - { - "value": { - "av1_enabled": false, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": true - }, - "prob": 0.35 - }, - { - "value": { - "av1_enabled": true, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": false - }, - "prob": 0.1 - } - ], - "low_end": [ - { - "value": { - "av1_enabled": false, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": true - }, - "prob": 0.85 - }, - { - "value": { - "av1_enabled": false, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": false - }, - "prob": 0.15 - } - ], - "mid_range": [ - { - "value": { - "av1_enabled": true, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": true - }, - "prob": 0.55 - }, - { - "value": { - "av1_enabled": false, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": true - }, - "prob": 0.35 - }, - { - "value": { - "av1_enabled": true, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": false - }, - "prob": 0.1 - } - ], - "high_end": [ - { - "value": { - "av1_enabled": true, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": true - }, - "prob": 0.85 - }, - { - "value": { - "av1_enabled": true, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": false - }, - "prob": 0.15 - } - ], - "workstation": [ - { - "value": { - "av1_enabled": true, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": true - }, - "prob": 0.7 - }, - { - "value": { - "av1_enabled": true, - "webm_encoder_enabled": true, - "mediasource_webm": true, - "mediasource_mp4": true, - "webspeech_synth": false - }, - "prob": 0.3 - } - ] - } -} \ No newline at end of file diff --git a/src/invisible_playwright/_fpforge/data/cpt_fonts_optional_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_fonts_optional_given_class.json deleted file mode 100644 index 12c098d..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_fonts_optional_given_class.json +++ /dev/null @@ -1,295 +0,0 @@ -{ - "_meta": { - "name": "optional_font presence | gpu_class", - "parents": [ - "gpu_class" - ], - "child": "optional_fonts_subset", - "description": "Per-optional-font presence probabilities given gpu_class. Each optional font in font_pool.json sampled INDEPENDENTLY with P(present | gpu_class) given here. Integrated_old: fewer language packs (older/cheaper machines). Workstation: more regional/language packs (international users, enterprise deployments).", - "rationale": "Near-invariant by design: most optional fonts have baseline P ~ 0.60-0.85 across classes. Per-session variance is small (~3-6 fonts toggling on/off out of 40 optional). Result: fingerprint always looks like 'typical Windows 11 + Office', with small realistic per-user variance in regional support." - }, - "table": { - "integrated_old": { - "aparajita": 0.45, - "calibri": 0.9, - "dengxian": 0.3, - "dfkai-sb": 0.25, - "dokchampa": 0.2, - "estrangelo edessa": 0.55, - "euphemia": 0.6, - "fangsong": 0.35, - "gadugi": 0.88, - "gautami": 0.55, - "helv": 0.7, - "iskoola pota": 0.5, - "javanese text": 0.85, - "kaiti": 0.3, - "kalinga": 0.5, - "kartika": 0.5, - "khmer ui": 0.35, - "kokila": 0.55, - "lao ui": 0.35, - "latha": 0.65, - "leelawadee ui": 0.87, - "mangal": 0.65, - "meiryo": 0.6, - "microsoft uighur": 0.4, - "ms pmincho": 0.65, - "ms reference sans serif": 0.55, - "ms reference specialty": 0.5, - "ms ui gothic": 0.82, - "myanmar text": 0.84, - "nyala": 0.55, - "plantagenet cherokee": 0.6, - "raavi": 0.55, - "segoe fluent icons": 0.5, - "segoe ui light": 0.75, - "shonar bangla": 0.55, - "shruti": 0.55, - "simkai": 0.25, - "small fonts": 0.75, - "traditional arabic": 0.55, - "tunga": 0.55, - "urdu typesetting": 0.45, - "utsaah": 0.55, - "vani": 0.55, - "vijaya": 0.55, - "yu mincho": 0.55 - }, - "integrated_modern": { - "aparajita": 0.65, - "calibri": 0.78, - "dengxian": 0.5, - "dfkai-sb": 0.4, - "dokchampa": 0.4, - "estrangelo edessa": 0.7, - "euphemia": 0.78, - "fangsong": 0.55, - "gadugi": 0.96, - "gautami": 0.75, - "helv": 0.6, - "iskoola pota": 0.7, - "javanese text": 0.94, - "kaiti": 0.45, - "kalinga": 0.7, - "kartika": 0.7, - "khmer ui": 0.55, - "kokila": 0.75, - "lao ui": 0.55, - "latha": 0.82, - "leelawadee ui": 0.95, - "mangal": 0.82, - "meiryo": 0.8, - "microsoft uighur": 0.55, - "ms pmincho": 0.85, - "ms reference sans serif": 0.72, - "ms reference specialty": 0.68, - "ms ui gothic": 0.75, - "myanmar text": 0.94, - "nyala": 0.72, - "plantagenet cherokee": 0.78, - "raavi": 0.72, - "segoe fluent icons": 0.92, - "segoe ui light": 0.72, - "shonar bangla": 0.72, - "shruti": 0.72, - "simkai": 0.4, - "small fonts": 0.65, - "traditional arabic": 0.72, - "tunga": 0.72, - "urdu typesetting": 0.65, - "utsaah": 0.72, - "vani": 0.72, - "vijaya": 0.72, - "yu mincho": 0.75 - }, - "low_end": { - "aparajita": 0.55, - "calibri": 0.94, - "dengxian": 0.4, - "dfkai-sb": 0.3, - "dokchampa": 0.3, - "estrangelo edessa": 0.62, - "euphemia": 0.68, - "fangsong": 0.45, - "gadugi": 0.93, - "gautami": 0.65, - "helv": 0.78, - "iskoola pota": 0.6, - "javanese text": 0.91, - "kaiti": 0.35, - "kalinga": 0.6, - "kartika": 0.6, - "khmer ui": 0.45, - "kokila": 0.65, - "lao ui": 0.45, - "latha": 0.72, - "leelawadee ui": 0.92, - "mangal": 0.72, - "meiryo": 0.7, - "microsoft uighur": 0.48, - "ms pmincho": 0.75, - "ms reference sans serif": 0.62, - "ms reference specialty": 0.58, - "ms ui gothic": 0.9, - "myanmar text": 0.9, - "nyala": 0.62, - "plantagenet cherokee": 0.68, - "raavi": 0.62, - "segoe fluent icons": 0.8, - "segoe ui light": 0.88, - "shonar bangla": 0.62, - "shruti": 0.62, - "simkai": 0.3, - "small fonts": 0.83, - "traditional arabic": 0.62, - "tunga": 0.62, - "urdu typesetting": 0.55, - "utsaah": 0.62, - "vani": 0.62, - "vijaya": 0.62, - "yu mincho": 0.65 - }, - "mid_range": { - "aparajita": 0.72, - "calibri": 0.98, - "dengxian": 0.6, - "dfkai-sb": 0.5, - "dokchampa": 0.5, - "estrangelo edessa": 0.78, - "euphemia": 0.82, - "fangsong": 0.65, - "gadugi": 0.97, - "gautami": 0.8, - "helv": 0.85, - "iskoola pota": 0.78, - "javanese text": 0.96, - "kaiti": 0.55, - "kalinga": 0.78, - "kartika": 0.78, - "khmer ui": 0.65, - "kokila": 0.8, - "lao ui": 0.65, - "latha": 0.85, - "leelawadee ui": 0.97, - "mangal": 0.85, - "meiryo": 0.85, - "microsoft uighur": 0.65, - "ms pmincho": 0.88, - "ms reference sans serif": 0.78, - "ms reference specialty": 0.75, - "ms ui gothic": 0.96, - "myanmar text": 0.96, - "nyala": 0.78, - "plantagenet cherokee": 0.82, - "raavi": 0.78, - "segoe fluent icons": 0.94, - "segoe ui light": 0.94, - "shonar bangla": 0.78, - "shruti": 0.78, - "simkai": 0.5, - "small fonts": 0.9, - "traditional arabic": 0.78, - "tunga": 0.78, - "urdu typesetting": 0.72, - "utsaah": 0.78, - "vani": 0.78, - "vijaya": 0.78, - "yu mincho": 0.8 - }, - "high_end": { - "aparajita": 0.8, - "calibri": 0.99, - "dengxian": 0.7, - "dfkai-sb": 0.6, - "dokchampa": 0.6, - "estrangelo edessa": 0.85, - "euphemia": 0.88, - "fangsong": 0.72, - "gadugi": 0.98, - "gautami": 0.85, - "helv": 0.88, - "iskoola pota": 0.82, - "javanese text": 0.97, - "kaiti": 0.65, - "kalinga": 0.82, - "kartika": 0.82, - "khmer ui": 0.72, - "kokila": 0.85, - "lao ui": 0.72, - "latha": 0.9, - "leelawadee ui": 0.98, - "mangal": 0.9, - "meiryo": 0.9, - "microsoft uighur": 0.72, - "ms pmincho": 0.92, - "ms reference sans serif": 0.85, - "ms reference specialty": 0.82, - "ms ui gothic": 0.98, - "myanmar text": 0.97, - "nyala": 0.85, - "plantagenet cherokee": 0.88, - "raavi": 0.85, - "segoe fluent icons": 0.97, - "segoe ui light": 0.96, - "shonar bangla": 0.85, - "shruti": 0.85, - "simkai": 0.6, - "small fonts": 0.92, - "traditional arabic": 0.85, - "tunga": 0.85, - "urdu typesetting": 0.8, - "utsaah": 0.85, - "vani": 0.85, - "vijaya": 0.85, - "yu mincho": 0.88 - }, - "workstation": { - "aparajita": 0.88, - "calibri": 0.99, - "dengxian": 0.8, - "dfkai-sb": 0.75, - "dokchampa": 0.72, - "estrangelo edessa": 0.9, - "euphemia": 0.92, - "fangsong": 0.82, - "gadugi": 0.99, - "gautami": 0.92, - "helv": 0.9, - "iskoola pota": 0.9, - "javanese text": 0.98, - "kaiti": 0.78, - "kalinga": 0.9, - "kartika": 0.9, - "khmer ui": 0.8, - "kokila": 0.92, - "lao ui": 0.8, - "latha": 0.95, - "leelawadee ui": 0.99, - "mangal": 0.95, - "meiryo": 0.95, - "microsoft uighur": 0.82, - "ms pmincho": 0.95, - "ms reference sans serif": 0.92, - "ms reference specialty": 0.9, - "ms ui gothic": 0.98, - "myanmar text": 0.98, - "nyala": 0.92, - "plantagenet cherokee": 0.92, - "raavi": 0.92, - "segoe fluent icons": 0.98, - "segoe ui light": 0.97, - "shonar bangla": 0.92, - "shruti": 0.92, - "simkai": 0.72, - "small fonts": 0.94, - "traditional arabic": 0.92, - "tunga": 0.92, - "urdu typesetting": 0.88, - "utsaah": 0.92, - "vani": 0.92, - "vijaya": 0.92, - "yu mincho": 0.92 - } - } -} \ No newline at end of file diff --git a/src/invisible_playwright/_fpforge/data/cpt_hwc_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_hwc_given_class.json deleted file mode 100644 index 68c6ce9..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_hwc_given_class.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "_meta": { - "name": "hw_concurrency | gpu_class", - "parents": ["gpu_class"], - "child": "hw_concurrency", - "source": "Curated from realistic CPU/GPU pairings (Steam HW Survey + DIY build norms + laptop SKU patterns)" - }, - "table": { - "integrated_old": [ - {"value": 2, "prob": 0.20}, - {"value": 4, "prob": 0.60}, - {"value": 8, "prob": 0.20} - ], - "integrated_modern": [ - {"value": 4, "prob": 0.20}, - {"value": 6, "prob": 0.15}, - {"value": 8, "prob": 0.35}, - {"value": 12, "prob": 0.20}, - {"value": 16, "prob": 0.10} - ], - "low_end": [ - {"value": 4, "prob": 0.25}, - {"value": 6, "prob": 0.25}, - {"value": 8, "prob": 0.35}, - {"value": 12, "prob": 0.15} - ], - "mid_range": [ - {"value": 6, "prob": 0.15}, - {"value": 8, "prob": 0.30}, - {"value": 12, "prob": 0.30}, - {"value": 16, "prob": 0.20}, - {"value": 24, "prob": 0.05} - ], - "high_end": [ - {"value": 8, "prob": 0.10}, - {"value": 12, "prob": 0.25}, - {"value": 16, "prob": 0.35}, - {"value": 20, "prob": 0.05}, - {"value": 24, "prob": 0.20}, - {"value": 32, "prob": 0.05} - ], - "workstation": [ - {"value": 8, "prob": 0.15}, - {"value": 12, "prob": 0.20}, - {"value": 16, "prob": 0.30}, - {"value": 24, "prob": 0.20}, - {"value": 32, "prob": 0.15} - ] - } -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_hwc_given_class_tier.json b/src/invisible_playwright/_fpforge/data/cpt_hwc_given_class_tier.json deleted file mode 100644 index b510e9a..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_hwc_given_class_tier.json +++ /dev/null @@ -1,337 +0,0 @@ -{ - "_meta": "hardware_concurrency given (gpu_class, intra_tier)", - "table": { - "[\"integrated_old\", \"budget\"]": [ - { - "value": 2, - "prob": 0.65 - }, - { - "value": 4, - "prob": 0.3 - }, - { - "value": 8, - "prob": 0.05 - } - ], - "[\"integrated_old\", \"standard\"]": [ - { - "value": 2, - "prob": 0.3 - }, - { - "value": 4, - "prob": 0.55 - }, - { - "value": 8, - "prob": 0.15 - } - ], - "[\"integrated_old\", \"premium\"]": [ - { - "value": 4, - "prob": 0.65 - }, - { - "value": 8, - "prob": 0.35 - } - ], - "[\"integrated_modern\", \"budget\"]": [ - { - "value": 6, - "prob": 0.45 - }, - { - "value": 8, - "prob": 0.4 - }, - { - "value": 12, - "prob": 0.15 - } - ], - "[\"integrated_modern\", \"standard\"]": [ - { - "value": 6, - "prob": 0.2 - }, - { - "value": 8, - "prob": 0.3 - }, - { - "value": 10, - "prob": 0.2 - }, - { - "value": 12, - "prob": 0.2 - }, - { - "value": 16, - "prob": 0.1 - } - ], - "[\"integrated_modern\", \"premium\"]": [ - { - "value": 8, - "prob": 0.2 - }, - { - "value": 10, - "prob": 0.2 - }, - { - "value": 12, - "prob": 0.3 - }, - { - "value": 14, - "prob": 0.15 - }, - { - "value": 16, - "prob": 0.15 - } - ], - "[\"low_end\", \"budget\"]": [ - { - "value": 4, - "prob": 0.5 - }, - { - "value": 6, - "prob": 0.25 - }, - { - "value": 8, - "prob": 0.2 - }, - { - "value": 12, - "prob": 0.05 - } - ], - "[\"low_end\", \"standard\"]": [ - { - "value": 4, - "prob": 0.1 - }, - { - "value": 6, - "prob": 0.35 - }, - { - "value": 8, - "prob": 0.3 - }, - { - "value": 12, - "prob": 0.18 - }, - { - "value": 16, - "prob": 0.07 - } - ], - "[\"low_end\", \"premium\"]": [ - { - "value": 6, - "prob": 0.1 - }, - { - "value": 8, - "prob": 0.3 - }, - { - "value": 12, - "prob": 0.3 - }, - { - "value": 16, - "prob": 0.22 - }, - { - "value": 24, - "prob": 0.08 - } - ], - "[\"mid_range\", \"budget\"]": [ - { - "value": 6, - "prob": 0.55 - }, - { - "value": 8, - "prob": 0.3 - }, - { - "value": 12, - "prob": 0.15 - } - ], - "[\"mid_range\", \"standard\"]": [ - { - "value": 6, - "prob": 0.4 - }, - { - "value": 8, - "prob": 0.3 - }, - { - "value": 12, - "prob": 0.18 - }, - { - "value": 16, - "prob": 0.1 - }, - { - "value": 24, - "prob": 0.02 - } - ], - "[\"mid_range\", \"premium\"]": [ - { - "value": 6, - "prob": 0.15 - }, - { - "value": 8, - "prob": 0.45 - }, - { - "value": 12, - "prob": 0.2 - }, - { - "value": 16, - "prob": 0.15 - }, - { - "value": 24, - "prob": 0.05 - } - ], - "[\"high_end\", \"budget\"]": [ - { - "value": 6, - "prob": 0.1 - }, - { - "value": 8, - "prob": 0.55 - }, - { - "value": 12, - "prob": 0.2 - }, - { - "value": 16, - "prob": 0.15 - } - ], - "[\"high_end\", \"standard\"]": [ - { - "value": 8, - "prob": 0.3 - }, - { - "value": 12, - "prob": 0.18 - }, - { - "value": 14, - "prob": 0.15 - }, - { - "value": 16, - "prob": 0.27 - }, - { - "value": 24, - "prob": 0.1 - } - ], - "[\"high_end\", \"premium\"]": [ - { - "value": 12, - "prob": 0.1 - }, - { - "value": 14, - "prob": 0.15 - }, - { - "value": 16, - "prob": 0.3 - }, - { - "value": 24, - "prob": 0.35 - }, - { - "value": 32, - "prob": 0.1 - } - ], - "[\"workstation\", \"budget\"]": [ - { - "value": 8, - "prob": 0.4 - }, - { - "value": 12, - "prob": 0.3 - }, - { - "value": 16, - "prob": 0.2 - }, - { - "value": 24, - "prob": 0.1 - } - ], - "[\"workstation\", \"standard\"]": [ - { - "value": 12, - "prob": 0.1 - }, - { - "value": 16, - "prob": 0.4 - }, - { - "value": 24, - "prob": 0.3 - }, - { - "value": 32, - "prob": 0.2 - } - ], - "[\"workstation\", \"premium\"]": [ - { - "value": 24, - "prob": 0.3 - }, - { - "value": 32, - "prob": 0.45 - }, - { - "value": 48, - "prob": 0.15 - }, - { - "value": 64, - "prob": 0.1 - } - ] - } -} \ No newline at end of file diff --git a/src/invisible_playwright/_fpforge/data/cpt_intra_tier_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_intra_tier_given_class.json deleted file mode 100644 index fcd8f31..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_intra_tier_given_class.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "_meta": { - "name": "intra_tier | gpu_class", - "parents": ["gpu_class"], - "child": "intra_tier", - "value_type": "str (budget|standard|premium)", - "rationale": "Hidden variable catching 'intra-class premium-ness'. Within a gpu_class, users vary in how premium their OTHER components are (RAM, SSD, cores). A mid_range GPU paired with 32 cores + 2TB SSD is a 'premium' mid_range user. Without this var, hwc/screen/storage would be statistically independent given gpu_class — unrealistic (real users pick coherent bundles). Tier distribution biased: integrated_old mostly budget/standard, workstation mostly premium." - }, - "table": { - "integrated_old": [{"value": "budget", "prob": 0.65}, {"value": "standard", "prob": 0.30}, {"value": "premium", "prob": 0.05}], - "integrated_modern": [{"value": "budget", "prob": 0.30}, {"value": "standard", "prob": 0.55}, {"value": "premium", "prob": 0.15}], - "low_end": [{"value": "budget", "prob": 0.50}, {"value": "standard", "prob": 0.40}, {"value": "premium", "prob": 0.10}], - "mid_range": [{"value": "budget", "prob": 0.25}, {"value": "standard", "prob": 0.50}, {"value": "premium", "prob": 0.25}], - "high_end": [{"value": "budget", "prob": 0.15}, {"value": "standard", "prob": 0.50}, {"value": "premium", "prob": 0.35}], - "workstation": [{"value": "budget", "prob": 0.10}, {"value": "standard", "prob": 0.40}, {"value": "premium", "prob": 0.50}] - } -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_msaa_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_msaa_given_class.json deleted file mode 100644 index e5f22d8..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_msaa_given_class.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "_meta": { - "name": "webgl.msaa-samples | gpu_class", - "parents": ["gpu_class"], - "child": "msaa_samples", - "source": "High-end GPUs more likely to have MSAA enabled in games; integrated usually off" - }, - "table": { - "integrated_old": [{"value": 0, "prob": 0.85}, {"value": 2, "prob": 0.15}], - "integrated_modern": [{"value": 0, "prob": 0.70}, {"value": 2, "prob": 0.25}, {"value": 4, "prob": 0.05}], - "low_end": [{"value": 0, "prob": 0.55}, {"value": 2, "prob": 0.35}, {"value": 4, "prob": 0.10}], - "mid_range": [{"value": 0, "prob": 0.35}, {"value": 2, "prob": 0.35}, {"value": 4, "prob": 0.30}], - "high_end": [{"value": 0, "prob": 0.20}, {"value": 2, "prob": 0.25}, {"value": 4, "prob": 0.55}], - "workstation": [{"value": 0, "prob": 0.50}, {"value": 2, "prob": 0.25}, {"value": 4, "prob": 0.25}] - } -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_msaa_given_class_screen.json b/src/invisible_playwright/_fpforge/data/cpt_msaa_given_class_screen.json deleted file mode 100644 index adf5c9e..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_msaa_given_class_screen.json +++ /dev/null @@ -1,305 +0,0 @@ -{ - "_meta": "msaa_samples given (gpu_class, screen_tier)", - "table": { - "[\"integrated_old\", \"1080p\"]": [ - { - "value": 2, - "prob": 0.75 - }, - { - "value": 4, - "prob": 0.2 - }, - { - "value": 8, - "prob": 0.05 - } - ], - "[\"integrated_old\", \"1440p\"]": [ - { - "value": 2, - "prob": 0.85 - }, - { - "value": 4, - "prob": 0.15 - } - ], - "[\"integrated_old\", \"2160p\"]": [ - { - "value": 2, - "prob": 1.0 - } - ], - "[\"integrated_old\", \"ultrawide\"]": [ - { - "value": 2, - "prob": 1.0 - } - ], - "[\"integrated_modern\", \"1080p\"]": [ - { - "value": 2, - "prob": 0.5 - }, - { - "value": 4, - "prob": 0.4 - }, - { - "value": 8, - "prob": 0.1 - } - ], - "[\"integrated_modern\", \"1440p\"]": [ - { - "value": 2, - "prob": 0.6 - }, - { - "value": 4, - "prob": 0.35 - }, - { - "value": 8, - "prob": 0.05 - } - ], - "[\"integrated_modern\", \"2160p\"]": [ - { - "value": 2, - "prob": 0.85 - }, - { - "value": 4, - "prob": 0.15 - } - ], - "[\"integrated_modern\", \"ultrawide\"]": [ - { - "value": 2, - "prob": 0.8 - }, - { - "value": 4, - "prob": 0.2 - } - ], - "[\"low_end\", \"1080p\"]": [ - { - "value": 2, - "prob": 0.4 - }, - { - "value": 4, - "prob": 0.45 - }, - { - "value": 8, - "prob": 0.15 - } - ], - "[\"low_end\", \"1440p\"]": [ - { - "value": 2, - "prob": 0.55 - }, - { - "value": 4, - "prob": 0.4 - }, - { - "value": 8, - "prob": 0.05 - } - ], - "[\"low_end\", \"2160p\"]": [ - { - "value": 2, - "prob": 0.85 - }, - { - "value": 4, - "prob": 0.15 - } - ], - "[\"low_end\", \"ultrawide\"]": [ - { - "value": 2, - "prob": 0.7 - }, - { - "value": 4, - "prob": 0.3 - } - ], - "[\"mid_range\", \"1080p\"]": [ - { - "value": 2, - "prob": 0.3 - }, - { - "value": 4, - "prob": 0.5 - }, - { - "value": 8, - "prob": 0.2 - } - ], - "[\"mid_range\", \"1440p\"]": [ - { - "value": 2, - "prob": 0.4 - }, - { - "value": 4, - "prob": 0.45 - }, - { - "value": 8, - "prob": 0.15 - } - ], - "[\"mid_range\", \"2160p\"]": [ - { - "value": 2, - "prob": 0.65 - }, - { - "value": 4, - "prob": 0.3 - }, - { - "value": 8, - "prob": 0.05 - } - ], - "[\"mid_range\", \"ultrawide\"]": [ - { - "value": 2, - "prob": 0.55 - }, - { - "value": 4, - "prob": 0.4 - }, - { - "value": 8, - "prob": 0.05 - } - ], - "[\"high_end\", \"1080p\"]": [ - { - "value": 2, - "prob": 0.2 - }, - { - "value": 4, - "prob": 0.45 - }, - { - "value": 8, - "prob": 0.35 - } - ], - "[\"high_end\", \"1440p\"]": [ - { - "value": 2, - "prob": 0.25 - }, - { - "value": 4, - "prob": 0.5 - }, - { - "value": 8, - "prob": 0.25 - } - ], - "[\"high_end\", \"2160p\"]": [ - { - "value": 2, - "prob": 0.4 - }, - { - "value": 4, - "prob": 0.45 - }, - { - "value": 8, - "prob": 0.15 - } - ], - "[\"high_end\", \"ultrawide\"]": [ - { - "value": 2, - "prob": 0.3 - }, - { - "value": 4, - "prob": 0.5 - }, - { - "value": 8, - "prob": 0.2 - } - ], - "[\"workstation\", \"1080p\"]": [ - { - "value": 2, - "prob": 0.15 - }, - { - "value": 4, - "prob": 0.5 - }, - { - "value": 8, - "prob": 0.35 - } - ], - "[\"workstation\", \"1440p\"]": [ - { - "value": 2, - "prob": 0.15 - }, - { - "value": 4, - "prob": 0.55 - }, - { - "value": 8, - "prob": 0.3 - } - ], - "[\"workstation\", \"2160p\"]": [ - { - "value": 2, - "prob": 0.25 - }, - { - "value": 4, - "prob": 0.55 - }, - { - "value": 8, - "prob": 0.2 - } - ], - "[\"workstation\", \"ultrawide\"]": [ - { - "value": 2, - "prob": 0.2 - }, - { - "value": 4, - "prob": 0.55 - }, - { - "value": 8, - "prob": 0.25 - } - ] - } -} \ No newline at end of file diff --git a/src/invisible_playwright/_fpforge/data/cpt_screen_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_screen_given_class.json deleted file mode 100644 index f1f3c02..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_screen_given_class.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "_meta": { - "name": "screen | gpu_class", - "parents": ["gpu_class"], - "child": "screen", - "value_shape": {"w": "int css px", "h": "int css px", "dpr": "float", "aw": "availWidth", "ah": "availHeight"}, - "source": "Curated Windows desktop/laptop resolutions. Restricted to width >= 1920 to avoid FP Pro's server-side screen_resolution normalization (FP Pro sorts non-standard landscape resolutions like 1536x864 into [smaller, larger] order in raw_device_attributes.screen_resolution, appearing flipped vs our spoof). All retained resolutions are common and NOT normalized by FP Pro." - }, - "table": { - "integrated_old": [ - {"value": {"w": 1920, "h": 1080, "dpr": 1.0, "aw": 1920, "ah": 1040}, "prob": 0.90}, - {"value": {"w": 1920, "h": 1200, "dpr": 1.0, "aw": 1920, "ah": 1160}, "prob": 0.10} - ], - "integrated_modern": [ - {"value": {"w": 1920, "h": 1080, "dpr": 1.0, "aw": 1920, "ah": 1040}, "prob": 0.60}, - {"value": {"w": 1920, "h": 1080, "dpr": 1.25, "aw": 1920, "ah": 1040}, "prob": 0.18}, - {"value": {"w": 2560, "h": 1440, "dpr": 1.0, "aw": 2560, "ah": 1400}, "prob": 0.10}, - {"value": {"w": 1920, "h": 1200, "dpr": 1.0, "aw": 1920, "ah": 1160}, "prob": 0.08}, - {"value": {"w": 2560, "h": 1600, "dpr": 1.25, "aw": 2560, "ah": 1560}, "prob": 0.04} - ], - "low_end": [ - {"value": {"w": 1920, "h": 1080, "dpr": 1.0, "aw": 1920, "ah": 1040}, "prob": 0.70}, - {"value": {"w": 2560, "h": 1440, "dpr": 1.0, "aw": 2560, "ah": 1400}, "prob": 0.20}, - {"value": {"w": 1920, "h": 1200, "dpr": 1.0, "aw": 1920, "ah": 1160}, "prob": 0.10} - ], - "mid_range": [ - {"value": {"w": 1920, "h": 1080, "dpr": 1.0, "aw": 1920, "ah": 1040}, "prob": 0.50}, - {"value": {"w": 2560, "h": 1440, "dpr": 1.0, "aw": 2560, "ah": 1400}, "prob": 0.25}, - {"value": {"w": 1920, "h": 1080, "dpr": 1.25, "aw": 1920, "ah": 1040}, "prob": 0.08}, - {"value": {"w": 2560, "h": 1440, "dpr": 1.25, "aw": 2560, "ah": 1400}, "prob": 0.05}, - {"value": {"w": 3840, "h": 2160, "dpr": 1.0, "aw": 3840, "ah": 2120}, "prob": 0.04}, - {"value": {"w": 3840, "h": 2160, "dpr": 1.5, "aw": 3840, "ah": 2120}, "prob": 0.04}, - {"value": {"w": 2560, "h": 1080, "dpr": 1.0, "aw": 2560, "ah": 1040}, "prob": 0.04} - ], - "high_end": [ - {"value": {"w": 1920, "h": 1080, "dpr": 1.0, "aw": 1920, "ah": 1040}, "prob": 0.25}, - {"value": {"w": 2560, "h": 1440, "dpr": 1.0, "aw": 2560, "ah": 1400}, "prob": 0.30}, - {"value": {"w": 3840, "h": 2160, "dpr": 1.0, "aw": 3840, "ah": 2120}, "prob": 0.15}, - {"value": {"w": 3840, "h": 2160, "dpr": 1.5, "aw": 3840, "ah": 2120}, "prob": 0.10}, - {"value": {"w": 3440, "h": 1440, "dpr": 1.0, "aw": 3440, "ah": 1400}, "prob": 0.08}, - {"value": {"w": 2560, "h": 1440, "dpr": 1.25, "aw": 2560, "ah": 1400}, "prob": 0.05}, - {"value": {"w": 5120, "h": 1440, "dpr": 1.0, "aw": 5120, "ah": 1400}, "prob": 0.04}, - {"value": {"w": 3840, "h": 2160, "dpr": 2.0, "aw": 3840, "ah": 2120}, "prob": 0.03} - ], - "workstation": [ - {"value": {"w": 1920, "h": 1080, "dpr": 1.0, "aw": 1920, "ah": 1040}, "prob": 0.25}, - {"value": {"w": 2560, "h": 1440, "dpr": 1.0, "aw": 2560, "ah": 1400}, "prob": 0.25}, - {"value": {"w": 3840, "h": 2160, "dpr": 1.0, "aw": 3840, "ah": 2120}, "prob": 0.25}, - {"value": {"w": 3840, "h": 2160, "dpr": 1.5, "aw": 3840, "ah": 2120}, "prob": 0.15}, - {"value": {"w": 5120, "h": 2880, "dpr": 1.0, "aw": 5120, "ah": 2840}, "prob": 0.05}, - {"value": {"w": 3840, "h": 2400, "dpr": 1.5, "aw": 3840, "ah": 2360}, "prob": 0.05} - ] - } -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_screen_given_class_tier.json b/src/invisible_playwright/_fpforge/data/cpt_screen_given_class_tier.json deleted file mode 100644 index d3bc32b..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_screen_given_class_tier.json +++ /dev/null @@ -1,761 +0,0 @@ -{ - "_meta": "screen given (gpu_class, intra_tier)", - "table": { - "[\"integrated_old\", \"budget\"]": [ - { - "value": { - "w": 1366, - "h": 768, - "aw": 1366, - "ah": 728, - "dpr": 1.0 - }, - "prob": 0.78 - }, - { - "value": { - "w": 1280, - "h": 800, - "aw": 1280, - "ah": 760, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 1024, - "h": 768, - "aw": 1024, - "ah": 728, - "dpr": 1.0 - }, - "prob": 0.07 - } - ], - "[\"integrated_old\", \"standard\"]": [ - { - "value": { - "w": 1366, - "h": 768, - "aw": 1366, - "ah": 728, - "dpr": 1.0 - }, - "prob": 0.55 - }, - { - "value": { - "w": 1600, - "h": 900, - "aw": 1600, - "ah": 860, - "dpr": 1.0 - }, - "prob": 0.25 - }, - { - "value": { - "w": 1280, - "h": 800, - "aw": 1280, - "ah": 760, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.1 - } - ], - "[\"integrated_old\", \"premium\"]": [ - { - "value": { - "w": 1600, - "h": 900, - "aw": 1600, - "ah": 860, - "dpr": 1.0 - }, - "prob": 0.45 - }, - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.4 - }, - { - "value": { - "w": 1366, - "h": 768, - "aw": 1366, - "ah": 728, - "dpr": 1.0 - }, - "prob": 0.15 - } - ], - "[\"integrated_modern\", \"budget\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.8 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 1920, - "h": 1200, - "aw": 1920, - "ah": 1160, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"integrated_modern\", \"standard\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.7 - }, - { - "value": { - "w": 1920, - "h": 1200, - "aw": 1920, - "ah": 1160, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.12 - }, - { - "value": { - "w": 2560, - "h": 1600, - "aw": 2560, - "ah": 1560, - "dpr": 1.0 - }, - "prob": 0.08 - } - ], - "[\"integrated_modern\", \"premium\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.3 - }, - { - "value": { - "w": 1920, - "h": 1200, - "aw": 1920, - "ah": 1160, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.25 - }, - { - "value": { - "w": 2560, - "h": 1600, - "aw": 2560, - "ah": 1560, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.2 - } - ], - "[\"low_end\", \"budget\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.85 - }, - { - "value": { - "w": 1920, - "h": 1200, - "aw": 1920, - "ah": 1160, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"low_end\", \"standard\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.6 - }, - { - "value": { - "w": 1920, - "h": 1200, - "aw": 1920, - "ah": 1160, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.25 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"low_end\", \"premium\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.25 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.45 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.2 - }, - { - "value": { - "w": 3440, - "h": 1440, - "aw": 3440, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.05 - }, - { - "value": { - "w": 1920, - "h": 1200, - "aw": 1920, - "ah": 1160, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"mid_range\", \"budget\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.75 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.2 - }, - { - "value": { - "w": 1920, - "h": 1200, - "aw": 1920, - "ah": 1160, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"mid_range\", \"standard\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.45 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.4 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 3440, - "h": 1440, - "aw": 3440, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"mid_range\", \"premium\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.5 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.2 - }, - { - "value": { - "w": 3440, - "h": 1440, - "aw": 3440, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 2560, - "h": 1080, - "aw": 2560, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"high_end\", \"budget\"]": [ - { - "value": { - "w": 1920, - "h": 1080, - "aw": 1920, - "ah": 1040, - "dpr": 1.0 - }, - "prob": 0.2 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.55 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.2 - }, - { - "value": { - "w": 3440, - "h": 1440, - "aw": 3440, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"high_end\", \"standard\"]": [ - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.4 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.4 - }, - { - "value": { - "w": 3440, - "h": 1440, - "aw": 3440, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 5120, - "h": 1440, - "aw": 5120, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"high_end\", \"premium\"]": [ - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.55 - }, - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 3440, - "h": 1440, - "aw": 3440, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 5120, - "h": 1440, - "aw": 5120, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 7680, - "h": 2160, - "aw": 7680, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"workstation\", \"budget\"]": [ - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.55 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.3 - }, - { - "value": { - "w": 1920, - "h": 1200, - "aw": 1920, - "ah": 1160, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 2560, - "h": 1600, - "aw": 2560, - "ah": 1560, - "dpr": 1.0 - }, - "prob": 0.05 - } - ], - "[\"workstation\", \"standard\"]": [ - { - "value": { - "w": 2560, - "h": 1440, - "aw": 2560, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.3 - }, - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.45 - }, - { - "value": { - "w": 2560, - "h": 1600, - "aw": 2560, - "ah": 1560, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 3440, - "h": 1440, - "aw": 3440, - "ah": 1400, - "dpr": 1.0 - }, - "prob": 0.1 - } - ], - "[\"workstation\", \"premium\"]": [ - { - "value": { - "w": 3840, - "h": 2160, - "aw": 3840, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.55 - }, - { - "value": { - "w": 2560, - "h": 1600, - "aw": 2560, - "ah": 1560, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 5120, - "h": 2160, - "aw": 5120, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.15 - }, - { - "value": { - "w": 3840, - "h": 2400, - "aw": 3840, - "ah": 2360, - "dpr": 1.0 - }, - "prob": 0.1 - }, - { - "value": { - "w": 7680, - "h": 2160, - "aw": 7680, - "ah": 2120, - "dpr": 1.0 - }, - "prob": 0.05 - } - ] - } -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_storage_given_class.json b/src/invisible_playwright/_fpforge/data/cpt_storage_given_class.json deleted file mode 100644 index c8647c9..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_storage_given_class.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "_meta": { - "name": "storage_quota_mb | gpu_class", - "parents": ["gpu_class"], - "child": "storage_quota_mb", - "value_shape": "int megabytes (reported as navigator.storage.estimate().quota / (1024*1024))", - "description": "Storage quota override returned by navigator.storage.estimate(). Real Firefox computes quota from disk space, which is a fingerprinting signal (stable per host). We replace it with a realistic per-session value conditioned on gpu_class — modern/high-end users tend to have larger SSDs, integrated_old older/smaller disks.", - "source": "Typical Windows 11 disk sizes 2024-2026 per segment: budget laptops 256-512GB SSD, mainstream 512GB-1TB SSD, gaming/workstation 1-4TB SSD. Firefox default storage quota is ~50% of available disk (capped). We simulate that computation per-tier.", - "rationale": "Values are pre-quota-limit MB as Firefox would return to navigator.storage.estimate().quota. Probabilities cover realistic ranges centered on the segment median. A single session returns one value; fingerprinters that hash the exact quota get per-session variance, matching cross-user diversity." - }, - "table": { - "integrated_old": [ - {"value": 61440, "prob": 0.30}, - {"value": 102400, "prob": 0.25}, - {"value": 122880, "prob": 0.20}, - {"value": 204800, "prob": 0.15}, - {"value": 40960, "prob": 0.10} - ], - "integrated_modern": [ - {"value": 204800, "prob": 0.30}, - {"value": 307200, "prob": 0.25}, - {"value": 122880, "prob": 0.15}, - {"value": 409600, "prob": 0.15}, - {"value": 102400, "prob": 0.10}, - {"value": 512000, "prob": 0.05} - ], - "low_end": [ - {"value": 122880, "prob": 0.30}, - {"value": 204800, "prob": 0.25}, - {"value": 102400, "prob": 0.20}, - {"value": 61440, "prob": 0.15}, - {"value": 307200, "prob": 0.10} - ], - "mid_range": [ - {"value": 307200, "prob": 0.30}, - {"value": 409600, "prob": 0.25}, - {"value": 204800, "prob": 0.20}, - {"value": 512000, "prob": 0.15}, - {"value": 716800, "prob": 0.05}, - {"value": 122880, "prob": 0.05} - ], - "high_end": [ - {"value": 512000, "prob": 0.25}, - {"value": 716800, "prob": 0.25}, - {"value": 409600, "prob": 0.20}, - {"value": 1024000, "prob": 0.15}, - {"value": 307200, "prob": 0.10}, - {"value": 1536000, "prob": 0.05} - ], - "workstation": [ - {"value": 1024000, "prob": 0.25}, - {"value": 1536000, "prob": 0.20}, - {"value": 716800, "prob": 0.20}, - {"value": 2048000, "prob": 0.15}, - {"value": 512000, "prob": 0.10}, - {"value": 3072000, "prob": 0.05}, - {"value": 409600, "prob": 0.05} - ] - } -} diff --git a/src/invisible_playwright/_fpforge/data/cpt_storage_given_class_tier.json b/src/invisible_playwright/_fpforge/data/cpt_storage_given_class_tier.json deleted file mode 100644 index 73746a2..0000000 --- a/src/invisible_playwright/_fpforge/data/cpt_storage_given_class_tier.json +++ /dev/null @@ -1,297 +0,0 @@ -{ - "_meta": "storage_quota_mb given (gpu_class, intra_tier)", - "table": { - "[\"integrated_old\", \"budget\"]": [ - { - "value": 32000, - "prob": 0.3 - }, - { - "value": 64000, - "prob": 0.4 - }, - { - "value": 128000, - "prob": 0.25 - }, - { - "value": 256000, - "prob": 0.05 - } - ], - "[\"integrated_old\", \"standard\"]": [ - { - "value": 64000, - "prob": 0.2 - }, - { - "value": 128000, - "prob": 0.45 - }, - { - "value": 256000, - "prob": 0.25 - }, - { - "value": 500000, - "prob": 0.1 - } - ], - "[\"integrated_old\", \"premium\"]": [ - { - "value": 128000, - "prob": 0.2 - }, - { - "value": 256000, - "prob": 0.45 - }, - { - "value": 500000, - "prob": 0.35 - } - ], - "[\"integrated_modern\", \"budget\"]": [ - { - "value": 256000, - "prob": 0.3 - }, - { - "value": 500000, - "prob": 0.45 - }, - { - "value": 1000000, - "prob": 0.25 - } - ], - "[\"integrated_modern\", \"standard\"]": [ - { - "value": 256000, - "prob": 0.25 - }, - { - "value": 500000, - "prob": 0.45 - }, - { - "value": 1000000, - "prob": 0.25 - }, - { - "value": 2000000, - "prob": 0.05 - } - ], - "[\"integrated_modern\", \"premium\"]": [ - { - "value": 500000, - "prob": 0.25 - }, - { - "value": 1000000, - "prob": 0.5 - }, - { - "value": 2000000, - "prob": 0.2 - }, - { - "value": 4000000, - "prob": 0.05 - } - ], - "[\"low_end\", \"budget\"]": [ - { - "value": 128000, - "prob": 0.2 - }, - { - "value": 256000, - "prob": 0.5 - }, - { - "value": 500000, - "prob": 0.25 - }, - { - "value": 1000000, - "prob": 0.05 - } - ], - "[\"low_end\", \"standard\"]": [ - { - "value": 256000, - "prob": 0.2 - }, - { - "value": 500000, - "prob": 0.5 - }, - { - "value": 1000000, - "prob": 0.25 - }, - { - "value": 2000000, - "prob": 0.05 - } - ], - "[\"low_end\", \"premium\"]": [ - { - "value": 500000, - "prob": 0.2 - }, - { - "value": 1000000, - "prob": 0.5 - }, - { - "value": 2000000, - "prob": 0.25 - }, - { - "value": 4000000, - "prob": 0.05 - } - ], - "[\"mid_range\", \"budget\"]": [ - { - "value": 256000, - "prob": 0.15 - }, - { - "value": 500000, - "prob": 0.5 - }, - { - "value": 1000000, - "prob": 0.3 - }, - { - "value": 2000000, - "prob": 0.05 - } - ], - "[\"mid_range\", \"standard\"]": [ - { - "value": 500000, - "prob": 0.2 - }, - { - "value": 1000000, - "prob": 0.55 - }, - { - "value": 2000000, - "prob": 0.2 - }, - { - "value": 4000000, - "prob": 0.05 - } - ], - "[\"mid_range\", \"premium\"]": [ - { - "value": 1000000, - "prob": 0.4 - }, - { - "value": 2000000, - "prob": 0.45 - }, - { - "value": 4000000, - "prob": 0.15 - } - ], - "[\"high_end\", \"budget\"]": [ - { - "value": 500000, - "prob": 0.15 - }, - { - "value": 1000000, - "prob": 0.5 - }, - { - "value": 2000000, - "prob": 0.3 - }, - { - "value": 4000000, - "prob": 0.05 - } - ], - "[\"high_end\", \"standard\"]": [ - { - "value": 1000000, - "prob": 0.3 - }, - { - "value": 2000000, - "prob": 0.5 - }, - { - "value": 4000000, - "prob": 0.2 - } - ], - "[\"high_end\", \"premium\"]": [ - { - "value": 2000000, - "prob": 0.4 - }, - { - "value": 4000000, - "prob": 0.45 - }, - { - "value": 8000000, - "prob": 0.15 - } - ], - "[\"workstation\", \"budget\"]": [ - { - "value": 1000000, - "prob": 0.3 - }, - { - "value": 2000000, - "prob": 0.5 - }, - { - "value": 4000000, - "prob": 0.2 - } - ], - "[\"workstation\", \"standard\"]": [ - { - "value": 2000000, - "prob": 0.3 - }, - { - "value": 4000000, - "prob": 0.5 - }, - { - "value": 8000000, - "prob": 0.2 - } - ], - "[\"workstation\", \"premium\"]": [ - { - "value": 4000000, - "prob": 0.35 - }, - { - "value": 8000000, - "prob": 0.45 - }, - { - "value": 16000000, - "prob": 0.2 - } - ] - } -} diff --git a/src/invisible_playwright/_fpforge/data/ff_win_distributions.json b/src/invisible_playwright/_fpforge/data/ff_win_distributions.json deleted file mode 100644 index becf2f5..0000000 --- a/src/invisible_playwright/_fpforge/data/ff_win_distributions.json +++ /dev/null @@ -1,650 +0,0 @@ -{ - "_source": "browserforge fingerprint-network.zip, FF/Windows slice, 3 userAgent leaves merged", - "_ff_win_uas": [ - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0" - ], - "_note": "Per-node weighted distributions. Marginal over the 3 Firefox/Windows UAs present in browserforge data.", - "distributions": { - "appCodeName": [ - [ - "Mozilla", - 1.0 - ] - ], - "appVersion": [ - [ - "5.0 (Windows)", - 1.0 - ] - ], - "doNotTrack": [ - [ - "1", - 1.0 - ] - ], - "extraProperties": [ - [ - { - "vendorFlavors": [], - "globalPrivacyControl": true, - "pdfViewerEnabled": true, - "installedApps": [] - }, - 0.6111111111111112 - ], - [ - { - "vendorFlavors": [], - "globalPrivacyControl": null, - "pdfViewerEnabled": null, - "installedApps": [] - }, - 0.3888888888888889 - ] - ], - "maxTouchPoints": [ - [ - 0, - 0.5777777777777778 - ], - [ - 1, - 0.3666666666666667 - ], - [ - 10, - 0.05555555555555555 - ] - ], - "oscpu": [ - [ - "Windows NT 10.0; Win64; x64", - 1.0 - ] - ], - "webdriver": [ - [ - false, - 1.0 - ] - ], - "productSub": [ - [ - "20100101", - 1.0 - ] - ], - "hardwareConcurrency": [ - [ - 12, - 0.3333333333333333 - ], - [ - 16, - 0.2777777777777778 - ], - [ - 8, - 0.13333333333333333 - ], - [ - 24, - 0.13333333333333333 - ], - [ - 32, - 0.06666666666666667 - ], - [ - 6, - 0.05555555555555555 - ] - ], - "platform": [ - [ - "Win32", - 1.0 - ] - ], - "screen": [ - [ - { - "availTop": 0, - "availLeft": 0, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 772, - "hasHDR": false, - "width": 1536, - "height": 960, - "availWidth": 1536, - "availHeight": 960, - "clientWidth": 0, - "clientHeight": 21, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 751, - "outerHeight": 886, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1.25 - }, - 0.3333333333333333 - ], - [ - { - "availTop": 0, - "availLeft": 2176, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 2169, - "hasHDR": false, - "width": 2176, - "height": 1224, - "availWidth": 2176, - "availHeight": 1176, - "clientWidth": 0, - "clientHeight": 19, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 2190, - "outerHeight": 1190, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1.7647058823529411 - }, - 0.13333333333333333 - ], - [ - { - "availTop": 0, - "availLeft": 0, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 318, - "hasHDR": false, - "width": 2560, - "height": 1440, - "availWidth": 2560, - "availHeight": 1440, - "clientWidth": 0, - "clientHeight": 18, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 2121, - "outerHeight": 1191, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1 - }, - 0.1111111111111111 - ], - [ - { - "availTop": 0, - "availLeft": 0, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 652, - "hasHDR": false, - "width": 2752, - "height": 1152, - "availWidth": 2752, - "availHeight": 1104, - "clientWidth": 0, - "clientHeight": 19, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 1806, - "outerHeight": 1104, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1.25 - }, - 0.06666666666666667 - ], - [ - { - "availTop": 0, - "availLeft": 0, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 1912, - "hasHDR": false, - "width": 1920, - "height": 1080, - "availWidth": 1920, - "availHeight": 1032, - "clientWidth": 0, - "clientHeight": 18, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 1936, - "outerHeight": 1048, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1 - }, - 0.06666666666666667 - ], - [ - { - "availTop": 29, - "availLeft": 21, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 15, - "hasHDR": false, - "width": 1376, - "height": 774, - "availWidth": 1355, - "availHeight": 745, - "clientWidth": 0, - "clientHeight": 21, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 1352, - "outerHeight": 749, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1 - }, - 0.05555555555555555 - ], - [ - { - "availTop": 0, - "availLeft": 0, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 58, - "hasHDR": false, - "width": 1707, - "height": 960, - "availWidth": 1707, - "availHeight": 928, - "clientWidth": 0, - "clientHeight": 19, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 1564, - "outerHeight": 793, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1 - }, - 0.05555555555555555 - ], - [ - { - "availTop": 0, - "availLeft": 0, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 34, - "hasHDR": false, - "width": 5120, - "height": 1440, - "availWidth": 5120, - "availHeight": 1392, - "clientWidth": 0, - "clientHeight": 18, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 2462, - "outerHeight": 1399, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1 - }, - 0.05555555555555555 - ], - [ - { - "availTop": 0, - "availLeft": 1920, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 1912, - "hasHDR": false, - "width": 1920, - "height": 1080, - "availWidth": 1920, - "availHeight": 1032, - "clientWidth": 0, - "clientHeight": 18, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 1936, - "outerHeight": 1048, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1 - }, - 0.05555555555555555 - ], - [ - { - "availTop": 0, - "availLeft": 0, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 95, - "hasHDR": false, - "width": 1366, - "height": 768, - "availWidth": 1366, - "availHeight": 768, - "clientWidth": 0, - "clientHeight": 18, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 1294, - "outerHeight": 1280, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1 - }, - 0.03333333333333333 - ], - [ - { - "availTop": 0, - "availLeft": 0, - "pageXOffset": 0, - "pageYOffset": 0, - "screenX": 1273, - "hasHDR": false, - "width": 2560, - "height": 1440, - "availWidth": 2560, - "availHeight": 1400, - "clientWidth": 0, - "clientHeight": 18, - "innerWidth": 0, - "innerHeight": 0, - "outerWidth": 1294, - "outerHeight": 1407, - "colorDepth": 24, - "pixelDepth": 24, - "devicePixelRatio": 1 - }, - 0.03333333333333333 - ] - ], - "pluginsData": [ - [ - { - "plugins": [ - { - "name": "PDF Viewer", - "description": "Portable Document Format", - "filename": "internal-pdf-viewer", - "mimeTypes": [ - { - "type": "application/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - }, - { - "type": "text/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - } - ] - }, - { - "name": "Chrome PDF Viewer", - "description": "Portable Document Format", - "filename": "internal-pdf-viewer", - "mimeTypes": [ - { - "type": "application/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - }, - { - "type": "text/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - } - ] - }, - { - "name": "Chromium PDF Viewer", - "description": "Portable Document Format", - "filename": "internal-pdf-viewer", - "mimeTypes": [ - { - "type": "application/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - }, - { - "type": "text/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - } - ] - }, - { - "name": "Microsoft Edge PDF Viewer", - "description": "Portable Document Format", - "filename": "internal-pdf-viewer", - "mimeTypes": [ - { - "type": "application/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - }, - { - "type": "text/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - } - ] - }, - { - "name": "WebKit built-in PDF", - "description": "Portable Document Format", - "filename": "internal-pdf-viewer", - "mimeTypes": [ - { - "type": "application/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - }, - { - "type": "text/pdf", - "suffixes": "pdf", - "description": "Portable Document Format", - "enabledPlugin": "PDF Viewer" - } - ] - } - ], - "mimeTypes": [ - "Portable Document Format~~application/pdf~~pdf", - "Portable Document Format~~text/pdf~~pdf" - ] - }, - 0.6111111111111112 - ], - [ - { - "plugins": [], - "mimeTypes": [] - }, - 0.3888888888888889 - ] - ], - "audioCodecs": [ - [ - { - "ogg": "probably", - "mp3": "maybe", - "wav": "probably", - "m4a": "maybe", - "aac": "maybe" - }, - 1.0 - ] - ], - "videoCodecs": [ - [ - { - "ogg": "", - "h264": "probably", - "webm": "probably" - }, - 1.0 - ] - ], - "videoCard": [ - [ - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar", - "vendor": "Google Inc. (NVIDIA)" - }, - 0.8444444444444444 - ], - [ - { - "renderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar", - "vendor": "Google Inc. (AMD)" - }, - 0.08888888888888889 - ], - [ - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar", - "vendor": "Google Inc. (Intel)" - }, - 0.06666666666666667 - ] - ], - "multimediaDevices": [ - [ - { - "speakers": [], - "micros": [], - "webcams": [] - }, - 1.0 - ] - ], - "fonts": [ - [ - [], - 0.3888888888888889 - ], - [ - [ - "Calibri", - "HELV", - "MS UI Gothic", - "Marlett", - "Segoe UI Light", - "Small Fonts" - ], - 0.3222222222222222 - ], - [ - [ - "Agency FB", - "Calibri", - "Century", - "Century Gothic", - "Franklin Gothic", - "HELV", - "Haettenschweiler", - "Leelawadee", - "Lucida Bright", - "Lucida Sans", - "MS Outlook", - "MS Reference Specialty", - "MS UI Gothic", - "MT Extra", - "Marlett", - "Microsoft Uighur", - "Monotype Corsiva", - "Pristina", - "Segoe UI Light", - "Small Fonts" - ], - 0.13333333333333333 - ], - [ - [ - "AvantGarde Bk BT", - "Calibri", - "Clarendon", - "Franklin Gothic", - "Futura Bk BT", - "Futura Md BT", - "GOTHAM", - "HELV", - "Humanst521 BT", - "MS UI Gothic", - "MYRIAD PRO", - "Marlett", - "Minion Pro", - "Segoe UI Light", - "Small Fonts", - "TRAJAN PRO" - ], - 0.06666666666666667 - ], - [ - [ - "Calibri", - "MS UI Gothic", - "Marlett", - "Segoe UI Light" - ], - 0.05555555555555555 - ], - [ - [ - "Agency FB", - "Calibri", - "Century", - "Century Gothic", - "Franklin Gothic", - "Futura Bk BT", - "Futura Md BT", - "GOTHAM", - "HELV", - "Haettenschweiler", - "Humanst521 BT", - "Lucida Bright", - "Lucida Sans", - "MS Outlook", - "MS Reference Specialty", - "MS UI Gothic", - "MT Extra", - "MYRIAD PRO", - "Marlett", - "Minion Pro", - "Monotype Corsiva", - "Pristina", - "Segoe UI Light", - "Small Fonts" - ], - 0.03333333333333333 - ] - ] - } -} \ No newline at end of file diff --git a/src/invisible_playwright/_fpforge/data/font_pool.json b/src/invisible_playwright/_fpforge/data/font_pool.json deleted file mode 100644 index 880f410..0000000 --- a/src/invisible_playwright/_fpforge/data/font_pool.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "core": [ - { - "name": "arial" - }, - { - "name": "calibri" - }, - { - "name": "cambria" - }, - { - "name": "cambria math" - }, - { - "name": "candara" - }, - { - "name": "comic sans ms" - }, - { - "name": "consolas" - }, - { - "name": "constantia" - }, - { - "name": "corbel" - }, - { - "name": "courier new" - }, - { - "name": "ebrima" - }, - { - "name": "franklin gothic medium" - }, - { - "name": "gabriola" - }, - { - "name": "gadugi" - }, - { - "name": "georgia" - }, - { - "name": "impact" - }, - { - "name": "javanese text" - }, - { - "name": "lucida console" - }, - { - "name": "lucida sans unicode" - }, - { - "name": "ms gothic" - }, - { - "name": "ms pgothic" - }, - { - "name": "mv boli" - }, - { - "name": "malgun gothic" - }, - { - "name": "marlett" - }, - { - "name": "microsoft himalaya" - }, - { - "name": "microsoft jhenghei" - }, - { - "name": "microsoft jhenghei ui" - }, - { - "name": "microsoft new tai lue" - }, - { - "name": "microsoft phagspa" - }, - { - "name": "microsoft sans serif" - }, - { - "name": "microsoft yahei" - }, - { - "name": "microsoft yi baiti" - }, - { - "name": "mingliu-extb" - }, - { - "name": "mongolian baiti" - }, - { - "name": "myanmar text" - }, - { - "name": "pmingliu-extb" - }, - { - "name": "palatino linotype" - }, - { - "name": "segoe print" - }, - { - "name": "segoe script" - }, - { - "name": "segoe ui" - }, - { - "name": "segoe ui symbol" - }, - { - "name": "simsun" - }, - { - "name": "simsun-extb" - }, - { - "name": "sitka small" - }, - { - "name": "sylfaen" - }, - { - "name": "trebuchet ms" - }, - { - "name": "verdana" - }, - { - "name": "webdings" - }, - { - "name": "yu gothic" - }, - { - "name": "courier" - }, - { - "name": "helvetica" - }, - { - "name": "segoe ui light" - } - ], - "optional": [], - "profiles": [ - { - "name": "win_clean", - "weight": 35, - "optional": [] - }, - { - "name": "win_office", - "weight": 65, - "optional": [] - } - ] -} diff --git a/src/invisible_playwright/_fpforge/data/prior_audio.json b/src/invisible_playwright/_fpforge/data/prior_audio.json deleted file mode 100644 index 866cedc..0000000 --- a/src/invisible_playwright/_fpforge/data/prior_audio.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "_meta": { - "name": "audio (joint: sample_rate, output_latency_ms, max_channel_count)", - "parents": [], - "child": "audio", - "source": "Curated from common Windows WASAPI/DirectSound configs on FF desktop" - }, - "table": [ - {"value": {"rate": 44100, "latency": 40, "channels": 2}, "prob": 0.20}, - {"value": {"rate": 48000, "latency": 30, "channels": 2}, "prob": 0.25}, - {"value": {"rate": 48000, "latency": 20, "channels": 2}, "prob": 0.15}, - {"value": {"rate": 48000, "latency": 40, "channels": 6}, "prob": 0.08}, - {"value": {"rate": 48000, "latency": 60, "channels": 2}, "prob": 0.12}, - {"value": {"rate": 44100, "latency": 50, "channels": 2}, "prob": 0.10}, - {"value": {"rate": 48000, "latency": 25, "channels": 2}, "prob": 0.10} - ] -} diff --git a/src/invisible_playwright/_fpforge/data/priors_independent.json b/src/invisible_playwright/_fpforge/data/priors_independent.json deleted file mode 100644 index 0b2bbc0..0000000 --- a/src/invisible_playwright/_fpforge/data/priors_independent.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "_meta": { - "name": "Independent marginal priors (no parents)", - "source": "StatCounter GlobalStats + Firefox defaults + community data 2025-2026", - "note": "Codec prefs (av1_enabled, webm_encoder_enabled, hw_video_decoding, wmf_enabled, ffvpx_enabled) moved to cpt_codec_given_class.json — they correlate with GPU class via Firefox version / user-tier distribution." - }, - "dark_theme": { - "_note": "0=light, 1=dark. StatCounter ~40% users report dark theme preference on desktop.", - "table": [ - {"value": 0, "prob": 0.60}, - {"value": 1, "prob": 0.40} - ] - } -} diff --git a/src/invisible_playwright/_fpforge/data/webgl_gpu_pool.json b/src/invisible_playwright/_fpforge/data/webgl_gpu_pool.json deleted file mode 100644 index 76f0fe5..0000000 --- a/src/invisible_playwright/_fpforge/data/webgl_gpu_pool.json +++ /dev/null @@ -1,476 +0,0 @@ -{ - "win": [ - { - "vendor": "Google Inc. (NVIDIA)", - "renderer_out": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar", - "prob": 0.470921, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (NVIDIA)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212988,35379|200704,35380|256,35657|4096,35658|16380,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|8,36203|4294967294,36347|4095,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (Intel)", - "renderer_out": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar", - "prob": 0.195745, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (Intel)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|8,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (Intel)", - "renderer_out": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0), or similar", - "prob": 0.160284, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (Intel)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|16,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (AMD)", - "renderer_out": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar", - "prob": 0.086524, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (AMD)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|8,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (AMD)", - "renderer_out": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0), or similar", - "prob": 0.053901, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (AMD)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|8,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (Microsoft)", - "renderer_out": "ANGLE (Microsoft, Microsoft Basic Render Driver Direct3D11 vs_5_0 ps_5_0), or similar", - "prob": 0.012766, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (Microsoft, Microsoft Basic Render Driver Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (Microsoft)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|0,32937|0,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|16,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (Intel)", - "renderer_out": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0)", - "prob": 0.007092, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (Intel)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|8,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (Intel)", - "renderer_out": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_1 ps_4_1), or similar", - "prob": 0.004255, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_1 ps_4_1, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (Intel)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|8192,34045|2,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|512,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|4,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16383:16383,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (AMD)", - "renderer_out": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0)", - "prob": 0.001419, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (AMD)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|8,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (Intel)", - "renderer_out": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_0 ps_4_0)", - "prob": 0.001419, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_0 ps_4_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (Intel)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3317|4,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32936|0,32937|0,32938|1,32968|0,32969|1,32970|0,32971|1,33170|4352,34016|33984,34024|8192,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34877|32774,34921|16,34930|16,35660|16,35661|32,35738|5121,35739|6408,36003|0,36004|2147483647,36005|2147483647,36347|4096,36348|14,36349|1024,37443|37444", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16383:16383,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": false - } - }, - { - "vendor": "Google Inc. (NVIDIA)", - "renderer_out": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_4_0 ps_4_0)", - "prob": 0.001419, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_4_0 ps_4_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (NVIDIA)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3317|4,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33170|4352,34016|33984,34024|8192,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34877|32774,34921|16,34930|16,35660|16,35661|32,35738|5121,35739|6408,36003|0,36004|2147483647,36005|2147483647,36347|4095,36348|14,36349|1024,37443|37444", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16383:16383,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": false - } - }, - { - "vendor": "Google Inc. (Intel)", - "renderer_out": "ANGLE (Intel, Intel 945GM Direct3D11 vs_4_0 ps_4_0)", - "prob": 0.001419, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (Intel, Intel 945GM Direct3D11 vs_4_0 ps_4_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (Intel)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3317|4,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32936|0,32937|0,32938|1,32968|0,32969|1,32970|0,32971|1,33170|4352,34016|33984,34024|8192,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34877|32774,34921|16,34930|16,35660|16,35661|32,35738|5121,35739|6408,36003|0,36004|2147483647,36005|2147483647,36347|4096,36348|14,36349|1024,37443|37444", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16383:16383,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": false - } - }, - { - "vendor": "Google Inc. (Intel)", - "renderer_out": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_1 ps_4_1)", - "prob": 0.001419, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_4_1 ps_4_1, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (Intel)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|8192,34045|2,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|512,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212992,35379|200704,35380|256,35657|4096,35658|16384,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|4,36203|4294967294,36347|4096,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16383:16383,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (NVIDIA)", - "renderer_out": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0)", - "prob": 0.001419, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (NVIDIA)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212988,35379|200704,35380|256,35657|4096,35658|16380,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|8,36203|4294967294,36347|4095,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - } - ], - "mac": [ - { - "vendor": "Apple", - "renderer_out": "Apple M1, or similar", - "prob": 0.84322, - "prefs": { - "zoom.stealth.webgl.renderer": "Apple M1, or similar", - "zoom.stealth.webgl.vendor": "Apple", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|4294967295,2964|7680,2965|7680,2966|7680,2967|0,2968|4294967295,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|1048575,33001|150000,33170|4352,34016|33984,34024|8192,34045|16,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|16,35373|16,35374|80,35375|80,35376|65536,35377|266240,35379|266240,35380|256,35657|4096,35658|4096,35659|124,35660|16,35661|80,35723|4352,35738|5121,35739|6408,35968|4,35978|64,35979|4,36003|0,36004|4294967295,36005|4294967295,36063|8,36183|4,36203|4294967295,36347|1024,36348|32,36349|1024,37137|18446744073709552000,37154|64,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33901|1:64,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Intel Inc.", - "renderer_out": "Intel(R) HD Graphics 400, or similar", - "prob": 0.076271, - "prefs": { - "zoom.stealth.webgl.renderer": "Intel(R) HD Graphics 400, or similar", - "zoom.stealth.webgl.vendor": "Intel Inc.", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|4294967295,2964|7680,2965|7680,2966|7680,2967|0,2968|4294967295,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|1048575,33001|150000,33170|4352,34016|33984,34024|8192,34045|16,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|15,35373|15,35374|75,35375|75,35376|65536,35377|249856,35379|249856,35380|256,35657|4096,35658|4096,35659|60,35660|16,35661|80,35723|4352,35738|5121,35739|6408,35968|4,35978|64,35979|4,36003|0,36004|4294967295,36005|4294967295,36063|8,36183|16,36203|4294967295,36347|1024,36348|32,36349|1024,37137|18446744073709552000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33902|1:1", - "zoom.stealth.webgl.float_params": "33901|1:255.875", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "ATI Technologies Inc.", - "renderer_out": "Radeon R9 200 Series, or similar", - "prob": 0.038136, - "prefs": { - "zoom.stealth.webgl.renderer": "Radeon R9 200 Series, or similar", - "zoom.stealth.webgl.vendor": "ATI Technologies Inc.", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|4294967295,2964|7680,2965|7680,2966|7680,2967|0,2968|4294967295,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|16384,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|1048575,33001|150000,33170|4352,34016|33984,34024|8192,34045|16,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|16,35373|16,35374|80,35375|80,35376|65536,35377|266240,35379|266240,35380|256,35657|4096,35658|4096,35659|128,35660|16,35661|80,35723|4352,35738|5121,35739|6408,35968|4,35978|64,35979|4,36003|0,36004|4294967295,36005|4294967295,36063|8,36183|8,36203|4294967295,36347|1024,36348|32,36349|1024,37137|18446744073709552000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33901|1:8191,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Intel Inc.", - "renderer_out": "Intel(R) HD Graphics, or similar", - "prob": 0.033898, - "prefs": { - "zoom.stealth.webgl.renderer": "Intel(R) HD Graphics, or similar", - "zoom.stealth.webgl.vendor": "Intel Inc.", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|4294967295,2964|7680,2965|7680,2966|7680,2967|0,2968|4294967295,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|1048575,33001|150000,33170|4352,34016|33984,34024|8192,34045|16,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|15,35373|15,35374|75,35375|75,35376|65536,35377|249856,35379|249856,35380|256,35657|4096,35658|4096,35659|60,35660|16,35661|80,35723|4352,35738|5121,35739|6408,35968|4,35978|64,35979|4,36003|0,36004|4294967295,36005|4294967295,36063|8,36183|16,36203|4294967295,36347|1024,36348|32,36349|1024,37137|18446744073709552000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33902|1:1", - "zoom.stealth.webgl.float_params": "33901|1:255.875", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Google Inc. (NVIDIA)", - "renderer_out": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar", - "prob": 0.008475, - "prefs": { - "zoom.stealth.webgl.renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "zoom.stealth.webgl.vendor": "Google Inc. (NVIDIA)", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context,WEBGL_provoking_vertex", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|2147483647,2964|7680,2965|7680,2966|7680,2967|0,2968|2147483647,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|2147483647,33001|2147483647,33170|4352,34016|33984,34024|16384,34045|2,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|16,35071|2048,35076|-8,35077|7,35371|12,35373|12,35374|24,35375|24,35376|65536,35377|212988,35379|200704,35380|256,35657|4096,35658|16380,35659|120,35660|16,35661|32,35723|4352,35738|5121,35739|6408,35968|4,35978|120,35979|4,36003|0,36004|2147483647,36005|2147483647,36063|8,36183|8,36203|4294967294,36347|4095,36348|30,36349|1024,37137|0,37154|120,37157|120,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32767:32767,33901|1:1024,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|31:30:0,35633*36340|31:30:0,35633*36341|31:30:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|31:30:0,35632*36340|31:30:0,35632*36341|31:30:0", - "zoom.stealth.webgl2.enabled": true - } - } - ], - "lin": [ - { - "vendor": "Intel", - "renderer_out": "Intel(R) HD Graphics, or similar", - "prob": 0.282051, - "prefs": { - "zoom.stealth.webgl.renderer": "Intel(R) HD Graphics, or similar", - "zoom.stealth.webgl.vendor": "Intel", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|255,2964|7680,2965|7680,2966|7680,2967|0,2968|255,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|3000,33001|3000,33170|4352,34016|33984,34024|8192,34045|15,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-8,35077|7,35371|15,35373|15,35374|90,35375|90,35376|65536,35377|262144,35379|262144,35380|32,35657|16384,35658|16384,35659|128,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|16,35978|64,35979|4,36003|0,36004|255,36005|255,36063|8,36183|16,36203|4294967295,36347|4096,36348|32,36349|4096,37137|9223372034707292000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33901|1:255,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "NVIDIA Corporation", - "renderer_out": "NVIDIA GeForce GTX 980, or similar", - "prob": 0.25641, - "prefs": { - "zoom.stealth.webgl.renderer": "NVIDIA GeForce GTX 980, or similar", - "zoom.stealth.webgl.vendor": "NVIDIA Corporation", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|4294967295,2964|7680,2965|7680,2966|7680,2967|0,2968|4294967295,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|32768,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|16384,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|1048576,33001|1048576,33170|4352,34016|33984,34024|32768,34045|15,34076|32768,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-8,35077|7,35371|14,35373|14,35374|84,35375|84,35376|65536,35377|233472,35379|233472,35380|256,35657|4096,35658|4096,35659|124,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|4,35978|128,35979|4,36003|0,36004|4294967295,36005|4294967295,36063|8,36183|32,36203|4294967295,36347|1024,36348|32,36349|1024,37137|18446744073709552000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32768:32768,33901|1:2047,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Intel", - "renderer_out": "Intel(R) HD Graphics 400, or similar", - "prob": 0.153846, - "prefs": { - "zoom.stealth.webgl.renderer": "Intel(R) HD Graphics 400, or similar", - "zoom.stealth.webgl.vendor": "Intel", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|255,2964|7680,2965|7680,2966|7680,2967|0,2968|255,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|3000,33001|3000,33170|4352,34016|33984,34024|8192,34045|15,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-8,35077|7,35371|15,35373|15,35374|90,35375|90,35376|65536,35377|262144,35379|262144,35380|32,35657|16384,35658|16384,35659|128,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|16,35978|64,35979|4,36003|0,36004|255,36005|255,36063|8,36183|8,36203|4294967295,36347|4096,36348|32,36349|4096,37137|9223372034707292000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33901|1:255,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "AMD", - "renderer_out": "Radeon R9 200 Series, or similar", - "prob": 0.102564, - "prefs": { - "zoom.stealth.webgl.renderer": "Radeon R9 200 Series, or similar", - "zoom.stealth.webgl.vendor": "AMD", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|255,2964|7680,2965|7680,2966|7680,2967|0,2968|255,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|3000,33001|3000,33170|4352,34016|33984,34024|16384,34045|16,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-32,35077|31,35371|15,35373|15,35374|90,35375|90,35376|4294967292,35377|16106143729,35379|16106143729,35380|4,35657|16384,35658|16384,35659|128,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|128,35978|128,35979|4,36003|0,36004|255,36005|255,36063|8,36183|8,36203|4294967295,36347|4096,36348|32,36349|4096,37137|9223372034707292000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33902|1:1", - "zoom.stealth.webgl.float_params": "33901|0.125:2048", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "AMD", - "renderer_out": "Radeon HD 3200 Graphics, or similar", - "prob": 0.083333, - "prefs": { - "zoom.stealth.webgl.renderer": "Radeon HD 3200 Graphics, or similar", - "zoom.stealth.webgl.vendor": "AMD", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|255,2964|7680,2965|7680,2966|7680,2967|0,2968|255,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|3000,33001|3000,33170|4352,34016|33984,34024|16384,34045|16,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-32,35077|31,35371|15,35373|15,35374|90,35375|90,35376|4051211264,35377|15192058624,35379|15192058624,35380|4,35657|16384,35658|16384,35659|128,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|128,35978|128,35979|4,36003|0,36004|255,36005|255,36063|8,36183|8,36203|4294967295,36347|4096,36348|32,36349|4096,37137|9223372034707292000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33902|1:1", - "zoom.stealth.webgl.float_params": "33901|0.125:2048", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Mesa", - "renderer_out": "llvmpipe, or similar", - "prob": 0.070513, - "prefs": { - "zoom.stealth.webgl.renderer": "llvmpipe, or similar", - "zoom.stealth.webgl.vendor": "Mesa", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|255,2964|7680,2965|7680,2966|7680,2967|0,2968|255,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|3000,33001|3000,33170|4352,34016|33984,34024|16384,34045|16,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-32,35077|31,35371|15,35373|15,35374|90,35375|90,35376|65536,35377|262144,35379|262144,35380|16,35657|16384,35658|16384,35659|128,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|64,35978|64,35979|4,36003|0,36004|255,36005|255,36063|8,36183|4,36203|4294967295,36347|4096,36348|32,36349|4096,37137|9223372034707292000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33901|1:255,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Intel", - "renderer_out": "Intel(R) HD Graphics 400", - "prob": 0.019231, - "prefs": { - "zoom.stealth.webgl.renderer": "Intel(R) HD Graphics 400", - "zoom.stealth.webgl.vendor": "Intel", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|255,2964|7680,2965|7680,2966|7680,2967|0,2968|255,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|8192,3408|4,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|3000,33001|3000,33170|4352,34016|33984,34024|8192,34045|15,34076|8192,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-8,35077|7,35371|15,35373|15,35374|90,35375|90,35376|65536,35377|262144,35379|262144,35380|32,35657|16384,35658|16384,35659|128,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|16,35978|64,35979|4,36003|0,36004|255,36005|255,36063|8,36183|8,36203|4294967295,36347|4096,36348|32,36349|4096,37137|9223372034707292000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33901|1:255,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Mesa", - "renderer_out": "llvmpipe", - "prob": 0.019231, - "prefs": { - "zoom.stealth.webgl.renderer": "llvmpipe", - "zoom.stealth.webgl.vendor": "Mesa", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|255,2964|7680,2965|7680,2966|7680,2967|0,2968|255,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|3000,33001|3000,33170|4352,34016|33984,34024|16384,34045|16,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-32,35077|31,35371|15,35373|15,35374|90,35375|90,35376|65536,35377|262144,35379|262144,35380|16,35657|16384,35658|16384,35659|128,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|64,35978|64,35979|4,36003|0,36004|255,36005|255,36063|8,36183|4,36203|4294967295,36347|4096,36348|32,36349|4096,37137|9223372034707292000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33901|1:255,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "NVIDIA Corporation", - "renderer_out": "NVIDIA GeForce GTX 980/PCIe/SSE2", - "prob": 0.00641, - "prefs": { - "zoom.stealth.webgl.renderer": "NVIDIA GeForce GTX 980/PCIe/SSE2", - "zoom.stealth.webgl.vendor": "NVIDIA Corporation", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|4294967295,2964|7680,2965|7680,2966|7680,2967|0,2968|4294967295,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|32768,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|16384,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|1048576,33001|1048576,33170|4352,34016|33984,34024|32768,34045|15,34076|32768,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-8,35077|7,35371|14,35373|14,35374|84,35375|84,35376|65536,35377|233472,35379|233472,35380|256,35657|4096,35658|4096,35659|124,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|4,35978|128,35979|4,36003|0,36004|4294967295,36005|4294967295,36063|8,36183|32,36203|4294967295,36347|1024,36348|32,36349|1024,37137|18446744073709552000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|32768:32768,33901|1:2047,33902|1:1", - "zoom.stealth.webgl.float_params": "", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - }, - { - "vendor": "Mesa", - "renderer_out": "GeForce GTX 980, or similar", - "prob": 0.00641, - "prefs": { - "zoom.stealth.webgl.renderer": "GeForce GTX 980, or similar", - "zoom.stealth.webgl.vendor": "Mesa", - "zoom.stealth.webgl.extensions": "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_depth_clamp,EXT_float_blend,EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint,OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear,OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object,WEBGL_color_buffer_float,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers,WEBGL_lose_context", - "zoom.stealth.webgl2.extensions": "EXT_color_buffer_float,EXT_depth_clamp,EXT_float_blend,EXT_texture_compression_bptc,EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed,OES_texture_float_linear,WEBGL_compressed_texture_astc,WEBGL_compressed_texture_etc,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_lose_context", - "zoom.stealth.webgl.int_params": "2849|1,2885|1029,2886|2305,2931|1,2932|513,2961|0,2962|519,2963|255,2964|7680,2965|7680,2966|7680,2967|0,2968|255,3074|1029,3314|0,3315|0,3316|0,3317|4,3330|0,3331|0,3332|0,3333|4,3379|16384,3408|8,3410|8,3411|8,3412|8,3413|8,3414|24,3415|0,10752|0,32777|32774,32824|0,32877|0,32878|0,32883|2048,32936|1,32937|4,32938|1,32968|0,32969|1,32970|0,32971|1,33000|3000,33001|3000,33170|4352,34016|33984,34024|16384,34045|15,34076|16384,34816|519,34817|7680,34818|7680,34819|7680,34852|8,34853|1029,34854|0,34855|0,34856|0,34857|0,34858|0,34859|0,34860|0,34877|32774,34921|16,34930|32,35071|2048,35076|-8,35077|7,35371|14,35373|14,35374|84,35375|84,35376|65536,35377|245760,35379|245760,35380|256,35657|16384,35658|16384,35659|124,35660|32,35661|192,35723|4352,35738|5121,35739|6408,35968|128,35978|128,35979|4,36003|0,36004|255,36005|255,36063|8,36183|8,36203|4294967295,36347|4096,36348|32,36349|4096,37137|9223372034707292000,37154|128,37157|128,37443|37444,37447|1000000000", - "zoom.stealth.webgl.int2_params": "2928|0:1,3386|16384:16384,33902|1:1", - "zoom.stealth.webgl.float_params": "33901|1:63.375", - "zoom.stealth.webgl.shader_precisions": "35633*36336|127:127:23,35633*36337|127:127:23,35633*36338|127:127:23,35633*36339|24:24:0,35633*36340|24:24:0,35633*36341|24:24:0,35632*36336|127:127:23,35632*36337|127:127:23,35632*36338|127:127:23,35632*36339|24:24:0,35632*36340|24:24:0,35632*36341|24:24:0", - "zoom.stealth.webgl2.enabled": true - } - } - ], - "_meta": { - "source": "camoufox webgl_data.db (offline extract; real Firefox WebGL telemetry)", - "note": "prefs are zoom.stealth.webgl.* override values; prob normalized per-OS" - } -} \ No newline at end of file diff --git a/src/invisible_playwright/_fpforge/data/webgl_renderer_pool.json b/src/invisible_playwright/_fpforge/data/webgl_renderer_pool.json deleted file mode 100644 index b1b05a2..0000000 --- a/src/invisible_playwright/_fpforge/data/webgl_renderer_pool.json +++ /dev/null @@ -1,1902 +0,0 @@ -{ - "source": "browserforge v1.2.3 fingerprint-network.zip [stealth: NVIDIA collapsed to 3 sanitize buckets 2026-04-26]", - "total": 474, - "entries": [ - { - "renderer": "ANGLE (AMD, AMD Radeon (TM) 630 (0x00006987) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon (TM) 860M Graphics (0x00001114) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon (TM) Graphics (0x000015E7) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon (TM) Graphics (0x00001681) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon (TM) R5 M330 (0x00006660) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon (TM) R9 390 Series (0x000067B1) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon (TM) R9 Fury Series (0x00007300) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon (TM) RX 570 (0x000067DF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon 610 Series (0x00006665) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon 740M Graphics (0x000015C8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon 740M Graphics (0x00001901) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon 760M Graphics (0x000015BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon 760M Graphics (0x00001900) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon 780M Graphics (0x000015BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon 780M Graphics (0x00001900) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon Graphics (0x000015BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon HD 5450 (0x000068F9) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon HD 7500M/7600M Series (0x00006841) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon HD 8600/8700M (0x00006600) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon HD 8600M Series (0x00006660) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon PRO Graphics (0x00001681) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon Pro W5500 (0x00007341) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon Pro W6800 (0x000073A3) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R5 230 (0x00006779) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R5 430 (0x00006611) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R5 Graphics (0x00009874) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R6 Graphics (0x00009874) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R7 200 Series (0x00006610) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R7 240 (0x00006837) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R7 M440 (0x00006900) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R7 M460 (0x00006900) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon R9 200 Series (0x00006810) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 550 (0x0000699F) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 5600 XT (0x0000731F) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 5700 (0x0000731F) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 5700 XT (0x0000731F) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 580 2048SP (0x00006FDF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6400 (0x0000743F) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6500 XT (0x0000743F) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6600 (0x000073FF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6600 XT (0x000073FF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6650 XT (0x000073EF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6700 XT (0x000073DF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6750 XT (0x000073DF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6800 (0x000073BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6800 XT (0x000073BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6900 XT (0x000073BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 6950 XT (0x000073A5) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 7600 (0x00007480) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 7700 XT (0x0000747E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 7800 XT (0x0000747E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 7900 XT (0x0000744C) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 7900 XTX (0x0000744C) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 9060 XT (0x00007590) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 9070 (0x00007550) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX 9070 XT (0x00007550) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon RX590 GME (0x00006FDF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon TM Graphics (0x00001900) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 610M (0x00001506) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 610M (0x0000164E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 660M (0x00001681) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 680M (0x00001681) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 760M (0x000015BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 780M (0x000015BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 780M Graphics (0x00001900) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 8060S Graphics (0x00001586) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 840M Graphics (0x00001114) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 860M Graphics (0x00001114) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 880M Graphics (0x0000150E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) 890M Graphics (0x0000150E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x000013C0) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x00001506) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x000015BF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x000015D8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x00001636) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x00001638) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x0000164C) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x0000164E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x00001681) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics (0x00001900) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Pro Graphics (0x00001638) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) R2 Graphics (0x00009853) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) R4 Graphics (0x00009851) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) R4 Graphics (0x000098E4) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) R5 Graphics (0x000098E4) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) R7 250 (0x00006610) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) R7 Graphics (0x0000130F) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) R7 Graphics (0x00001313) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) R7 Graphics (0x00009874) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) RX Vega 10 Graphics (0x000015D8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) RX Vega 11 Graphics (0x000015D8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) RX Vega 11 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 10 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 3 Graphics (0x000015D8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 3 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 6 Graphics (0x000015D8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 6 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 8 Graphics (0x000015D8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 8 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 8 Mobile Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD Radeon(TM) Vega 9 Graphics (0x000015D8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD RadeonT 660M (0x00001681) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, AMD RadeonT 680M (0x00001681) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon (TM) Pro WX 5100 Graphics (0x000067C7) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon (TM) RX 470 Series (0x000067DF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon RX 550 Series (0x000067FF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon RX 5500 XT (0x00007340) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon RX 560 Series (0x000067FF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon RX 560X (0x000067EF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon RX 570 Series (0x000067DF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon RX 580 Series (0x000067DF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon RX 590 Series (0x000067DF) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (AMD, Radeon RX550/550 Series (0x0000699F) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (AMD)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) 130T GPU (16GB) (0x00007D51) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) 130V GPU (8GB) (0x000064A0) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) 140T GPU (16GB) (0x00007D51) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) 140T GPU (32GB) (0x00007D51) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) 140T GPU (8GB) (0x00007D51) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) 140V GPU (16GB) (0x000064A0) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) 140V GPU (16GB) Direct3D9Ex vs_3_0 ps_3_0, igd9trinity64.dll)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) 140V GPU (8GB) (0x000064A0) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) A380 Graphics (0x000056A5) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) Graphics (0x00007D55) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) Pro 140T GPU (16GB) (0x00007D51) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) Pro 140T GPU (32GB) (0x00007D51) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) Pro 140T GPU (48GB) (0x00007D51) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Arc(TM) Pro Graphics (0x00007D55) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) G41 Express Chipset (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0, igdumd64.dll)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Graphics (0x000046D4) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Graphics (0x00007D41) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Graphics (0x00007D45) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Graphics (0x00007D67) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Graphics (0x00007DD5) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Graphics (0x0000A7AC) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Graphics (0x0000A7AD) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics (0x00000102) Direct3D11 vs_4_1 ps_4_1, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics (0x00000152) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics (0x00000402) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics (0x00000F31) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics (0x00001606) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics (0x000022B1) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 3000 (0x00000116) Direct3D11 vs_4_1 ps_4_1, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 3000 (0x00000126) Direct3D11 vs_4_1 ps_4_1, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 3000 Direct3D9Ex vs_3_0 ps_3_0, igdumd64.dll)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4000 (0x00000166) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4000 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4400 (0x0000041E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4400 (0x00000A16) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4400 Direct3D9Ex vs_3_0 ps_3_0, igdumdim64.dll)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4400 manual-gen9_2015-134121 (0x0000041E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4600 (0x00000412) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4600 (0x00000416) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 4600 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 5000 (0x00000A26) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 505 (0x00005A84) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 510 (0x00001902) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 510 (0x00001906) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 515 (0x0000191E) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 520 (0x00001916) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 520 (0x00001921) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 520 (0x00001921) Direct3D11 vs_5_0 ps_5_0, D3D11-24.20.100.6293)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 530 (0x00001912) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 530 (0x0000191B) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 5500 (0x00001616) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 5500 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 610 (0x00005906) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 620 (0x00005916) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 620 (0x00005917) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 620 (0x00005921) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 630 (0x00005912) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics 630 (0x0000591B) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.10.4358)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D9Ex vs_3_0 ps_3_0, igdumd64.dll)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics Direct3D9Ex vs_3_0 ps_3_0, igdumdx32.dll)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics Family (0x00000A16) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics Family Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) HD Graphics P530 (0x0000191D) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Plus Graphics (0x00008A52) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Plus Graphics (0x00008A5A) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Plus Graphics 640 (0x00005926) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics (0x000046A6) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics (0x000046A8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics (0x000046AA) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics (0x00009A40) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics (0x00009A49) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics (0x0000A7A0) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics (0x0000A7A1) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) Q45/Q43 Express Chipset (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0, igdumd64.dll)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00004626) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00004628) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00004688) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x0000468B) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x000046A3) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x000046B3) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x000046D0) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x000046D1) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x000046D2) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00004E55) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00004E71) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00008A56) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009A60) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009A68) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009A78) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009B21) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009B41) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009BA4) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009BC4) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009BCA) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x00009BCC) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x0000A720) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x0000A721) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x0000A788) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x0000A78B) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x0000A7A8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics (0x0000A7A9) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 600 (0x00003185) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 605 (0x00003184) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 610 (0x00003E90) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 610 (0x00003EA1) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.100.9466)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 615 (0x0000591C) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 620 (0x00003EA0) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 620 (0x00005917) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00003E91) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00003E92) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00003E98) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00003E9B) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00009BC5) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00009BC8) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 730 (0x00004682) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 730 (0x00004692) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 730 (0x00004C8B) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 750 (0x00004C8A) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 770 (0x00004680) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 770 (0x00004690) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel, Intel(R) UHD Graphics 770 (0x0000A780) Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (Intel)" - }, - { - "renderer": "ANGLE (Intel(R) HD Graphics Family Direct3D11 vs_5_0 ps_5_0)", - "vendor": "Intel Inc." - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 480 Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - }, - { - "renderer": "ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0, D3D11)", - "vendor": "Google Inc. (NVIDIA)" - } - ] -} \ No newline at end of file diff --git a/src/invisible_playwright/_fpforge/data/win_hw_marginals.json b/src/invisible_playwright/_fpforge/data/win_hw_marginals.json deleted file mode 100644 index 9d1d71b..0000000 --- a/src/invisible_playwright/_fpforge/data/win_hw_marginals.json +++ /dev/null @@ -1,469 +0,0 @@ -{ - "_meta": { - "source": "browserforge Windows UAs (offline; OS-level screen/cores marginal)" - }, - "screens": [ - { - "w": 1536, - "h": 864, - "availW": 1536, - "availH": 816, - "dpr": 1.25, - "prob": 0.264935 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1032, - "dpr": 1, - "prob": 0.161965 - }, - { - "w": 1280, - "h": 720, - "availW": 1280, - "availH": 672, - "dpr": 1.5, - "prob": 0.07915 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1040, - "dpr": 1, - "prob": 0.06376 - }, - { - "w": 1366, - "h": 768, - "availW": 1366, - "availH": 728, - "dpr": 1, - "prob": 0.054416 - }, - { - "w": 1366, - "h": 768, - "availW": 1366, - "availH": 720, - "dpr": 1, - "prob": 0.046171 - }, - { - "w": 1536, - "h": 864, - "availW": 1536, - "availH": 824, - "dpr": 1.25, - "prob": 0.036644 - }, - { - "w": 1536, - "h": 960, - "availW": 1536, - "availH": 912, - "dpr": 1.25, - "prob": 0.029681 - }, - { - "w": 2560, - "h": 1440, - "availW": 2560, - "availH": 1392, - "dpr": 1, - "prob": 0.029133 - }, - { - "w": 1280, - "h": 800, - "availW": 1280, - "availH": 752, - "dpr": 1.5, - "prob": 0.024917 - }, - { - "w": 1536, - "h": 864, - "availW": 1536, - "availH": 864, - "dpr": 1.25, - "prob": 0.024733 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1080, - "dpr": 1, - "prob": 0.013742 - }, - { - "w": 1280, - "h": 720, - "availW": 1280, - "availH": 680, - "dpr": 1.5, - "prob": 0.012643 - }, - { - "w": 1280, - "h": 720, - "availW": 1280, - "availH": 720, - "dpr": 1.5, - "prob": 0.01081 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1032, - "dpr": 1, - "prob": 0.009527 - }, - { - "w": 1707, - "h": 1067, - "availW": 1707, - "availH": 1019, - "dpr": 1.5, - "prob": 0.009344 - }, - { - "w": 1440, - "h": 900, - "availW": 1440, - "availH": 852, - "dpr": 2, - "prob": 0.008795 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1032, - "dpr": 1, - "prob": 0.008795 - }, - { - "w": 1920, - "h": 1200, - "availW": 1920, - "availH": 1152, - "dpr": 1, - "prob": 0.007513 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1032, - "dpr": 1, - "prob": 0.007146 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1032, - "dpr": 1, - "prob": 0.006596 - }, - { - "w": 1600, - "h": 900, - "availW": 1600, - "availH": 860, - "dpr": 1, - "prob": 0.006229 - }, - { - "w": 2048, - "h": 1152, - "availW": 2048, - "availH": 1104, - "dpr": 1.25, - "prob": 0.006045 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1032, - "dpr": 1, - "prob": 0.005864 - }, - { - "w": 1536, - "h": 864, - "availW": 1536, - "availH": 816, - "dpr": 1.25, - "prob": 0.005864 - }, - { - "w": 1366, - "h": 768, - "availW": 1366, - "availH": 768, - "dpr": 1, - "prob": 0.00568 - }, - { - "w": 2560, - "h": 1440, - "availW": 2560, - "availH": 1392, - "dpr": 1.5, - "prob": 0.00513 - }, - { - "w": 1707, - "h": 960, - "availW": 1707, - "availH": 912, - "dpr": 1.5, - "prob": 0.004946 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1040, - "dpr": 1, - "prob": 0.004946 - }, - { - "w": 3440, - "h": 1440, - "availW": 3440, - "availH": 1392, - "dpr": 1, - "prob": 0.00458 - }, - { - "w": 1504, - "h": 1003, - "availW": 1504, - "availH": 955, - "dpr": 1.5, - "prob": 0.004396 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1032, - "dpr": 1, - "prob": 0.004396 - }, - { - "w": 1280, - "h": 800, - "availW": 1280, - "availH": 752, - "dpr": 2, - "prob": 0.004396 - }, - { - "w": 1536, - "h": 864, - "availW": 1536, - "availH": 816, - "dpr": 1.25, - "prob": 0.004396 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1040, - "dpr": 1, - "prob": 0.004031 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1050, - "dpr": 1, - "prob": 0.003847 - }, - { - "w": 2560, - "h": 1440, - "availW": 2560, - "availH": 1400, - "dpr": 1, - "prob": 0.003847 - }, - { - "w": 1366, - "h": 768, - "availW": 1366, - "availH": 728, - "dpr": 1, - "prob": 0.003664 - }, - { - "w": 1920, - "h": 1080, - "availW": 1920, - "availH": 1032, - "dpr": 1, - "prob": 0.003664 - }, - { - "w": 1600, - "h": 900, - "availW": 1600, - "availH": 852, - "dpr": 1, - "prob": 0.003664 - } - ], - "cores": [ - { - "value": 8, - "prob": 0.271311 - }, - { - "value": 12, - "prob": 0.21567 - }, - { - "value": 4, - "prob": 0.157888 - }, - { - "value": 16, - "prob": 0.136607 - }, - { - "value": 20, - "prob": 0.03971 - }, - { - "value": 2, - "prob": 0.025086 - }, - { - "value": 24, - "prob": 0.023184 - }, - { - "value": 6, - "prob": 0.022233 - }, - { - "value": 32, - "prob": 0.021876 - }, - { - "value": 14, - "prob": 0.015575 - }, - { - "value": 3, - "prob": 0.011651 - }, - { - "value": 28, - "prob": 0.010462 - }, - { - "value": 22, - "prob": 0.010225 - }, - { - "value": 5, - "prob": 0.008441 - }, - { - "value": 10, - "prob": 0.005588 - }, - { - "value": 7, - "prob": 0.005469 - }, - { - "value": 9, - "prob": 0.004042 - }, - { - "value": 11, - "prob": 0.003923 - }, - { - "value": 18, - "prob": 0.003567 - }, - { - "value": 15, - "prob": 0.001189 - }, - { - "value": 13, - "prob": 0.000951 - }, - { - "value": 36, - "prob": 0.000713 - }, - { - "value": 64, - "prob": 0.000594 - }, - { - "value": 44, - "prob": 0.000594 - }, - { - "value": 19, - "prob": 0.000476 - }, - { - "value": 17, - "prob": 0.000357 - }, - { - "value": 23, - "prob": 0.000357 - }, - { - "value": 40, - "prob": 0.000357 - }, - { - "value": 21, - "prob": 0.000357 - }, - { - "value": 48, - "prob": 0.000357 - }, - { - "value": 640, - "prob": 0.000357 - }, - { - "value": 56, - "prob": 0.000357 - }, - { - "value": 26, - "prob": 0.000238 - }, - { - "value": 27, - "prob": 0.000119 - }, - { - "value": 25, - "prob": 0.000119 - } - ] -} \ No newline at end of file diff --git a/src/invisible_playwright/_fpforge/profile.py b/src/invisible_playwright/_fpforge/profile.py deleted file mode 100644 index 85809c0..0000000 --- a/src/invisible_playwright/_fpforge/profile.py +++ /dev/null @@ -1,273 +0,0 @@ -"""Public dataclass surface for fpforge.""" -from __future__ import annotations - -from dataclasses import dataclass, field, replace as _dc_replace -from typing import Any, Dict, List, Optional - -from ._sampler import sample as _sample_raw - - -@dataclass(frozen=True) -class GPUProfile: - vendor: str - renderer: str - class_tier: str # "low_end" | "mid_range" | "high_end" | "integrated_old" | "integrated_modern" - - -@dataclass(frozen=True) -class ScreenProfile: - width: int - height: int - avail_width: int - avail_height: int - dpr: float - tier: str - - -@dataclass(frozen=True) -class HardwareProfile: - concurrency: int - storage_quota_mb: int - - -@dataclass(frozen=True) -class AudioProfile: - sample_rate: int - output_latency_ms: int - max_channel_count: int - - -@dataclass(frozen=True) -class CodecProfile: - av1_enabled: bool - webm_encoder_enabled: bool - mediasource_webm: bool - mediasource_mp4: bool - webspeech_synth: bool - - -@dataclass(frozen=True) -class WebGLProfile: - msaa_samples: int - - -# ────────────────────────────────────────────────────────────────────── -# Pin map: flat dotted-path -> value. Set via `pin=` on generate_profile. -# -# Supported keys: -# "gpu.vendor", "gpu.renderer", "gpu.class_tier" -# "screen.width", "screen.height", "screen.avail_width", -# "screen.avail_height", "screen.dpr", "screen.tier" -# "hardware.concurrency", "hardware.storage_quota_mb" -# "audio.sample_rate", "audio.output_latency_ms", -# "audio.max_channel_count" -# "codec.av1_enabled", "codec.webm_encoder_enabled", -# "codec.mediasource_webm", "codec.mediasource_mp4", -# "codec.webspeech_synth" -# "webgl.msaa_samples" -# "fonts" (replaces the whole list) -# "dark_theme" -# ────────────────────────────────────────────────────────────────────── - -_PIN_GROUPS = { - "gpu": {"vendor", "renderer", "class_tier"}, - "screen": {"width", "height", "avail_width", "avail_height", "dpr", "tier"}, - "hardware": {"concurrency", "storage_quota_mb"}, - "audio": {"sample_rate", "output_latency_ms", "max_channel_count"}, - "codec": { - "av1_enabled", "webm_encoder_enabled", - "mediasource_webm", "mediasource_mp4", "webspeech_synth", - }, - "webgl": {"msaa_samples"}, -} -_PIN_TOP = {"fonts", "dark_theme"} - - -def _validate_pin_key(key: str) -> None: - if key in _PIN_TOP: - return - if "." not in key: - raise ValueError( - f"pin key {key!r} is not valid. " - f"Use 'group.field' (e.g. 'screen.width') or one of {sorted(_PIN_TOP)}." - ) - group, field_name = key.split(".", 1) - if group not in _PIN_GROUPS: - raise ValueError( - f"pin key {key!r}: unknown group {group!r}. " - f"Known groups: {sorted(_PIN_GROUPS)}." - ) - if field_name not in _PIN_GROUPS[group]: - raise ValueError( - f"pin key {key!r}: unknown field {field_name!r} in group {group!r}. " - f"Known fields: {sorted(_PIN_GROUPS[group])}." - ) - - -@dataclass(frozen=True) -class Profile: - """Coherent browser fingerprint profile sampled from a single integer seed. - - Use `generate_profile(seed)` to build one. Pin specific values at build - time with `generate_profile(seed, pin={"screen.width": 2560, ...})`. - """ - seed: int - gpu: GPUProfile - screen: ScreenProfile - hardware: HardwareProfile - audio: AudioProfile - codec: CodecProfile - webgl: WebGLProfile - fonts: List[str] - dark_theme: bool - # Bayesian browsing-history: list of {name, category, cookie_profile} - # dicts sampled from data/browsing_pool.json with per-class CPT. Used - # by _recaptcha_seed.py to build a coherent cookie pre-seed when the - # caller opts in via Stealthfox(prep_recaptcha=True). - browsing_history: List[Dict[str, str]] = field(default_factory=list) - _raw: Dict[str, Any] = field(default_factory=dict, repr=False, compare=False) - - def to_prefs_dict(self) -> Dict[str, Any]: - """Return the flat dict of raw sampler fields, as produced by the - underlying Bayesian sampler. Stable across releases for a given seed.""" - return dict(self._raw) - - -# Mapping from flat pin key -> raw sampler dict key, so `to_prefs_dict()` -# and `invisible_playwright.prefs.translate_profile_to_prefs` observe the pinned value. -_PIN_TO_RAW = { - "gpu.vendor": "webgl_vendor", - "gpu.renderer": "webgl_renderer", - "gpu.class_tier": "gpu_class", - "screen.width": "screen_w", - "screen.height": "screen_h", - "screen.avail_width": "screen_avail_w", - "screen.avail_height": "screen_avail_h", - "screen.dpr": "dpr", - "screen.tier": "screen_tier", - "hardware.concurrency": "hw_concurrency", - "hardware.storage_quota_mb": "storage_quota_mb", - "audio.sample_rate": "audio_sample_rate", - "audio.output_latency_ms": "audio_output_latency_ms", - "audio.max_channel_count": "audio_max_channel_count", - "codec.av1_enabled": "av1_enabled", - "codec.webm_encoder_enabled": "webm_encoder_enabled", - "codec.mediasource_webm": "mediasource_webm", - "codec.mediasource_mp4": "mediasource_mp4", - "codec.webspeech_synth": "webspeech_synth", - "webgl.msaa_samples": "msaa_samples", - "dark_theme": "dark_theme", - # "fonts" is a list — handled specially (joined into font_whitelist). -} - - -def _apply_pins_to_raw(raw: Dict[str, Any], pin: Dict[str, Any]) -> Dict[str, Any]: - """Return a copy of `raw` with the pinned sampler-level fields updated.""" - out = dict(raw) - for key, value in pin.items(): - if key == "fonts": - if not isinstance(value, (list, tuple)): - raise TypeError("pin 'fonts' must be a list/tuple of strings") - out["font_whitelist"] = ",".join(value) - continue - raw_key = _PIN_TO_RAW.get(key) - if raw_key is None: - # Shouldn't happen after validation, but guard anyway. - continue - out[raw_key] = value - return out - - -def generate_profile( - seed: int, - pin: Optional[Dict[str, Any]] = None, - fixed_gpu_class: Optional[str] = None, -) -> Profile: - """Return a deterministic Profile for the given integer seed. - - pin: optional dict of dotted-path keys (e.g. "screen.width", "gpu.renderer") - to values that are FORCED in the resulting profile. All other fields - are still sampled from the Bayesian network based on `seed`, so the - same seed + same pin map always yields the same profile. - - Example — force a specific GPU and screen while letting everything - else vary with the seed (via the public invisible_playwright API): - - from invisible_playwright import InvisiblePlaywright - - with InvisiblePlaywright( - seed=42, - pin={ - "gpu.renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 4090 Direct3D11)", - "gpu.vendor": "Google Inc. (NVIDIA)", - "gpu.class_tier": "high_end", - "screen.width": 2560, - "screen.height": 1440, - }, - ) as browser: - ... - - Warning: pinning breaks Bayesian coherence across the pinned fields - (if you pin a high-end GPU but leave screen unpinned, you may get a - 1080p screen that would be unusual for that GPU class). Pin related - fields together when coherence matters. - - Supported keys: see the module-level _PIN_GROUPS / _PIN_TOP tables - or run `help(generate_profile)` after import. - """ - if pin: - for key in pin: - _validate_pin_key(key) - - # fixed_gpu_class re-conditions the whole bundle on a chosen class (used so the - # bundle stays coherent with the validated WebGL persona we expose on Windows/mac). - # An explicit gpu.class_tier pin still wins. - eff_class = (pin or {}).get("gpu.class_tier") or fixed_gpu_class - raw = _sample_raw(int(seed), fixed_gpu_class=eff_class) - if pin: - raw = _apply_pins_to_raw(raw, pin) - - # Font whitelist is stored as a comma-separated string in raw; split it. - font_wl = raw.get("font_whitelist", "") - if isinstance(font_wl, str): - fonts = [f.strip() for f in font_wl.split(",") if f.strip()] - else: - fonts = list(font_wl) if font_wl else [] - - return Profile( - seed=int(raw["stealth_seed"]), - gpu=GPUProfile( - vendor=raw["webgl_vendor"], - renderer=raw["webgl_renderer"], - class_tier=raw["gpu_class"], - ), - screen=ScreenProfile( - width=int(raw["screen_w"]), - height=int(raw["screen_h"]), - avail_width=int(raw["screen_avail_w"]), - avail_height=int(raw["screen_avail_h"]), - dpr=float(raw["dpr"]), - tier=str(raw.get("screen_tier", "")), - ), - hardware=HardwareProfile( - concurrency=int(raw["hw_concurrency"]), - storage_quota_mb=int(raw["storage_quota_mb"]), - ), - audio=AudioProfile( - sample_rate=int(raw["audio_sample_rate"]), - output_latency_ms=int(raw["audio_output_latency_ms"]), - max_channel_count=int(raw["audio_max_channel_count"]), - ), - codec=CodecProfile( - av1_enabled=bool(raw["av1_enabled"]), - webm_encoder_enabled=bool(raw["webm_encoder_enabled"]), - mediasource_webm=bool(raw["mediasource_webm"]), - mediasource_mp4=bool(raw["mediasource_mp4"]), - webspeech_synth=bool(raw["webspeech_synth"]), - ), - webgl=WebGLProfile(msaa_samples=int(raw["msaa_samples"])), - fonts=fonts, - dark_theme=bool(raw["dark_theme"]), - browsing_history=list(raw.get("browsing_history") or []), - _raw=raw, - ) diff --git a/src/invisible_playwright/_geo.py b/src/invisible_playwright/_geo.py index 5c552f2..ced7009 100644 --- a/src/invisible_playwright/_geo.py +++ b/src/invisible_playwright/_geo.py @@ -1,268 +1,4 @@ -"""Resolve the session timezone from the egress IP (``timezone="auto"``). - -Approach B: discover the egress IP with one HTTP request — routed *through the -proxy* when one is set, otherwise a direct request that sees the host's own -public IP — then map IP → IANA timezone with an offline mmdb -(``daijro/geoip-all-in-one``, downloaded + cached by ``download.py``). - -Precedence (see ``resolve_session_timezone``): - - explicit IANA → unchanged explicit always wins - "" / "auto" → egress ALWAYS resolve. With a proxy, from the proxy - egress IP; without a proxy, from the host's - own public IP. This is the default. - -On failure: - with a proxy → raise a foreign proxy paired with the host TZ is - the precise ``timezone_mismatch`` signal, so - we fail loudly rather than fall back silently. - without a proxy → "" (host) the host TZ is a safe default, so a transient - lookup failure must not break the launch. -""" -from __future__ import annotations - -import ipaddress -from typing import Any, Dict, NamedTuple, Optional -from urllib.parse import quote - -import requests - - -class GeoTimezoneError(RuntimeError): - """Raised when ``timezone="auto"`` cannot resolve a valid IANA zone.""" - - -# Plain-text IP echo endpoints (each returns just the caller's public IP). -_IP_ECHO_ENDPOINTS = ( - "https://api.ipify.org", - "https://icanhazip.com", - "https://checkip.amazonaws.com", -) - -_SOCKS_SCHEMES = ("socks5://", "socks4://", "socks://") - - -def _proxy_is_set(proxy: Optional[Dict[str, str]]) -> bool: - if not proxy: - return False - server = (proxy.get("server") or "").strip() - return bool(server) and server.lower() != "direct://" - - -def _proxies_for_requests(proxy: Dict[str, str]) -> Dict[str, str]: - """Translate our proxy dict into a ``requests`` proxies mapping. - - SOCKS5 uses the ``socks5h`` scheme so DNS is resolved proxy-side (matches - ``network.proxy.socks_remote_dns=True`` in the Firefox path). HTTP/HTTPS - pass through unchanged. Credentials are URL-encoded. - """ - server = (proxy.get("server") or "").strip() - low = server.lower() - if low.startswith("socks5://") or low.startswith("socks://"): - scheme = "socks5h" - elif low.startswith("socks4://"): - scheme = "socks4" - elif low.startswith("https://"): - scheme = "https" - else: - scheme = "http" - - host_port = server.split("://", 1)[1] if "://" in server else server - user = proxy.get("username") or "" - pwd = proxy.get("password") or "" - if user: - auth = f"{quote(user, safe='')}:{quote(pwd, safe='')}@" - else: - auth = "" - url = f"{scheme}://{auth}{host_port}" - return {"http": url, "https": url} - - -def discover_egress_ip( - proxy: Optional[Dict[str, str]] = None, *, timeout: float = 10.0 -) -> str: - """Return the public egress IP. - - Routes the request through ``proxy`` when given (SOCKS support requires - ``requests[socks]`` / PySocks); with ``proxy=None`` it makes a direct - request that sees the host's own public IP. Tries each echo endpoint in - turn; raises :class:`GeoTimezoneError` if none return a valid IP. - """ - proxies = _proxies_for_requests(proxy) if proxy else None - last_err: Optional[Exception] = None - for url in _IP_ECHO_ENDPOINTS: - try: - resp = requests.get(url, proxies=proxies, timeout=timeout) - resp.raise_for_status() - ip = resp.text.strip() - ipaddress.ip_address(ip) # validate (raises ValueError if not an IP) - return ip - except Exception as exc: # noqa: BLE001 - try the next endpoint - last_err = exc - continue - raise GeoTimezoneError( - f"could not discover the proxy egress IP via {len(_IP_ECHO_ENDPOINTS)} " - f"endpoints (last error: {last_err!r}). For SOCKS proxies make sure " - f"requests[socks] / PySocks is installed." - ) - - -def ip_to_timezone(ip: str, mmdb_path: Any) -> str: - """Map ``ip`` to its IANA timezone using the offline mmdb. - - Reads the standard MaxMind ``location.time_zone`` field and validates it - against the system tz database. Raises :class:`GeoTimezoneError` if the IP - is absent from the DB or the zone is missing / not a valid IANA name. - """ - import maxminddb - - with maxminddb.open_database(str(mmdb_path)) as reader: - record = reader.get(ip) - if not record: - raise GeoTimezoneError(f"egress IP {ip} not present in the geoip database") - tz = ((record.get("location") or {}) if isinstance(record, dict) else {}).get( - "time_zone" - ) - if not tz: - raise GeoTimezoneError(f"no timezone for egress IP {ip} in the geoip database") - from zoneinfo import ZoneInfo, ZoneInfoNotFoundError - - try: - ZoneInfo(tz) - except (ZoneInfoNotFoundError, ValueError) as exc: - raise GeoTimezoneError( - f"geoip returned an invalid IANA zone {tz!r} for {ip}: {exc}" - ) from exc - return tz - - -# ISO 3166 country code -> the primary BCP-47 locale a real Windows machine in that -# country most commonly runs. Multi-language countries use the majority language; the -# user can always force a specific locale instead of "auto". Unknown -> en-US. -_COUNTRY_LOCALE = { - "US": "en-US", "GB": "en-GB", "CA": "en-CA", "AU": "en-AU", "NZ": "en-NZ", "IE": "en-IE", - "ZA": "en-ZA", "IN": "en-IN", "SG": "en-SG", "PH": "en-PH", - "FR": "fr-FR", "BE": "fr-BE", "LU": "fr-LU", - "DE": "de-DE", "AT": "de-AT", "CH": "de-CH", - "IT": "it-IT", "ES": "es-ES", "PT": "pt-PT", "NL": "nl-NL", - "SE": "sv-SE", "NO": "nb-NO", "DK": "da-DK", "FI": "fi-FI", "IS": "is-IS", - "PL": "pl-PL", "CZ": "cs-CZ", "SK": "sk-SK", "HU": "hu-HU", "RO": "ro-RO", - "GR": "el-GR", "BG": "bg-BG", "HR": "hr-HR", "RS": "sr-RS", "SI": "sl-SI", - "RU": "ru-RU", "UA": "uk-UA", "TR": "tr-TR", "IL": "he-IL", - "BR": "pt-BR", "MX": "es-MX", "AR": "es-AR", "CL": "es-CL", "CO": "es-CO", "PE": "es-PE", - "JP": "ja-JP", "KR": "ko-KR", "CN": "zh-CN", "TW": "zh-TW", "HK": "zh-HK", - "ID": "id-ID", "TH": "th-TH", "VN": "vi-VN", "MY": "ms-MY", - "SA": "ar-SA", "AE": "ar-AE", "EG": "ar-EG", -} - - -def ip_to_locale(ip: str, mmdb_path: Any) -> str: - """Map ``ip`` -> a BCP-47 locale via the MaxMind ``country.iso_code`` field, so the - browser language stays consistent with the proxy egress country. Falls back to - ``en-US`` for IPs absent from the DB or countries we don't map.""" - import maxminddb - - with maxminddb.open_database(str(mmdb_path)) as reader: - record = reader.get(ip) - cc = "" - if isinstance(record, dict): - cc = ((record.get("country") or {}).get("iso_code") or "") - return _COUNTRY_LOCALE.get(cc.upper(), "en-US") - - -def resolve_session_locale(egress_ip: Optional[str], proxy: Optional[Dict[str, str]]) -> str: - """Resolve ``locale="auto"`` to a BCP-47 locale from the egress country. Behind a proxy - it reuses the already-discovered ``egress_ip`` (no extra round-trip); without a proxy it - discovers the host's public IP. On any failure it returns ``en-US`` (never breaks launch - — locale is cosmetic, unlike timezone which traps a foreign-proxy mismatch).""" - from .download import ensure_geoip_mmdb - - try: - ip = egress_ip if _proxy_is_set(proxy) else discover_egress_ip(None) - if ip is None: - return "en-US" - return ip_to_locale(ip, ensure_geoip_mmdb()) - except Exception: # noqa: BLE001 - return "en-US" - - -class SessionGeo(NamedTuple): - """Geo facts resolved once per session from a single egress round-trip. - - ``timezone`` follows the precedence in the module docstring. - ``egress_ip`` is the proxy egress IP (the IP the *outside world* sees) when - a proxy is set, else ``None`` — it feeds the WebRTC srflx override, which is - only meaningful behind a proxy (a direct connection's real STUN already - reports the truthful public IP, so we leave it alone). - """ - - timezone: str - egress_ip: Optional[str] - - -def prepare_session_geo( - timezone: str, proxy: Optional[Dict[str, str]] -) -> SessionGeo: - """Resolve the session timezone AND the proxy egress IP in ONE round-trip. - - The egress IP is discovered once and reused for both the timezone mapping - (when ``timezone`` is ``""``/``"auto"``) and the WebRTC public-IP override. - Timezone precedence is identical to :func:`resolve_session_timezone`; the - egress IP is best-effort for the WebRTC side (a discovery failure that the - timezone path doesn't need won't break the launch — but if the timezone - path *does* need it behind a proxy, that path still fails loudly). - """ - from .download import ensure_geoip_mmdb - - tz = (timezone or "").strip() - proxy_set = _proxy_is_set(proxy) - - # One discovery, reused below. Behind a proxy we always want the egress IP - # (for WebRTC) regardless of the timezone setting. - egress_ip: Optional[str] = None - egress_err: Optional[Exception] = None - if proxy_set: - try: - egress_ip = discover_egress_ip(proxy) - except Exception as exc: # noqa: BLE001 - egress_err = exc - - # Timezone resolution — same precedence as resolve_session_timezone. - if tz and tz.lower() != "auto": - return SessionGeo(tz, egress_ip) # explicit IANA wins - try: - ip = egress_ip if proxy_set else discover_egress_ip(None) - if ip is None: # proxy set but discovery failed above - raise egress_err or GeoTimezoneError("egress IP discovery failed") - return SessionGeo(ip_to_timezone(ip, ensure_geoip_mmdb()), egress_ip) - except Exception: - if proxy_set: - raise # fail-early behind a proxy (timezone_mismatch trap) - return SessionGeo("", None) # no proxy: host TZ is a safe fallback - - -def resolve_session_timezone( - timezone: str, proxy: Optional[Dict[str, str]] -) -> str: - """Map the user's ``timezone`` setting to a concrete IANA zone (or ``""``). - - Timezone-only path (no WebRTC side effects): an explicit IANA zone wins and - triggers NO network call; ``""``/``"auto"`` resolve from the egress IP. The - launch path uses :func:`prepare_session_geo` instead (which additionally - returns the egress IP for WebRTC); this standalone resolver is kept for - third-party integrations that only want the zone. See the module docstring - for the precedence table. - """ - tz = (timezone or "").strip() - if tz and tz.lower() != "auto": - return tz # explicit IANA wins — no egress lookup - from .download import ensure_geoip_mmdb - - proxy_set = _proxy_is_set(proxy) - try: - ip = discover_egress_ip(proxy if proxy_set else None) - return ip_to_timezone(ip, ensure_geoip_mmdb()) - except Exception: - if proxy_set: - raise # fail-early behind a proxy (timezone_mismatch trap) - return "" # no proxy: host TZ is a safe fallback +"""Backward-compat shim — spostato in invisible_core._geo (alias completo).""" +import sys as _sys +from invisible_core import _geo as _mod +_sys.modules[__name__] = _mod diff --git a/src/invisible_playwright/_headless.py b/src/invisible_playwright/_headless.py index 3cfee09..64fb2bd 100644 --- a/src/invisible_playwright/_headless.py +++ b/src/invisible_playwright/_headless.py @@ -1,178 +1,4 @@ -"""Invisible-but-headed browser windows. - -Playwright's ``headless=True`` flips Firefox onto a different code path — -no widget tree, software-only rendering, distinct timing — and anti-bot -systems can spot the divergence. Running the browser *headed* but hidden -gives us the real rendering pipeline while keeping the windows off screen. - -Two mechanisms, by platform: - -- **Windows & macOS**: the patched binary cloaks its OWN chrome windows - when ``zoom.stealth.cloak_windows`` is set — ``DWMWA_CLOAK`` (Windows) - / ``NSWindow`` alpha-0 + pinned occlusion-ignore (macOS). The window - renders on the real GPU but never appears on screen, in the taskbar or - the Dock. The launcher injects the pref; nothing host-side is spawned. - -- **Linux**: spawns its own ``Xvfb`` instance and points ``DISPLAY`` at - it (X11/Wayland have no per-window cloak that keeps the GPU rendering). -""" -from __future__ import annotations - -import os -import subprocess -import sys -import time -from typing import Optional - - -# Inherited from WSLg / GNOME / etc. these env vars make Firefox prefer a -# Wayland compositor over the X11 DISPLAY we set, so the window leaks onto -# the real desktop. Strip them all before starting. -_WAYLAND_LEAK_VARS = ( - "WAYLAND_DISPLAY", - "XDG_RUNTIME_DIR", - "XDG_SESSION_TYPE", - "PULSE_SERVER", - "WSL2_GUI_APPS_ENABLED", -) - - -class _LinuxVirtualDisplay: - """Standalone Xvfb instance owned by this InvisiblePlaywright session.""" - - def __init__(self, width: int = 1920, height: int = 1080) -> None: - self._geometry = f"{width}x{height}x24" - self._proc: Optional[subprocess.Popen] = None - self._display: Optional[str] = None - self._saved_env: dict[str, Optional[str]] = {} - - def start(self) -> None: - if not _binary_on_path("Xvfb"): - raise RuntimeError( - "invisible_playwright headless=True requires Xvfb. " - "Install it: sudo apt install xvfb" - ) - # Retry: when many workers start in parallel they can pick the same - # display number before any has created its lockfile. Xvfb on the - # losing side exits immediately — try again with a fresh number. - last_err: Optional[Exception] = None - for _ in range(10): - display = self._pick_display() - try: - self._spawn(display) - self._wait_until_ready(display) - self._display = display - self._apply_env(display) - return - except RuntimeError as e: - last_err = e - if self._proc is not None and self._proc.poll() is None: - self._proc.kill() - self._proc = None - raise RuntimeError(f"Xvfb failed to start after 10 attempts: {last_err}") - - def _spawn(self, display: str) -> None: - self._proc = subprocess.Popen( - [ - "Xvfb", display, - "-screen", "0", self._geometry, - "+extension", "GLX", - "+extension", "RENDER", - "-nolisten", "unix", - "-listen", "tcp", - "-ac", - ], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - start_new_session=True, - ) - - def _pick_display(self) -> str: - for n in range(99, 400): - if not os.path.exists(f"/tmp/.X{n}-lock"): - return f":{n}" - raise RuntimeError("no free X display number in :99–:399") - - def _wait_until_ready(self, display: str) -> None: - # We start Xvfb with -nolisten unix → no /tmp/.X11-unix socket appears. - # Xvfb creates /tmp/.X{n}-lock immediately though — wait for that. - lockfile = f"/tmp/.X{display[1:]}-lock" - deadline = time.monotonic() + 3.0 - assert self._proc is not None - while time.monotonic() < deadline: - if self._proc.poll() is not None: - raise RuntimeError(f"Xvfb {display} exited immediately") - if os.path.exists(lockfile): - return - time.sleep(0.02) - raise RuntimeError(f"Xvfb {display} did not become ready in 3s") - - def _apply_env(self, display: str) -> None: - keys = ("DISPLAY", "MOZ_ENABLE_WAYLAND", "GDK_BACKEND") + _WAYLAND_LEAK_VARS - for k in keys: - self._saved_env[k] = os.environ.get(k) - for k in _WAYLAND_LEAK_VARS: - os.environ.pop(k, None) - os.environ["DISPLAY"] = display - os.environ["MOZ_ENABLE_WAYLAND"] = "0" - os.environ["GDK_BACKEND"] = "x11" - - def stop(self) -> None: - for k, v in self._saved_env.items(): - if v is None: - os.environ.pop(k, None) - else: - os.environ[k] = v - self._saved_env.clear() - - if self._proc is not None and self._proc.poll() is None: - self._proc.terminate() - try: - self._proc.wait(timeout=3) - except subprocess.TimeoutExpired: - self._proc.kill() - self._proc.wait(timeout=2) - self._proc = None - self._display = None - - -# Windows & macOS: the patched Firefox cloaks its own chrome windows when this -# pref is set (DWMWA_CLOAK / NSWindow alpha-0 + pinned occlusion-ignore), so the -# window renders on the real GPU but never shows on screen / in the taskbar or -# Dock. window_occlusion_tracking is disabled so a hidden window keeps painting. -CLOAK_PREFS = { - "zoom.stealth.cloak_windows": True, - "widget.windows.window_occlusion_tracking.enabled": False, -} - - -def cloak_prefs() -> dict: - """Prefs that make the patched binary self-cloak its chrome windows. - - Used on Windows & macOS, where hiding is done inside the binary rather than - with a host-side virtual display. - """ - return dict(CLOAK_PREFS) - - -def make_virtual_display(): - """Return a start()/stop()-able virtual display, or ``None`` when the - platform hides windows via the in-binary cloak pref instead. - - - Linux: a fresh ``Xvfb`` (the launcher start()s/stop()s it). - - Windows / macOS: ``None`` — the binary self-cloaks via ``cloak_prefs()``, - injected by the launcher; nothing host-side needs spawning. - """ - if sys.platform.startswith("linux"): - return _LinuxVirtualDisplay() - if sys.platform in ("win32", "darwin"): - return None - raise RuntimeError( - f"invisible_playwright supports Windows, macOS and Linux " - f"(got {sys.platform!r})" - ) - - -def _binary_on_path(name: str) -> bool: - import shutil - return shutil.which(name) is not None +"""Backward-compat shim — spostato in invisible_core._headless (alias completo).""" +import sys as _sys +from invisible_core import _headless as _mod +_sys.modules[__name__] = _mod diff --git a/src/invisible_playwright/_proxy.py b/src/invisible_playwright/_proxy.py index 85a4e77..e2417bf 100644 --- a/src/invisible_playwright/_proxy.py +++ b/src/invisible_playwright/_proxy.py @@ -1,56 +1,4 @@ -"""Proxy translation shared by sync and async launchers. - -SOCKS proxies are driven entirely by the patched Firefox prefs (the -``nsProtocolProxyService`` patch reads ``network.proxy.socks_username`` -and ``socks_password``). HTTP/HTTPS proxies go through Playwright's own -``proxy=`` kwarg so it can negotiate Basic auth. -""" -from __future__ import annotations - -from typing import Any, Dict, Optional - - -_SOCKS_SCHEMES = ("socks5://", "socks4://", "socks://") - - -def configure_proxy( - proxy: Optional[Dict[str, str]], - prefs: Dict[str, Any], -) -> Optional[Dict[str, str]]: - """Mutate ``prefs`` for SOCKS auth; return what to pass to Playwright. - - * ``None`` proxy → returns ``None``. - * SOCKS proxy → writes the auth prefs and returns ``None`` (Playwright - gets nothing; Firefox does the rest). - * HTTP / HTTPS proxy → returns the dict unchanged for Playwright. - """ - if not proxy: - return None - - server = (proxy.get("server") or "").strip() - if not server or server.lower() == "direct://": - return None - if not _is_socks_scheme(server): - return proxy - - host_port = _strip_scheme(server) - if ":" not in host_port: - return None # malformed, drop silently - - host, port_str = host_port.rsplit(":", 1) - prefs["network.proxy.type"] = 1 - prefs["network.proxy.socks"] = host - prefs["network.proxy.socks_port"] = int(port_str) - prefs["network.proxy.socks_version"] = 4 if server.lower().startswith("socks4://") else 5 - prefs["network.proxy.socks_username"] = proxy.get("username") or "" - prefs["network.proxy.socks_password"] = proxy.get("password") or "" - prefs["network.proxy.socks_remote_dns"] = True - return None - - -def _is_socks_scheme(server: str) -> bool: - return server.lower().startswith(_SOCKS_SCHEMES) - - -def _strip_scheme(server: str) -> str: - return server.split("://", 1)[1] if "://" in server else server +"""Backward-compat shim — spostato in invisible_core._proxy (alias completo).""" +import sys as _sys +from invisible_core import _proxy as _mod +_sys.modules[__name__] = _mod diff --git a/src/invisible_playwright/_webgl_personas.py b/src/invisible_playwright/_webgl_personas.py index 18ab1b1..d16096f 100644 --- a/src/invisible_playwright/_webgl_personas.py +++ b/src/invisible_playwright/_webgl_personas.py @@ -1,202 +1,4 @@ -"""Empirically-calibrated WebGL GPU personas for Windows ANGLE D3D11. - -We expose a FALSE GPU (this is a multi-user tool — never leak each host's real GPU), -chosen deterministically per seed from a small set of renderer-string "buckets" that -Firefox's SanitizeRenderer emits and that FP Pro's tampering_ml scores as CLEAN. - -## What actually gates a persona (calibrated 2026-06-14, supersedes the old theory) - -The blocker is NOT anti_detect and NOT a "render-vs-renderer" check. It is FP Pro's -**tampering_ml** (gate <=0.5), a holistic ML coherence score. We reverse-engineered its -GPU sensitivity with single-variable A/Bs on demo.fingerprint.com (deterministic per -(seed, renderer, IP); tools in tests/_gpu_isolate.py / _gpu_landscape.py / _gpu_sweep.py / -_gpu_sweep2.py / _gpu_persona_pure.py). Findings: - - 1. tampering_ml = f(renderer STRING, seed baseline = canvas/audio). The renderer string - carries a STABLE per-bucket penalty; the seed sets the floor it adds to. - 2. gpu_class is IRRELEVANT to tampering_ml (nv_980 scored identically on mid_range / - high_end / premium / workstation). So pairing a fake GPU with a "matching" hardware - tier does NOT help the score (we still set a coherent class — see gpu_class below — - for OTHER detectors that cross-check cores/screen, just not for this). - 3. It is NOT render-consistency: a cross-vendor AMD string is CLEAN on our Intel-Arc - host. So the real silicon's pixels are not the dominant signal; falsifying to a - different vendor works — IF the string is one FP Pro scores low. - -Sweep over all 10 Windows SanitizeRenderer buckets x 10 seeds (clean = tml<=0.5 AND not -anti_detect), on our Intel Arc A750 host: - - amd_r9 (Radeon R9 200 Series) ...... 10/10 clean, max tml 0.346 <- SHIP - - intel_arc (Arc A750) ............... 10/10 clean, max tml 0.377 <- SHIP - - amd_hd5850 ......................... 9/10 (fails the hardest seed) - - amd_hd3200 / intel_hd .............. 6/10 (seed-dependent, risky) - - intel_hd400 ........................ 3/10 - - ALL NVIDIA (8800/480/980) .......... 0/10 (penalized everywhere, ~0.7-0.99) - - intel_945 (ancient Intel) .......... 0/10 -So only TWO buckets are robustly clean across profiles. We ship exactly those, weighted -to real-world prevalence ("Radeon R9 200 Series" is the bucket for ALL modern AMD = a big -real slice; "Arc A750" covers Intel discrete = rarer). Cross-vendor, so the fleet is not a -single-GPU cluster. More names require lowering the seed floor first (see CAVEAT 2). - -## ⚠️ CAVEATS - 1. HOST-INDEPENDENCE NOT PROVEN. Everything above was measured on ONE host (Intel Arc - A750). The host's real render is embedded in the seed baseline, so the clean-bucket set - *might* be host-dependent (on a real NVIDIA host, maybe nv_980 is clean and amd_r9 is - not). This MUST be validated on a non-Arc machine before trusting it fleet-wide; if it - turns out host-dependent, add a pre-launch host-GPU-class probe and pick a bucket per - detected class. Until then: safe for Arc hosts (incl. the dev's), unvalidated elsewhere. - 2. DIVERSITY CEILING = 2 names because "hard" seeds (high canvas/audio floor, e.g. seed 4 - ~0.35) only stay clean on the 2 best buckets. Lowering that floor (an fpforge CPT fix — - candidate: 8-channel audio + 1TB storage emitted on a mid_range profile) would unlock - amd_hd5850 / intel_hd for more seeds => up to ~5 names. Follow-up, not done yet. - -## Load-bearing format requirements (unchanged, still true) - - renderer MUST end ", D3D11)" (full ANGLE wire format) or SanitizeRenderer returns - "Generic Renderer" (a tell). The C++ passes our string through SanitizeRenderer, which - buckets "AMD Radeon R9 200 Series" -> "Radeon R9 200 Series" and "Arc A750" -> itself. - - the forced extension list MUST be the EXACT NATIVE ORDER getSupportedExtensions returns. - The set+order is fixed by Firefox+ANGLE on D3D11 FL11_0 (VENDOR-INDEPENDENT — verified - via 20-agent source study), so ONE list is correct for both personas. A reorder is caught - (tampering_ml 0.34 -> 0.84). The lists below are the verbatim native-order Arc capture. - -Calibration data + sweep tooling live in the local workbench (not shipped). -""" -from __future__ import annotations - -import sys -from typing import Dict, List, Optional - -# Vendor-independent ext lists (native order, Arc host capture). Identical for every persona -# because the set+order is fixed by Firefox+ANGLE on D3D11 FL11_0, not by the GPU vendor. -_EXT1 = ( - "ANGLE_instanced_arrays,EXT_blend_minmax,EXT_color_buffer_half_float,EXT_float_blend," - "EXT_frag_depth,EXT_shader_texture_lod,EXT_sRGB,EXT_texture_compression_bptc," - "EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_element_index_uint," - "OES_fbo_render_mipmap,OES_standard_derivatives,OES_texture_float,OES_texture_float_linear," - "OES_texture_half_float,OES_texture_half_float_linear,OES_vertex_array_object," - "WEBGL_color_buffer_float,WEBGL_compressed_texture_s3tc,WEBGL_compressed_texture_s3tc_srgb," - "WEBGL_debug_renderer_info,WEBGL_debug_shaders,WEBGL_depth_texture,WEBGL_draw_buffers," - "WEBGL_lose_context,WEBGL_provoking_vertex" -) -_EXT2 = ( - "EXT_color_buffer_float,EXT_float_blend,EXT_texture_compression_bptc," - "EXT_texture_compression_rgtc,EXT_texture_filter_anisotropic,OES_draw_buffers_indexed," - "OES_texture_float_linear,OVR_multiview2,WEBGL_compressed_texture_s3tc," - "WEBGL_compressed_texture_s3tc_srgb,WEBGL_debug_renderer_info,WEBGL_debug_shaders," - "WEBGL_lose_context,WEBGL_provoking_vertex" -) - - -# ── Real-Firefox GPU pool (2026-06-18, supersedes the 2-bucket sweep above) ─────────────── -# The personas are now sourced from `_fpforge/data/webgl_gpu_pool.json` — an OFFLINE extract -# of camoufox's real-Firefox WebGL telemetry DB (17 Windows GPUs with their REAL per-OS -# prevalence AND the full coherent WebGL fingerprint: renderer + vendor + extensions + -# ~100 getParameter values + shader-precision formats). prefs.py applies ALL of these, not -# just the renderer string. The linchpin A/B (2026-06-18) proved that the OLD "NVIDIA 0/10" -# verdict was an artifact of spoofing the renderer string over the host's REAL (Arc) params: -# FP Pro cross-checks renderer<->params, so a GTX 980 string over Arc params mismatched -# (~0.7-0.85). Injecting camoufox's REAL GTX 980 params makes it coherent (tml median 0.333, -# flags clean). So the params are NOT vendor-independent (the old assumption) and per-GPU -# real data is what unlocks the full real GPU mix — including NVIDIA (~47% of real FF-Win), -# which we no longer gate. -_ENABLED = True -_POOL_PATH = __import__("pathlib").Path(__file__).parent / "_fpforge" / "data" / "webgl_gpu_pool.json" -_GPU_POOL_CACHE: Optional[List[Dict]] = None - - -def _gpu_pool() -> List[Dict]: - """Lazy-load the Windows GPU pool (we always claim Windows). Each entry: - {key, renderer (input form), vendor, gpu_class (via classify_gpu), prefs (full - zoom.stealth.webgl.* override dict), weight (real per-OS prevalence)}.""" - global _GPU_POOL_CACHE - if _GPU_POOL_CACHE is not None: - return _GPU_POOL_CACHE - import json - from ._fpforge._sampler import classify_gpu # lazy import → no module cycle - raw = json.loads(_POOL_PATH.read_text(encoding="utf-8")) - pool: List[Dict] = [] - for e in raw.get("win", []): - prefs = e["prefs"] - rend_in = prefs["zoom.stealth.webgl.renderer"] - cls = classify_gpu({"renderer": rend_in, - "vendor": prefs.get("zoom.stealth.webgl.vendor", "")}) - pool.append({ - "key": e.get("renderer_out", rend_in)[:48], - "renderer": rend_in, - "vendor": prefs["zoom.stealth.webgl.vendor"], - "gpu_class": cls, - "prefs": prefs, - "weight": float(e["prob"]), - }) - _GPU_POOL_CACHE = pool - return pool - - -def select_persona(seed: int) -> Optional[Dict]: - """Deterministic, prevalence-weighted GPU persona for this seed — on EVERY host. - - Same seed -> same persona (fppro_consistency: identity stable per seed). Different seeds - spread across the REAL Windows GPU mix by prevalence. Returns the Windows-ANGLE persona on - Linux/Mac too: we must always look Windows, and the C++ WebGL override (SanitizeRenderer + - pref-driven params/extensions) is platform-independent, so the same Windows GPU is presented - on any host without consulting the real GL backend (no more Linux "Generic Renderer").""" - if not _ENABLED: - return None - pool = _gpu_pool() - if not pool: - return None - total = sum(p["weight"] for p in pool) or 1.0 - h = ((int(seed) * 2654435761) % 1_000_003) / 1_000_003.0 * total - cum = 0.0 - for p in pool: - cum += p["weight"] - if h < cum: - return p - return pool[-1] - - -def forced_gpu_class(seed: int) -> Optional[str]: - """The gpu_class the forge conditions the bundle on (== the selected GPU's class via - classify_gpu), so cores/screen/fonts stay coherent with the GPU we expose. Does NOT - affect FP Pro tampering_ml (proven) but matters for detectors that cross-check hardware - tier. None on Linux.""" - p = select_persona(seed) - return p["gpu_class"] if p else None - - -# ── Render-noise seed pool (canvas/WebGL gamma) ────────────────────────────── -# zoom.stealth.fpp.hw_seed drives the per-seed canvas2D + WebGL readPixels gamma -# LUT in C++. The render-image HASH it produces is the DOMINANT FP Pro tampering_ml -# driver (proven 2026-06-14: holding a fixed profile and varying ONLY hw_seed moved -# tml 0.25->0.75). The monotonic gamma preserves the GPU's render structure, so some -# hw_seeds yield a "suspicious" render hash. We therefore DECOUPLE the render-noise -# seed from the identity seed and pick from a calibrated pool of hw_seeds that score -# CLEAN even on the hardest attribute profile (sweep 1..30 vs the worst seed: these -# 14 all gave tml<=0.285). Diversity is preserved (14 distinct render hashes spread -# across the population — real GPUs cluster to few canvas hashes anyway); identity -# stays per-seed (the rest of the fingerprint differs). Same seed -> same render seed -# (fppro_consistency holds). -# CAVEAT: the render hash = f(host GPU render, gamma), so this pool is calibrated on -# the Intel-Arc host. On other GPUs the clean set may differ (host-independence open, -# same as the personas) — Option B (substitution = GPU-independent render hash) would -# remove that dependency. Validate per-host or move to B before trusting fleet-wide. -# RECALIBRATED 2026-06-18 for the real-Firefox GPU mix (incl NVIDIA, which is more -# consistency-sensitive than the old amd/arc personas). Swept hw_seed 0..30 on the hottest -# persona (NVIDIA GTX 980) through a residential exit: these 9 stayed well within the clean -# band with a wide margin to the rest. The old pool's picks scored dirty on NVIDIA (clean -# only on the retired amd/arc mix) → dropped. NVIDIA is the worst case, so these are clean on -# amd/intel too. hw_seed = the canvas/WebGL gamma render hash (the dominant consistency-score -# driver); host-calibrated. -# 2026-06-21: with WebGL Option B (zoom.stealth.webgl.substitute_pixels, ON in prefs.py) the WebGL -# render hash is hash(seed,idx) = HOST-INDEPENDENT, so this list NO LONGER needs per-host calibration -# — it only supplies per-session diversity. A 2026-06-21 attempt to re-calibrate it per-host FAILED -# cross-OS: hw_seed clean on Windows went dirty on the Linux GL backend (b008 0.034->0.839; Win-dirty -# {7,11,20,27} = Linux-clean and vice-versa; + identity×hw_seed interaction on Linux). That proved -# calibration can't work cross-host → substitution replaces it. Kept the original diverse 9-set. -CLEAN_RENDER_SEEDS = [0, 5, 6, 9, 11, 16, 19, 20, 28] - - -def render_noise_seed(seed: int) -> int: - """Deterministic clean render-noise seed for hw_seed (decoupled from identity). - - Maps the identity seed into CLEAN_RENDER_SEEDS so every session gets a calibrated - clean canvas/WebGL render hash while keeping per-user diversity. Stable per seed.""" - return CLEAN_RENDER_SEEDS[(int(seed) * 2654435761) % len(CLEAN_RENDER_SEEDS)] +"""Backward-compat shim — spostato in invisible_core._webgl_personas (alias completo).""" +import sys as _sys +from invisible_core import _webgl_personas as _mod +_sys.modules[__name__] = _mod diff --git a/src/invisible_playwright/config.py b/src/invisible_playwright/config.py index 16e3a8a..f6d4b15 100644 --- a/src/invisible_playwright/config.py +++ b/src/invisible_playwright/config.py @@ -1,112 +1,4 @@ -"""Public helpers for building Firefox launch config without using ``InvisiblePlaywright``. - -Use these when you need to call ``playwright.firefox.launch()`` (or -``firefox.launch_persistent_context()``) directly with our patched binary -and stealth prefs, instead of using the ``InvisiblePlaywright`` context -manager. - -Typical caller is an external integration that owns its own browser -lifecycle (a Crawlee/Skyvern/changedetection-style fetcher, a Playwright -Server wrapper, a multi-language harness) and just wants the building -blocks:: - - from playwright.async_api import async_playwright - from invisible_playwright import ensure_binary, get_default_stealth_prefs - - async with async_playwright() as p: - browser = await p.firefox.launch( - executable_path=str(ensure_binary()), - firefox_user_prefs=get_default_stealth_prefs(seed=42), - ) - -For everyday Python usage the ``InvisiblePlaywright`` context manager is -still the recommended entry point; these helpers expose the same internals -without the lifecycle ownership. - -.. note:: - When calling ``firefox.launch()`` yourself, pass ``headless=False`` and - manage the display hiding (Xvfb on Linux, hidden desktop on Windows) - externally. Passing ``headless=True`` directly to Playwright puts - Firefox in true headless mode, which skips the real rendering pipeline - and breaks canvas / audio / WebGL fingerprint coherence. The - ``InvisiblePlaywright`` context manager does this translation - automatically; the public helpers leave it to the caller. -""" -from __future__ import annotations - -import secrets -from typing import Any, Dict, List, Optional, Union - -from ._fpforge import generate_profile -from ._webgl_personas import forced_gpu_class -from .prefs import translate_profile_to_prefs - - -def get_default_stealth_prefs( - seed: Optional[int] = None, - *, - pin: Optional[Dict[str, Any]] = None, - locale: str = "en-US", - timezone: str = "", - extra_prefs: Optional[Dict[str, Any]] = None, - humanize: Union[bool, float] = True, - virtual_display: bool = False, -) -> Dict[str, Any]: - """Build a complete ``firefox_user_prefs`` dict for ``firefox.launch()``. - - Same prefs that ``InvisiblePlaywright(seed=..., locale=..., timezone=..., - extra_prefs=..., humanize=...)`` would inject. Use this when you need to - drive ``playwright.firefox.launch()`` yourself. - - Args: - seed: Integer seed for the Bayesian fingerprint sampler. Same seed - produces the same fingerprint. ``None`` generates a fresh - random int31 (matches ``InvisiblePlaywright`` default). - pin: Optional dict forcing specific fingerprint fields while the - rest stays seed-derived. See ``docs/pinning.md``. - locale: BCP-47 tag (e.g. ``"en-US"``). Drives ``Accept-Language`` - and ``navigator.language``. - timezone: IANA timezone (e.g. ``"America/New_York"``). Empty means - use the host TZ. This pure pref builder does NOT resolve - ``"auto"`` (that needs the proxy + a network lookup at launch - time) — pass a concrete zone here, or use ``InvisiblePlaywright`` - / ``resolve_session_timezone(timezone, proxy)`` for ``"auto"``. - extra_prefs: Optional dict overlaid LAST onto the generated prefs. - humanize: When True (default), every mouse move is expanded into - a Bezier trajectory by the patched Juggler. A float caps the - motion in seconds. False disables the behavior. - virtual_display: When True on Windows, apply GPU-disabling prefs - to prevent GPU process crashes on virtual desktops without - D3D11 backend. - - Returns: - Dict ready to pass as ``firefox_user_prefs=`` to - ``playwright.firefox.launch()`` or ``launch_persistent_context()``. - """ - resolved_seed = int(seed) if seed is not None else secrets.randbits(31) - profile = generate_profile(resolved_seed, pin=pin, fixed_gpu_class=forced_gpu_class(resolved_seed)) - prefs = translate_profile_to_prefs( - profile, - locale=locale, - timezone=timezone, - extra_prefs=extra_prefs, - virtual_display=virtual_display, - ) - # stealthfox.* is the namespace the binary's Juggler reads (see launcher.py note). - prefs["stealthfox.humanize"] = bool(humanize) - if humanize: - max_seconds = float(humanize) if not isinstance(humanize, bool) else 1.5 - prefs["stealthfox.humanize.maxTime"] = str(max_seconds) - return prefs - - -def get_default_args() -> List[str]: - """Return the default Firefox CLI args to pass via ``args=``. - - Currently empty list, since all our stealth configuration is delivered - via ``firefox_user_prefs`` rather than CLI flags. Exposed for parity - with the ``cloakbrowser.config.get_default_stealth_args`` pattern and - to future-proof integrations that already wire ``args=[*existing, - *get_default_args()]``. - """ - return [] +"""Backward-compat shim — spostato in invisible_core.config (alias completo).""" +import sys as _sys +from invisible_core import config as _mod +_sys.modules[__name__] = _mod diff --git a/src/invisible_playwright/constants.py b/src/invisible_playwright/constants.py index ea588eb..2d5b8e7 100644 --- a/src/invisible_playwright/constants.py +++ b/src/invisible_playwright/constants.py @@ -1,80 +1,4 @@ -"""Compile-time constants that pin the wrapper to a specific Firefox build. - -BINARY_VERSION is bumped every time new Firefox patches are released. It is -deliberately decoupled from the Python package version so that pure-Python -bugfixes don't force a multi-hour Firefox rebuild. -""" -from __future__ import annotations - -# Bump this when a new patched Firefox build is released on GitHub. -BINARY_VERSION: str = "firefox-13" - -# Releases known to be broken — ensure_binary() refuses them with a clear error -# instead of handing the user an unusable binary. firefox-8 was packaged without -# the juggler automation layer, so Playwright cannot drive it (TargetClosedError); -# fixed in firefox-9 (package-manifest.in now ships chrome/juggler). A cached -# firefox-8 from before the bump would otherwise keep being used silently. -BROKEN_VERSIONS: frozenset[str] = frozenset({"firefox-8"}) - -# Underlying Firefox version (for display only; does not drive downloads). -FIREFOX_UPSTREAM_VERSION: str = "150.0.1" - -# The base filename prefix used inside archives. -BINARY_BASENAME: str = f"firefox-{FIREFOX_UPSTREAM_VERSION}-stealth" - - -def ARCHIVE_NAME(platform_key: str, machine: str) -> str: - """Return the platform-specific archive filename. - - platform_key: sys.platform ("win32", "linux", "darwin") - machine: platform.machine() ("AMD64", "x86_64", "arm64", "aarch64", ...) - """ - pk = platform_key.lower() - m = machine.lower() - if m in {"amd64", "x86_64"}: - arch = "x86_64" - elif m in {"arm64", "aarch64"}: - arch = "arm64" - else: - raise NotImplementedError(f"unsupported arch: {machine}") - - if pk == "win32": - return f"{BINARY_BASENAME}-win-{arch}.zip" - if pk == "linux": - return f"{BINARY_BASENAME}-linux-{arch}.tar.gz" - if pk == "darwin": - return f"{BINARY_BASENAME}-macos-{arch}.tar.gz" - raise NotImplementedError(f"unsupported platform: {platform_key}") - - -# Binary entry point relative path inside the extracted archive root. -# macOS ships the .app bundle (renamed to a stable "Firefox.app" by release.yml); -# the wrapper execs the inner binary directly, which sidesteps Gatekeeper. -BINARY_ENTRY_REL = { - "win32": "firefox.exe", - "linux": "firefox", - "darwin": "Firefox.app/Contents/MacOS/firefox", -} - -# GitHub release URL template. The "TODO" owner is resolved at publication time. -RELEASE_URL_TEMPLATE = ( - "https://github.com/feder-cr/invisible_playwright/releases/download/{tag}/{asset}" -) - -# ───────────────────────────────────────────────────────────────────────── -# GeoIP database (timezone="auto" → resolve IANA zone from proxy egress IP) -# ───────────────────────────────────────────────────────────────────────── -# daijro/geoip-all-in-one merges IP2Location LITE + GeoLite2 + DB-IP into a -# single mmdb (country ISO + coordinates + IANA timezone via tzfpy), rebuilt -# weekly. GPL-3.0, so we DOWNLOAD it at runtime into the user cache (like the -# Firefox binary) rather than bundling it into this MIT package. The `-all` -# variant covers IPv4+IPv6. download.py NEVER pins a tag (daijro prunes old -# releases, so a pinned tag eventually 404s): on every launch it resolves the -# CURRENT latest tag from the `releases/latest/download` permalink (no GitHub -# API, no rate limit) and pulls it if newer than the cache. -GEOIP_REPO: str = "daijro/geoip-all-in-one" -GEOIP_ASSET: str = "geoip-aio-all.mmdb.zip" -GEOIP_MMDB_NAME: str = "geoip-aio-all.mmdb" -GEOIP_RELEASE_URL_TEMPLATE: str = ( - "https://github.com/daijro/geoip-all-in-one/releases/download/{tag}/{asset}" -) +"""Backward-compat shim — spostato in invisible_core.constants (alias completo).""" +import sys as _sys +from invisible_core import constants as _mod +_sys.modules[__name__] = _mod diff --git a/src/invisible_playwright/data/font-map.json b/src/invisible_playwright/data/font-map.json deleted file mode 100644 index 9c46b95..0000000 --- a/src/invisible_playwright/data/font-map.json +++ /dev/null @@ -1,1846 +0,0 @@ -{ - "win11": { - "core": [ - "Arial", - "Bahnschrift", - "Calibri", - "Cambria", - "Cambria Math", - "Candara", - "Comic Sans MS", - "Consolas", - "Constantia", - "Corbel", - "Courier New", - "Ebrima", - "Franklin Gothic Medium", - "Gabriola", - "Gadugi", - "Georgia", - "Impact", - "Ink Free", - "Javanese Text", - "Leelawadee UI", - "MS UI Gothic", - "MV Boli", - "Marlett", - "Microsoft Himalaya", - "Microsoft JhengHei UI", - "Microsoft New Tai Lue", - "Microsoft PhagsPa", - "Microsoft Sans Serif", - "Microsoft Tai Le", - "Microsoft YaHei UI", - "Microsoft Yi Baiti", - "Mongolian Baiti", - "Myanmar Text", - "Palatino Linotype", - "Segoe Fluent Icons", - "Segoe MDL2 Assets", - "Segoe Print", - "Segoe Script", - "Segoe UI", - "Segoe UI Emoji", - "Segoe UI Historic", - "Segoe UI Symbol", - "Segoe UI Variable", - "SimSun-ExtB", - "Sitka", - "Sylfaen", - "Symbol", - "Tahoma", - "Times New Roman", - "Trebuchet MS", - "Verdana", - "Webdings", - "Wingdings", - "Yu Gothic UI", - "宋体", - "微軟正黑體", - "微软雅黑", - "新宋体", - "新細明體-ExtB", - "游ゴシック", - "細明體-ExtB", - "細明體_HKSCS-ExtB", - "細明體_MSCS-ExtB", - "맑은 고딕", - "MS ゴシック", - "MS Pゴシック" - ], - "am": [ - "Nyala" - ], - "am-ET": [ - "Nyala" - ], - "ar": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-AE": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-BH": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-DJ": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-DZ": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-EG": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-ER": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-IL": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-IQ": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-JO": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-KM": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-KW": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-LB": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-LY": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-MA": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-MR": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-OM": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-PS": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-QA": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-SA": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-SD": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-SO": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-SS": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-SY": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-TD": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-TN": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ar-YE": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "arc-Syrc": [ - "Estrangelo Edessa" - ], - "arz-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "as": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "as-IN": [ - "Shonar Bangla", - "Vrinda" - ], - "bh-Deva": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "bn": [ - "Shonar Bangla", - "Vrinda" - ], - "bn-BD": [ - "Shonar Bangla", - "Vrinda" - ], - "bn-IN": [ - "Shonar Bangla", - "Vrinda" - ], - "bpy-Beng": [ - "Shonar Bangla", - "Vrinda" - ], - "brx": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "brx-Deva": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "brx-IN": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "byn": [ - "Nyala" - ], - "byn-ER": [ - "Nyala" - ], - "byn-Ethi": [ - "Nyala" - ], - "chr-Cher": [ - "Plantagenet Cherokee" - ], - "chr-Cher-US": [ - "Plantagenet Cherokee" - ], - "ckb-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "cmn-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "cmn-Hant": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "eu": [ - "Arial Nova", - "Georgia Pro", - "Gill Sans Nova", - "Neue Haas Grotesk Text Pro", - "Rockwell Nova", - "Verdana Pro" - ], - "fa": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "fa-AF": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "fa-IR": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "gan-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "glk-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "gu": [ - "Shruti" - ], - "gu-IN": [ - "Shruti" - ], - "ha-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "hak-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "hak-Hant": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "he": [ - "Aharoni", - "David", - "FrankRuehl", - "Gisha", - "Levenim MT", - "Miriam", - "Miriam Fixed", - "Narkisim", - "Rod" - ], - "he-IL": [ - "Aharoni", - "David", - "FrankRuehl", - "Gisha", - "Levenim MT", - "Miriam", - "Miriam Fixed", - "Narkisim", - "Rod" - ], - "hi": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "hi-IN": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "iu-Cans": [ - "Euphemia" - ], - "iu-Cans-CA": [ - "Euphemia" - ], - "ja": [ - "BIZ UDPゴシック", - "BIZ UDP明朝", - "BIZ UDゴシック", - "BIZ UD明朝", - "Meiryo UI", - "UD デジタル 教科書体 N", - "UD デジタル 教科書体 NK", - "UD デジタル 教科書体 NP", - "メイリオ", - "游明朝", - "MS 明朝", - "MS P明朝" - ], - "ja-JP": [ - "BIZ UDPゴシック", - "BIZ UDP明朝", - "BIZ UDゴシック", - "BIZ UD明朝", - "Meiryo UI", - "UD デジタル 教科書体 N", - "UD デジタル 教科書体 NK", - "UD デジタル 教科書体 NP", - "メイリオ", - "游明朝", - "MS 明朝", - "MS P明朝" - ], - "km": [ - "DaunPenh", - "Khmer UI", - "MoolBoran" - ], - "km-KH": [ - "DaunPenh", - "Khmer UI", - "MoolBoran" - ], - "kn": [ - "Tunga" - ], - "kn-IN": [ - "Tunga" - ], - "ko": [ - "굴림", - "굴림체", - "궁서", - "궁서체", - "돋움", - "돋움체", - "바탕", - "바탕체" - ], - "ko-KR": [ - "굴림", - "굴림체", - "궁서", - "궁서체", - "돋움", - "돋움체", - "바탕", - "바탕체" - ], - "ks-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ks-Arab-IN": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ks-Deva": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "ku-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ku-Arab-IQ": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "lo": [ - "DokChampa", - "Lao UI" - ], - "lo-LA": [ - "DokChampa", - "Lao UI" - ], - "lzh-Hant": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "mai": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "ml": [ - "Kartika" - ], - "ml-IN": [ - "Kartika" - ], - "mr": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "mr-IN": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "mzn-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ne": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "ne-IN": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "ne-NP": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "new-Deva": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "or": [ - "Kalinga" - ], - "or-IN": [ - "Kalinga" - ], - "pa": [ - "Raavi" - ], - "pa-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "pa-Arab-PK": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "pa-Guru": [ - "Raavi" - ], - "pa-IN": [ - "Raavi" - ], - "pi-Deva": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "pnb-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "prs": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "prs-AF": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "prs-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ps": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ps-AF": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "sa": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "sa-Deva": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "sa-IN": [ - "Aparajita", - "Kokila", - "Mangal", - "Sanskrit Text", - "Utsaah" - ], - "sd-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "sd-Arab-PK": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "si": [ - "Iskoola Pota" - ], - "si-LK": [ - "Iskoola Pota" - ], - "syr": [ - "Estrangelo Edessa" - ], - "syr-SY": [ - "Estrangelo Edessa" - ], - "syr-Syrc": [ - "Estrangelo Edessa" - ], - "ta": [ - "Latha", - "Vijaya" - ], - "ta-IN": [ - "Latha", - "Vijaya" - ], - "ta-LK": [ - "Latha", - "Vijaya" - ], - "ta-MY": [ - "Latha", - "Vijaya" - ], - "ta-SG": [ - "Latha", - "Vijaya" - ], - "te": [ - "Gautami", - "Vani" - ], - "te-IN": [ - "Gautami", - "Vani" - ], - "th": [ - "Angsana New", - "AngsanaUPC", - "Browallia New", - "BrowalliaUPC", - "Cordia New", - "CordiaUPC", - "DilleniaUPC", - "EucrosiaUPC", - "FreesiaUPC", - "IrisUPC", - "JasmineUPC", - "KodchiangUPC", - "Leelawadee", - "LilyUPC" - ], - "th-TH": [ - "Angsana New", - "AngsanaUPC", - "Browallia New", - "BrowalliaUPC", - "Cordia New", - "CordiaUPC", - "DilleniaUPC", - "EucrosiaUPC", - "FreesiaUPC", - "IrisUPC", - "JasmineUPC", - "KodchiangUPC", - "Leelawadee", - "LilyUPC" - ], - "ti": [ - "Nyala" - ], - "ti-ER": [ - "Nyala" - ], - "ti-ET": [ - "Nyala" - ], - "tig": [ - "Nyala" - ], - "tig-ER": [ - "Nyala" - ], - "tig-Ethi": [ - "Nyala" - ], - "tk-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ug": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ug-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ug-CN": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ur": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ur-IN": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ur-PK": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "uz-Arab": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "uz-Arab-AF": [ - "Aldhabi", - "Andalus", - "Arabic Typesetting", - "Microsoft Uighur", - "Sakkal Majalla", - "Simplified Arabic", - "Simplified Arabic Fixed", - "Traditional Arabic", - "Urdu Typesetting" - ], - "ve-Ethi": [ - "Nyala" - ], - "wal": [ - "Nyala" - ], - "wal-ET": [ - "Nyala" - ], - "wal-Ethi": [ - "Nyala" - ], - "wuu-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "yi": [ - "Aharoni", - "David", - "FrankRuehl", - "Gisha", - "Levenim MT", - "Miriam", - "Miriam Fixed", - "Narkisim", - "Rod" - ], - "yue-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "zh-CN": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "zh-HK": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "zh-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "zh-Hant": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "zh-MO": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "zh-SG": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "zh-TW": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "zh-gan-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "zh-hak-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "zh-hak-Hant": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "zh-lzh-Hant": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ], - "zh-wuu-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "zh-yue-Hans": [ - "仿宋", - "楷体", - "等线", - "黑体" - ], - "zh-yue-Hant": [ - "DFKai-SB", - "新細明體", - "細明體", - "細明體_HKSCS", - "細明體_MSCS" - ] - }, - "ubuntu": { - "core": [ - "C059", - "D050000L", - "DejaVu Sans", - "DejaVu Sans Mono", - "DejaVu Serif", - "Droid Sans Fallback", - "FreeMono", - "FreeSans", - "FreeSerif", - "Liberation Mono", - "Liberation Sans", - "Liberation Sans Narrow", - "Liberation Serif", - "Nimbus Mono PS", - "Nimbus Roman", - "Nimbus Sans", - "Nimbus Sans Narrow", - "Noto Color Emoji", - "Noto Kufi Arabic", - "Noto Looped Lao", - "Noto Looped Thai", - "Noto Mono", - "Noto Music", - "Noto Naskh Arabic", - "Noto Nastaliq Urdu", - "Noto Rashi Hebrew", - "Noto Sans", - "Noto Sans Adlam", - "Noto Sans Adlam Unjoined", - "Noto Sans Anatolian Hieroglyphs", - "Noto Sans Arabic", - "Noto Sans Armenian", - "Noto Sans Avestan", - "Noto Sans Balinese", - "Noto Sans Bamum", - "Noto Sans Bassa Vah", - "Noto Sans Batak", - "Noto Sans Bengali", - "Noto Sans Bhaiksuki", - "Noto Sans Brahmi", - "Noto Sans Buginese", - "Noto Sans Buhid", - "Noto Sans CJK HK", - "Noto Sans CJK JP", - "Noto Sans CJK KR", - "Noto Sans CJK SC", - "Noto Sans CJK TC", - "Noto Sans Canadian Aboriginal", - "Noto Sans Carian", - "Noto Sans Caucasian Albanian", - "Noto Sans Chakma", - "Noto Sans Cham", - "Noto Sans Cherokee", - "Noto Sans Coptic", - "Noto Sans Cuneiform", - "Noto Sans Cypriot", - "Noto Sans Deseret", - "Noto Sans Devanagari", - "Noto Sans Display", - "Noto Sans Duployan", - "Noto Sans Egyptian Hieroglyphs", - "Noto Sans Elbasan", - "Noto Sans Elymaic", - "Noto Sans Ethiopic", - "Noto Sans Georgian", - "Noto Sans Glagolitic", - "Noto Sans Gothic", - "Noto Sans Grantha", - "Noto Sans Gujarati", - "Noto Sans Gunjala Gondi", - "Noto Sans Gurmukhi", - "Noto Sans Hanifi Rohingya", - "Noto Sans Hanunoo", - "Noto Sans Hatran", - "Noto Sans Hebrew", - "Noto Sans Imperial Aramaic", - "Noto Sans Indic Siyaq Numbers", - "Noto Sans Inscriptional Pahlavi", - "Noto Sans Inscriptional Parthian", - "Noto Sans Javanese", - "Noto Sans Kaithi", - "Noto Sans Kannada", - "Noto Sans Kayah Li", - "Noto Sans Kharoshthi", - "Noto Sans Khmer", - "Noto Sans Khojki", - "Noto Sans Khudawadi", - "Noto Sans Lao", - "Noto Sans Lepcha", - "Noto Sans Limbu", - "Noto Sans Linear A", - "Noto Sans Linear B", - "Noto Sans Lisu", - "Noto Sans Lycian", - "Noto Sans Lydian", - "Noto Sans Mahajani", - "Noto Sans Malayalam", - "Noto Sans Mandaic", - "Noto Sans Manichaean", - "Noto Sans Marchen", - "Noto Sans Masaram Gondi", - "Noto Sans Math", - "Noto Sans Mayan Numerals", - "Noto Sans Medefaidrin", - "Noto Sans Meetei Mayek", - "Noto Sans Mende Kikakui", - "Noto Sans Meroitic", - "Noto Sans Miao", - "Noto Sans Modi", - "Noto Sans Mongolian", - "Noto Sans Mono", - "Noto Sans Mono CJK HK", - "Noto Sans Mono CJK JP", - "Noto Sans Mono CJK KR", - "Noto Sans Mono CJK SC", - "Noto Sans Mono CJK TC", - "Noto Sans Mro", - "Noto Sans Multani", - "Noto Sans Myanmar", - "Noto Sans NKo", - "Noto Sans Nabataean", - "Noto Sans New Tai Lue", - "Noto Sans Newa", - "Noto Sans Nushu", - "Noto Sans Ogham", - "Noto Sans Ol Chiki", - "Noto Sans Old Hungarian", - "Noto Sans Old Italic", - "Noto Sans Old North Arabian", - "Noto Sans Old Permic", - "Noto Sans Old Persian", - "Noto Sans Old Sogdian", - "Noto Sans Old South Arabian", - "Noto Sans Old Turkic", - "Noto Sans Oriya", - "Noto Sans Osage", - "Noto Sans Osmanya", - "Noto Sans Pahawh Hmong", - "Noto Sans Palmyrene", - "Noto Sans Pau Cin Hau", - "Noto Sans PhagsPa", - "Noto Sans Phoenician", - "Noto Sans Psalter Pahlavi", - "Noto Sans Rejang", - "Noto Sans Runic", - "Noto Sans Samaritan", - "Noto Sans Saurashtra", - "Noto Sans Sharada", - "Noto Sans Shavian", - "Noto Sans Siddham", - "Noto Sans SignWriting", - "Noto Sans Sinhala", - "Noto Sans Sogdian", - "Noto Sans Sora Sompeng", - "Noto Sans Soyombo", - "Noto Sans Sundanese", - "Noto Sans Syloti Nagri", - "Noto Sans Symbols", - "Noto Sans Symbols2", - "Noto Sans Syriac", - "Noto Sans Tagalog", - "Noto Sans Tagbanwa", - "Noto Sans Tai Le", - "Noto Sans Tai Tham", - "Noto Sans Tai Viet", - "Noto Sans Takri", - "Noto Sans Tamil", - "Noto Sans Tamil Supplement", - "Noto Sans Telugu", - "Noto Sans Thaana", - "Noto Sans Thai", - "Noto Sans Tifinagh", - "Noto Sans Tifinagh APT", - "Noto Sans Tifinagh Adrar", - "Noto Sans Tifinagh Agraw Imazighen", - "Noto Sans Tifinagh Ahaggar", - "Noto Sans Tifinagh Air", - "Noto Sans Tifinagh Azawagh", - "Noto Sans Tifinagh Ghat", - "Noto Sans Tifinagh Hawad", - "Noto Sans Tifinagh Rhissa Ixa", - "Noto Sans Tifinagh SIL", - "Noto Sans Tifinagh Tawellemmet", - "Noto Sans Tirhuta", - "Noto Sans Ugaritic", - "Noto Sans Vai", - "Noto Sans Wancho", - "Noto Sans Warang Citi", - "Noto Sans Yi", - "Noto Sans Zanabazar Square", - "Noto Serif", - "Noto Serif Ahom", - "Noto Serif Armenian", - "Noto Serif Balinese", - "Noto Serif Bengali", - "Noto Serif CJK HK", - "Noto Serif CJK JP", - "Noto Serif CJK KR", - "Noto Serif CJK SC", - "Noto Serif CJK TC", - "Noto Serif Devanagari", - "Noto Serif Display", - "Noto Serif Dogra", - "Noto Serif Ethiopic", - "Noto Serif Georgian", - "Noto Serif Grantha", - "Noto Serif Gujarati", - "Noto Serif Gurmukhi", - "Noto Serif Hebrew", - "Noto Serif Hmong Nyiakeng", - "Noto Serif Kannada", - "Noto Serif Khmer", - "Noto Serif Khojki", - "Noto Serif Lao", - "Noto Serif Malayalam", - "Noto Serif Myanmar", - "Noto Serif Sinhala", - "Noto Serif Tamil", - "Noto Serif Tamil Slanted", - "Noto Serif Tangut", - "Noto Serif Telugu", - "Noto Serif Thai", - "Noto Serif Tibetan", - "Noto Serif Yezidi", - "Noto Traditional Nushu", - "OpenSymbol", - "P052", - "Standard Symbols PS", - "URW Bookman", - "URW Gothic", - "Ubuntu", - "Ubuntu Mono", - "Ubuntu Sans", - "Ubuntu Sans Mono", - "Z003" - ], - "am": [ - "Abyssinica SIL" - ], - "ar": [ - "KacstArt", - "KacstBook", - "KacstDecorative", - "KacstDigital", - "KacstFarsi", - "KacstLetter", - "KacstNaskh", - "KacstOffice", - "KacstOne", - "KacstPen", - "KacstPoster", - "KacstQurn", - "KacstScreen", - "KacstTitle", - "KacstTitleL", - "mry_KacstQurn" - ], - "as": [ - "Lohit Assamese" - ], - "bn": [ - "Jamrul", - "Likhan", - "Lohit Bengali", - "Mitra ", - "Mukti", - "অনি" - ], - "gu": [ - "Kalapi", - "Lohit Gujarati", - "Rasa", - "Rekha", - "Samyak Gujarati", - "Samyak Malayalam", - "Samyak Tamil", - "Yrsa", - "aakar", - "padmmaa" - ], - "hi": [ - "Annapurna SIL", - "Chandas", - "Lohit Devanagari", - "Nakula", - "Pagul", - "Sahadeva", - "Samanata", - "Samyak Devanagari", - "Sarai", - "गार्गी", - "नालिमाटी" - ], - "km": [ - "Khmer OS", - "Khmer OS Battambang", - "Khmer OS Bokor", - "Khmer OS Content", - "Khmer OS Fasthand", - "Khmer OS Freehand", - "Khmer OS Metal Chrieng", - "Khmer OS Muol", - "Khmer OS Muol Light", - "Khmer OS Muol Pali", - "Khmer OS Siemreap", - "Khmer OS System" - ], - "kn": [ - "Gubbi", - "Lohit Kannada", - "Navilu" - ], - "lo": [ - "Phetsarath OT" - ], - "ml": [ - "AnjaliOldLipi", - "Chilanka", - "Dyuthi", - "Gayathri", - "Karumbi", - "Keraleeyam", - "Lohit Malayalam", - "Manjari", - "Meera", - "Rachana", - "RaghuMalayalamSans", - "Samyak Gujarati", - "Samyak Malayalam", - "Samyak Tamil", - "Suruma", - "Uroob" - ], - "my": [ - "Padauk", - "Padauk Book" - ], - "ne": [ - "Annapurna SIL" - ], - "or": [ - "Lohit Odia", - "ori1Uni" - ], - "pa": [ - "Lohit Gurmukhi", - "Saab" - ], - "si": [ - "LKLUG" - ], - "ta": [ - "Lohit Tamil", - "Lohit Tamil Classical", - "Samyak Gujarati", - "Samyak Malayalam", - "Samyak Tamil" - ], - "te": [ - "Dhurjati", - "Gidugu", - "Gurajada", - "LakkiReddy", - "Lohit Telugu", - "Mallanna", - "Mandali", - "NATS", - "NTR", - "Peddana", - "Ponnala", - "Pothana2000", - "Potti Sreeramulu", - "Ramabhadra", - "Ramaraja", - "RaviPrakash", - "Sree Krushnadevaraya", - "Suranna", - "Suravaram", - "Syamala Ramana", - "TenaliRamakrishna", - "Timmana", - "Vemana2000" - ], - "th": [ - "Garuda", - "Kinnari", - "Laksaman", - "Loma", - "Norasi", - "Purisa", - "Sawasdee", - "Tlwg Mono", - "Tlwg Typewriter", - "Tlwg Typist", - "Tlwg Typo", - "Umpush", - "Waree" - ] - }, - "extras": { - "core": [ - "Abadi MT Condensed Light", - "Adobe Caslon Pro", - "Adobe Garamond Pro", - "Agency FB", - "Aharoni", - "Algerian", - "Angsana New", - "AngsanaUPC", - "Arial MT", - "Baskerville Old Face", - "Bauhaus 93", - "Bell MT", - "Berlin Sans FB", - "Bernard MT Condensed", - "Bitstream Charter", - "Bitstream Vera Sans Mono", - "Blackadder ITC", - "Bodoni MT", - "Bodoni MT Poster Compressed", - "Book Antiqua", - "Bookman Old Style", - "Bookshelf Symbol 7", - "Bradley Hand ITC", - "Britannic Bold", - "Broadway", - "Browallia New", - "BrowalliaUPC", - "Californian FB", - "Calisto MT", - "Castellar", - "Centaur", - "Century", - "Century Gothic", - "Century Schoolbook", - "Chiller", - "Cochin", - "Colonna MT", - "Cooper Black", - "Copperplate", - "Copperplate Gothic", - "Copperplate Gothic Bold", - "Copperplate Gothic Light", - "Cordia New", - "CordiaUPC", - "Courier", - "Curlz MT", - "David", - "Edwardian Script ITC", - "Elephant", - "Engravers MT", - "EngraversGothic BT", - "Eras Bold ITC", - "Eras Demi ITC", - "Eras Light ITC", - "Eras Medium ITC", - "EucrosiaUPC", - "Eurostile", - "Felix Titling", - "Footlight MT Light", - "Forte", - "Forum", - "Franklin Gothic", - "FreesiaUPC", - "Freestyle Script", - "French Script MT", - "Futura", - "Futura Condensed", - "Geo", - "Gigi", - "Gill Sans", - "Gill Sans MT", - "Gill Sans MT Condensed", - "Gill Sans MT Ext Condensed Bold", - "Gill Sans Ultra", - "Gill Sans Ultra Bold", - "Gill Sans Ultra Bold Condensed", - "Gloucester MT Extra Condensed", - "Goudy Old Style", - "Goudy Stout", - "Graduate", - "Haettenschweiler", - "Harlow Solid Italic", - "Harrington", - "Helvetica", - "Helvetica Light", - "High Tower Text", - "Hoefler Text", - "Imprint MT Shadow", - "Informal Roman", - "IrisUPC", - "Japan", - "JasmineUPC", - "Jokerman", - "Juice ITC", - "Kaufmann BT", - "KodchiangUPC", - "Kristen ITC", - "Kunstler Script", - "Levenim MT", - "LilyUPC", - "Lucida Bright", - "Lucida Console", - "Lucida Fax", - "Lucida Sans", - "Lucida Sans Typewriter", - "Lucida Sans Unicode", - "MS Outlook", - "MS Reference Sans Serif", - "MS Reference Specialty", - "MT Extra", - "Maiandra GD", - "Matura MT Script Capitals", - "Metal", - "Minion Pro", - "Mistral", - "Modern No. 20", - "Monotype Corsiva", - "Myriad Pro", - "Niagara Engraved", - "Niagara Solid", - "OCR A Extended", - "Old English Text MT", - "Onyx", - "Optima", - "Palace Script MT", - "Parchment", - "Perpetua", - "Playbill", - "Poor Richard", - "Pristina", - "Rage Italic", - "Ravie", - "Rockwell Condensed", - "Rockwell Extra", - "Rockwell Extra Bold", - "Script MT", - "Script MT Bold", - "Segoe Script", - "Segoe UI", - "Showcard Gothic", - "Simplified Arabic", - "Sindbad", - "Skia", - "Snap ITC", - "Stencil", - "Tempus Sans ITC", - "Times", - "Times New Roman", - "Traditional Arabic", - "Trajan Pro", - "Tw Cen MT", - "Tw Cen MT Condensed", - "Tw Cen MT Condensed Extra Bold", - "TypoUpright BT", - "Viner Hand ITC", - "Vladimir Script", - "Wide Latin" - ] - } -} \ No newline at end of file diff --git a/src/invisible_playwright/download.py b/src/invisible_playwright/download.py index 4e07b8f..a596c95 100644 --- a/src/invisible_playwright/download.py +++ b/src/invisible_playwright/download.py @@ -1,343 +1,4 @@ -"""Download and cache the patched Firefox binary from GitHub Releases.""" -from __future__ import annotations - -import hashlib -import os -import platform -import re -import shutil -import subprocess -import sys -import tarfile -import tempfile -import time -import zipfile -from pathlib import Path - -import platformdirs -import requests - -from .constants import ( - ARCHIVE_NAME, - BINARY_ENTRY_REL, - BINARY_VERSION, - BROKEN_VERSIONS, - GEOIP_ASSET, - GEOIP_MMDB_NAME, - GEOIP_REPO, - GEOIP_RELEASE_URL_TEMPLATE, - RELEASE_URL_TEMPLATE, -) - - -def _github_token() -> str | None: - return os.environ.get("STEALTHFOX_GITHUB_TOKEN") or os.environ.get("GITHUB_TOKEN") - - -def _parse_owner_repo(template: str) -> tuple[str, str]: - """Extract (owner, repo) from RELEASE_URL_TEMPLATE.""" - m = re.match(r"https://github\.com/([^/]+)/([^/]+)/releases/", template) - if not m: - raise RuntimeError(f"cannot parse owner/repo from {template!r}") - return m.group(1), m.group(2) - - -def cache_root() -> Path: - """Directory where all cached binaries live.""" - return Path(platformdirs.user_cache_dir("invisible-playwright")) - - -def cache_dir_for_version(version: str = BINARY_VERSION) -> Path: - return cache_root() / version - - -def _resolve_asset_url(tag: str, asset_name: str) -> str: - """Return a downloadable URL for the asset. - - For private repos the direct `releases/download//` URL returns - 404 even with a token, so we resolve via the API: list assets for the - release tag, find the one matching `asset_name`, and use its API URL with - `Accept: application/octet-stream` (which 302-redirects to a signed URL). - For public repos the direct URL still works without a token. - """ - token = _github_token() - if not token: - return RELEASE_URL_TEMPLATE.format(tag=tag, asset=asset_name) - owner, repo = _parse_owner_repo(RELEASE_URL_TEMPLATE) - api = f"https://api.github.com/repos/{owner}/{repo}/releases/tags/{tag}" - r = requests.get(api, headers={"Authorization": f"token {token}"}, timeout=30) - r.raise_for_status() - for a in r.json().get("assets", []): - if a.get("name") == asset_name: - return a["url"] - raise RuntimeError(f"asset {asset_name!r} not found in release {tag!r}") - - -def _download_file(url: str, dst: Path, chunk_size: int = 1 << 16) -> None: - dst.parent.mkdir(parents=True, exist_ok=True) - headers: dict[str, str] = {} - token = _github_token() - if token and url.startswith("https://api.github.com/"): - headers["Authorization"] = f"token {token}" - headers["Accept"] = "application/octet-stream" - with requests.get(url, stream=True, timeout=60, headers=headers) as r: - r.raise_for_status() - with open(dst, "wb") as f: - for chunk in r.iter_content(chunk_size): - if chunk: - f.write(chunk) - - -def _sha256_file(path: Path) -> str: - h = hashlib.sha256() - with open(path, "rb") as f: - for chunk in iter(lambda: f.read(1 << 16), b""): - h.update(chunk) - return h.hexdigest() - - -def _parse_checksums(text: str) -> dict[str, str]: - out: dict[str, str] = {} - for line in text.splitlines(): - line = line.strip() - if not line or line.startswith("#"): - continue - parts = line.split() - if len(parts) >= 2: - # sha256sum uses ' *' or ' ' prefix for binary vs text mode - key = parts[-1].lstrip("*") - out[key] = parts[0] - return out - - -def _extract(archive: Path, dst: Path) -> None: - dst.mkdir(parents=True, exist_ok=True) - if archive.suffix == ".zip": - with zipfile.ZipFile(archive) as zf: - zf.extractall(dst) - elif archive.name.endswith(".tar.gz") or archive.suffix in {".tgz", ".gz"}: - with tarfile.open(archive, "r:gz") as tf: - tf.extractall(dst) - else: - raise RuntimeError(f"unknown archive format: {archive}") - - -def _post_extract_darwin(app_root: Path, entry: Path) -> None: - """Make an ad-hoc-signed .app launchable on macOS. - - The .app is downloaded via requests (no Finder quarantine attached), but we - strip com.apple.quarantine defensively and ensure the inner binary is - executable. We exec the inner binary directly (not via LaunchServices), so - Gatekeeper's first-launch prompt does not apply; the ad-hoc signature - (applied in release.yml) is what lets the arm64 Mach-O run at all. - """ - app = app_root - # walk up to the .app bundle dir if entry points inside it - for parent in entry.parents: - if parent.name.endswith(".app"): - app = parent - break - try: - subprocess.run(["xattr", "-dr", "com.apple.quarantine", str(app)], check=False) - except FileNotFoundError: - pass - try: - entry.chmod(0o755) - except OSError: - pass - - -def ensure_binary(version: str = BINARY_VERSION) -> Path: - """Return a path to a runnable Firefox executable. Download if needed.""" - if version in BROKEN_VERSIONS: - raise RuntimeError( - f"{version} is a known-broken release (the juggler automation layer is " - f"missing, so Playwright cannot drive it). Upgrade invisible_playwright " - f"(current BINARY_VERSION={BINARY_VERSION}) or pass a newer version." - ) - plat = sys.platform - mach = platform.machine() - asset = ARCHIVE_NAME(plat, mach) - entry_rel = BINARY_ENTRY_REL.get(plat) - if entry_rel is None: - raise NotImplementedError(f"no binary entry for platform {plat}") - - version_dir = cache_dir_for_version(version) - entry = version_dir / entry_rel - if entry.exists(): - return entry - - url_archive = _resolve_asset_url(version, asset) - url_sums = _resolve_asset_url(version, "checksums.txt") - - with tempfile.TemporaryDirectory() as td: - tmp = Path(td) - archive_path = tmp / asset - _download_file(url_archive, archive_path) - sums_path = tmp / "checksums.txt" - _download_file(url_sums, sums_path) - sums = _parse_checksums(sums_path.read_text()) - expected = sums.get(asset) - if expected is None: - raise RuntimeError(f"no SHA256 for {asset} in checksums.txt") - actual = _sha256_file(archive_path) - if actual.lower() != expected.lower(): - raise RuntimeError( - f"SHA256 mismatch for {asset}: got {actual}, expected {expected}" - ) - _extract(archive_path, version_dir) - - if plat == "darwin": - _post_extract_darwin(version_dir, entry) - - if not entry.exists(): - raise RuntimeError(f"binary not found after extraction: {entry}") - return entry - - -# ───────────────────────────────────────────────────────────────────────── -# GeoIP mmdb (timezone="auto" → map egress IP → IANA zone) -# -# daijro/geoip-all-in-one is rebuilt weekly and KEEPS ONLY the latest ~2 -# releases — older tags are pruned and 404. So we NEVER pin a tag: on every -# launch we resolve the CURRENT latest tag from the `releases/latest/download` -# permalink (its 302 Location carries the tag — a plain CDN request, NOT the -# rate-limited GitHub API) and download it if it differs from the cached one. -# Offline → reuse the cached mmdb; cold cache + offline → raise (the caller can -# then fall back off timezone="auto"). No stale pinned tag to rot. -# ───────────────────────────────────────────────────────────────────────── - - -def _geoip_root() -> Path: - return cache_root() / "geoip" - - -def _cached_geoip_mmdb() -> Path | None: - """Newest cached mmdb across tag dirs, or None. Tag dirs are date strings - (e.g. ``2026.06.17``) so a lexical sort is chronological.""" - root = _geoip_root() - if not root.exists(): - return None - cands = sorted(root.glob("*/*.mmdb")) - return cands[-1] if cands else None - - -def _geoip_latest_url() -> str: - return f"https://github.com/{GEOIP_REPO}/releases/latest/download/{GEOIP_ASSET}" - - -def _latest_geoip_tag_api() -> str: - """Latest ``daijro/geoip-all-in-one`` release tag via the GitHub API - (fallback for :func:`_resolve_latest_geoip_tag` when the permalink HEAD - can't be parsed).""" - headers = {"Accept": "application/vnd.github+json"} - token = _github_token() - if token: - headers["Authorization"] = f"token {token}" - r = requests.get( - f"https://api.github.com/repos/{GEOIP_REPO}/releases/latest", - headers=headers, timeout=15, - ) - r.raise_for_status() - tag = r.json().get("tag_name") - if not tag: - raise RuntimeError("no tag_name in geoip-all-in-one latest release") - return tag - - -def _resolve_latest_geoip_tag() -> str | None: - """Current latest release tag WITHOUT the rate-limited API: HEAD the - ``releases/latest/download`` permalink — GitHub answers 302 with - ``Location: …/releases/download//``. Falls back to the API, - then to ``None`` (offline / unparseable).""" - try: - r = requests.head(_geoip_latest_url(), allow_redirects=False, timeout=10) - loc = r.headers.get("Location") or r.headers.get("location") or "" - m = re.search(r"/releases/download/([^/]+)/", loc) - if m: - return m.group(1) - except Exception: - pass - try: - return _latest_geoip_tag_api() - except Exception: - return None - - -def _download_geoip_tag(tag: str) -> Path: - """Download + extract a specific tag's mmdb if not already cached.""" - dst_dir = _geoip_root() / tag - target = dst_dir / GEOIP_MMDB_NAME - if not target.exists(): - url = GEOIP_RELEASE_URL_TEMPLATE.format(tag=tag, asset=GEOIP_ASSET) - dst_dir.mkdir(parents=True, exist_ok=True) - with tempfile.TemporaryDirectory() as td: - archive = Path(td) / GEOIP_ASSET - _download_file(url, archive) - _extract(archive, dst_dir) - if target.exists(): - return target - # asset name inside the zip may differ from GEOIP_MMDB_NAME - found = sorted(dst_dir.glob("*.mmdb")) - if found: - return found[0] - raise RuntimeError(f"geoip mmdb not found after extraction in {dst_dir}") - - -def _prune_old_geoip_tags(keep: str) -> None: - """Drop every cached tag dir except ``keep`` to bound disk usage.""" - root = _geoip_root() - if not root.exists(): - return - for d in root.iterdir(): - if d.is_dir() and d.name != keep: - shutil.rmtree(d, ignore_errors=True) - - -def geoip_mmdb_path() -> Path | None: - """Path to the currently-cached mmdb (newest tag), or None if none cached.""" - return _cached_geoip_mmdb() - - -def ensure_geoip_mmdb() -> Path: - """Return the geoip mmdb, always the latest daijro build. Checked on EVERY - call — a single cheap permalink HEAD (no GitHub API, so no rate limit). - - Resolution order: - 1. ``STEALTHFOX_GEOIP_MMDB`` env → use that file (user-supplied / test). - 2. Resolve the CURRENT latest tag. If it differs from the newest cached - tag (or nothing is cached) → download it, prune older tags, return it. - 3. Latest tag == newest cached tag → use the cache (no download). - 4. Couldn't resolve the tag (offline / unparseable): cached mmdb → use it; - cold cache → raise (caller can then drop timezone="auto"). - """ - override = os.environ.get("STEALTHFOX_GEOIP_MMDB") - if override: - p = Path(override) - if not p.exists(): - raise RuntimeError(f"STEALTHFOX_GEOIP_MMDB points to a missing file: {p}") - return p - - cached = _cached_geoip_mmdb() - cached_tag = cached.parent.name if cached else None - - latest = _resolve_latest_geoip_tag() - if latest and latest != cached_tag: - # newer build available (or nothing cached) → fetch it - try: - mmdb = _download_geoip_tag(latest) - _prune_old_geoip_tags(mmdb.parent.name) - return mmdb - except Exception: - if cached: - return cached # transient download failure → keep using the cache - raise - - if cached: - return cached # cache is already the latest, or we're offline - - raise RuntimeError( - "geoip mmdb unavailable: no cached copy and GitHub is unreachable. " - "Connect once to download it, or set STEALTHFOX_GEOIP_MMDB to a local " - "geoip-aio-all.mmdb file." - ) +"""Backward-compat shim — spostato in invisible_core.download (alias completo).""" +import sys as _sys +from invisible_core import download as _mod +_sys.modules[__name__] = _mod diff --git a/src/invisible_playwright/prefs.py b/src/invisible_playwright/prefs.py index f06778e..f81c0e9 100644 --- a/src/invisible_playwright/prefs.py +++ b/src/invisible_playwright/prefs.py @@ -1,673 +1,4 @@ -"""Translate an internal Profile into the Firefox prefs dict that the -patched Firefox binary expects. - -The output dict keys map 1:1 to ``user.js`` preferences. Playwright passes -them via ``firefox_user_prefs=``. The patched binary propagates them to all -content processes over IPC; C++ patches read the ``zoom.stealth.*`` -namespace. - -The translation is split into: - - * ``_BASELINE`` — global stealth policy (RFP off, WebRTC leaks blocked, - safebrowsing disabled, debugger detach, …) plus Windows-canonical - constants that don't depend on the Profile (system colors palette, - WebGL extensions whitelist, speech voices, navigator identity). - * ``translate_profile_to_prefs`` — overlays the Profile fields plus the - user-supplied ``locale`` and ``timezone``. -""" -from __future__ import annotations - -import sys -from typing import Any, Dict, Optional - -from ._fpforge import Profile -from ._webgl_personas import render_noise_seed, select_persona - - -# ────────────────────────────────────────────────────────────────────── -# Navigator identity — locked to Firefox 150 Windows so the binary -# reports the same UA / platform / oscpu regardless of the host OS. -# ────────────────────────────────────────────────────────────────────── - -_NAVIGATOR_OVERRIDES: Dict[str, str] = { - "general.useragent.override": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) " - "Gecko/20100101 Firefox/150.0.1", - "general.platform.override": "Win32", - "general.oscpu.override": "Windows NT 10.0; Win64; x64", - # general.buildID.override removed 2026-04-28: the previous value - # "20181001000000" was a 2018 buildID stuck on a 2026-built Firefox 150 - # binary (real BuildID=20260426192818 from application.ini). The 7.5-yr - # discrepancy is the kind of internal-consistency check Google reCAPTCHA - # can use to flag bot/spoofed browsers. Deleting the override lets - # Firefox emit its compiled-in buildID, which auto-tracks the binary. - # A/B knockout 2026-04-28 (n=30): F2 delete +0.083 RC vs BASE; n=100 - # confirm: +0.021; overnight isolated: +0.155 single-variant. Variable - # signal, but the underlying data error is unambiguous. - "general.appversion.override": "5.0 (Windows)", -} - - -# ────────────────────────────────────────────────────────────────────── -# System colors — FP Pro probes getComputedStyle(div) with CSS system -# keywords (ButtonFace, Menu, Highlight, …) and hashes the result into -# signal s142. On Linux, Firefox resolves these via GTK theme → GTK -# RGB values diverge from Windows Win32 palette → server-side anomaly -# even with Windows UA. Pinning the palette to Win10 default closes -# the gap (see project_css_system_colors.md memory). -# ────────────────────────────────────────────────────────────────────── - -_WIN_LIGHT_COLORS: Dict[str, str] = { - "ui.activeborder": "#B4B4B4", - "ui.activecaption": "#99B4D1", - "ui.appworkspace": "#ABABAB", - "ui.background": "#000000", - "ui.buttonface": "#F0F0F0", - "ui.buttonhighlight": "#FFFFFF", - "ui.buttonshadow": "#A0A0A0", - "ui.buttontext": "#000000", - "ui.buttonborder": "#000000", - "ui.captiontext": "#000000", - "ui.graytext": "#6D6D6D", - "ui.highlight": "#0078D7", - "ui.highlighttext": "#FFFFFF", - "ui.inactiveborder": "#F4F7FC", - "ui.inactivecaption": "#BFCDDB", - "ui.inactivecaptiontext": "#434E54", - "ui.infobackground": "#FFFFE1", - "ui.infotext": "#000000", - "ui.menu": "#F9F9FB", - "ui.menutext": "#000000", - "ui.scrollbar": "#C8C8C8", - "ui.threeddarkshadow": "#696969", - "ui.threedface": "#F0F0F0", - "ui.threedhighlight": "#FFFFFF", - "ui.threedlightshadow": "#E3E3E3", - "ui.threedshadow": "#A0A0A0", - "ui.window": "#FFFFFF", - "ui.windowframe": "#646464", - "ui.windowtext": "#000000", - "ui.mark": "#FFFF00", - "ui.marktext": "#000000", - "ui.accentcolor": "#0078D4", - "ui.accentcolortext": "#FFFFFF", - "ui.selecteditem": "#0078D7", - "ui.selecteditemtext": "#FFFFFF", - "ui.-moz-hyperlinktext": "#0066CC", - "ui.-moz-activehyperlinktext": "#EE0000", - "ui.-moz-visitedhyperlinktext": "#551A8B", -} - - -# ────────────────────────────────────────────────────────────────────── -# WebGL extensions — Windows ANGLE canonical lists. Empty string = -# fall back to native Mesa/ANGLE; non-empty = `getSupportedExtensions` -# returns this list verbatim and `IsSupported()` rejects anything else. -# ────────────────────────────────────────────────────────────────────── - -_WEBGL1_EXTENSIONS = ",".join([ - "ANGLE_instanced_arrays", - "EXT_blend_minmax", - "EXT_color_buffer_half_float", - "EXT_float_blend", - "EXT_frag_depth", - "EXT_sRGB", - "EXT_shader_texture_lod", - "EXT_texture_compression_bptc", - "EXT_texture_compression_rgtc", - "EXT_texture_filter_anisotropic", - "OES_element_index_uint", - "OES_fbo_render_mipmap", - "OES_standard_derivatives", - "OES_texture_float", - "OES_texture_float_linear", - "OES_texture_half_float", - "OES_texture_half_float_linear", - "OES_vertex_array_object", - "WEBGL_color_buffer_float", - "WEBGL_compressed_texture_s3tc", - "WEBGL_compressed_texture_s3tc_srgb", - "WEBGL_debug_renderer_info", - "WEBGL_debug_shaders", - "WEBGL_depth_texture", - "WEBGL_draw_buffers", - "WEBGL_lose_context", - "WEBGL_provoking_vertex", -]) - -_WEBGL2_EXTENSIONS = ",".join([ - "EXT_color_buffer_float", - "EXT_color_buffer_half_float", - "EXT_float_blend", - "EXT_texture_compression_bptc", - "EXT_texture_compression_rgtc", - "EXT_texture_filter_anisotropic", - "OES_draw_buffers_indexed", - "OES_texture_float_linear", - "OES_texture_half_float_linear", - "OVR_multiview2", - "WEBGL_compressed_texture_s3tc", - "WEBGL_compressed_texture_s3tc_srgb", - "WEBGL_debug_renderer_info", - "WEBGL_debug_shaders", - "WEBGL_lose_context", - "WEBGL_provoking_vertex", -]) - - -# ────────────────────────────────────────────────────────────────────── -# Speech voices — Windows canonical "Microsoft *" set. Format: -# "NAME|LANG|DEFAULT|LOCAL,...". Non-empty value drives the -# speechSynthesis.getVoices() patch; empty disables it. -# ────────────────────────────────────────────────────────────────────── - -_WIN_VOICES = ",".join([ - "Microsoft David - English (United States)|en-US|1|1", - "Microsoft Zira - English (United States)|en-US|0|1", - "Microsoft Mark - English (United States)|en-US|0|1", - "Microsoft David Desktop - English (United States)|en-US|0|1", - "Microsoft Zira Desktop - English (United States)|en-US|0|1", -]) - - -# ────────────────────────────────────────────────────────────────────── -# Baseline — applied to every session regardless of Profile. -# ────────────────────────────────────────────────────────────────────── - -_BASELINE: Dict[str, Any] = { - # Turn off Firefox's own resistFingerprinting; we do our own via patches. - "privacy.resistFingerprinting": False, - "privacy.resistFingerprinting.letterboxing": False, - - # FF150 fingerprintingProtection — enabled by default (or remotely via - # Mozilla webcompat overrides). FP Pro detects the side-effects and - # flips `privacy_settings: true`. On FF146 these were all off → False. - # Force off so FP Pro reports privacy_settings:false (matches FF146). - "privacy.fingerprintingProtection": False, - "privacy.fingerprintingProtection.pbmode": False, - "privacy.fingerprintingProtection.remoteOverrides.enabled": False, - - # WebRTC: enabled, looks like a real Firefox behind NAT, no real-IP leak. - # obfuscate_host_addresses=true → host candidate is `.local` mDNS, - # exactly like vanilla Firefox (BrowserLeaks "No Leak", Local IP "-"). - # The mDNS-IPC hang feared on older builds does NOT reproduce on FF150. - # The proxy-egress srflx is injected by our C++ (srflx swap §17 + fallback - # §17.B), fed the egress IP via STEALTHFOX_WEBRTC_PUBLIC_IP from - # launcher._build_env (auto-discovered from the proxy). - # IPv6: media.peerconnection.ice.disableIPv6 is DEAD on FF150 (read by no - # ICE-gathering code). The real switch is our zoom.stealth.webrtc.disable_ipv6 - # (nICEr addrs.cpp filter) + the STEALTHFOX_WEBRTC_DISABLE_IPV6 env. - "media.peerconnection.enabled": True, - "media.peerconnection.ice.no_host": False, - "media.peerconnection.ice.default_address_only": False, - "media.peerconnection.ice.obfuscate_host_addresses": True, - "zoom.stealth.webrtc.disable_ipv6": True, - "media.peerconnection.ice.proxy_only": False, - "media.peerconnection.ice.relay_only": False, - "media.peerconnection.use_document_iceservers": True, - - # Proxy — route DNS through SOCKS proxies to avoid local DNS leaks. - "network.proxy.socks_remote_dns": True, - "network.proxy.failover_direct": False, - - # TLS ClientHello fingerprint — match stock Firefox byte-for-byte. - # The Playwright/Juggler Firefox build this binary derives from re-enables - # cipher 0xC009 (TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), which retail Firefox - # 150 does NOT offer. That extra (17th) cipher shifts our JA3/JA4 away from - # any real Firefox (ja4 t13d1717h2 vs stock t13d1617h2). A ClientHello that - # matches no real browser is itself a consistency tell. Disabling it makes - # JA3/JA4/peetprint byte-identical to retail FF150 (verified on tls.peet.ws). - # Stock Firefox ships without 0xC009 and works on the whole web, so this only - # improves fingerprint consistency — it cannot break connectivity. - "security.ssl3.ecdhe_ecdsa_aes_128_sha": False, - - # Safebrowsing — chatty and fingerprintable. - "browser.safebrowsing.malware.enabled": False, - "browser.safebrowsing.phishing.enabled": False, - "browser.safebrowsing.downloads.enabled": False, - "browser.safebrowsing.downloads.remote.enabled": False, - - # First-run / welcome UI noise. - "browser.startup.page": 0, - "browser.shell.checkDefaultBrowser": False, - "browser.aboutwelcome.enabled": False, - "browser.startup.upgradeDialog.enabled": False, - "termsofuse.acceptedVersion": 999, - - # Disable about:newtab auto-load — TopSitesFeed.sys.mjs auto-fetches when - # a tab opens, triggering a cross-process BC swap that hijacks the first - # page.goto() (NS_BINDING_ABORTED on creepjs/peet/sannysoft/fppro). - "browser.newtabpage.enabled": False, - "browser.newtab.preload": False, - "browser.newtabpage.activity-stream.feeds.topsites": False, - "browser.newtabpage.activity-stream.feeds.section.topstories": False, - "browser.newtabpage.activity-stream.enabled": False, - - # Disable Firefox internal services that hit the network on startup. - # Through a residential SOCKS5 proxy these compete with the test - # navigation and trigger NS_BINDING_FAILED (server-side rate-limit / - # connection drops). Domains observed in MOZ_LOG: push.services, - # firefox.settings.services, detectportal, ohttp-gateway, location. - "browser.aboutConfig.showWarning": False, - "network.captive-portal-service.enabled": False, - "network.connectivity-service.enabled": False, - "dom.push.enabled": False, - "dom.push.connection.enabled": False, - "geo.enabled": False, - "geo.provider.network.url": "", - "browser.region.network.url": "", - "browser.region.update.enabled": False, - "services.settings.server": "", - "browser.search.geoSpecificDefaults": False, - "browser.contentblocking.report.lockwise.enabled": False, - "browser.contentblocking.report.monitor.enabled": False, - "extensions.systemAddon.update.enabled": False, - "extensions.update.enabled": False, - "extensions.getAddons.cache.enabled": False, - "browser.discovery.enabled": False, - "browser.ping-centre.telemetry": False, - "app.normandy.enabled": False, - "dom.private-attribution.submission.enabled": False, - "browser.translations.enable": False, - "browser.search.update": False, - - # HTTP/3 + speculative + Alt-Svc disabled. SOCKS5 proxy doesn't - # support UDP ASSOCIATE so HTTP/3 fails. Speculative connections - # under load cause early channel cancel (NS_BINDING_FAILED). - "network.http.http3.enable": False, - "network.http.http3.enabled": False, - "network.http.altsvc.enabled": False, - "network.http.altsvc.oe": False, - "network.http.speculative-parallel-limit": 0, - "network.predictor.enabled": False, - "network.dns.disablePrefetch": True, - "network.dns.disablePrefetchFromHTTPS": True, - "network.dns.echconfig.enabled": False, - "network.dns.use_https_rr_as_altsvc": False, - - # === Fission / site-isolation disabled (FF146 Playwright parity) === - # Force a single content-process model. Three knobs are required in FF150: - # upstream Playwright Firefox (FF146-based) only needed fission.autostart=False - # because FF146's default isolation strategy was looser. FF150 ships with - # fission.webContentIsolationStrategy=1 (IsolateEverything) which still - # site-isolates cross-origin iframes into separate `webIsolated` content - # processes EVEN WHEN fission.autostart is False. From the parent process's - # point of view, those iframes get a Juggler Frame placeholder with no - # docShell, no URL, and an execution context that wraps the wrong global, - # so frame.evaluate() fails with cross-origin SOP errors and - # element_handle.content_frame() returns None. - # - # Pinning the strategy to 0 keeps every cross-origin web iframe in the - # parent's content process, where the Juggler code paths from the FF146 - # era expect them. processCount.webIsolated=1 is kept as belt-and-suspenders - # in case some path still classifies an origin as webIsolated despite the - # strategy change. It costs nothing to leave. - # - # See issue #20 + tests/test_cross_origin_iframe.py for the regression - # sentinel that catches a future A/B flipping these back. - "fission.autostart": False, - "fission.autostart.session": False, - "fission.webContentIsolationStrategy": 0, # IsolateNothing - "dom.ipc.processCount.webIsolated": 1, - - - # Telemetry & data reporting. - "datareporting.healthreport.uploadEnabled": False, - "datareporting.policy.dataSubmissionEnabled": False, - "toolkit.telemetry.enabled": False, - "toolkit.telemetry.unified": False, - "app.shield.optoutstudies.enabled": False, - - # Update channels. - "app.update.enabled": False, - "app.update.auto": False, - - # Speech synth: enabled (the C++ patch fabricates voices from the - # comma list above) regardless of the host OS. - "media.webspeech.synth.enabled": True, - "zoom.stealth.voices.list": _WIN_VOICES, - - # WebGL extensions whitelist — non-empty pre-empts native enumeration. - "zoom.stealth.webgl.extensions": _WEBGL1_EXTENSIONS, - "zoom.stealth.webgl2.extensions": _WEBGL2_EXTENSIONS, - # WebGL numeric param overrides — kept empty (A/B test 2026-04-22 showed - # mismatches between the values we shipped and ANGLE's real envelope - # raised FP Pro's ML tampering score). Slot kept for future experiments. - "zoom.stealth.webgl.int_params": "", - "zoom.stealth.webgl.int2_params": "", - "zoom.stealth.webgl.shader_precisions": "", - "zoom.stealth.webgl.float_params": "", - - # DevTools anti-detection. - "zoom.stealth.debugger.force_detach": True, - - # Canvas substitution (Option B for canvas) — replace pixels with hash(seed,idx), - # uniform-skip (red-box exact, masking-safe) + full overwrite. Makes the canvas - # render a pure function of (seed) = HOST-INDEPENDENT (kills the DWrite-vs-FreeType - # text-raster leak: Canvas Hash + Font hash were the residual Win!=Linux signals). - # ON by default (paired with webgl.substitute_pixels). - "zoom.stealth.canvas.substitute_pixels": True, - - # WebGL substitution (Option B) — replace readback/snapshot RGB with - # hash(seed,idx), endpoint-preserving. Makes the WebGL render hash a pure - # function of (seed, dims) = HOST-INDEPENDENT, so no per-host hw_seed - # calibration is needed (the gamma path was per-host: NVIDIA/Arc-on-Win clean - # seeds went dirty on the Linux GL backend). ON by default. - "zoom.stealth.webgl.substitute_pixels": True, - - # WebGPU presence consistency. Firefox enables dom.webgpu.enabled by default on - # Windows/Mac-ARM but NOT on Linux/Mac-x64. We ALWAYS claim Windows, so force it ON - # on every host: a Windows FF MUST expose navigator.gpu (object); a Linux host leaving - # it undefined while the UA says Windows is an inconsistency tell (RE 2026-06-22: - # has_gpu was object on Win, undefined on WSL). adapter.info is empty (FF privacy - # default) so no GPU-name leak; requestAdapter may be null on a GPU-less host, which - # is itself plausible for a real Windows machine. - "dom.webgpu.enabled": True, - - # Audio fingerprint noise OFF. RE 2026-06-22: the per-session OfflineAudioContext - # noise (gated by hw_seed) was THE dominant driver of FP Pro tampering_ml on Windows - # — b005 Win dropped 0.4349 -> 0.0564 with audio noise alone disabled (canvas_text/ - # emoji unchanged, so they were a red-herring). The audio value is already host-indep - # AND identical to a real FF's canonical OfflineAudioContext sum, so a fixed (un-noised) - # audio is NOT a linking signal (every real FF has the same value) — removing the noise - # matches real Firefox and clears the tampering flag. - "zoom.stealth.audio.fp_noise": False, - - # Navigator identity (locked to Windows Firefox 150). - **_NAVIGATOR_OVERRIDES, -} - - -# ────────────────────────────────────────────────────────────────────── -# Linux-only Xvfb workarounds — the Linux Firefox build under Xvfb -# cannot run WebRender (`ConnectToCompositor` retries forever). We -# disable WebRender + force WebGL through the GL software path so -# webgl_basics / webgl_extensions still report. -# ────────────────────────────────────────────────────────────────────── - -_LINUX_XVFB_WORKAROUNDS: Dict[str, Any] = { - "gfx.webrender.all": False, - "gfx.webrender.force-disabled": True, - "webgl.force-enabled": True, - # webgl.software-rendering-enabled / webgl.force-layers-readback removed in FF150. -} - -# ────────────────────────────────────────────────────────────────────── -# Windows virtual-desktop workarounds — when headless=True on Windows, -# Firefox runs on a CreateDesktop virtual desktop. The hardware GPU is -# inaccessible from the virtual desktop, so the GPU process crashes when -# it tries to initialize the D3D11 compositor with hardware acceleration. -# -# Approach: force D3D11 WARP (CPU software renderer) for the GPU process. -# layers.d3d11.force-warp=True → compositor uses WARP → GPU process stable. -# webgl.angle.force-warp=True → ANGLE uses WARP → WebGL context creates. -# -# CRITICAL: do NOT set webgl.out-of-process=False. That moves WebGL from the -# GPU process to the sandboxed content process. The content process sandbox -# blocks D3D11 access entirely → ANGLE crashes the content process → -# canvas.getContext('webgl') throws instead of returning null. -# -# gfx.canvas.accelerated=False: default is true, disabling avoids any -# hardware GPU dependency for 2D canvas in the content process. -# ────────────────────────────────────────────────────────────────────── - -_WIN_VIRT_DESKTOP_WORKAROUNDS: Dict[str, Any] = { - # FF150 regression vs FF146 on CreateDesktop alt-desktop: - # The GPU process sandbox (level=1, default since FF110) tries to parent - # its compositor window to the parent process's window. Our worker spawns - # Firefox on a CreateDesktop-created alt desktop — parent and GPU process - # do not share the same desktop/HWND namespace, so window parenting fails - # silently. WebRender falls back to "Software D3D11" and OOP-WebGL never - # publishes a hardware ANGLE renderer → getContext('webgl') returns a - # context but extensions/parameters/$hash all come back null/empty (FF146 - # had a more permissive sandbox, so the same setup worked there). - # Bugzilla refs: 1798091, 1524591, 1229829. Lowering the GPU sandbox to 0 - # restores hardware compositor + functional WebGL on alt desktops. - "security.sandbox.gpu.level": 0, - # Same root cause as above, content process side. Wrapper repo issue #18 - # (tab crash on cross-process navigation under headless=True). Sandbox - # content level > 4 puts content processes on the sandbox's own - # kAlternateWinstation (see security/sandbox/win/src/sandboxbroker/ - # sandboxBroker.cpp line 1113-1114: - # `if (aSandboxLevel > 4) config->SetDesktop(kAlternateWinstation)`). - # Combined with our CreateDesktop alt-desktop, that puts browser process - # and content processes on DIFFERENT desktops. Cross-process navigation - # then fails window parenting between parent and child, the content - # process exits cleanly (exitCode=0, signal=null) and Playwright fires - # page.on('crash') ~10s after page load. Lowering content sandbox to 4 - # keeps content processes on the same desktop as the browser process, - # which is what we want here (still tight enough — level 4 blocks - # file/registry write, network calls, hardware access). - "security.sandbox.content.level": 4, -} - - -# ────────────────────────────────────────────────────────────────────── -# Public helpers -# ────────────────────────────────────────────────────────────────────── - -def _accept_language(locale: str) -> str: - # ", " — the desktop-default shape (e.g. "en-US, en"). Firefox expands it - # to navigator.languages=["en-US","en"] AND (via the patched binary) the q-valued header - # "en-US,en;q=0.5". The patched nsHttpHandler (STEALTHFOX, RE 2026-06-23) builds the - # Accept-Language header from THIS pref even when juggler sets a per-context locale - # override, so header and navigator.languages stay consistent 2/2 — the most authentic - # (real desktop) form. Supersedes the 2026-06-22 single-tag workaround. - lang = locale.replace("_", "-") - base = lang.split("-")[0] - return f"{lang}, {base}" if base != lang else lang - - -def translate_profile_to_prefs( - profile: Profile, - *, - locale: str = "en-US", - timezone: str = "", - extra_prefs: Optional[Dict[str, Any]] = None, - virtual_display: bool = False, -) -> Dict[str, Any]: - """Return a complete prefs dict ready for Playwright's firefox_user_prefs=. - - Args: - profile: Bayesian-sampled fingerprint (from ``generate_profile``). - locale: BCP-47 tag, e.g. ``"en-US"``. - timezone: IANA timezone name, e.g. ``"America/New_York"``. - extra_prefs: Optional overlay applied LAST. - virtual_display: When True on Windows, apply GPU-disabling workarounds - to prevent the GPU process from crashing on virtual - desktops that have no D3D11 backend. - """ - prefs: Dict[str, Any] = dict(_BASELINE) - - # GPU / WebGL renderer/vendor. - # On Linux we spoof to a Windows ANGLE renderer string (profile.gpu.renderer) - # so cross-platform sessions report a consistent Windows GPU identity. - # On Windows/mac, spoofing a renderer string ALONE is unsafe — the ~81 - # getParameter values stay real, so a name↔params hash mismatch FP Pro flags - # (setting GTX 980 over real Arc A750 params scored ~0.70). Instead we apply a - # VALIDATED PERSONA (see _webgl_personas): a {renderer, vendor} whose params are - # the shared ANGLE D3D11 caps (vendor-independent — identical on any host, per the - # ANGLE source) and whose extension list is FORCED below. That is a coherent fake - # GPU that passes FP Pro host-independently (the host's real GPU never leaks). If no - # validated persona exists for the sampled gpu_class yet, fall back to the host-real - # renderer (empty → native ANGLE; SanitizeRenderer at ClientWebGLContext.cpp:2592). - # Apply the camoufox-derived real-Firefox GPU persona on EVERY host (Win/Linux/Mac). - # We must ALWAYS look Windows (rule), and the WebGL override is platform-independent: - # SanitizeRenderer (ClientWebGLContext.cpp) is pure string regex, and the param/extension - # overrides are pref-driven, so the C++ presents the SAME Windows ANGLE GPU regardless of - # the host's real GL backend (it never consults it when the pref is set). This is why a - # Windows GPU shows correctly even on a Linux/Mesa host (no more "Generic Renderer"). - _persona = select_persona(profile.seed) - if _persona: - # Apply the FULL coherent WebGL override (renderer + vendor + webgl1/webgl2 extensions - # + ~100 getParameter values + shader-precision formats). Setting ALL of them — not just - # the renderer string — keeps renderer<->params coherent (FP Pro cross-checks them); a - # string-only spoof over the host's real params is the old ~0.85 mismatch. - for _k, _v in _persona["prefs"].items(): - if _k == "zoom.stealth.webgl2.enabled": - prefs["webgl.enable-webgl2"] = bool(_v) - else: - prefs[_k] = _v - else: - prefs["zoom.stealth.webgl.renderer"] = "" - prefs["zoom.stealth.webgl.vendor"] = "" - # Canvas-noise mask is calibrated to the REAL host GPU's rendering variance — the canvas is - # drawn by real hardware, NOT the persona's claimed GPU, so it must NOT follow the persona - # (a non-Intel persona on an Intel host would over-noise). Dev/deployment host is Intel. - _renderer_lo = "intel" - - # MSAA: on Windows, pin to 4 (Firefox default for ANGLE) so gl.SAMPLES is - # constant across all sessions. Different MSAA values cause different CN-set - # parameters hashes even with the same renderer → detectable variation. - # Vanilla Intel Arc A750 parameters hash (66544db8) verified at msaa=4. - _msaa = profile.webgl.msaa_samples if sys.platform.startswith("linux") else 4 - prefs["zoom.stealth.webgl.msaa"] = _msaa - prefs["webgl.msaa-samples"] = _msaa - prefs["webgl.msaa-force"] = _msaa > 0 - - # Canvas pixel-noise density per vendor. Intel has lower natural - # rendering variance than NVIDIA/AMD, so the default 1/8 noise rate - # over-amplifies the FP Pro tampering ML signal. Drop to 1/16 for Intel - # to keep tampering_ml below the detection threshold while still - # breaking the canvas geometry hash. - if "intel" in _renderer_lo: - prefs["zoom.stealth.canvas.noise_skip_mask"] = 15 # 1/16, ~6.25% - else: - prefs["zoom.stealth.canvas.noise_skip_mask"] = 7 # 1/8, ~12.5% - - # Screen - prefs["zoom.stealth.screen.width"] = profile.screen.width - prefs["zoom.stealth.screen.height"] = profile.screen.height - prefs["zoom.stealth.screen.avail_width"] = profile.screen.avail_width - prefs["zoom.stealth.screen.avail_height"] = profile.screen.avail_height - prefs["zoom.stealth.screen.dpr"] = profile.screen.dpr - prefs["layout.css.devPixelsPerPx"] = str(profile.screen.dpr) - - # Hardware — coherent with the sampled gpu_class by construction (the forge - # draws hw_concurrency conditioned on the GPU class). - prefs["zoom.stealth.hw_concurrency"] = profile.hardware.concurrency - prefs["zoom.stealth.storage.quota_mb"] = profile.hardware.storage_quota_mb - - # Audio - prefs["zoom.stealth.audio.sample_rate"] = profile.audio.sample_rate - prefs["zoom.stealth.audio.output_latency_ms"] = profile.audio.output_latency_ms - prefs["zoom.stealth.audio.max_channel_count"] = profile.audio.max_channel_count - - # Codec - prefs["media.av1.enabled"] = profile.codec.av1_enabled - prefs["media.encoder.webm.enabled"] = profile.codec.webm_encoder_enabled - prefs["media.mediasource.webm.enabled"] = profile.codec.mediasource_webm - prefs["media.mediasource.mp4.enabled"] = profile.codec.mediasource_mp4 - - # Fonts — real bundled fonts (no collapse). The binary ships the real - # Windows font files in /fonts and loads them via MOZ_BUNDLED_FONTS, so - # glyphs are genuine on every host. We expose this profile's family set via - # the per-profile fontlist, which the binary applies to the native system - # font allow-list AT CONSTRUCTION (no runtime rebuild → no scan stall), and - # force the system-ui generic to Segoe UI. profile.fonts is the _fpforge - # sample (core always + a conditioned optional subset). Per-profile metric - # uniqueness comes from the shared fpp.hw_seed jitter in the HarfBuzz shaper - # (set with the other fpp prefs), not from fabricated widths. - prefs["zoom.stealth.font.fontlist"] = ",".join(profile.fonts) - prefs["zoom.stealth.font.system_ui"] = "Segoe UI" - - # Activate the bundled real-Windows fonts (MOZ_BUNDLED_FONTS / /fonts). - prefs["gfx.bundled-fonts.activate"] = 1 - # Point the CSS generics at Windows defaults. On a Windows HOST Firefox's - # built-in name-lists already resolve to these (and they're in the fontlist - # so they survive the allow-list); but on a non-Windows host (Linux/Mac) the - # built-in defaults name host fonts (DejaVu/Liberation/…) which the allow-list - # hides — so the generics would collapse. Setting them explicitly keeps the - # generics resolving to the bundled Windows families on EVERY host (system-ui - # is forced to Segoe UI by the C++ hook above, so it is not listed here). - prefs["font.name-list.serif.x-western"] = "Times New Roman" - prefs["font.name-list.sans-serif.x-western"] = "Arial" - prefs["font.name-list.monospace.x-western"] = "Consolas" - prefs["font.name-list.sans-serif.ja"] = "Yu Gothic UI" - prefs["font.name-list.serif.ja"] = "Yu Gothic UI" - prefs["font.name-list.sans-serif.ko"] = "Malgun Gothic" - prefs["font.name-list.serif.ko"] = "Malgun Gothic" - prefs["font.name-list.sans-serif.zh-CN"] = "Microsoft YaHei UI" - prefs["font.name-list.sans-serif.zh-TW"] = "Microsoft JhengHei UI" - prefs["font.name-list.sans-serif.zh-HK"] = "Microsoft JhengHei UI" - - # UI / dark mode + Windows colors palette (only when light theme). - prefs["ui.systemUsesDarkTheme"] = int(profile.dark_theme) - if not profile.dark_theme: - prefs.update(_WIN_LIGHT_COLORS) - - # Locale prefs. - locale = locale or "en-US" - lang = locale.replace("_", "-") - prefs["intl.accept_languages"] = _accept_language(locale) - prefs["general.useragent.locale"] = lang - prefs["intl.locale.requested"] = lang - prefs["privacy.spoof_english"] = 0 - # juggler.locale.override seeds the BrowsingContext LanguageOverride FIELD in - # the parent process (BrowsingContext::Attach), whose DidSet drives BOTH - # navigator.languages (the full list) AND the realm Intl default locale (the - # primary tag it extracts) — so Intl.DateTimeFormat / NumberFormat / - # toLocaleString follow the locale, not just the Accept-Language header. Seed - # it with the full Accept-Language list so navigator.languages stays the - # desktop-default 2 elements (["fr-FR","fr"]); the C++ DidSet takes "fr-FR" - # for Intl. Mirrors juggler.timezone.override; the SOLE source of truth. - prefs["juggler.locale.override"] = _accept_language(locale) - - if timezone: - # juggler.timezone.override is the SOLE source of truth read by the C++ - # timezone chain (BrowsingContext::Attach/DidSet, ContentChild). The old - # zoom.stealth.timezone pref was declared in the yaml but read by NO - # code — dropped here on 2026-06-10 (see 20-our-patches.md §8). - prefs["juggler.timezone.override"] = timezone - - # Cross-process seed (canvas noise + DWrite gamma share this). Only - # zoom.stealth.fpp.hw_seed is read by the C++; the old zoom.stealth.seed - # alias was never declared in the yaml and read by nothing — dropped - # 2026-06-10. The render-noise seed is DECOUPLED from the identity seed and - # drawn from a calibrated CLEAN pool: the canvas/WebGL render HASH it drives - # is the dominant FP Pro tampering_ml signal, and some hw_seeds yield a - # "suspicious" render hash. render_noise_seed() maps to the clean pool while - # keeping per-seed determinism + diversity. See _webgl_personas. - prefs["zoom.stealth.fpp.hw_seed"] = render_noise_seed(profile.seed) - - # Synthetic host ICE candidate — injected by C++ when addr_ct==0 (SOCKS5 - # proxy suppresses all local addresses so Firefox can't gather host cands). - # LAN IP is seed-derived so it's consistent per session and looks like a - # real home router assignment (192.168.x.x range). - _s = profile.seed - _lan_ip = f"192.168.{(_s >> 8) % 254 + 1}.{_s % 254 + 1}" - prefs["zoom.stealth.webrtc.host_ip"] = _lan_ip - - # Windows/mac extension list: - # - persona active → the coherent webgl1/webgl2 extension lists (in the GPU's real - # native order) were ALREADY applied above from the GPU pool's `prefs`, alongside the - # matching renderer + params + shader-precisions. Nothing to do here. - # - no persona → clear so the host-real renderer reports its native extension set - # (matches real vanilla captures for that host's GPU). - if not sys.platform.startswith("linux") and not _persona: - prefs["zoom.stealth.webgl.extensions"] = "" - prefs["zoom.stealth.webgl2.extensions"] = "" - - # Linux Xvfb workarounds (no-op on Windows). - if sys.platform.startswith("linux"): - for k, v in _LINUX_XVFB_WORKAROUNDS.items(): - prefs.setdefault(k, v) - - # Windows virtual-desktop workarounds (headless=True on Windows). - if virtual_display and sys.platform == "win32": - for k, v in _WIN_VIRT_DESKTOP_WORKAROUNDS.items(): - prefs.setdefault(k, v) - - # Caller overlay LAST so users can override anything we set. A value of - # None is treated as a sentinel meaning "delete this pref entirely from - # the final dict" — useful for A/B harnesses that need to test what - # happens when an override is unset (vs set to empty string, which for - # some prefs like general.useragent.override means literally empty UA). - if extra_prefs: - for k, v in extra_prefs.items(): - if v is None: - prefs.pop(k, None) - else: - prefs[k] = v - - return prefs +"""Backward-compat shim — spostato in invisible_core.prefs (alias completo).""" +import sys as _sys +from invisible_core import prefs as _mod +_sys.modules[__name__] = _mod diff --git a/tests/test_backcompat.py b/tests/test_backcompat.py new file mode 100644 index 0000000..99e82a7 --- /dev/null +++ b/tests/test_backcompat.py @@ -0,0 +1,84 @@ +"""Backward-compatibility guard for the invisible_core / invisible_playwright split. + +After extracting the pure config into ``invisible_core`` and turning the moved +modules into aliasing shims, EVERY import path that external users (and our own +outreach PRs) rely on must keep working — same objects, same behavior. This test +is the contract: if it breaks, we broke someone's install. +""" +import importlib + +import pytest + + +@pytest.mark.unit +def test_top_level_public_api_imports(): + import invisible_playwright as ip + for name in [ + "InvisiblePlaywright", "ensure_binary", "ensure_geoip_mmdb", + "get_default_stealth_prefs", "get_default_args", + "resolve_session_timezone", "GeoTimezoneError", + "BINARY_VERSION", "FIREFOX_UPSTREAM_VERSION", "__version__", + ]: + assert hasattr(ip, name), f"invisible_playwright.{name} missing" + + +@pytest.mark.unit +def test_submodule_imports_external_users_rely_on(): + # These are the exact import shapes used in the wild + in our Skyvern/onyx/etc PRs. + from invisible_playwright._fpforge import generate_profile, Profile # noqa: F401 + from invisible_playwright._webgl_personas import forced_gpu_class # noqa: F401 + from invisible_playwright.prefs import translate_profile_to_prefs # noqa: F401 + from invisible_playwright.download import ensure_binary # noqa: F401 + from invisible_playwright.constants import BINARY_VERSION # noqa: F401 + from invisible_playwright.config import get_default_stealth_prefs # noqa: F401 + + +@pytest.mark.unit +def test_deep_submodule_and_private_names_still_import(): + from invisible_playwright._fpforge.profile import Profile # noqa: F401 + from invisible_playwright._fpforge import _sampler # noqa: F401 + from invisible_playwright.prefs import _BASELINE # noqa: F401 + assert isinstance(_BASELINE, dict) + + +@pytest.mark.unit +def test_class_identity_is_shared_with_core(): + # isinstance must hold: the object returned by generate_profile must be an + # instance of BOTH the invisible_playwright-path Profile and the core Profile + # (they must be the SAME class object, not duplicates). + from invisible_playwright._fpforge import generate_profile + from invisible_playwright._fpforge import Profile as PW_Profile + from invisible_playwright._fpforge.profile import Profile as PW_Profile2 + import invisible_core + from invisible_core import Profile as Core_Profile + + p = generate_profile(seed=42) + assert isinstance(p, PW_Profile) + assert isinstance(p, PW_Profile2) + assert isinstance(p, Core_Profile) + assert PW_Profile is Core_Profile + assert PW_Profile2 is Core_Profile + + +@pytest.mark.unit +def test_shim_output_matches_core_output(): + from invisible_playwright._fpforge import generate_profile as gp_pw + from invisible_playwright._webgl_personas import forced_gpu_class as fgc_pw + from invisible_playwright.prefs import translate_profile_to_prefs as tp_pw + import invisible_core as ic + + a = tp_pw(gp_pw(42, fixed_gpu_class=fgc_pw(42))) + b = ic.translate_profile_to_prefs(ic.generate_profile(42, fixed_gpu_class=ic.forced_gpu_class(42))) + assert a == b + + +@pytest.mark.unit +def test_core_imports_without_playwright(monkeypatch): + # invisible_core must be importable even if playwright is absent. We simulate + # by asserting the core modules never pulled playwright into sys.modules as a + # side effect of their own import (the wrapper may have, but core must not need it). + import sys + import invisible_core # noqa: F401 + # invisible_core itself must not hard-depend on playwright at import time. + core_file = importlib.import_module("invisible_core").__file__ + assert "invisible_core" in core_file