Efradeca commited on
Commit
bd75e4a
·
verified ·
1 Parent(s): fff8eab

chore: deploy private lightloom build

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. app.py +58 -1
  2. frontend/css/tokens.css +2 -2
  3. frontend/index.html +3 -0
  4. frontend/js/stage-pano.js +172 -0
  5. node_modules/.bin/playwright +16 -0
  6. node_modules/.bin/playwright-core +16 -0
  7. node_modules/.bin/playwright-core.cmd +17 -0
  8. node_modules/.bin/playwright-core.ps1 +28 -0
  9. node_modules/.bin/playwright.cmd +17 -0
  10. node_modules/.bin/playwright.ps1 +28 -0
  11. node_modules/.package-lock.json +37 -0
  12. node_modules/playwright-core/LICENSE +202 -0
  13. node_modules/playwright-core/NOTICE +5 -0
  14. node_modules/playwright-core/README.md +3 -0
  15. node_modules/playwright-core/ThirdPartyNotices.txt +13 -0
  16. node_modules/playwright-core/bin/install_media_pack.ps1 +5 -0
  17. node_modules/playwright-core/bin/install_webkit_wsl.ps1 +33 -0
  18. node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +42 -0
  19. node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +13 -0
  20. node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1 +24 -0
  21. node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +42 -0
  22. node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +12 -0
  23. node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1 +24 -0
  24. node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +48 -0
  25. node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +11 -0
  26. node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1 +23 -0
  27. node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +48 -0
  28. node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +11 -0
  29. node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1 +23 -0
  30. node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +48 -0
  31. node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +11 -0
  32. node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1 +24 -0
  33. node_modules/playwright-core/browsers.json +81 -0
  34. node_modules/playwright-core/cli.js +21 -0
  35. node_modules/playwright-core/index.d.ts +17 -0
  36. node_modules/playwright-core/index.js +32 -0
  37. node_modules/playwright-core/index.mjs +28 -0
  38. node_modules/playwright-core/lib/bootstrap.js +77 -0
  39. node_modules/playwright-core/lib/coreBundle.js +0 -0
  40. node_modules/playwright-core/lib/entry/cliDaemon.js +5 -0
  41. node_modules/playwright-core/lib/entry/dashboardApp.js +3 -0
  42. node_modules/playwright-core/lib/entry/mcp.js +10 -0
  43. node_modules/playwright-core/lib/entry/oopBrowserDownload.js +3 -0
  44. node_modules/playwright-core/lib/package.js +50 -0
  45. node_modules/playwright-core/lib/server/deviceDescriptorsSource.json +1779 -0
  46. node_modules/playwright-core/lib/server/electron/loader.js +115 -0
  47. node_modules/playwright-core/lib/serverRegistry.js +0 -0
  48. node_modules/playwright-core/lib/serverRegistry.js.LICENSE +354 -0
  49. node_modules/playwright-core/lib/tools/cli-client/channelSessions.js +141 -0
  50. node_modules/playwright-core/lib/tools/cli-client/cli.js +6 -0
app.py CHANGED
@@ -144,7 +144,7 @@ def health() -> dict[str, Any]:
144
  "privacy_mode": os.getenv("LIGHTLOOM_PRIVACY_MODE", "1") == "1",
145
  "cpu_count": os.cpu_count(),
146
  "director_backend": CONFIG.director_backend,
147
- "build": "pano-probe-2",
148
  }
149
 
150
 
@@ -313,6 +313,63 @@ def pano_frame_endpoint(name: str):
313
  return FileResponse(path)
314
 
315
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  @app.post("/internal/bench/director-probe")
317
  def director_probe_endpoint(backend: str = "transformers", threads: int = 8) -> dict[str, Any]:
318
  if os.getenv("LIGHTLOOM_ENABLE_INTERNAL_BENCH", "0") != "1":
 
144
  "privacy_mode": os.getenv("LIGHTLOOM_PRIVACY_MODE", "1") == "1",
145
  "cpu_count": os.cpu_count(),
146
  "director_backend": CONFIG.director_backend,
147
+ "build": "pano-world-1",
148
  }
149
 
150
 
 
313
  return FileResponse(path)
314
 
315
 
316
+ # --- THE PANORAMA WORLD (Voice-Scroll-in-3D): narration -> one immersive
317
+ # equirectangular world (klein-base + 360 LoRA) + its depth -> the browser renders
318
+ # it as a sphere the camera lives inside. Streams via @app.api/@gradio/client. ---
319
+ @spaces.GPU(duration=110)
320
+ def _panorama_world(text: str, session: str):
321
+ import numpy as np
322
+ from PIL import Image
323
+
324
+ from lightloom.depth.depth import estimate_depth, load_depth_pipeline
325
+ from lightloom.director.director import generate_shot_transformers, load_director_transformers
326
+ from lightloom.director.state import initial_state
327
+ from lightloom.paint.panorama import generate_panorama, load_panorama_pipeline
328
+
329
+ out_dir = Path("/tmp/lightloom/pano") / session
330
+ out_dir.mkdir(parents=True, exist_ok=True)
331
+ yield {"stage": "warming"}
332
+
333
+ # Director turns the narration into one vivid establishing scene for the world.
334
+ tokenizer, model = load_director_transformers()
335
+ first = (text or "").strip().split("\n\n")[0][:300] or "a world at the edge of the world"
336
+ shot, _m = generate_shot_transformers(tokenizer, model, first, initial_state().model_dump())
337
+ scene = f"{shot.image_prompt_en}, {shot.lighting}"
338
+ yield {"stage": "directed", "shot": shot.model_dump(), "scene": scene[:160]}
339
+
340
+ yield {"stage": "painting"}
341
+ pano_pipe = load_panorama_pipeline()
342
+ pano = generate_panorama(pano_pipe, scene)
343
+ pano.save(out_dir / "world.webp", "WEBP", quality=92)
344
+ yield {"stage": "painted", "panorama": f"/frames-pano/{session}/world.webp"}
345
+
346
+ depth_pipeline = load_depth_pipeline()
347
+ dmap = estimate_depth(pano)
348
+ Image.fromarray((dmap * 255).astype(np.uint8)).save(out_dir / "world_depth.png")
349
+ yield {"stage": "depth", "depth": f"/frames-pano/{session}/world_depth.png"}
350
+ yield {"stage": "done", "session": session}
351
+
352
+
353
+ @app.api(name="panorama", concurrency_id="gpu", concurrency_limit=1, stream_every=0.05)
354
+ def panorama_api(text: str = _GOLDEN_RECITAL, lang: str = "en") -> dict:
355
+ session = uuid.uuid4().hex[:8]
356
+ try:
357
+ for event in _panorama_world((text or _GOLDEN_RECITAL).strip(), session):
358
+ yield event
359
+ except Exception as exc: # noqa: BLE001 - quota guard.
360
+ message = str(exc).lower()
361
+ stage = "quota_exceeded" if any(t in message for t in ("gpu", "quota", "zerogpu", "exceeded")) else "error"
362
+ yield {"stage": stage, "error": str(exc)[:200]}
363
+
364
+
365
+ @app.get("/frames-pano/{session}/{name}")
366
+ def pano_world_frame(session: str, name: str):
367
+ path = Path("/tmp/lightloom/pano") / Path(session).name / Path(name).name
368
+ if not path.is_file():
369
+ return JSONResponse({"error": "not found"}, status_code=404)
370
+ return FileResponse(path)
371
+
372
+
373
  @app.post("/internal/bench/director-probe")
374
  def director_probe_endpoint(backend: str = "transformers", threads: int = 8) -> dict[str, Any]:
375
  if os.getenv("LIGHTLOOM_ENABLE_INTERNAL_BENCH", "0") != "1":
frontend/css/tokens.css CHANGED
@@ -35,8 +35,8 @@
35
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
36
  --reveal-ms: 700ms;
37
  --transition-ms: 700ms;
38
- --grain-opacity: 0.05;
39
- --vignette: 0.12;
40
  }
41
 
42
  /* Self-hosted OFL fonts. Drop the .woff2 files in assets/fonts/; until then the
 
35
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
36
  --reveal-ms: 700ms;
37
  --transition-ms: 700ms;
38
+ --grain-opacity: 0.016; /* light film grain — the WebGL stage adds its own; avoid doubling into "fog" */
39
+ --vignette: 0.08;
40
  }
41
 
42
  /* Self-hosted OFL fonts. Drop the .woff2 files in assets/fonts/; until then the
frontend/index.html CHANGED
@@ -483,6 +483,9 @@ Years later, the same road lay buried under snow and silence.</textarea>
483
  stage.js so the controller picks up the overwritten LL.stage at boot.
484
  -->
485
  <script type="module" src="/frontend/js/stage3d.js"></script>
 
 
 
486
  <script type="module" src="/frontend/js/slate.js"></script>
487
  <script type="module" src="/frontend/js/subtitles.js"></script>
488
  <script type="module" src="/frontend/js/hud.js"></script>
 
483
  stage.js so the controller picks up the overwritten LL.stage at boot.
484
  -->
485
  <script type="module" src="/frontend/js/stage3d.js"></script>
486
+ <!-- The immersive PANORAMA world (LL.pano): an equirectangular sphere the camera
487
+ lives inside. The controller uses it for the "Voice Scroll in 3D" experience. -->
488
+ <script type="module" src="/frontend/js/stage-pano.js"></script>
489
  <script type="module" src="/frontend/js/slate.js"></script>
490
  <script type="module" src="/frontend/js/subtitles.js"></script>
491
  <script type="module" src="/frontend/js/hud.js"></script>
frontend/js/stage-pano.js ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Lightloom · frontend/js/stage-pano.js
2
+ * ============================================================================
3
+ * THE IMMERSIVE PANORAMA WORLD — "Voice Scroll in 3D".
4
+ *
5
+ * Instead of discrete shots that flash by, the narration paints ONE continuous
6
+ * equirectangular (2:1) panorama, and the camera lives INSIDE it, slowly looking
7
+ * around and drifting forward — a world you inhabit, not images that flash.
8
+ *
9
+ * Render model (the most robust 3D pattern there is): an inward-facing sphere
10
+ * textured with the equirectangular panorama (camera at its center), whose
11
+ * vertices are pushed along their radius by a depth map so near things come
12
+ * toward you and the world has real parallax as the camera turns/dollies.
13
+ *
14
+ * Exposes window.LL.pano = { init(canvas), show({panoramaUrl, depthUrl, lookText}),
15
+ * dispose(), setReducedMotion(flag) }. The controller drives it; show() returns a
16
+ * Promise that resolves once the new world has cross-faded in.
17
+ * ==========================================================================*/
18
+ "use strict";
19
+ import * as THREE from "three";
20
+
21
+ window.LL = window.LL || {};
22
+
23
+ const Pano = (() => {
24
+ let renderer = null, scene = null, camera = null, canvas = null;
25
+ let sphere = null, nextSphere = null, raf = 0, t0 = 0;
26
+ let reduced = false, ok = false;
27
+ let yaw = 0, targetYaw = 0, dolly = 0, targetDolly = 0;
28
+ const loader = new THREE.TextureLoader();
29
+ loader.crossOrigin = "anonymous";
30
+
31
+ const VERT = `
32
+ varying vec2 vUv;
33
+ uniform sampler2D uDepth;
34
+ uniform float uRelief; // how far near pixels pop toward the camera
35
+ void main() {
36
+ vUv = uv;
37
+ // Depth: white(=near) pulls the surface inward (toward the centered camera),
38
+ // black(=far) leaves it on the far shell -> real parallax when the camera turns.
39
+ float d = texture2D(uDepth, uv).r;
40
+ vec3 p = position + normal * (-uRelief * d);
41
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);
42
+ }`;
43
+ const FRAG = `
44
+ varying vec2 vUv;
45
+ uniform sampler2D uTex;
46
+ uniform float uOpacity;
47
+ uniform float uVignette;
48
+ void main() {
49
+ vec4 c = texture2D(uTex, vUv);
50
+ // gentle vignette toward the poles for a cinematic frame
51
+ float v = smoothstep(0.0, 0.35, vUv.y) * smoothstep(1.0, 0.65, vUv.y);
52
+ c.rgb *= mix(1.0, 0.78, uVignette * (1.0 - v));
53
+ gl_FragColor = vec4(c.rgb, uOpacity);
54
+ }`;
55
+
56
+ function makeSphere(tex, depthTex) {
57
+ const geo = new THREE.SphereGeometry(50, 96, 64);
58
+ geo.scale(-1, 1, 1); // flip so we see the inside
59
+ tex.colorSpace = THREE.SRGBColorSpace;
60
+ const mat = new THREE.ShaderMaterial({
61
+ uniforms: {
62
+ uTex: { value: tex },
63
+ uDepth: { value: depthTex },
64
+ uRelief: { value: reduced ? 0.0 : 9.0 },
65
+ uOpacity: { value: 0.0 },
66
+ uVignette: { value: 0.5 },
67
+ },
68
+ vertexShader: VERT, fragmentShader: FRAG, transparent: true, depthWrite: false,
69
+ });
70
+ return new THREE.Mesh(geo, mat);
71
+ }
72
+
73
+ function loadTex(url) {
74
+ return new Promise((resolve) => {
75
+ if (!url) return resolve(null);
76
+ loader.load(url, (t) => { t.colorSpace = THREE.SRGBColorSpace; resolve(t); }, undefined, () => resolve(null));
77
+ });
78
+ }
79
+
80
+ function init(cv) {
81
+ if (ok) return;
82
+ try {
83
+ canvas = cv;
84
+ renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: false });
85
+ renderer.setPixelRatio(Math.min(devicePixelRatio || 1, 2));
86
+ resize();
87
+ scene = new THREE.Scene();
88
+ camera = new THREE.PerspectiveCamera(78, 1, 0.1, 200);
89
+ camera.position.set(0, 0, 0.01);
90
+ window.addEventListener("resize", resize);
91
+ ok = true;
92
+ loop();
93
+ } catch (e) { ok = false; }
94
+ }
95
+
96
+ function resize() {
97
+ if (!renderer || !canvas) return;
98
+ const w = canvas.clientWidth || canvas.parentElement.clientWidth || 1280;
99
+ const h = canvas.clientHeight || canvas.parentElement.clientHeight || 536;
100
+ renderer.setSize(w, h, false);
101
+ if (camera) { camera.aspect = w / h; camera.updateProjectionMatrix(); }
102
+ }
103
+
104
+ function reducedNow() {
105
+ return reduced || (document.body && document.body.classList.contains("reduced-motion")) ||
106
+ (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches);
107
+ }
108
+
109
+ function loop() {
110
+ raf = requestAnimationFrame(loop);
111
+ if (!renderer || !scene || !camera) return;
112
+ const t = (performance.now() - t0) / 1000;
113
+ const rm = reducedNow();
114
+ // Slow cinematic look-around + a breathing forward drift (the "fly through").
115
+ yaw += (targetYaw - yaw) * 0.02;
116
+ dolly += (targetDolly - dolly) * 0.02;
117
+ const driftYaw = rm ? 0 : Math.sin(t * 0.06) * 0.32;
118
+ const pitch = rm ? 0 : Math.sin(t * 0.05) * 0.06;
119
+ camera.rotation.set(pitch, yaw + driftYaw + Math.PI, 0, "YXZ");
120
+ camera.position.z = 0.01 + (rm ? 0 : dolly);
121
+ renderer.render(scene, camera);
122
+ }
123
+
124
+ async function show({ panoramaUrl, depthUrl }) {
125
+ if (!ok) return;
126
+ const [tex, depthTex] = await Promise.all([loadTex(panoramaUrl), loadTex(depthUrl)]);
127
+ if (!tex) return; // never blank the world on a failed load
128
+ const mesh = makeSphere(tex, depthTex || tex);
129
+ scene.add(mesh);
130
+ nextSphere = mesh;
131
+ t0 = t0 || performance.now();
132
+ // nudge the camera to slowly drift forward into the fresh world
133
+ targetDolly = reducedNow() ? 0 : 6;
134
+ targetYaw += (Math.random() - 0.5) * 0.4;
135
+ return new Promise((resolve) => {
136
+ const start = performance.now();
137
+ const dur = reducedNow() ? 260 : 900;
138
+ const old = sphere;
139
+ const step = () => {
140
+ const k = Math.min(1, (performance.now() - start) / dur);
141
+ const e = k * k * (3 - 2 * k);
142
+ mesh.material.uniforms.uOpacity.value = e;
143
+ if (old) old.material.uniforms.uOpacity.value = 1 - e;
144
+ if (k < 1) requestAnimationFrame(step);
145
+ else {
146
+ if (old) { scene.remove(old); old.geometry.dispose(); old.material.dispose(); }
147
+ sphere = mesh; nextSphere = null;
148
+ targetDolly = 0; // settle, then idle-drift handles the rest
149
+ resolve();
150
+ }
151
+ };
152
+ requestAnimationFrame(step);
153
+ });
154
+ }
155
+
156
+ function setReducedMotion(flag) {
157
+ reduced = !!flag;
158
+ if (sphere) sphere.material.uniforms.uRelief.value = reducedNow() ? 0 : 9;
159
+ }
160
+
161
+ function dispose() {
162
+ cancelAnimationFrame(raf);
163
+ window.removeEventListener("resize", resize);
164
+ if (renderer) renderer.dispose();
165
+ ok = false;
166
+ }
167
+
168
+ return { init, show, setReducedMotion, dispose, get ready() { return ok; } };
169
+ })();
170
+
171
+ LL.pano = Pano;
172
+ export default LL.pano;
node_modules/.bin/playwright ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -x "$basedir/node" ]; then
13
+ exec "$basedir/node" "$basedir/../playwright/cli.js" "$@"
14
+ else
15
+ exec node "$basedir/../playwright/cli.js" "$@"
16
+ fi
node_modules/.bin/playwright-core ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -x "$basedir/node" ]; then
13
+ exec "$basedir/node" "$basedir/../playwright-core/cli.js" "$@"
14
+ else
15
+ exec node "$basedir/../playwright-core/cli.js" "$@"
16
+ fi
node_modules/.bin/playwright-core.cmd ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @ECHO off
2
+ GOTO start
3
+ :find_dp0
4
+ SET dp0=%~dp0
5
+ EXIT /b
6
+ :start
7
+ SETLOCAL
8
+ CALL :find_dp0
9
+
10
+ IF EXIST "%dp0%\node.exe" (
11
+ SET "_prog=%dp0%\node.exe"
12
+ ) ELSE (
13
+ SET "_prog=node"
14
+ SET PATHEXT=%PATHEXT:;.JS;=;%
15
+ )
16
+
17
+ endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\playwright-core\cli.js" %*
node_modules/.bin/playwright-core.ps1 ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env pwsh
2
+ $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
3
+
4
+ $exe=""
5
+ if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
6
+ # Fix case when both the Windows and Linux builds of Node
7
+ # are installed in the same directory
8
+ $exe=".exe"
9
+ }
10
+ $ret=0
11
+ if (Test-Path "$basedir/node$exe") {
12
+ # Support pipeline input
13
+ if ($MyInvocation.ExpectingInput) {
14
+ $input | & "$basedir/node$exe" "$basedir/../playwright-core/cli.js" $args
15
+ } else {
16
+ & "$basedir/node$exe" "$basedir/../playwright-core/cli.js" $args
17
+ }
18
+ $ret=$LASTEXITCODE
19
+ } else {
20
+ # Support pipeline input
21
+ if ($MyInvocation.ExpectingInput) {
22
+ $input | & "node$exe" "$basedir/../playwright-core/cli.js" $args
23
+ } else {
24
+ & "node$exe" "$basedir/../playwright-core/cli.js" $args
25
+ }
26
+ $ret=$LASTEXITCODE
27
+ }
28
+ exit $ret
node_modules/.bin/playwright.cmd ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @ECHO off
2
+ GOTO start
3
+ :find_dp0
4
+ SET dp0=%~dp0
5
+ EXIT /b
6
+ :start
7
+ SETLOCAL
8
+ CALL :find_dp0
9
+
10
+ IF EXIST "%dp0%\node.exe" (
11
+ SET "_prog=%dp0%\node.exe"
12
+ ) ELSE (
13
+ SET "_prog=node"
14
+ SET PATHEXT=%PATHEXT:;.JS;=;%
15
+ )
16
+
17
+ endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\playwright\cli.js" %*
node_modules/.bin/playwright.ps1 ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env pwsh
2
+ $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
3
+
4
+ $exe=""
5
+ if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
6
+ # Fix case when both the Windows and Linux builds of Node
7
+ # are installed in the same directory
8
+ $exe=".exe"
9
+ }
10
+ $ret=0
11
+ if (Test-Path "$basedir/node$exe") {
12
+ # Support pipeline input
13
+ if ($MyInvocation.ExpectingInput) {
14
+ $input | & "$basedir/node$exe" "$basedir/../playwright/cli.js" $args
15
+ } else {
16
+ & "$basedir/node$exe" "$basedir/../playwright/cli.js" $args
17
+ }
18
+ $ret=$LASTEXITCODE
19
+ } else {
20
+ # Support pipeline input
21
+ if ($MyInvocation.ExpectingInput) {
22
+ $input | & "node$exe" "$basedir/../playwright/cli.js" $args
23
+ } else {
24
+ & "node$exe" "$basedir/../playwright/cli.js" $args
25
+ }
26
+ $ret=$LASTEXITCODE
27
+ }
28
+ exit $ret
node_modules/.package-lock.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "Lightloom",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {
6
+ "node_modules/playwright": {
7
+ "version": "1.60.0",
8
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz",
9
+ "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==",
10
+ "license": "Apache-2.0",
11
+ "dependencies": {
12
+ "playwright-core": "1.60.0"
13
+ },
14
+ "bin": {
15
+ "playwright": "cli.js"
16
+ },
17
+ "engines": {
18
+ "node": ">=18"
19
+ },
20
+ "optionalDependencies": {
21
+ "fsevents": "2.3.2"
22
+ }
23
+ },
24
+ "node_modules/playwright-core": {
25
+ "version": "1.60.0",
26
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz",
27
+ "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==",
28
+ "license": "Apache-2.0",
29
+ "bin": {
30
+ "playwright-core": "cli.js"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ }
35
+ }
36
+ }
37
+ }
node_modules/playwright-core/LICENSE ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Portions Copyright (c) Microsoft Corporation.
190
+ Portions Copyright 2017 Google Inc.
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
node_modules/playwright-core/NOTICE ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Playwright
2
+ Copyright (c) Microsoft Corporation
3
+
4
+ This software contains code derived from the Puppeteer project (https://github.com/puppeteer/puppeteer),
5
+ available under the Apache 2.0 license (https://github.com/puppeteer/puppeteer/blob/master/LICENSE).
node_modules/playwright-core/README.md ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # playwright-core
2
+
3
+ This package contains the no-browser flavor of [Playwright](http://github.com/microsoft/playwright).
node_modules/playwright-core/ThirdPartyNotices.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ microsoft/playwright-core
2
+
3
+ THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
4
+
5
+ This package bundles third-party software inside individual files under
6
+ `lib/`. Each bundled output has a sidecar `<bundle>.js.LICENSE` file next
7
+ to it listing every npm package whose source was inlined into that
8
+ bundle, together with the full license text for each.
9
+
10
+ For example:
11
+ - lib/utilsBundle.js.LICENSE
12
+
13
+ This project incorporates components from the projects listed below. The original copyright notices and the licenses under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise.
node_modules/playwright-core/bin/install_media_pack.ps1 ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ $osInfo = Get-WmiObject -Class Win32_OperatingSystem
2
+ # check if running on Windows Server
3
+ if ($osInfo.ProductType -eq 3) {
4
+ Install-WindowsFeature Server-Media-Foundation
5
+ }
node_modules/playwright-core/bin/install_webkit_wsl.ps1 ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $ErrorActionPreference = 'Stop'
2
+
3
+ # This script sets up a WSL distribution that will be used to run WebKit.
4
+
5
+ $Distribution = "playwright"
6
+ $Username = "pwuser"
7
+
8
+ $distributions = (wsl --list --quiet) -split "\r?\n"
9
+ if ($distributions -contains $Distribution) {
10
+ Write-Host "WSL distribution '$Distribution' already exists. Skipping installation."
11
+ } else {
12
+ Write-Host "Installing new WSL distribution '$Distribution'..."
13
+ $VhdSize = "10GB"
14
+ wsl --install -d Ubuntu-24.04 --name $Distribution --no-launch --vhd-size $VhdSize
15
+ wsl -d $Distribution -u root adduser --gecos GECOS --disabled-password $Username
16
+ }
17
+
18
+ $pwshDirname = (Resolve-Path -Path $PSScriptRoot).Path;
19
+ $playwrightCoreRoot = Resolve-Path (Join-Path $pwshDirname "..")
20
+
21
+ $initScript = @"
22
+ if [ ! -f "/home/$Username/node/bin/node" ]; then
23
+ mkdir -p /home/$Username/node
24
+ curl -fsSL https://nodejs.org/dist/v22.17.0/node-v22.17.0-linux-x64.tar.xz -o /home/$Username/node/node-v22.17.0-linux-x64.tar.xz
25
+ tar -xJf /home/$Username/node/node-v22.17.0-linux-x64.tar.xz -C /home/$Username/node --strip-components=1
26
+ sudo -u $Username echo 'export PATH=/home/$Username/node/bin:\`$PATH' >> /home/$Username/.profile
27
+ fi
28
+ /home/$Username/node/bin/node cli.js install-deps webkit
29
+ sudo -u $Username PLAYWRIGHT_SKIP_BROWSER_GC=1 /home/$Username/node/bin/node cli.js install webkit
30
+ "@ -replace "\r\n", "`n"
31
+
32
+ wsl -d $Distribution --cd $playwrightCoreRoot -u root -- bash -c "$initScript"
33
+ Write-Host "Done!"
node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -e
3
+ set -x
4
+
5
+ if [[ $(arch) == "aarch64" ]]; then
6
+ echo "ERROR: not supported on Linux Arm64"
7
+ exit 1
8
+ fi
9
+
10
+ if [ -z "$PLAYWRIGHT_HOST_PLATFORM_OVERRIDE" ]; then
11
+ if [[ ! -f "/etc/os-release" ]]; then
12
+ echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
13
+ exit 1
14
+ fi
15
+
16
+ ID=$(bash -c 'source /etc/os-release && echo $ID')
17
+ if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
18
+ echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
19
+ exit 1
20
+ fi
21
+ fi
22
+
23
+ # 1. make sure to remove old beta if any.
24
+ if dpkg --get-selections | grep -q "^google-chrome-beta[[:space:]]*install$" >/dev/null; then
25
+ apt-get remove -y google-chrome-beta
26
+ fi
27
+
28
+ # 2. Update apt lists (needed to install curl and chrome dependencies)
29
+ apt-get update
30
+
31
+ # 3. Install curl to download chrome
32
+ if ! command -v curl >/dev/null; then
33
+ apt-get install -y curl
34
+ fi
35
+
36
+ # 4. download chrome beta from dl.google.com and install it.
37
+ cd /tmp
38
+ curl -O https://dl.google.com/linux/direct/google-chrome-beta_current_amd64.deb
39
+ apt-get install -y ./google-chrome-beta_current_amd64.deb
40
+ rm -rf ./google-chrome-beta_current_amd64.deb
41
+ cd -
42
+ google-chrome-beta --version
node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -e
3
+ set -x
4
+
5
+ rm -rf "/Applications/Google Chrome Beta.app"
6
+ cd /tmp
7
+ curl --retry 3 -o ./googlechromebeta.dmg https://dl.google.com/chrome/mac/universal/beta/googlechromebeta.dmg
8
+ hdiutil attach -nobrowse -quiet -noautofsck -noautoopen -mountpoint /Volumes/googlechromebeta.dmg ./googlechromebeta.dmg
9
+ cp -pR "/Volumes/googlechromebeta.dmg/Google Chrome Beta.app" /Applications
10
+ hdiutil detach /Volumes/googlechromebeta.dmg
11
+ rm -rf /tmp/googlechromebeta.dmg
12
+
13
+ /Applications/Google\ Chrome\ Beta.app/Contents/MacOS/Google\ Chrome\ Beta --version
node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1 ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $ErrorActionPreference = 'Stop'
2
+
3
+ $url = 'https://dl.google.com/tag/s/dl/chrome/install/beta/googlechromebetastandaloneenterprise64.msi'
4
+
5
+ Write-Host "Downloading Google Chrome Beta"
6
+ $wc = New-Object net.webclient
7
+ $msiInstaller = "$env:temp\google-chrome-beta.msi"
8
+ $wc.Downloadfile($url, $msiInstaller)
9
+
10
+ Write-Host "Installing Google Chrome Beta"
11
+ $arguments = "/i `"$msiInstaller`" /quiet"
12
+ Start-Process msiexec.exe -ArgumentList $arguments -Wait
13
+ Remove-Item $msiInstaller
14
+
15
+ $suffix = "\\Google\\Chrome Beta\\Application\\chrome.exe"
16
+ if (Test-Path "${env:ProgramFiles(x86)}$suffix") {
17
+ (Get-Item "${env:ProgramFiles(x86)}$suffix").VersionInfo
18
+ } elseif (Test-Path "${env:ProgramFiles}$suffix") {
19
+ (Get-Item "${env:ProgramFiles}$suffix").VersionInfo
20
+ } else {
21
+ Write-Host "ERROR: Failed to install Google Chrome Beta."
22
+ Write-Host "ERROR: This could be due to insufficient privileges, in which case re-running as Administrator may help."
23
+ exit 1
24
+ }
node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -e
3
+ set -x
4
+
5
+ if [[ $(arch) == "aarch64" ]]; then
6
+ echo "ERROR: not supported on Linux Arm64"
7
+ exit 1
8
+ fi
9
+
10
+ if [ -z "$PLAYWRIGHT_HOST_PLATFORM_OVERRIDE" ]; then
11
+ if [[ ! -f "/etc/os-release" ]]; then
12
+ echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
13
+ exit 1
14
+ fi
15
+
16
+ ID=$(bash -c 'source /etc/os-release && echo $ID')
17
+ if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
18
+ echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
19
+ exit 1
20
+ fi
21
+ fi
22
+
23
+ # 1. make sure to remove old stable if any.
24
+ if dpkg --get-selections | grep -q "^google-chrome[[:space:]]*install$" >/dev/null; then
25
+ apt-get remove -y google-chrome
26
+ fi
27
+
28
+ # 2. Update apt lists (needed to install curl and chrome dependencies)
29
+ apt-get update
30
+
31
+ # 3. Install curl to download chrome
32
+ if ! command -v curl >/dev/null; then
33
+ apt-get install -y curl
34
+ fi
35
+
36
+ # 4. download chrome stable from dl.google.com and install it.
37
+ cd /tmp
38
+ curl -O https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
39
+ apt-get install -y ./google-chrome-stable_current_amd64.deb
40
+ rm -rf ./google-chrome-stable_current_amd64.deb
41
+ cd -
42
+ google-chrome --version
node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -e
3
+ set -x
4
+
5
+ rm -rf "/Applications/Google Chrome.app"
6
+ cd /tmp
7
+ curl --retry 3 -o ./googlechrome.dmg https://dl.google.com/chrome/mac/universal/stable/GGRO/googlechrome.dmg
8
+ hdiutil attach -nobrowse -quiet -noautofsck -noautoopen -mountpoint /Volumes/googlechrome.dmg ./googlechrome.dmg
9
+ cp -pR "/Volumes/googlechrome.dmg/Google Chrome.app" /Applications
10
+ hdiutil detach /Volumes/googlechrome.dmg
11
+ rm -rf /tmp/googlechrome.dmg
12
+ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1 ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $ErrorActionPreference = 'Stop'
2
+ $url = 'https://dl.google.com/tag/s/dl/chrome/install/googlechromestandaloneenterprise64.msi'
3
+
4
+ $wc = New-Object net.webclient
5
+ $msiInstaller = "$env:temp\google-chrome.msi"
6
+ Write-Host "Downloading Google Chrome"
7
+ $wc.Downloadfile($url, $msiInstaller)
8
+
9
+ Write-Host "Installing Google Chrome"
10
+ $arguments = "/i `"$msiInstaller`" /quiet"
11
+ Start-Process msiexec.exe -ArgumentList $arguments -Wait
12
+ Remove-Item $msiInstaller
13
+
14
+
15
+ $suffix = "\\Google\\Chrome\\Application\\chrome.exe"
16
+ if (Test-Path "${env:ProgramFiles(x86)}$suffix") {
17
+ (Get-Item "${env:ProgramFiles(x86)}$suffix").VersionInfo
18
+ } elseif (Test-Path "${env:ProgramFiles}$suffix") {
19
+ (Get-Item "${env:ProgramFiles}$suffix").VersionInfo
20
+ } else {
21
+ Write-Host "ERROR: Failed to install Google Chrome."
22
+ Write-Host "ERROR: This could be due to insufficient privileges, in which case re-running as Administrator may help."
23
+ exit 1
24
+ }
node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+ set -x
5
+
6
+ if [[ $(arch) == "aarch64" ]]; then
7
+ echo "ERROR: not supported on Linux Arm64"
8
+ exit 1
9
+ fi
10
+
11
+ if [ -z "$PLAYWRIGHT_HOST_PLATFORM_OVERRIDE" ]; then
12
+ if [[ ! -f "/etc/os-release" ]]; then
13
+ echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
14
+ exit 1
15
+ fi
16
+
17
+ ID=$(bash -c 'source /etc/os-release && echo $ID')
18
+ if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
19
+ echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
20
+ exit 1
21
+ fi
22
+ fi
23
+
24
+ # 1. make sure to remove old beta if any.
25
+ if dpkg --get-selections | grep -q "^microsoft-edge-beta[[:space:]]*install$" >/dev/null; then
26
+ apt-get remove -y microsoft-edge-beta
27
+ fi
28
+
29
+ # 2. Install curl to download Microsoft gpg key
30
+ if ! command -v curl >/dev/null; then
31
+ apt-get update
32
+ apt-get install -y curl
33
+ fi
34
+
35
+ # GnuPG is not preinstalled in slim images
36
+ if ! command -v gpg >/dev/null; then
37
+ apt-get update
38
+ apt-get install -y gpg
39
+ fi
40
+
41
+ # 3. Add the GPG key, the apt repo, update the apt cache, and install the package
42
+ curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /tmp/microsoft.gpg
43
+ install -o root -g root -m 644 /tmp/microsoft.gpg /etc/apt/trusted.gpg.d/
44
+ sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/edge stable main" > /etc/apt/sources.list.d/microsoft-edge-dev.list'
45
+ rm /tmp/microsoft.gpg
46
+ apt-get update && apt-get install -y microsoft-edge-beta
47
+
48
+ microsoft-edge-beta --version
node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -e
3
+ set -x
4
+
5
+ cd /tmp
6
+ curl --retry 3 -o ./msedge_beta.pkg "$1"
7
+ # Note: there's no way to uninstall previously installed MSEdge.
8
+ # However, running PKG again seems to update installation.
9
+ sudo installer -pkg /tmp/msedge_beta.pkg -target /
10
+ rm -rf /tmp/msedge_beta.pkg
11
+ /Applications/Microsoft\ Edge\ Beta.app/Contents/MacOS/Microsoft\ Edge\ Beta --version
node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1 ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $ErrorActionPreference = 'Stop'
2
+ $url = $args[0]
3
+
4
+ Write-Host "Downloading Microsoft Edge Beta"
5
+ $wc = New-Object net.webclient
6
+ $msiInstaller = "$env:temp\microsoft-edge-beta.msi"
7
+ $wc.Downloadfile($url, $msiInstaller)
8
+
9
+ Write-Host "Installing Microsoft Edge Beta"
10
+ $arguments = "/i `"$msiInstaller`" /quiet"
11
+ Start-Process msiexec.exe -ArgumentList $arguments -Wait
12
+ Remove-Item $msiInstaller
13
+
14
+ $suffix = "\\Microsoft\\Edge Beta\\Application\\msedge.exe"
15
+ if (Test-Path "${env:ProgramFiles(x86)}$suffix") {
16
+ (Get-Item "${env:ProgramFiles(x86)}$suffix").VersionInfo
17
+ } elseif (Test-Path "${env:ProgramFiles}$suffix") {
18
+ (Get-Item "${env:ProgramFiles}$suffix").VersionInfo
19
+ } else {
20
+ Write-Host "ERROR: Failed to install Microsoft Edge Beta."
21
+ Write-Host "ERROR: This could be due to insufficient privileges, in which case re-running as Administrator may help."
22
+ exit 1
23
+ }
node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+ set -x
5
+
6
+ if [[ $(arch) == "aarch64" ]]; then
7
+ echo "ERROR: not supported on Linux Arm64"
8
+ exit 1
9
+ fi
10
+
11
+ if [ -z "$PLAYWRIGHT_HOST_PLATFORM_OVERRIDE" ]; then
12
+ if [[ ! -f "/etc/os-release" ]]; then
13
+ echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
14
+ exit 1
15
+ fi
16
+
17
+ ID=$(bash -c 'source /etc/os-release && echo $ID')
18
+ if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
19
+ echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
20
+ exit 1
21
+ fi
22
+ fi
23
+
24
+ # 1. make sure to remove old dev if any.
25
+ if dpkg --get-selections | grep -q "^microsoft-edge-dev[[:space:]]*install$" >/dev/null; then
26
+ apt-get remove -y microsoft-edge-dev
27
+ fi
28
+
29
+ # 2. Install curl to download Microsoft gpg key
30
+ if ! command -v curl >/dev/null; then
31
+ apt-get update
32
+ apt-get install -y curl
33
+ fi
34
+
35
+ # GnuPG is not preinstalled in slim images
36
+ if ! command -v gpg >/dev/null; then
37
+ apt-get update
38
+ apt-get install -y gpg
39
+ fi
40
+
41
+ # 3. Add the GPG key, the apt repo, update the apt cache, and install the package
42
+ curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /tmp/microsoft.gpg
43
+ install -o root -g root -m 644 /tmp/microsoft.gpg /etc/apt/trusted.gpg.d/
44
+ sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/edge stable main" > /etc/apt/sources.list.d/microsoft-edge-dev.list'
45
+ rm /tmp/microsoft.gpg
46
+ apt-get update && apt-get install -y microsoft-edge-dev
47
+
48
+ microsoft-edge-dev --version
node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -e
3
+ set -x
4
+
5
+ cd /tmp
6
+ curl --retry 3 -o ./msedge_dev.pkg "$1"
7
+ # Note: there's no way to uninstall previously installed MSEdge.
8
+ # However, running PKG again seems to update installation.
9
+ sudo installer -pkg /tmp/msedge_dev.pkg -target /
10
+ rm -rf /tmp/msedge_dev.pkg
11
+ /Applications/Microsoft\ Edge\ Dev.app/Contents/MacOS/Microsoft\ Edge\ Dev --version
node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1 ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $ErrorActionPreference = 'Stop'
2
+ $url = $args[0]
3
+
4
+ Write-Host "Downloading Microsoft Edge Dev"
5
+ $wc = New-Object net.webclient
6
+ $msiInstaller = "$env:temp\microsoft-edge-dev.msi"
7
+ $wc.Downloadfile($url, $msiInstaller)
8
+
9
+ Write-Host "Installing Microsoft Edge Dev"
10
+ $arguments = "/i `"$msiInstaller`" /quiet"
11
+ Start-Process msiexec.exe -ArgumentList $arguments -Wait
12
+ Remove-Item $msiInstaller
13
+
14
+ $suffix = "\\Microsoft\\Edge Dev\\Application\\msedge.exe"
15
+ if (Test-Path "${env:ProgramFiles(x86)}$suffix") {
16
+ (Get-Item "${env:ProgramFiles(x86)}$suffix").VersionInfo
17
+ } elseif (Test-Path "${env:ProgramFiles}$suffix") {
18
+ (Get-Item "${env:ProgramFiles}$suffix").VersionInfo
19
+ } else {
20
+ Write-Host "ERROR: Failed to install Microsoft Edge Dev."
21
+ Write-Host "ERROR: This could be due to insufficient privileges, in which case re-running as Administrator may help."
22
+ exit 1
23
+ }
node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+ set -x
5
+
6
+ if [[ $(arch) == "aarch64" ]]; then
7
+ echo "ERROR: not supported on Linux Arm64"
8
+ exit 1
9
+ fi
10
+
11
+ if [ -z "$PLAYWRIGHT_HOST_PLATFORM_OVERRIDE" ]; then
12
+ if [[ ! -f "/etc/os-release" ]]; then
13
+ echo "ERROR: cannot install on unknown linux distribution (/etc/os-release is missing)"
14
+ exit 1
15
+ fi
16
+
17
+ ID=$(bash -c 'source /etc/os-release && echo $ID')
18
+ if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
19
+ echo "ERROR: cannot install on $ID distribution - only Ubuntu and Debian are supported"
20
+ exit 1
21
+ fi
22
+ fi
23
+
24
+ # 1. make sure to remove old stable if any.
25
+ if dpkg --get-selections | grep -q "^microsoft-edge-stable[[:space:]]*install$" >/dev/null; then
26
+ apt-get remove -y microsoft-edge-stable
27
+ fi
28
+
29
+ # 2. Install curl to download Microsoft gpg key
30
+ if ! command -v curl >/dev/null; then
31
+ apt-get update
32
+ apt-get install -y curl
33
+ fi
34
+
35
+ # GnuPG is not preinstalled in slim images
36
+ if ! command -v gpg >/dev/null; then
37
+ apt-get update
38
+ apt-get install -y gpg
39
+ fi
40
+
41
+ # 3. Add the GPG key, the apt repo, update the apt cache, and install the package
42
+ curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /tmp/microsoft.gpg
43
+ install -o root -g root -m 644 /tmp/microsoft.gpg /etc/apt/trusted.gpg.d/
44
+ sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/edge stable main" > /etc/apt/sources.list.d/microsoft-edge-stable.list'
45
+ rm /tmp/microsoft.gpg
46
+ apt-get update && apt-get install -y microsoft-edge-stable
47
+
48
+ microsoft-edge-stable --version
node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -e
3
+ set -x
4
+
5
+ cd /tmp
6
+ curl --retry 3 -o ./msedge_stable.pkg "$1"
7
+ # Note: there's no way to uninstall previously installed MSEdge.
8
+ # However, running PKG again seems to update installation.
9
+ sudo installer -pkg /tmp/msedge_stable.pkg -target /
10
+ rm -rf /tmp/msedge_stable.pkg
11
+ /Applications/Microsoft\ Edge.app/Contents/MacOS/Microsoft\ Edge --version
node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1 ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $ErrorActionPreference = 'Stop'
2
+
3
+ $url = $args[0]
4
+
5
+ Write-Host "Downloading Microsoft Edge"
6
+ $wc = New-Object net.webclient
7
+ $msiInstaller = "$env:temp\microsoft-edge-stable.msi"
8
+ $wc.Downloadfile($url, $msiInstaller)
9
+
10
+ Write-Host "Installing Microsoft Edge"
11
+ $arguments = "/i `"$msiInstaller`" /quiet"
12
+ Start-Process msiexec.exe -ArgumentList $arguments -Wait
13
+ Remove-Item $msiInstaller
14
+
15
+ $suffix = "\\Microsoft\\Edge\\Application\\msedge.exe"
16
+ if (Test-Path "${env:ProgramFiles(x86)}$suffix") {
17
+ (Get-Item "${env:ProgramFiles(x86)}$suffix").VersionInfo
18
+ } elseif (Test-Path "${env:ProgramFiles}$suffix") {
19
+ (Get-Item "${env:ProgramFiles}$suffix").VersionInfo
20
+ } else {
21
+ Write-Host "ERROR: Failed to install Microsoft Edge."
22
+ Write-Host "ERROR: This could be due to insufficient privileges, in which case re-running as Administrator may help."
23
+ exit 1
24
+ }
node_modules/playwright-core/browsers.json ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "comment": "Do not edit this file, use utils/roll_browser.js",
3
+ "browsers": [
4
+ {
5
+ "name": "chromium",
6
+ "revision": "1223",
7
+ "installByDefault": true,
8
+ "browserVersion": "148.0.7778.96",
9
+ "title": "Chrome for Testing"
10
+ },
11
+ {
12
+ "name": "chromium-headless-shell",
13
+ "revision": "1223",
14
+ "installByDefault": true,
15
+ "browserVersion": "148.0.7778.96",
16
+ "title": "Chrome Headless Shell"
17
+ },
18
+ {
19
+ "name": "chromium-tip-of-tree",
20
+ "revision": "1427",
21
+ "installByDefault": false,
22
+ "browserVersion": "149.0.7827.0",
23
+ "title": "Chrome Canary for Testing"
24
+ },
25
+ {
26
+ "name": "chromium-tip-of-tree-headless-shell",
27
+ "revision": "1427",
28
+ "installByDefault": false,
29
+ "browserVersion": "149.0.7827.0",
30
+ "title": "Chrome Canary Headless Shell"
31
+ },
32
+ {
33
+ "name": "firefox",
34
+ "revision": "1522",
35
+ "installByDefault": true,
36
+ "browserVersion": "150.0.2",
37
+ "title": "Firefox"
38
+ },
39
+ {
40
+ "name": "firefox-beta",
41
+ "revision": "1512",
42
+ "installByDefault": false,
43
+ "browserVersion": "151.0b5",
44
+ "title": "Firefox Beta"
45
+ },
46
+ {
47
+ "name": "webkit",
48
+ "revision": "2287",
49
+ "installByDefault": true,
50
+ "revisionOverrides": {
51
+ "mac14": "2251",
52
+ "mac14-arm64": "2251",
53
+ "debian11-x64": "2105",
54
+ "debian11-arm64": "2105",
55
+ "ubuntu20.04-x64": "2092",
56
+ "ubuntu20.04-arm64": "2092"
57
+ },
58
+ "browserVersion": "26.4",
59
+ "title": "WebKit"
60
+ },
61
+ {
62
+ "name": "ffmpeg",
63
+ "revision": "1011",
64
+ "installByDefault": true,
65
+ "revisionOverrides": {
66
+ "mac12": "1010",
67
+ "mac12-arm64": "1010"
68
+ }
69
+ },
70
+ {
71
+ "name": "winldd",
72
+ "revision": "1007",
73
+ "installByDefault": false
74
+ },
75
+ {
76
+ "name": "android",
77
+ "revision": "1001",
78
+ "installByDefault": false
79
+ }
80
+ ]
81
+ }
node_modules/playwright-core/cli.js ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Copyright (c) Microsoft Corporation.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ const { libCli, libCliTestStub } = require('./lib/coreBundle');
18
+ const { program } = require('./lib/utilsBundle');
19
+ libCli.decorateProgram(program);
20
+ libCliTestStub.decorateProgram(program);
21
+ program.parse(process.argv);
node_modules/playwright-core/index.d.ts ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ export * from './types/types';
node_modules/playwright-core/index.js ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ const minimumMajorNodeVersion = 18;
17
+ const currentNodeVersion = process.versions.node;
18
+ const semver = currentNodeVersion.split('.');
19
+ const [major] = [+semver[0]];
20
+
21
+ if (major < minimumMajorNodeVersion) {
22
+ console.error(
23
+ 'You are running Node.js ' +
24
+ currentNodeVersion +
25
+ '.\n' +
26
+ `Playwright requires Node.js ${minimumMajorNodeVersion} or higher. \n` +
27
+ 'Please update your version of Node.js.'
28
+ );
29
+ process.exit(1);
30
+ }
31
+
32
+ module.exports = require('./lib/coreBundle').inprocess.playwright;
node_modules/playwright-core/index.mjs ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import playwright from './index.js';
18
+
19
+ export const chromium = playwright.chromium;
20
+ export const firefox = playwright.firefox;
21
+ export const webkit = playwright.webkit;
22
+ export const selectors = playwright.selectors;
23
+ export const devices = playwright.devices;
24
+ export const errors = playwright.errors;
25
+ export const request = playwright.request;
26
+ export const _electron = playwright._electron;
27
+ export const _android = playwright._android;
28
+ export default playwright;
node_modules/playwright-core/lib/bootstrap.js ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ if (process.env.PW_INSTRUMENT_MODULES) {
3
+ const Module = require("module");
4
+ const originalLoad = Module._load;
5
+ const root = { name: "<root>", selfMs: 0, totalMs: 0, childrenMs: 0, children: [] };
6
+ let current = root;
7
+ const stack = [];
8
+ Module._load = function(request, _parent, _isMain) {
9
+ const node = { name: request, selfMs: 0, totalMs: 0, childrenMs: 0, children: [] };
10
+ current.children.push(node);
11
+ stack.push(current);
12
+ current = node;
13
+ const start = performance.now();
14
+ let result;
15
+ try {
16
+ result = originalLoad.apply(this, arguments);
17
+ } catch (e) {
18
+ current = stack.pop();
19
+ current.children.pop();
20
+ throw e;
21
+ }
22
+ const duration = performance.now() - start;
23
+ node.totalMs = duration;
24
+ node.selfMs = Math.max(0, duration - node.childrenMs);
25
+ current = stack.pop();
26
+ current.childrenMs += duration;
27
+ return result;
28
+ };
29
+ process.on("exit", () => {
30
+ function printTree(node, prefix, isLast, lines2, depth) {
31
+ if (node.totalMs < 1 && depth > 0)
32
+ return;
33
+ const connector = depth === 0 ? "" : isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
34
+ const time = `${node.totalMs.toFixed(1).padStart(8)}ms`;
35
+ const self = node.children.length ? ` (self: ${node.selfMs.toFixed(1)}ms)` : "";
36
+ lines2.push(`${time} ${prefix}${connector}${node.name}${self}`);
37
+ const childPrefix = prefix + (depth === 0 ? "" : isLast ? " " : "\u2502 ");
38
+ const sorted2 = node.children.slice().sort((a, b) => b.totalMs - a.totalMs);
39
+ for (let i = 0; i < sorted2.length; i++)
40
+ printTree(sorted2[i], childPrefix, i === sorted2.length - 1, lines2, depth + 1);
41
+ }
42
+ let totalModules = 0;
43
+ function count(n) {
44
+ totalModules++;
45
+ n.children.forEach(count);
46
+ }
47
+ root.children.forEach(count);
48
+ const lines = [];
49
+ const sorted = root.children.slice().sort((a, b) => b.totalMs - a.totalMs);
50
+ for (let i = 0; i < sorted.length; i++)
51
+ printTree(sorted[i], "", i === sorted.length - 1, lines, 0);
52
+ const totalMs = root.children.reduce((s, c) => s + c.totalMs, 0);
53
+ process.stderr.write(`
54
+ --- Module load tree: ${totalModules} modules, ${totalMs.toFixed(0)}ms total ---
55
+ ` + lines.join("\n") + "\n");
56
+ const flat = /* @__PURE__ */ new Map();
57
+ function gather(n) {
58
+ const existing = flat.get(n.name);
59
+ if (existing) {
60
+ existing.selfMs += n.selfMs;
61
+ existing.totalMs += n.totalMs;
62
+ existing.count++;
63
+ } else {
64
+ flat.set(n.name, { selfMs: n.selfMs, totalMs: n.totalMs, count: 1 });
65
+ }
66
+ n.children.forEach(gather);
67
+ }
68
+ root.children.forEach(gather);
69
+ const top50 = [...flat.entries()].sort((a, b) => b[1].selfMs - a[1].selfMs).slice(0, 50);
70
+ const flatLines = top50.map(
71
+ ([mod, { selfMs, totalMs: totalMs2, count: count2 }]) => `${selfMs.toFixed(1).padStart(8)}ms self ${totalMs2.toFixed(1).padStart(8)}ms total (x${String(count2).padStart(3)}) ${mod}`
72
+ );
73
+ process.stderr.write(`
74
+ --- Top 50 modules by self time ---
75
+ ` + flatLines.join("\n") + "\n");
76
+ });
77
+ }
node_modules/playwright-core/lib/coreBundle.js ADDED
The diff for this file is too large to render. See raw diff
 
node_modules/playwright-core/lib/entry/cliDaemon.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ "use strict";
2
+ var import_coreBundle = require("../coreBundle");
3
+ const { program } = require("../utilsBundle");
4
+ import_coreBundle.tools.decorateCliDaemonProgram(program);
5
+ void program.parseAsync();
node_modules/playwright-core/lib/entry/dashboardApp.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ "use strict";
2
+ var import_coreBundle = require("../coreBundle");
3
+ import_coreBundle.tools.openDashboardApp();
node_modules/playwright-core/lib/entry/mcp.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ var import_coreBundle = require("../coreBundle");
3
+ var import_package = require("../package");
4
+ const { program } = require("../utilsBundle");
5
+ const p = program.version("Version " + import_package.packageJSON.version).name("Playwright MCP");
6
+ import_coreBundle.tools.decorateMCPCommand(p);
7
+ program.parseAsync(process.argv).catch((e) => {
8
+ console.error(e.message);
9
+ import_coreBundle.utils.gracefullyProcessExitDoNotHang(1);
10
+ });
node_modules/playwright-core/lib/entry/oopBrowserDownload.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ "use strict";
2
+ var import_coreBundle = require("../coreBundle");
3
+ import_coreBundle.registry.runOopDownloadBrowserMain();
node_modules/playwright-core/lib/package.js ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var package_exports = {};
30
+ __export(package_exports, {
31
+ binPath: () => binPath,
32
+ libPath: () => libPath,
33
+ packageJSON: () => packageJSON,
34
+ packageRoot: () => packageRoot
35
+ });
36
+ module.exports = __toCommonJS(package_exports);
37
+ var import_path = __toESM(require("path"));
38
+ const packageRoot = import_path.default.join(__dirname, "..");
39
+ const packageJSON = require(import_path.default.join(packageRoot, "package.json"));
40
+ const binPath = import_path.default.join(packageRoot, "bin");
41
+ function libPath(...parts) {
42
+ return import_path.default.join(packageRoot, "lib", ...parts);
43
+ }
44
+ // Annotate the CommonJS export names for ESM import in node:
45
+ 0 && (module.exports = {
46
+ binPath,
47
+ libPath,
48
+ packageJSON,
49
+ packageRoot
50
+ });
node_modules/playwright-core/lib/server/deviceDescriptorsSource.json ADDED
@@ -0,0 +1,1779 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "Blackberry PlayBook": {
3
+ "userAgent": "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/26.4 Safari/536.2+",
4
+ "viewport": {
5
+ "width": 600,
6
+ "height": 1024
7
+ },
8
+ "deviceScaleFactor": 1,
9
+ "isMobile": true,
10
+ "hasTouch": true,
11
+ "defaultBrowserType": "webkit"
12
+ },
13
+ "Blackberry PlayBook landscape": {
14
+ "userAgent": "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/26.4 Safari/536.2+",
15
+ "viewport": {
16
+ "width": 1024,
17
+ "height": 600
18
+ },
19
+ "deviceScaleFactor": 1,
20
+ "isMobile": true,
21
+ "hasTouch": true,
22
+ "defaultBrowserType": "webkit"
23
+ },
24
+ "BlackBerry Z30": {
25
+ "userAgent": "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/26.4 Mobile Safari/537.10+",
26
+ "viewport": {
27
+ "width": 360,
28
+ "height": 640
29
+ },
30
+ "deviceScaleFactor": 2,
31
+ "isMobile": true,
32
+ "hasTouch": true,
33
+ "defaultBrowserType": "webkit"
34
+ },
35
+ "BlackBerry Z30 landscape": {
36
+ "userAgent": "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/26.4 Mobile Safari/537.10+",
37
+ "viewport": {
38
+ "width": 640,
39
+ "height": 360
40
+ },
41
+ "deviceScaleFactor": 2,
42
+ "isMobile": true,
43
+ "hasTouch": true,
44
+ "defaultBrowserType": "webkit"
45
+ },
46
+ "Galaxy Note 3": {
47
+ "userAgent": "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/26.4 Mobile Safari/534.30",
48
+ "viewport": {
49
+ "width": 360,
50
+ "height": 640
51
+ },
52
+ "deviceScaleFactor": 3,
53
+ "isMobile": true,
54
+ "hasTouch": true,
55
+ "defaultBrowserType": "webkit"
56
+ },
57
+ "Galaxy Note 3 landscape": {
58
+ "userAgent": "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/26.4 Mobile Safari/534.30",
59
+ "viewport": {
60
+ "width": 640,
61
+ "height": 360
62
+ },
63
+ "deviceScaleFactor": 3,
64
+ "isMobile": true,
65
+ "hasTouch": true,
66
+ "defaultBrowserType": "webkit"
67
+ },
68
+ "Galaxy Note II": {
69
+ "userAgent": "Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/26.4 Mobile Safari/534.30",
70
+ "viewport": {
71
+ "width": 360,
72
+ "height": 640
73
+ },
74
+ "deviceScaleFactor": 2,
75
+ "isMobile": true,
76
+ "hasTouch": true,
77
+ "defaultBrowserType": "webkit"
78
+ },
79
+ "Galaxy Note II landscape": {
80
+ "userAgent": "Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/26.4 Mobile Safari/534.30",
81
+ "viewport": {
82
+ "width": 640,
83
+ "height": 360
84
+ },
85
+ "deviceScaleFactor": 2,
86
+ "isMobile": true,
87
+ "hasTouch": true,
88
+ "defaultBrowserType": "webkit"
89
+ },
90
+ "Galaxy S III": {
91
+ "userAgent": "Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/26.4 Mobile Safari/534.30",
92
+ "viewport": {
93
+ "width": 360,
94
+ "height": 640
95
+ },
96
+ "deviceScaleFactor": 2,
97
+ "isMobile": true,
98
+ "hasTouch": true,
99
+ "defaultBrowserType": "webkit"
100
+ },
101
+ "Galaxy S III landscape": {
102
+ "userAgent": "Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/26.4 Mobile Safari/534.30",
103
+ "viewport": {
104
+ "width": 640,
105
+ "height": 360
106
+ },
107
+ "deviceScaleFactor": 2,
108
+ "isMobile": true,
109
+ "hasTouch": true,
110
+ "defaultBrowserType": "webkit"
111
+ },
112
+ "Galaxy S5": {
113
+ "userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
114
+ "viewport": {
115
+ "width": 360,
116
+ "height": 640
117
+ },
118
+ "deviceScaleFactor": 3,
119
+ "isMobile": true,
120
+ "hasTouch": true,
121
+ "defaultBrowserType": "chromium"
122
+ },
123
+ "Galaxy S5 landscape": {
124
+ "userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
125
+ "viewport": {
126
+ "width": 640,
127
+ "height": 360
128
+ },
129
+ "deviceScaleFactor": 3,
130
+ "isMobile": true,
131
+ "hasTouch": true,
132
+ "defaultBrowserType": "chromium"
133
+ },
134
+ "Galaxy S8": {
135
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
136
+ "viewport": {
137
+ "width": 360,
138
+ "height": 740
139
+ },
140
+ "deviceScaleFactor": 3,
141
+ "isMobile": true,
142
+ "hasTouch": true,
143
+ "defaultBrowserType": "chromium"
144
+ },
145
+ "Galaxy S8 landscape": {
146
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
147
+ "viewport": {
148
+ "width": 740,
149
+ "height": 360
150
+ },
151
+ "deviceScaleFactor": 3,
152
+ "isMobile": true,
153
+ "hasTouch": true,
154
+ "defaultBrowserType": "chromium"
155
+ },
156
+ "Galaxy S9+": {
157
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
158
+ "viewport": {
159
+ "width": 320,
160
+ "height": 658
161
+ },
162
+ "deviceScaleFactor": 4.5,
163
+ "isMobile": true,
164
+ "hasTouch": true,
165
+ "defaultBrowserType": "chromium"
166
+ },
167
+ "Galaxy S9+ landscape": {
168
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
169
+ "viewport": {
170
+ "width": 658,
171
+ "height": 320
172
+ },
173
+ "deviceScaleFactor": 4.5,
174
+ "isMobile": true,
175
+ "hasTouch": true,
176
+ "defaultBrowserType": "chromium"
177
+ },
178
+ "Galaxy S24": {
179
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-S921U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
180
+ "viewport": {
181
+ "width": 360,
182
+ "height": 780
183
+ },
184
+ "deviceScaleFactor": 3,
185
+ "isMobile": true,
186
+ "hasTouch": true,
187
+ "defaultBrowserType": "chromium"
188
+ },
189
+ "Galaxy S24 landscape": {
190
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-S921U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
191
+ "viewport": {
192
+ "width": 780,
193
+ "height": 360
194
+ },
195
+ "deviceScaleFactor": 3,
196
+ "isMobile": true,
197
+ "hasTouch": true,
198
+ "defaultBrowserType": "chromium"
199
+ },
200
+ "Galaxy A55": {
201
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-A556B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
202
+ "viewport": {
203
+ "width": 480,
204
+ "height": 1040
205
+ },
206
+ "deviceScaleFactor": 2.25,
207
+ "isMobile": true,
208
+ "hasTouch": true,
209
+ "defaultBrowserType": "chromium"
210
+ },
211
+ "Galaxy A55 landscape": {
212
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-A556B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
213
+ "viewport": {
214
+ "width": 1040,
215
+ "height": 480
216
+ },
217
+ "deviceScaleFactor": 2.25,
218
+ "isMobile": true,
219
+ "hasTouch": true,
220
+ "defaultBrowserType": "chromium"
221
+ },
222
+ "Galaxy Tab S4": {
223
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
224
+ "viewport": {
225
+ "width": 712,
226
+ "height": 1138
227
+ },
228
+ "deviceScaleFactor": 2.25,
229
+ "isMobile": true,
230
+ "hasTouch": true,
231
+ "defaultBrowserType": "chromium"
232
+ },
233
+ "Galaxy Tab S4 landscape": {
234
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
235
+ "viewport": {
236
+ "width": 1138,
237
+ "height": 712
238
+ },
239
+ "deviceScaleFactor": 2.25,
240
+ "isMobile": true,
241
+ "hasTouch": true,
242
+ "defaultBrowserType": "chromium"
243
+ },
244
+ "Galaxy Tab S9": {
245
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
246
+ "viewport": {
247
+ "width": 640,
248
+ "height": 1024
249
+ },
250
+ "deviceScaleFactor": 2.5,
251
+ "isMobile": true,
252
+ "hasTouch": true,
253
+ "defaultBrowserType": "chromium"
254
+ },
255
+ "Galaxy Tab S9 landscape": {
256
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
257
+ "viewport": {
258
+ "width": 1024,
259
+ "height": 640
260
+ },
261
+ "deviceScaleFactor": 2.5,
262
+ "isMobile": true,
263
+ "hasTouch": true,
264
+ "defaultBrowserType": "chromium"
265
+ },
266
+ "iPad (gen 5)": {
267
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
268
+ "viewport": {
269
+ "width": 768,
270
+ "height": 1024
271
+ },
272
+ "deviceScaleFactor": 2,
273
+ "isMobile": true,
274
+ "hasTouch": true,
275
+ "defaultBrowserType": "webkit"
276
+ },
277
+ "iPad (gen 5) landscape": {
278
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
279
+ "viewport": {
280
+ "width": 1024,
281
+ "height": 768
282
+ },
283
+ "deviceScaleFactor": 2,
284
+ "isMobile": true,
285
+ "hasTouch": true,
286
+ "defaultBrowserType": "webkit"
287
+ },
288
+ "iPad (gen 6)": {
289
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
290
+ "viewport": {
291
+ "width": 768,
292
+ "height": 1024
293
+ },
294
+ "deviceScaleFactor": 2,
295
+ "isMobile": true,
296
+ "hasTouch": true,
297
+ "defaultBrowserType": "webkit"
298
+ },
299
+ "iPad (gen 6) landscape": {
300
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
301
+ "viewport": {
302
+ "width": 1024,
303
+ "height": 768
304
+ },
305
+ "deviceScaleFactor": 2,
306
+ "isMobile": true,
307
+ "hasTouch": true,
308
+ "defaultBrowserType": "webkit"
309
+ },
310
+ "iPad (gen 7)": {
311
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
312
+ "viewport": {
313
+ "width": 810,
314
+ "height": 1080
315
+ },
316
+ "deviceScaleFactor": 2,
317
+ "isMobile": true,
318
+ "hasTouch": true,
319
+ "defaultBrowserType": "webkit"
320
+ },
321
+ "iPad (gen 7) landscape": {
322
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
323
+ "viewport": {
324
+ "width": 1080,
325
+ "height": 810
326
+ },
327
+ "deviceScaleFactor": 2,
328
+ "isMobile": true,
329
+ "hasTouch": true,
330
+ "defaultBrowserType": "webkit"
331
+ },
332
+ "iPad (gen 11)": {
333
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/19E241 Safari/604.1",
334
+ "viewport": {
335
+ "width": 656,
336
+ "height": 944
337
+ },
338
+ "deviceScaleFactor": 2.5,
339
+ "isMobile": true,
340
+ "hasTouch": true,
341
+ "defaultBrowserType": "webkit"
342
+ },
343
+ "iPad (gen 11) landscape": {
344
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/19E241 Safari/604.1",
345
+ "viewport": {
346
+ "width": 944,
347
+ "height": 656
348
+ },
349
+ "deviceScaleFactor": 2.5,
350
+ "isMobile": true,
351
+ "hasTouch": true,
352
+ "defaultBrowserType": "webkit"
353
+ },
354
+ "iPad Mini": {
355
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
356
+ "viewport": {
357
+ "width": 768,
358
+ "height": 1024
359
+ },
360
+ "deviceScaleFactor": 2,
361
+ "isMobile": true,
362
+ "hasTouch": true,
363
+ "defaultBrowserType": "webkit"
364
+ },
365
+ "iPad Mini landscape": {
366
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
367
+ "viewport": {
368
+ "width": 1024,
369
+ "height": 768
370
+ },
371
+ "deviceScaleFactor": 2,
372
+ "isMobile": true,
373
+ "hasTouch": true,
374
+ "defaultBrowserType": "webkit"
375
+ },
376
+ "iPad Pro 11": {
377
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
378
+ "viewport": {
379
+ "width": 834,
380
+ "height": 1194
381
+ },
382
+ "deviceScaleFactor": 2,
383
+ "isMobile": true,
384
+ "hasTouch": true,
385
+ "defaultBrowserType": "webkit"
386
+ },
387
+ "iPad Pro 11 landscape": {
388
+ "userAgent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
389
+ "viewport": {
390
+ "width": 1194,
391
+ "height": 834
392
+ },
393
+ "deviceScaleFactor": 2,
394
+ "isMobile": true,
395
+ "hasTouch": true,
396
+ "defaultBrowserType": "webkit"
397
+ },
398
+ "iPhone 6": {
399
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
400
+ "viewport": {
401
+ "width": 375,
402
+ "height": 667
403
+ },
404
+ "deviceScaleFactor": 2,
405
+ "isMobile": true,
406
+ "hasTouch": true,
407
+ "defaultBrowserType": "webkit"
408
+ },
409
+ "iPhone 6 landscape": {
410
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
411
+ "viewport": {
412
+ "width": 667,
413
+ "height": 375
414
+ },
415
+ "deviceScaleFactor": 2,
416
+ "isMobile": true,
417
+ "hasTouch": true,
418
+ "defaultBrowserType": "webkit"
419
+ },
420
+ "iPhone 6 Plus": {
421
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
422
+ "viewport": {
423
+ "width": 414,
424
+ "height": 736
425
+ },
426
+ "deviceScaleFactor": 3,
427
+ "isMobile": true,
428
+ "hasTouch": true,
429
+ "defaultBrowserType": "webkit"
430
+ },
431
+ "iPhone 6 Plus landscape": {
432
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
433
+ "viewport": {
434
+ "width": 736,
435
+ "height": 414
436
+ },
437
+ "deviceScaleFactor": 3,
438
+ "isMobile": true,
439
+ "hasTouch": true,
440
+ "defaultBrowserType": "webkit"
441
+ },
442
+ "iPhone 7": {
443
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
444
+ "viewport": {
445
+ "width": 375,
446
+ "height": 667
447
+ },
448
+ "deviceScaleFactor": 2,
449
+ "isMobile": true,
450
+ "hasTouch": true,
451
+ "defaultBrowserType": "webkit"
452
+ },
453
+ "iPhone 7 landscape": {
454
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
455
+ "viewport": {
456
+ "width": 667,
457
+ "height": 375
458
+ },
459
+ "deviceScaleFactor": 2,
460
+ "isMobile": true,
461
+ "hasTouch": true,
462
+ "defaultBrowserType": "webkit"
463
+ },
464
+ "iPhone 7 Plus": {
465
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
466
+ "viewport": {
467
+ "width": 414,
468
+ "height": 736
469
+ },
470
+ "deviceScaleFactor": 3,
471
+ "isMobile": true,
472
+ "hasTouch": true,
473
+ "defaultBrowserType": "webkit"
474
+ },
475
+ "iPhone 7 Plus landscape": {
476
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
477
+ "viewport": {
478
+ "width": 736,
479
+ "height": 414
480
+ },
481
+ "deviceScaleFactor": 3,
482
+ "isMobile": true,
483
+ "hasTouch": true,
484
+ "defaultBrowserType": "webkit"
485
+ },
486
+ "iPhone 8": {
487
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
488
+ "viewport": {
489
+ "width": 375,
490
+ "height": 667
491
+ },
492
+ "deviceScaleFactor": 2,
493
+ "isMobile": true,
494
+ "hasTouch": true,
495
+ "defaultBrowserType": "webkit"
496
+ },
497
+ "iPhone 8 landscape": {
498
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
499
+ "viewport": {
500
+ "width": 667,
501
+ "height": 375
502
+ },
503
+ "deviceScaleFactor": 2,
504
+ "isMobile": true,
505
+ "hasTouch": true,
506
+ "defaultBrowserType": "webkit"
507
+ },
508
+ "iPhone 8 Plus": {
509
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
510
+ "viewport": {
511
+ "width": 414,
512
+ "height": 736
513
+ },
514
+ "deviceScaleFactor": 3,
515
+ "isMobile": true,
516
+ "hasTouch": true,
517
+ "defaultBrowserType": "webkit"
518
+ },
519
+ "iPhone 8 Plus landscape": {
520
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
521
+ "viewport": {
522
+ "width": 736,
523
+ "height": 414
524
+ },
525
+ "deviceScaleFactor": 3,
526
+ "isMobile": true,
527
+ "hasTouch": true,
528
+ "defaultBrowserType": "webkit"
529
+ },
530
+ "iPhone SE": {
531
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/26.4 Mobile/14E304 Safari/602.1",
532
+ "viewport": {
533
+ "width": 320,
534
+ "height": 568
535
+ },
536
+ "deviceScaleFactor": 2,
537
+ "isMobile": true,
538
+ "hasTouch": true,
539
+ "defaultBrowserType": "webkit"
540
+ },
541
+ "iPhone SE landscape": {
542
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/26.4 Mobile/14E304 Safari/602.1",
543
+ "viewport": {
544
+ "width": 568,
545
+ "height": 320
546
+ },
547
+ "deviceScaleFactor": 2,
548
+ "isMobile": true,
549
+ "hasTouch": true,
550
+ "defaultBrowserType": "webkit"
551
+ },
552
+ "iPhone SE (3rd gen)": {
553
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/26.4 Mobile/19E241 Safari/602.1",
554
+ "viewport": {
555
+ "width": 375,
556
+ "height": 667
557
+ },
558
+ "deviceScaleFactor": 2,
559
+ "isMobile": true,
560
+ "hasTouch": true,
561
+ "defaultBrowserType": "webkit"
562
+ },
563
+ "iPhone SE (3rd gen) landscape": {
564
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/26.4 Mobile/19E241 Safari/602.1",
565
+ "viewport": {
566
+ "width": 667,
567
+ "height": 375
568
+ },
569
+ "deviceScaleFactor": 2,
570
+ "isMobile": true,
571
+ "hasTouch": true,
572
+ "defaultBrowserType": "webkit"
573
+ },
574
+ "iPhone X": {
575
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
576
+ "viewport": {
577
+ "width": 375,
578
+ "height": 812
579
+ },
580
+ "deviceScaleFactor": 3,
581
+ "isMobile": true,
582
+ "hasTouch": true,
583
+ "defaultBrowserType": "webkit"
584
+ },
585
+ "iPhone X landscape": {
586
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/26.4 Mobile/15A372 Safari/604.1",
587
+ "viewport": {
588
+ "width": 812,
589
+ "height": 375
590
+ },
591
+ "deviceScaleFactor": 3,
592
+ "isMobile": true,
593
+ "hasTouch": true,
594
+ "defaultBrowserType": "webkit"
595
+ },
596
+ "iPhone XR": {
597
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
598
+ "viewport": {
599
+ "width": 414,
600
+ "height": 896
601
+ },
602
+ "deviceScaleFactor": 3,
603
+ "isMobile": true,
604
+ "hasTouch": true,
605
+ "defaultBrowserType": "webkit"
606
+ },
607
+ "iPhone XR landscape": {
608
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
609
+ "viewport": {
610
+ "width": 896,
611
+ "height": 414
612
+ },
613
+ "deviceScaleFactor": 3,
614
+ "isMobile": true,
615
+ "hasTouch": true,
616
+ "defaultBrowserType": "webkit"
617
+ },
618
+ "iPhone 11": {
619
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
620
+ "screen": {
621
+ "width": 414,
622
+ "height": 896
623
+ },
624
+ "viewport": {
625
+ "width": 414,
626
+ "height": 715
627
+ },
628
+ "deviceScaleFactor": 2,
629
+ "isMobile": true,
630
+ "hasTouch": true,
631
+ "defaultBrowserType": "webkit"
632
+ },
633
+ "iPhone 11 landscape": {
634
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
635
+ "screen": {
636
+ "width": 414,
637
+ "height": 896
638
+ },
639
+ "viewport": {
640
+ "width": 800,
641
+ "height": 364
642
+ },
643
+ "deviceScaleFactor": 2,
644
+ "isMobile": true,
645
+ "hasTouch": true,
646
+ "defaultBrowserType": "webkit"
647
+ },
648
+ "iPhone 11 Pro": {
649
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
650
+ "screen": {
651
+ "width": 375,
652
+ "height": 812
653
+ },
654
+ "viewport": {
655
+ "width": 375,
656
+ "height": 635
657
+ },
658
+ "deviceScaleFactor": 3,
659
+ "isMobile": true,
660
+ "hasTouch": true,
661
+ "defaultBrowserType": "webkit"
662
+ },
663
+ "iPhone 11 Pro landscape": {
664
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
665
+ "screen": {
666
+ "width": 375,
667
+ "height": 812
668
+ },
669
+ "viewport": {
670
+ "width": 724,
671
+ "height": 325
672
+ },
673
+ "deviceScaleFactor": 3,
674
+ "isMobile": true,
675
+ "hasTouch": true,
676
+ "defaultBrowserType": "webkit"
677
+ },
678
+ "iPhone 11 Pro Max": {
679
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
680
+ "screen": {
681
+ "width": 414,
682
+ "height": 896
683
+ },
684
+ "viewport": {
685
+ "width": 414,
686
+ "height": 715
687
+ },
688
+ "deviceScaleFactor": 3,
689
+ "isMobile": true,
690
+ "hasTouch": true,
691
+ "defaultBrowserType": "webkit"
692
+ },
693
+ "iPhone 11 Pro Max landscape": {
694
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
695
+ "screen": {
696
+ "width": 414,
697
+ "height": 896
698
+ },
699
+ "viewport": {
700
+ "width": 808,
701
+ "height": 364
702
+ },
703
+ "deviceScaleFactor": 3,
704
+ "isMobile": true,
705
+ "hasTouch": true,
706
+ "defaultBrowserType": "webkit"
707
+ },
708
+ "iPhone 12": {
709
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
710
+ "screen": {
711
+ "width": 390,
712
+ "height": 844
713
+ },
714
+ "viewport": {
715
+ "width": 390,
716
+ "height": 664
717
+ },
718
+ "deviceScaleFactor": 3,
719
+ "isMobile": true,
720
+ "hasTouch": true,
721
+ "defaultBrowserType": "webkit"
722
+ },
723
+ "iPhone 12 landscape": {
724
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
725
+ "screen": {
726
+ "width": 390,
727
+ "height": 844
728
+ },
729
+ "viewport": {
730
+ "width": 750,
731
+ "height": 340
732
+ },
733
+ "deviceScaleFactor": 3,
734
+ "isMobile": true,
735
+ "hasTouch": true,
736
+ "defaultBrowserType": "webkit"
737
+ },
738
+ "iPhone 12 Pro": {
739
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
740
+ "screen": {
741
+ "width": 390,
742
+ "height": 844
743
+ },
744
+ "viewport": {
745
+ "width": 390,
746
+ "height": 664
747
+ },
748
+ "deviceScaleFactor": 3,
749
+ "isMobile": true,
750
+ "hasTouch": true,
751
+ "defaultBrowserType": "webkit"
752
+ },
753
+ "iPhone 12 Pro landscape": {
754
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
755
+ "screen": {
756
+ "width": 390,
757
+ "height": 844
758
+ },
759
+ "viewport": {
760
+ "width": 750,
761
+ "height": 340
762
+ },
763
+ "deviceScaleFactor": 3,
764
+ "isMobile": true,
765
+ "hasTouch": true,
766
+ "defaultBrowserType": "webkit"
767
+ },
768
+ "iPhone 12 Pro Max": {
769
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
770
+ "screen": {
771
+ "width": 428,
772
+ "height": 926
773
+ },
774
+ "viewport": {
775
+ "width": 428,
776
+ "height": 746
777
+ },
778
+ "deviceScaleFactor": 3,
779
+ "isMobile": true,
780
+ "hasTouch": true,
781
+ "defaultBrowserType": "webkit"
782
+ },
783
+ "iPhone 12 Pro Max landscape": {
784
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
785
+ "screen": {
786
+ "width": 428,
787
+ "height": 926
788
+ },
789
+ "viewport": {
790
+ "width": 832,
791
+ "height": 378
792
+ },
793
+ "deviceScaleFactor": 3,
794
+ "isMobile": true,
795
+ "hasTouch": true,
796
+ "defaultBrowserType": "webkit"
797
+ },
798
+ "iPhone 12 Mini": {
799
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
800
+ "screen": {
801
+ "width": 375,
802
+ "height": 812
803
+ },
804
+ "viewport": {
805
+ "width": 375,
806
+ "height": 629
807
+ },
808
+ "deviceScaleFactor": 3,
809
+ "isMobile": true,
810
+ "hasTouch": true,
811
+ "defaultBrowserType": "webkit"
812
+ },
813
+ "iPhone 12 Mini landscape": {
814
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
815
+ "screen": {
816
+ "width": 375,
817
+ "height": 812
818
+ },
819
+ "viewport": {
820
+ "width": 712,
821
+ "height": 325
822
+ },
823
+ "deviceScaleFactor": 3,
824
+ "isMobile": true,
825
+ "hasTouch": true,
826
+ "defaultBrowserType": "webkit"
827
+ },
828
+ "iPhone 13": {
829
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
830
+ "screen": {
831
+ "width": 390,
832
+ "height": 844
833
+ },
834
+ "viewport": {
835
+ "width": 390,
836
+ "height": 664
837
+ },
838
+ "deviceScaleFactor": 3,
839
+ "isMobile": true,
840
+ "hasTouch": true,
841
+ "defaultBrowserType": "webkit"
842
+ },
843
+ "iPhone 13 landscape": {
844
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
845
+ "screen": {
846
+ "width": 390,
847
+ "height": 844
848
+ },
849
+ "viewport": {
850
+ "width": 750,
851
+ "height": 342
852
+ },
853
+ "deviceScaleFactor": 3,
854
+ "isMobile": true,
855
+ "hasTouch": true,
856
+ "defaultBrowserType": "webkit"
857
+ },
858
+ "iPhone 13 Pro": {
859
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
860
+ "screen": {
861
+ "width": 390,
862
+ "height": 844
863
+ },
864
+ "viewport": {
865
+ "width": 390,
866
+ "height": 664
867
+ },
868
+ "deviceScaleFactor": 3,
869
+ "isMobile": true,
870
+ "hasTouch": true,
871
+ "defaultBrowserType": "webkit"
872
+ },
873
+ "iPhone 13 Pro landscape": {
874
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
875
+ "screen": {
876
+ "width": 390,
877
+ "height": 844
878
+ },
879
+ "viewport": {
880
+ "width": 750,
881
+ "height": 342
882
+ },
883
+ "deviceScaleFactor": 3,
884
+ "isMobile": true,
885
+ "hasTouch": true,
886
+ "defaultBrowserType": "webkit"
887
+ },
888
+ "iPhone 13 Pro Max": {
889
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
890
+ "screen": {
891
+ "width": 428,
892
+ "height": 926
893
+ },
894
+ "viewport": {
895
+ "width": 428,
896
+ "height": 746
897
+ },
898
+ "deviceScaleFactor": 3,
899
+ "isMobile": true,
900
+ "hasTouch": true,
901
+ "defaultBrowserType": "webkit"
902
+ },
903
+ "iPhone 13 Pro Max landscape": {
904
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
905
+ "screen": {
906
+ "width": 428,
907
+ "height": 926
908
+ },
909
+ "viewport": {
910
+ "width": 832,
911
+ "height": 380
912
+ },
913
+ "deviceScaleFactor": 3,
914
+ "isMobile": true,
915
+ "hasTouch": true,
916
+ "defaultBrowserType": "webkit"
917
+ },
918
+ "iPhone 13 Mini": {
919
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
920
+ "screen": {
921
+ "width": 375,
922
+ "height": 812
923
+ },
924
+ "viewport": {
925
+ "width": 375,
926
+ "height": 629
927
+ },
928
+ "deviceScaleFactor": 3,
929
+ "isMobile": true,
930
+ "hasTouch": true,
931
+ "defaultBrowserType": "webkit"
932
+ },
933
+ "iPhone 13 Mini landscape": {
934
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
935
+ "screen": {
936
+ "width": 375,
937
+ "height": 812
938
+ },
939
+ "viewport": {
940
+ "width": 712,
941
+ "height": 327
942
+ },
943
+ "deviceScaleFactor": 3,
944
+ "isMobile": true,
945
+ "hasTouch": true,
946
+ "defaultBrowserType": "webkit"
947
+ },
948
+ "iPhone 14": {
949
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
950
+ "screen": {
951
+ "width": 390,
952
+ "height": 844
953
+ },
954
+ "viewport": {
955
+ "width": 390,
956
+ "height": 664
957
+ },
958
+ "deviceScaleFactor": 3,
959
+ "isMobile": true,
960
+ "hasTouch": true,
961
+ "defaultBrowserType": "webkit"
962
+ },
963
+ "iPhone 14 landscape": {
964
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
965
+ "screen": {
966
+ "width": 390,
967
+ "height": 844
968
+ },
969
+ "viewport": {
970
+ "width": 750,
971
+ "height": 340
972
+ },
973
+ "deviceScaleFactor": 3,
974
+ "isMobile": true,
975
+ "hasTouch": true,
976
+ "defaultBrowserType": "webkit"
977
+ },
978
+ "iPhone 14 Plus": {
979
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
980
+ "screen": {
981
+ "width": 428,
982
+ "height": 926
983
+ },
984
+ "viewport": {
985
+ "width": 428,
986
+ "height": 746
987
+ },
988
+ "deviceScaleFactor": 3,
989
+ "isMobile": true,
990
+ "hasTouch": true,
991
+ "defaultBrowserType": "webkit"
992
+ },
993
+ "iPhone 14 Plus landscape": {
994
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
995
+ "screen": {
996
+ "width": 428,
997
+ "height": 926
998
+ },
999
+ "viewport": {
1000
+ "width": 832,
1001
+ "height": 378
1002
+ },
1003
+ "deviceScaleFactor": 3,
1004
+ "isMobile": true,
1005
+ "hasTouch": true,
1006
+ "defaultBrowserType": "webkit"
1007
+ },
1008
+ "iPhone 14 Pro": {
1009
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1010
+ "screen": {
1011
+ "width": 393,
1012
+ "height": 852
1013
+ },
1014
+ "viewport": {
1015
+ "width": 393,
1016
+ "height": 660
1017
+ },
1018
+ "deviceScaleFactor": 3,
1019
+ "isMobile": true,
1020
+ "hasTouch": true,
1021
+ "defaultBrowserType": "webkit"
1022
+ },
1023
+ "iPhone 14 Pro landscape": {
1024
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1025
+ "screen": {
1026
+ "width": 393,
1027
+ "height": 852
1028
+ },
1029
+ "viewport": {
1030
+ "width": 734,
1031
+ "height": 343
1032
+ },
1033
+ "deviceScaleFactor": 3,
1034
+ "isMobile": true,
1035
+ "hasTouch": true,
1036
+ "defaultBrowserType": "webkit"
1037
+ },
1038
+ "iPhone 14 Pro Max": {
1039
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1040
+ "screen": {
1041
+ "width": 430,
1042
+ "height": 932
1043
+ },
1044
+ "viewport": {
1045
+ "width": 430,
1046
+ "height": 740
1047
+ },
1048
+ "deviceScaleFactor": 3,
1049
+ "isMobile": true,
1050
+ "hasTouch": true,
1051
+ "defaultBrowserType": "webkit"
1052
+ },
1053
+ "iPhone 14 Pro Max landscape": {
1054
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1055
+ "screen": {
1056
+ "width": 430,
1057
+ "height": 932
1058
+ },
1059
+ "viewport": {
1060
+ "width": 814,
1061
+ "height": 380
1062
+ },
1063
+ "deviceScaleFactor": 3,
1064
+ "isMobile": true,
1065
+ "hasTouch": true,
1066
+ "defaultBrowserType": "webkit"
1067
+ },
1068
+ "iPhone 15": {
1069
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1070
+ "screen": {
1071
+ "width": 393,
1072
+ "height": 852
1073
+ },
1074
+ "viewport": {
1075
+ "width": 393,
1076
+ "height": 659
1077
+ },
1078
+ "deviceScaleFactor": 3,
1079
+ "isMobile": true,
1080
+ "hasTouch": true,
1081
+ "defaultBrowserType": "webkit"
1082
+ },
1083
+ "iPhone 15 landscape": {
1084
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1085
+ "screen": {
1086
+ "width": 393,
1087
+ "height": 852
1088
+ },
1089
+ "viewport": {
1090
+ "width": 734,
1091
+ "height": 343
1092
+ },
1093
+ "deviceScaleFactor": 3,
1094
+ "isMobile": true,
1095
+ "hasTouch": true,
1096
+ "defaultBrowserType": "webkit"
1097
+ },
1098
+ "iPhone 15 Plus": {
1099
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1100
+ "screen": {
1101
+ "width": 430,
1102
+ "height": 932
1103
+ },
1104
+ "viewport": {
1105
+ "width": 430,
1106
+ "height": 739
1107
+ },
1108
+ "deviceScaleFactor": 3,
1109
+ "isMobile": true,
1110
+ "hasTouch": true,
1111
+ "defaultBrowserType": "webkit"
1112
+ },
1113
+ "iPhone 15 Plus landscape": {
1114
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1115
+ "screen": {
1116
+ "width": 430,
1117
+ "height": 932
1118
+ },
1119
+ "viewport": {
1120
+ "width": 814,
1121
+ "height": 380
1122
+ },
1123
+ "deviceScaleFactor": 3,
1124
+ "isMobile": true,
1125
+ "hasTouch": true,
1126
+ "defaultBrowserType": "webkit"
1127
+ },
1128
+ "iPhone 15 Pro": {
1129
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1130
+ "screen": {
1131
+ "width": 393,
1132
+ "height": 852
1133
+ },
1134
+ "viewport": {
1135
+ "width": 393,
1136
+ "height": 659
1137
+ },
1138
+ "deviceScaleFactor": 3,
1139
+ "isMobile": true,
1140
+ "hasTouch": true,
1141
+ "defaultBrowserType": "webkit"
1142
+ },
1143
+ "iPhone 15 Pro landscape": {
1144
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1145
+ "screen": {
1146
+ "width": 393,
1147
+ "height": 852
1148
+ },
1149
+ "viewport": {
1150
+ "width": 734,
1151
+ "height": 343
1152
+ },
1153
+ "deviceScaleFactor": 3,
1154
+ "isMobile": true,
1155
+ "hasTouch": true,
1156
+ "defaultBrowserType": "webkit"
1157
+ },
1158
+ "iPhone 15 Pro Max": {
1159
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1160
+ "screen": {
1161
+ "width": 430,
1162
+ "height": 932
1163
+ },
1164
+ "viewport": {
1165
+ "width": 430,
1166
+ "height": 739
1167
+ },
1168
+ "deviceScaleFactor": 3,
1169
+ "isMobile": true,
1170
+ "hasTouch": true,
1171
+ "defaultBrowserType": "webkit"
1172
+ },
1173
+ "iPhone 15 Pro Max landscape": {
1174
+ "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Mobile/15E148 Safari/604.1",
1175
+ "screen": {
1176
+ "width": 430,
1177
+ "height": 932
1178
+ },
1179
+ "viewport": {
1180
+ "width": 814,
1181
+ "height": 380
1182
+ },
1183
+ "deviceScaleFactor": 3,
1184
+ "isMobile": true,
1185
+ "hasTouch": true,
1186
+ "defaultBrowserType": "webkit"
1187
+ },
1188
+ "Kindle Fire HDX": {
1189
+ "userAgent": "Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
1190
+ "viewport": {
1191
+ "width": 800,
1192
+ "height": 1280
1193
+ },
1194
+ "deviceScaleFactor": 2,
1195
+ "isMobile": true,
1196
+ "hasTouch": true,
1197
+ "defaultBrowserType": "webkit"
1198
+ },
1199
+ "Kindle Fire HDX landscape": {
1200
+ "userAgent": "Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
1201
+ "viewport": {
1202
+ "width": 1280,
1203
+ "height": 800
1204
+ },
1205
+ "deviceScaleFactor": 2,
1206
+ "isMobile": true,
1207
+ "hasTouch": true,
1208
+ "defaultBrowserType": "webkit"
1209
+ },
1210
+ "LG Optimus L70": {
1211
+ "userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/148.0.7778.96 Mobile Safari/537.36",
1212
+ "viewport": {
1213
+ "width": 384,
1214
+ "height": 640
1215
+ },
1216
+ "deviceScaleFactor": 1.25,
1217
+ "isMobile": true,
1218
+ "hasTouch": true,
1219
+ "defaultBrowserType": "chromium"
1220
+ },
1221
+ "LG Optimus L70 landscape": {
1222
+ "userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/148.0.7778.96 Mobile Safari/537.36",
1223
+ "viewport": {
1224
+ "width": 640,
1225
+ "height": 384
1226
+ },
1227
+ "deviceScaleFactor": 1.25,
1228
+ "isMobile": true,
1229
+ "hasTouch": true,
1230
+ "defaultBrowserType": "chromium"
1231
+ },
1232
+ "Microsoft Lumia 550": {
1233
+ "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36 Edge/14.14263",
1234
+ "viewport": {
1235
+ "width": 360,
1236
+ "height": 640
1237
+ },
1238
+ "deviceScaleFactor": 2,
1239
+ "isMobile": true,
1240
+ "hasTouch": true,
1241
+ "defaultBrowserType": "chromium"
1242
+ },
1243
+ "Microsoft Lumia 550 landscape": {
1244
+ "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36 Edge/14.14263",
1245
+ "viewport": {
1246
+ "width": 640,
1247
+ "height": 360
1248
+ },
1249
+ "deviceScaleFactor": 2,
1250
+ "isMobile": true,
1251
+ "hasTouch": true,
1252
+ "defaultBrowserType": "chromium"
1253
+ },
1254
+ "Microsoft Lumia 950": {
1255
+ "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36 Edge/14.14263",
1256
+ "viewport": {
1257
+ "width": 360,
1258
+ "height": 640
1259
+ },
1260
+ "deviceScaleFactor": 4,
1261
+ "isMobile": true,
1262
+ "hasTouch": true,
1263
+ "defaultBrowserType": "chromium"
1264
+ },
1265
+ "Microsoft Lumia 950 landscape": {
1266
+ "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36 Edge/14.14263",
1267
+ "viewport": {
1268
+ "width": 640,
1269
+ "height": 360
1270
+ },
1271
+ "deviceScaleFactor": 4,
1272
+ "isMobile": true,
1273
+ "hasTouch": true,
1274
+ "defaultBrowserType": "chromium"
1275
+ },
1276
+ "Nexus 10": {
1277
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
1278
+ "viewport": {
1279
+ "width": 800,
1280
+ "height": 1280
1281
+ },
1282
+ "deviceScaleFactor": 2,
1283
+ "isMobile": true,
1284
+ "hasTouch": true,
1285
+ "defaultBrowserType": "chromium"
1286
+ },
1287
+ "Nexus 10 landscape": {
1288
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
1289
+ "viewport": {
1290
+ "width": 1280,
1291
+ "height": 800
1292
+ },
1293
+ "deviceScaleFactor": 2,
1294
+ "isMobile": true,
1295
+ "hasTouch": true,
1296
+ "defaultBrowserType": "chromium"
1297
+ },
1298
+ "Nexus 4": {
1299
+ "userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1300
+ "viewport": {
1301
+ "width": 384,
1302
+ "height": 640
1303
+ },
1304
+ "deviceScaleFactor": 2,
1305
+ "isMobile": true,
1306
+ "hasTouch": true,
1307
+ "defaultBrowserType": "chromium"
1308
+ },
1309
+ "Nexus 4 landscape": {
1310
+ "userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1311
+ "viewport": {
1312
+ "width": 640,
1313
+ "height": 384
1314
+ },
1315
+ "deviceScaleFactor": 2,
1316
+ "isMobile": true,
1317
+ "hasTouch": true,
1318
+ "defaultBrowserType": "chromium"
1319
+ },
1320
+ "Nexus 5": {
1321
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1322
+ "viewport": {
1323
+ "width": 360,
1324
+ "height": 640
1325
+ },
1326
+ "deviceScaleFactor": 3,
1327
+ "isMobile": true,
1328
+ "hasTouch": true,
1329
+ "defaultBrowserType": "chromium"
1330
+ },
1331
+ "Nexus 5 landscape": {
1332
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1333
+ "viewport": {
1334
+ "width": 640,
1335
+ "height": 360
1336
+ },
1337
+ "deviceScaleFactor": 3,
1338
+ "isMobile": true,
1339
+ "hasTouch": true,
1340
+ "defaultBrowserType": "chromium"
1341
+ },
1342
+ "Nexus 5X": {
1343
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1344
+ "viewport": {
1345
+ "width": 412,
1346
+ "height": 732
1347
+ },
1348
+ "deviceScaleFactor": 2.625,
1349
+ "isMobile": true,
1350
+ "hasTouch": true,
1351
+ "defaultBrowserType": "chromium"
1352
+ },
1353
+ "Nexus 5X landscape": {
1354
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1355
+ "viewport": {
1356
+ "width": 732,
1357
+ "height": 412
1358
+ },
1359
+ "deviceScaleFactor": 2.625,
1360
+ "isMobile": true,
1361
+ "hasTouch": true,
1362
+ "defaultBrowserType": "chromium"
1363
+ },
1364
+ "Nexus 6": {
1365
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1366
+ "viewport": {
1367
+ "width": 412,
1368
+ "height": 732
1369
+ },
1370
+ "deviceScaleFactor": 3.5,
1371
+ "isMobile": true,
1372
+ "hasTouch": true,
1373
+ "defaultBrowserType": "chromium"
1374
+ },
1375
+ "Nexus 6 landscape": {
1376
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1377
+ "viewport": {
1378
+ "width": 732,
1379
+ "height": 412
1380
+ },
1381
+ "deviceScaleFactor": 3.5,
1382
+ "isMobile": true,
1383
+ "hasTouch": true,
1384
+ "defaultBrowserType": "chromium"
1385
+ },
1386
+ "Nexus 6P": {
1387
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1388
+ "viewport": {
1389
+ "width": 412,
1390
+ "height": 732
1391
+ },
1392
+ "deviceScaleFactor": 3.5,
1393
+ "isMobile": true,
1394
+ "hasTouch": true,
1395
+ "defaultBrowserType": "chromium"
1396
+ },
1397
+ "Nexus 6P landscape": {
1398
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1399
+ "viewport": {
1400
+ "width": 732,
1401
+ "height": 412
1402
+ },
1403
+ "deviceScaleFactor": 3.5,
1404
+ "isMobile": true,
1405
+ "hasTouch": true,
1406
+ "defaultBrowserType": "chromium"
1407
+ },
1408
+ "Nexus 7": {
1409
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
1410
+ "viewport": {
1411
+ "width": 600,
1412
+ "height": 960
1413
+ },
1414
+ "deviceScaleFactor": 2,
1415
+ "isMobile": true,
1416
+ "hasTouch": true,
1417
+ "defaultBrowserType": "chromium"
1418
+ },
1419
+ "Nexus 7 landscape": {
1420
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
1421
+ "viewport": {
1422
+ "width": 960,
1423
+ "height": 600
1424
+ },
1425
+ "deviceScaleFactor": 2,
1426
+ "isMobile": true,
1427
+ "hasTouch": true,
1428
+ "defaultBrowserType": "chromium"
1429
+ },
1430
+ "Nokia Lumia 520": {
1431
+ "userAgent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)",
1432
+ "viewport": {
1433
+ "width": 320,
1434
+ "height": 533
1435
+ },
1436
+ "deviceScaleFactor": 1.5,
1437
+ "isMobile": true,
1438
+ "hasTouch": true,
1439
+ "defaultBrowserType": "chromium"
1440
+ },
1441
+ "Nokia Lumia 520 landscape": {
1442
+ "userAgent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)",
1443
+ "viewport": {
1444
+ "width": 533,
1445
+ "height": 320
1446
+ },
1447
+ "deviceScaleFactor": 1.5,
1448
+ "isMobile": true,
1449
+ "hasTouch": true,
1450
+ "defaultBrowserType": "chromium"
1451
+ },
1452
+ "Nokia N9": {
1453
+ "userAgent": "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13",
1454
+ "viewport": {
1455
+ "width": 480,
1456
+ "height": 854
1457
+ },
1458
+ "deviceScaleFactor": 1,
1459
+ "isMobile": true,
1460
+ "hasTouch": true,
1461
+ "defaultBrowserType": "webkit"
1462
+ },
1463
+ "Nokia N9 landscape": {
1464
+ "userAgent": "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13",
1465
+ "viewport": {
1466
+ "width": 854,
1467
+ "height": 480
1468
+ },
1469
+ "deviceScaleFactor": 1,
1470
+ "isMobile": true,
1471
+ "hasTouch": true,
1472
+ "defaultBrowserType": "webkit"
1473
+ },
1474
+ "Pixel 2": {
1475
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1476
+ "viewport": {
1477
+ "width": 411,
1478
+ "height": 731
1479
+ },
1480
+ "deviceScaleFactor": 2.625,
1481
+ "isMobile": true,
1482
+ "hasTouch": true,
1483
+ "defaultBrowserType": "chromium"
1484
+ },
1485
+ "Pixel 2 landscape": {
1486
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1487
+ "viewport": {
1488
+ "width": 731,
1489
+ "height": 411
1490
+ },
1491
+ "deviceScaleFactor": 2.625,
1492
+ "isMobile": true,
1493
+ "hasTouch": true,
1494
+ "defaultBrowserType": "chromium"
1495
+ },
1496
+ "Pixel 2 XL": {
1497
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1498
+ "viewport": {
1499
+ "width": 411,
1500
+ "height": 823
1501
+ },
1502
+ "deviceScaleFactor": 3.5,
1503
+ "isMobile": true,
1504
+ "hasTouch": true,
1505
+ "defaultBrowserType": "chromium"
1506
+ },
1507
+ "Pixel 2 XL landscape": {
1508
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1509
+ "viewport": {
1510
+ "width": 823,
1511
+ "height": 411
1512
+ },
1513
+ "deviceScaleFactor": 3.5,
1514
+ "isMobile": true,
1515
+ "hasTouch": true,
1516
+ "defaultBrowserType": "chromium"
1517
+ },
1518
+ "Pixel 3": {
1519
+ "userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1520
+ "viewport": {
1521
+ "width": 393,
1522
+ "height": 786
1523
+ },
1524
+ "deviceScaleFactor": 2.75,
1525
+ "isMobile": true,
1526
+ "hasTouch": true,
1527
+ "defaultBrowserType": "chromium"
1528
+ },
1529
+ "Pixel 3 landscape": {
1530
+ "userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1531
+ "viewport": {
1532
+ "width": 786,
1533
+ "height": 393
1534
+ },
1535
+ "deviceScaleFactor": 2.75,
1536
+ "isMobile": true,
1537
+ "hasTouch": true,
1538
+ "defaultBrowserType": "chromium"
1539
+ },
1540
+ "Pixel 4": {
1541
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1542
+ "viewport": {
1543
+ "width": 353,
1544
+ "height": 745
1545
+ },
1546
+ "deviceScaleFactor": 3,
1547
+ "isMobile": true,
1548
+ "hasTouch": true,
1549
+ "defaultBrowserType": "chromium"
1550
+ },
1551
+ "Pixel 4 landscape": {
1552
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1553
+ "viewport": {
1554
+ "width": 745,
1555
+ "height": 353
1556
+ },
1557
+ "deviceScaleFactor": 3,
1558
+ "isMobile": true,
1559
+ "hasTouch": true,
1560
+ "defaultBrowserType": "chromium"
1561
+ },
1562
+ "Pixel 4a (5G)": {
1563
+ "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1564
+ "screen": {
1565
+ "width": 412,
1566
+ "height": 892
1567
+ },
1568
+ "viewport": {
1569
+ "width": 412,
1570
+ "height": 765
1571
+ },
1572
+ "deviceScaleFactor": 2.63,
1573
+ "isMobile": true,
1574
+ "hasTouch": true,
1575
+ "defaultBrowserType": "chromium"
1576
+ },
1577
+ "Pixel 4a (5G) landscape": {
1578
+ "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1579
+ "screen": {
1580
+ "height": 892,
1581
+ "width": 412
1582
+ },
1583
+ "viewport": {
1584
+ "width": 840,
1585
+ "height": 312
1586
+ },
1587
+ "deviceScaleFactor": 2.63,
1588
+ "isMobile": true,
1589
+ "hasTouch": true,
1590
+ "defaultBrowserType": "chromium"
1591
+ },
1592
+ "Pixel 5": {
1593
+ "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1594
+ "screen": {
1595
+ "width": 393,
1596
+ "height": 851
1597
+ },
1598
+ "viewport": {
1599
+ "width": 393,
1600
+ "height": 727
1601
+ },
1602
+ "deviceScaleFactor": 2.75,
1603
+ "isMobile": true,
1604
+ "hasTouch": true,
1605
+ "defaultBrowserType": "chromium"
1606
+ },
1607
+ "Pixel 5 landscape": {
1608
+ "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1609
+ "screen": {
1610
+ "width": 851,
1611
+ "height": 393
1612
+ },
1613
+ "viewport": {
1614
+ "width": 802,
1615
+ "height": 293
1616
+ },
1617
+ "deviceScaleFactor": 2.75,
1618
+ "isMobile": true,
1619
+ "hasTouch": true,
1620
+ "defaultBrowserType": "chromium"
1621
+ },
1622
+ "Pixel 7": {
1623
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1624
+ "screen": {
1625
+ "width": 412,
1626
+ "height": 915
1627
+ },
1628
+ "viewport": {
1629
+ "width": 412,
1630
+ "height": 839
1631
+ },
1632
+ "deviceScaleFactor": 2.625,
1633
+ "isMobile": true,
1634
+ "hasTouch": true,
1635
+ "defaultBrowserType": "chromium"
1636
+ },
1637
+ "Pixel 7 landscape": {
1638
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1639
+ "screen": {
1640
+ "width": 915,
1641
+ "height": 412
1642
+ },
1643
+ "viewport": {
1644
+ "width": 863,
1645
+ "height": 360
1646
+ },
1647
+ "deviceScaleFactor": 2.625,
1648
+ "isMobile": true,
1649
+ "hasTouch": true,
1650
+ "defaultBrowserType": "chromium"
1651
+ },
1652
+ "Moto G4": {
1653
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1654
+ "viewport": {
1655
+ "width": 360,
1656
+ "height": 640
1657
+ },
1658
+ "deviceScaleFactor": 3,
1659
+ "isMobile": true,
1660
+ "hasTouch": true,
1661
+ "defaultBrowserType": "chromium"
1662
+ },
1663
+ "Moto G4 landscape": {
1664
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Mobile Safari/537.36",
1665
+ "viewport": {
1666
+ "width": 640,
1667
+ "height": 360
1668
+ },
1669
+ "deviceScaleFactor": 3,
1670
+ "isMobile": true,
1671
+ "hasTouch": true,
1672
+ "defaultBrowserType": "chromium"
1673
+ },
1674
+ "Desktop Chrome HiDPI": {
1675
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
1676
+ "screen": {
1677
+ "width": 1792,
1678
+ "height": 1120
1679
+ },
1680
+ "viewport": {
1681
+ "width": 1280,
1682
+ "height": 720
1683
+ },
1684
+ "deviceScaleFactor": 2,
1685
+ "isMobile": false,
1686
+ "hasTouch": false,
1687
+ "defaultBrowserType": "chromium"
1688
+ },
1689
+ "Desktop Edge HiDPI": {
1690
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36 Edg/148.0.7778.96",
1691
+ "screen": {
1692
+ "width": 1792,
1693
+ "height": 1120
1694
+ },
1695
+ "viewport": {
1696
+ "width": 1280,
1697
+ "height": 720
1698
+ },
1699
+ "deviceScaleFactor": 2,
1700
+ "isMobile": false,
1701
+ "hasTouch": false,
1702
+ "defaultBrowserType": "chromium"
1703
+ },
1704
+ "Desktop Firefox HiDPI": {
1705
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0.2) Gecko/20100101 Firefox/150.0.2",
1706
+ "screen": {
1707
+ "width": 1792,
1708
+ "height": 1120
1709
+ },
1710
+ "viewport": {
1711
+ "width": 1280,
1712
+ "height": 720
1713
+ },
1714
+ "deviceScaleFactor": 2,
1715
+ "isMobile": false,
1716
+ "hasTouch": false,
1717
+ "defaultBrowserType": "firefox"
1718
+ },
1719
+ "Desktop Safari": {
1720
+ "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Safari/605.1.15",
1721
+ "screen": {
1722
+ "width": 1792,
1723
+ "height": 1120
1724
+ },
1725
+ "viewport": {
1726
+ "width": 1280,
1727
+ "height": 720
1728
+ },
1729
+ "deviceScaleFactor": 2,
1730
+ "isMobile": false,
1731
+ "hasTouch": false,
1732
+ "defaultBrowserType": "webkit"
1733
+ },
1734
+ "Desktop Chrome": {
1735
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36",
1736
+ "screen": {
1737
+ "width": 1920,
1738
+ "height": 1080
1739
+ },
1740
+ "viewport": {
1741
+ "width": 1280,
1742
+ "height": 720
1743
+ },
1744
+ "deviceScaleFactor": 1,
1745
+ "isMobile": false,
1746
+ "hasTouch": false,
1747
+ "defaultBrowserType": "chromium"
1748
+ },
1749
+ "Desktop Edge": {
1750
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.7778.96 Safari/537.36 Edg/148.0.7778.96",
1751
+ "screen": {
1752
+ "width": 1920,
1753
+ "height": 1080
1754
+ },
1755
+ "viewport": {
1756
+ "width": 1280,
1757
+ "height": 720
1758
+ },
1759
+ "deviceScaleFactor": 1,
1760
+ "isMobile": false,
1761
+ "hasTouch": false,
1762
+ "defaultBrowserType": "chromium"
1763
+ },
1764
+ "Desktop Firefox": {
1765
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0.2) Gecko/20100101 Firefox/150.0.2",
1766
+ "screen": {
1767
+ "width": 1920,
1768
+ "height": 1080
1769
+ },
1770
+ "viewport": {
1771
+ "width": 1280,
1772
+ "height": 720
1773
+ },
1774
+ "deviceScaleFactor": 1,
1775
+ "isMobile": false,
1776
+ "hasTouch": false,
1777
+ "defaultBrowserType": "firefox"
1778
+ }
1779
+ }
node_modules/playwright-core/lib/server/electron/loader.js ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+
3
+ // packages/playwright-core/src/server/electron/loader.ts
4
+ var import_electron = require("electron");
5
+
6
+ // packages/playwright-core/src/server/chromium/chromiumSwitches.ts
7
+ var disabledFeatures = [
8
+ // See https://github.com/microsoft/playwright/issues/14047
9
+ "AvoidUnnecessaryBeforeUnloadCheckSync",
10
+ // See https://github.com/microsoft/playwright/issues/38568
11
+ "BoundaryEventDispatchTracksNodeRemoval",
12
+ "DestroyProfileOnBrowserClose",
13
+ // See https://github.com/microsoft/playwright/pull/13854
14
+ "DialMediaRouteProvider",
15
+ "GlobalMediaControls",
16
+ // See https://github.com/microsoft/playwright/pull/27605
17
+ "HttpsUpgrades",
18
+ // Hides the Lens feature in the URL address bar. Its not working in unofficial builds.
19
+ "LensOverlay",
20
+ // See https://github.com/microsoft/playwright/pull/8162
21
+ "MediaRouter",
22
+ // See https://github.com/microsoft/playwright/issues/28023
23
+ "PaintHolding",
24
+ // See https://github.com/microsoft/playwright/issues/32230
25
+ "ThirdPartyStoragePartitioning",
26
+ // See https://github.com/microsoft/playwright/issues/16126
27
+ "Translate",
28
+ // See https://issues.chromium.org/u/1/issues/435410220
29
+ "AutoDeElevate",
30
+ // See https://github.com/microsoft/playwright/issues/37714
31
+ "RenderDocument",
32
+ // Prevents downloading optimization hints on startup.
33
+ "OptimizationHints",
34
+ // Disables forced sign-in in Edge.
35
+ "msForceBrowserSignIn",
36
+ // Disables updating the preferred version in LaunchServices preferences on mac.
37
+ "msEdgeUpdateLaunchServicesPreferredVersion"
38
+ ].filter(Boolean);
39
+ var chromiumSwitches = (options) => [
40
+ "--disable-field-trial-config",
41
+ // https://source.chromium.org/chromium/chromium/src/+/main:testing/variations/README.md
42
+ "--disable-background-networking",
43
+ "--disable-background-timer-throttling",
44
+ "--disable-backgrounding-occluded-windows",
45
+ "--disable-back-forward-cache",
46
+ // Avoids surprises like main request not being intercepted during page.goBack().
47
+ "--disable-breakpad",
48
+ "--disable-client-side-phishing-detection",
49
+ "--disable-component-extensions-with-background-pages",
50
+ "--disable-component-update",
51
+ // Avoids unneeded network activity after startup.
52
+ "--no-default-browser-check",
53
+ "--disable-default-apps",
54
+ "--disable-dev-shm-usage",
55
+ "--disable-edgeupdater",
56
+ // Disables Edge-specific updater on mac.
57
+ "--disable-extensions",
58
+ "--disable-features=" + disabledFeatures.join(","),
59
+ process.env.PLAYWRIGHT_LEGACY_SCREENSHOT ? "" : "--enable-features=CDPScreenshotNewSurface",
60
+ "--allow-pre-commit-input",
61
+ "--disable-hang-monitor",
62
+ "--disable-ipc-flooding-protection",
63
+ "--disable-popup-blocking",
64
+ "--disable-prompt-on-repost",
65
+ "--disable-renderer-backgrounding",
66
+ "--force-color-profile=srgb",
67
+ "--metrics-recording-only",
68
+ "--no-first-run",
69
+ "--password-store=basic",
70
+ "--use-mock-keychain",
71
+ // See https://chromium-review.googlesource.com/c/chromium/src/+/2436773
72
+ "--no-service-autorun",
73
+ "--export-tagged-pdf",
74
+ // https://chromium-review.googlesource.com/c/chromium/src/+/4853540
75
+ "--disable-search-engine-choice-screen",
76
+ // https://issues.chromium.org/41491762
77
+ "--unsafely-disable-devtools-self-xss-warnings",
78
+ // Edge can potentially restart on Windows (msRelaunchNoCompatLayer) which looses its file descriptors (stdout/stderr) and CDP (3/4). Disable until fixed upstream.
79
+ "--edge-skip-compat-layer-relaunch",
80
+ // This disables Chrome for Testing infobar that is visible in the persistent context.
81
+ // The switch is ignored everywhere else, including Chromium/Chrome/Edge.
82
+ "--disable-infobars",
83
+ // Less annoying popups.
84
+ "--disable-search-engine-choice-screen",
85
+ // Prevents the "three dots" menu crash in IdentityManager::HasPrimaryAccount for ephemeral contexts.
86
+ options?.android ? "" : "--disable-sync"
87
+ ].filter(Boolean);
88
+
89
+ // packages/playwright-core/src/server/electron/loader.ts
90
+ process.argv.splice(1, process.argv.indexOf("--remote-debugging-port=0"));
91
+ for (const arg of chromiumSwitches()) {
92
+ const match = arg.match(/--([^=]*)=?(.*)/);
93
+ import_electron.app.commandLine.appendSwitch(match[1], match[2]);
94
+ }
95
+ var originalWhenReady = import_electron.app.whenReady();
96
+ var originalEmit = import_electron.app.emit.bind(import_electron.app);
97
+ var readyEventArgs;
98
+ import_electron.app.emit = (event, ...args) => {
99
+ if (event === "ready") {
100
+ readyEventArgs = args;
101
+ return import_electron.app.listenerCount("ready") > 0;
102
+ }
103
+ return originalEmit(event, ...args);
104
+ };
105
+ var isReady = false;
106
+ var whenReadyCallback;
107
+ var whenReadyPromise = new Promise((f) => whenReadyCallback = f);
108
+ import_electron.app.isReady = () => isReady;
109
+ import_electron.app.whenReady = () => whenReadyPromise;
110
+ globalThis.__playwright_run = async () => {
111
+ const event = await originalWhenReady;
112
+ isReady = true;
113
+ whenReadyCallback(event);
114
+ originalEmit("ready", ...readyEventArgs);
115
+ };
node_modules/playwright-core/lib/serverRegistry.js ADDED
The diff for this file is too large to render. See raw diff
 
node_modules/playwright-core/lib/serverRegistry.js.LICENSE ADDED
@@ -0,0 +1,354 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ packages/playwright-core/lib/serverRegistry.js
2
+
3
+ THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
4
+
5
+ The following npm packages are inlined into this bundle.
6
+
7
+ - anymatch@3.1.3 (https://github.com/micromatch/anymatch)
8
+ - binary-extensions@2.3.0 (https://github.com/sindresorhus/binary-extensions)
9
+ - braces@3.0.3 (https://github.com/micromatch/braces)
10
+ - chokidar@3.6.0 (https://github.com/paulmillr/chokidar)
11
+ - fill-range@7.1.1 (https://github.com/jonschlinkert/fill-range)
12
+ - glob-parent@5.1.2 (https://github.com/gulpjs/glob-parent)
13
+ - is-binary-path@2.1.0 (https://github.com/sindresorhus/is-binary-path)
14
+ - is-extglob@2.1.1 (https://github.com/jonschlinkert/is-extglob)
15
+ - is-glob@4.0.3 (https://github.com/micromatch/is-glob)
16
+ - is-number@7.0.0 (https://github.com/jonschlinkert/is-number)
17
+ - normalize-path@3.0.0 (https://github.com/jonschlinkert/normalize-path)
18
+ - picomatch@2.3.2 (https://github.com/micromatch/picomatch)
19
+ - readdirp@3.6.0 (https://github.com/paulmillr/readdirp)
20
+ - to-regex-range@5.0.1 (https://github.com/micromatch/to-regex-range)
21
+
22
+ %% anymatch@3.1.3 NOTICES AND INFORMATION BEGIN HERE
23
+ =========================================
24
+ The ISC License
25
+
26
+ Copyright (c) 2019 Elan Shanker, Paul Miller (https://paulmillr.com)
27
+
28
+ Permission to use, copy, modify, and/or distribute this software for any
29
+ purpose with or without fee is hereby granted, provided that the above
30
+ copyright notice and this permission notice appear in all copies.
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
33
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
34
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
35
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
36
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
37
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
38
+ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
39
+ =========================================
40
+ END OF anymatch@3.1.3 NOTICES AND INFORMATION
41
+
42
+ %% binary-extensions@2.3.0 NOTICES AND INFORMATION BEGIN HERE
43
+ =========================================
44
+ MIT License
45
+
46
+ Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
47
+ Copyright (c) Paul Miller (https://paulmillr.com)
48
+
49
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
54
+ =========================================
55
+ END OF binary-extensions@2.3.0 NOTICES AND INFORMATION
56
+
57
+ %% braces@3.0.3 NOTICES AND INFORMATION BEGIN HERE
58
+ =========================================
59
+ The MIT License (MIT)
60
+
61
+ Copyright (c) 2014-present, Jon Schlinkert.
62
+
63
+ Permission is hereby granted, free of charge, to any person obtaining a copy
64
+ of this software and associated documentation files (the "Software"), to deal
65
+ in the Software without restriction, including without limitation the rights
66
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
67
+ copies of the Software, and to permit persons to whom the Software is
68
+ furnished to do so, subject to the following conditions:
69
+
70
+ The above copyright notice and this permission notice shall be included in
71
+ all copies or substantial portions of the Software.
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
75
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
76
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
77
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
78
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
79
+ THE SOFTWARE.
80
+ =========================================
81
+ END OF braces@3.0.3 NOTICES AND INFORMATION
82
+
83
+ %% chokidar@3.6.0 NOTICES AND INFORMATION BEGIN HERE
84
+ =========================================
85
+ The MIT License (MIT)
86
+
87
+ Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker
88
+
89
+ Permission is hereby granted, free of charge, to any person obtaining a copy
90
+ of this software and associated documentation files (the “Software”), to deal
91
+ in the Software without restriction, including without limitation the rights
92
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
93
+ copies of the Software, and to permit persons to whom the Software is
94
+ furnished to do so, subject to the following conditions:
95
+
96
+ The above copyright notice and this permission notice shall be included in
97
+ all copies or substantial portions of the Software.
98
+
99
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
100
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
101
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
102
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
103
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
104
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
105
+ THE SOFTWARE.
106
+ =========================================
107
+ END OF chokidar@3.6.0 NOTICES AND INFORMATION
108
+
109
+ %% fill-range@7.1.1 NOTICES AND INFORMATION BEGIN HERE
110
+ =========================================
111
+ The MIT License (MIT)
112
+
113
+ Copyright (c) 2014-present, Jon Schlinkert.
114
+
115
+ Permission is hereby granted, free of charge, to any person obtaining a copy
116
+ of this software and associated documentation files (the "Software"), to deal
117
+ in the Software without restriction, including without limitation the rights
118
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
119
+ copies of the Software, and to permit persons to whom the Software is
120
+ furnished to do so, subject to the following conditions:
121
+
122
+ The above copyright notice and this permission notice shall be included in
123
+ all copies or substantial portions of the Software.
124
+
125
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
126
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
127
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
128
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
129
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
130
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
131
+ THE SOFTWARE.
132
+ =========================================
133
+ END OF fill-range@7.1.1 NOTICES AND INFORMATION
134
+
135
+ %% glob-parent@5.1.2 NOTICES AND INFORMATION BEGIN HERE
136
+ =========================================
137
+ The ISC License
138
+
139
+ Copyright (c) 2015, 2019 Elan Shanker
140
+
141
+ Permission to use, copy, modify, and/or distribute this software for any
142
+ purpose with or without fee is hereby granted, provided that the above
143
+ copyright notice and this permission notice appear in all copies.
144
+
145
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
146
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
147
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
148
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
149
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
150
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
151
+ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
152
+ =========================================
153
+ END OF glob-parent@5.1.2 NOTICES AND INFORMATION
154
+
155
+ %% is-binary-path@2.1.0 NOTICES AND INFORMATION BEGIN HERE
156
+ =========================================
157
+ MIT License
158
+
159
+ Copyright (c) 2019 Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com), Paul Miller (https://paulmillr.com)
160
+
161
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
162
+
163
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
164
+
165
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
166
+ =========================================
167
+ END OF is-binary-path@2.1.0 NOTICES AND INFORMATION
168
+
169
+ %% is-extglob@2.1.1 NOTICES AND INFORMATION BEGIN HERE
170
+ =========================================
171
+ The MIT License (MIT)
172
+
173
+ Copyright (c) 2014-2016, Jon Schlinkert
174
+
175
+ Permission is hereby granted, free of charge, to any person obtaining a copy
176
+ of this software and associated documentation files (the "Software"), to deal
177
+ in the Software without restriction, including without limitation the rights
178
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
179
+ copies of the Software, and to permit persons to whom the Software is
180
+ furnished to do so, subject to the following conditions:
181
+
182
+ The above copyright notice and this permission notice shall be included in
183
+ all copies or substantial portions of the Software.
184
+
185
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
186
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
188
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
189
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
190
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
191
+ THE SOFTWARE.
192
+ =========================================
193
+ END OF is-extglob@2.1.1 NOTICES AND INFORMATION
194
+
195
+ %% is-glob@4.0.3 NOTICES AND INFORMATION BEGIN HERE
196
+ =========================================
197
+ The MIT License (MIT)
198
+
199
+ Copyright (c) 2014-2017, Jon Schlinkert.
200
+
201
+ Permission is hereby granted, free of charge, to any person obtaining a copy
202
+ of this software and associated documentation files (the "Software"), to deal
203
+ in the Software without restriction, including without limitation the rights
204
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
205
+ copies of the Software, and to permit persons to whom the Software is
206
+ furnished to do so, subject to the following conditions:
207
+
208
+ The above copyright notice and this permission notice shall be included in
209
+ all copies or substantial portions of the Software.
210
+
211
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
212
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
213
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
214
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
215
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
216
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
217
+ THE SOFTWARE.
218
+ =========================================
219
+ END OF is-glob@4.0.3 NOTICES AND INFORMATION
220
+
221
+ %% is-number@7.0.0 NOTICES AND INFORMATION BEGIN HERE
222
+ =========================================
223
+ The MIT License (MIT)
224
+
225
+ Copyright (c) 2014-present, Jon Schlinkert.
226
+
227
+ Permission is hereby granted, free of charge, to any person obtaining a copy
228
+ of this software and associated documentation files (the "Software"), to deal
229
+ in the Software without restriction, including without limitation the rights
230
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
231
+ copies of the Software, and to permit persons to whom the Software is
232
+ furnished to do so, subject to the following conditions:
233
+
234
+ The above copyright notice and this permission notice shall be included in
235
+ all copies or substantial portions of the Software.
236
+
237
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
238
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
239
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
240
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
241
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
242
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
243
+ THE SOFTWARE.
244
+ =========================================
245
+ END OF is-number@7.0.0 NOTICES AND INFORMATION
246
+
247
+ %% normalize-path@3.0.0 NOTICES AND INFORMATION BEGIN HERE
248
+ =========================================
249
+ The MIT License (MIT)
250
+
251
+ Copyright (c) 2014-2018, Jon Schlinkert.
252
+
253
+ Permission is hereby granted, free of charge, to any person obtaining a copy
254
+ of this software and associated documentation files (the "Software"), to deal
255
+ in the Software without restriction, including without limitation the rights
256
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
257
+ copies of the Software, and to permit persons to whom the Software is
258
+ furnished to do so, subject to the following conditions:
259
+
260
+ The above copyright notice and this permission notice shall be included in
261
+ all copies or substantial portions of the Software.
262
+
263
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
264
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
265
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
266
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
267
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
268
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
269
+ THE SOFTWARE.
270
+ =========================================
271
+ END OF normalize-path@3.0.0 NOTICES AND INFORMATION
272
+
273
+ %% picomatch@2.3.2 NOTICES AND INFORMATION BEGIN HERE
274
+ =========================================
275
+ The MIT License (MIT)
276
+
277
+ Copyright (c) 2017-present, Jon Schlinkert.
278
+
279
+ Permission is hereby granted, free of charge, to any person obtaining a copy
280
+ of this software and associated documentation files (the "Software"), to deal
281
+ in the Software without restriction, including without limitation the rights
282
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
283
+ copies of the Software, and to permit persons to whom the Software is
284
+ furnished to do so, subject to the following conditions:
285
+
286
+ The above copyright notice and this permission notice shall be included in
287
+ all copies or substantial portions of the Software.
288
+
289
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
290
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
291
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
292
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
293
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
294
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
295
+ THE SOFTWARE.
296
+ =========================================
297
+ END OF picomatch@2.3.2 NOTICES AND INFORMATION
298
+
299
+ %% readdirp@3.6.0 NOTICES AND INFORMATION BEGIN HERE
300
+ =========================================
301
+ MIT License
302
+
303
+ Copyright (c) 2012-2019 Thorsten Lorenz, Paul Miller (https://paulmillr.com)
304
+
305
+ Permission is hereby granted, free of charge, to any person obtaining a copy
306
+ of this software and associated documentation files (the "Software"), to deal
307
+ in the Software without restriction, including without limitation the rights
308
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
309
+ copies of the Software, and to permit persons to whom the Software is
310
+ furnished to do so, subject to the following conditions:
311
+
312
+ The above copyright notice and this permission notice shall be included in all
313
+ copies or substantial portions of the Software.
314
+
315
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
316
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
317
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
318
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
319
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
320
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
321
+ SOFTWARE.
322
+ =========================================
323
+ END OF readdirp@3.6.0 NOTICES AND INFORMATION
324
+
325
+ %% to-regex-range@5.0.1 NOTICES AND INFORMATION BEGIN HERE
326
+ =========================================
327
+ The MIT License (MIT)
328
+
329
+ Copyright (c) 2015-present, Jon Schlinkert.
330
+
331
+ Permission is hereby granted, free of charge, to any person obtaining a copy
332
+ of this software and associated documentation files (the "Software"), to deal
333
+ in the Software without restriction, including without limitation the rights
334
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
335
+ copies of the Software, and to permit persons to whom the Software is
336
+ furnished to do so, subject to the following conditions:
337
+
338
+ The above copyright notice and this permission notice shall be included in
339
+ all copies or substantial portions of the Software.
340
+
341
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
342
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
343
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
344
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
345
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
346
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
347
+ THE SOFTWARE.
348
+ =========================================
349
+ END OF to-regex-range@5.0.1 NOTICES AND INFORMATION
350
+
351
+ SUMMARY
352
+ =========================================
353
+ Total Packages: 14
354
+ =========================================
node_modules/playwright-core/lib/tools/cli-client/channelSessions.js ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var channelSessions_exports = {};
30
+ __export(channelSessions_exports, {
31
+ isKnownChannel: () => isKnownChannel,
32
+ listChannelSessions: () => listChannelSessions
33
+ });
34
+ module.exports = __toCommonJS(channelSessions_exports);
35
+ var import_fs = __toESM(require("fs"));
36
+ var import_net = __toESM(require("net"));
37
+ var import_os = __toESM(require("os"));
38
+ var import_path = __toESM(require("path"));
39
+ var import_extension = require("../utils/extension");
40
+ function isKnownChannel(name) {
41
+ return channelToUserDataDir.has(name);
42
+ }
43
+ async function listChannelSessions() {
44
+ if (process.env.PWTEST_CLI_CHANNEL_SCAN_DISABLED_FOR_TEST)
45
+ return [];
46
+ const result = [];
47
+ for (const [channel, dirs] of channelToUserDataDir) {
48
+ const userDataDir = dirs[process.platform];
49
+ if (!userDataDir)
50
+ continue;
51
+ if (!await pathExists(userDataDir))
52
+ continue;
53
+ const [endpoint, extensionInstalled] = await Promise.all([
54
+ readEndpoint(userDataDir),
55
+ (0, import_extension.isPlaywrightExtensionInstalled)(userDataDir)
56
+ ]);
57
+ result.push({ channel, userDataDir, endpoint, extensionInstalled });
58
+ }
59
+ return result;
60
+ }
61
+ async function pathExists(p) {
62
+ try {
63
+ await import_fs.default.promises.access(p);
64
+ return true;
65
+ } catch {
66
+ return false;
67
+ }
68
+ }
69
+ async function readEndpoint(userDataDir) {
70
+ let contents;
71
+ try {
72
+ contents = await import_fs.default.promises.readFile(import_path.default.join(userDataDir, "DevToolsActivePort"), "utf-8");
73
+ } catch {
74
+ return void 0;
75
+ }
76
+ const port = parseInt(contents.trim().split("\n")[0], 10);
77
+ if (!Number.isFinite(port))
78
+ return void 0;
79
+ if (!await isPortOpen(port))
80
+ return void 0;
81
+ return `http://localhost:${port}`;
82
+ }
83
+ async function isPortOpen(port) {
84
+ return new Promise((resolve) => {
85
+ const socket = import_net.default.createConnection(port, "127.0.0.1");
86
+ const done = (value) => {
87
+ socket.destroy();
88
+ resolve(value);
89
+ };
90
+ socket.once("connect", () => done(true));
91
+ socket.once("error", () => done(false));
92
+ socket.setTimeout(250, () => done(false));
93
+ });
94
+ }
95
+ const channelToUserDataDir = /* @__PURE__ */ new Map([
96
+ ["chrome", {
97
+ "linux": import_path.default.join(import_os.default.homedir(), ".config", "google-chrome"),
98
+ "darwin": import_path.default.join(import_os.default.homedir(), "Library", "Application Support", "Google", "Chrome"),
99
+ "win32": import_path.default.join(process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"), "Google", "Chrome", "User Data")
100
+ }],
101
+ ["chrome-beta", {
102
+ "linux": import_path.default.join(import_os.default.homedir(), ".config", "google-chrome-beta"),
103
+ "darwin": import_path.default.join(import_os.default.homedir(), "Library", "Application Support", "Google", "Chrome Beta"),
104
+ "win32": import_path.default.join(process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"), "Google", "Chrome Beta", "User Data")
105
+ }],
106
+ ["chrome-dev", {
107
+ "linux": import_path.default.join(import_os.default.homedir(), ".config", "google-chrome-unstable"),
108
+ "darwin": import_path.default.join(import_os.default.homedir(), "Library", "Application Support", "Google", "Chrome Dev"),
109
+ "win32": import_path.default.join(process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"), "Google", "Chrome Dev", "User Data")
110
+ }],
111
+ ["chrome-canary", {
112
+ "linux": import_path.default.join(import_os.default.homedir(), ".config", "google-chrome-canary"),
113
+ "darwin": import_path.default.join(import_os.default.homedir(), "Library", "Application Support", "Google", "Chrome Canary"),
114
+ "win32": import_path.default.join(process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"), "Google", "Chrome SxS", "User Data")
115
+ }],
116
+ ["msedge", {
117
+ "linux": import_path.default.join(import_os.default.homedir(), ".config", "microsoft-edge"),
118
+ "darwin": import_path.default.join(import_os.default.homedir(), "Library", "Application Support", "Microsoft Edge"),
119
+ "win32": import_path.default.join(process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"), "Microsoft", "Edge", "User Data")
120
+ }],
121
+ ["msedge-beta", {
122
+ "linux": import_path.default.join(import_os.default.homedir(), ".config", "microsoft-edge-beta"),
123
+ "darwin": import_path.default.join(import_os.default.homedir(), "Library", "Application Support", "Microsoft Edge Beta"),
124
+ "win32": import_path.default.join(process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"), "Microsoft", "Edge Beta", "User Data")
125
+ }],
126
+ ["msedge-dev", {
127
+ "linux": import_path.default.join(import_os.default.homedir(), ".config", "microsoft-edge-dev"),
128
+ "darwin": import_path.default.join(import_os.default.homedir(), "Library", "Application Support", "Microsoft Edge Dev"),
129
+ "win32": import_path.default.join(process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"), "Microsoft", "Edge Dev", "User Data")
130
+ }],
131
+ ["msedge-canary", {
132
+ "linux": import_path.default.join(import_os.default.homedir(), ".config", "microsoft-edge-canary"),
133
+ "darwin": import_path.default.join(import_os.default.homedir(), "Library", "Application Support", "Microsoft Edge Canary"),
134
+ "win32": import_path.default.join(process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"), "Microsoft", "Edge SxS", "User Data")
135
+ }]
136
+ ]);
137
+ // Annotate the CommonJS export names for ESM import in node:
138
+ 0 && (module.exports = {
139
+ isKnownChannel,
140
+ listChannelSessions
141
+ });
node_modules/playwright-core/lib/tools/cli-client/cli.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ "use strict";
2
+ var import_program = require("./program");
3
+ (0, import_program.program)().catch((e) => {
4
+ console.error(e.message);
5
+ process.exit(1);
6
+ });