chrome-devtools-mcp 0.0.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +6 -3
  2. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Settings.js +3 -32
  3. package/build/node_modules/chrome-devtools-frontend/front_end/core/i18n/i18n.js +35 -8
  4. package/build/node_modules/chrome-devtools-frontend/front_end/core/root/Runtime.js +4 -1
  5. package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +4 -4
  6. package/build/node_modules/chrome-devtools-frontend/front_end/generated/SupportedCSSProperties.js +12 -0
  7. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.js +366 -0
  8. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AICallTree.js +366 -0
  9. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AIContext.js +64 -0
  10. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AIQueries.js +105 -0
  11. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CSSWorkspaceBinding.js +243 -0
  12. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +407 -0
  13. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/ContentProviderBasedProject.js +128 -0
  14. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/DebuggerLanguagePlugins.js +992 -0
  15. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/DebuggerWorkspaceBinding.js +574 -0
  16. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/DefaultScriptMapping.js +112 -0
  17. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/FileUtils.js +186 -0
  18. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/LiveLocation.js +60 -0
  19. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/NetworkProject.js +107 -0
  20. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/PresentationConsoleMessageHelper.js +244 -0
  21. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/ResourceMapping.js +473 -0
  22. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/ResourceScriptMapping.js +399 -0
  23. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/ResourceUtils.js +87 -0
  24. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/SASSSourceMapping.js +181 -0
  25. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/StylesSourceMapping.js +268 -0
  26. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/TempFile.js +55 -0
  27. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/bindings.js +20 -0
  28. package/build/node_modules/chrome-devtools-frontend/front_end/models/crux-manager/CrUXManager.js +283 -0
  29. package/build/node_modules/chrome-devtools-frontend/front_end/models/crux-manager/crux-manager.js +4 -0
  30. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/DeviceModeModel.js +775 -0
  31. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/EmulatedDevices.js +1706 -0
  32. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/emulation.js +6 -0
  33. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +131 -0
  34. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/ScriptFormatter.js +77 -0
  35. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/formatter.js +6 -0
  36. package/build/node_modules/chrome-devtools-frontend/front_end/models/geometry/GeometryImpl.js +347 -0
  37. package/build/node_modules/chrome-devtools-frontend/front_end/models/geometry/geometry.js +4 -0
  38. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/NamesResolver.js +626 -0
  39. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/ScopeChainModel.js +59 -0
  40. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/ScopeTreeCache.js +32 -0
  41. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/source_map_scopes.js +7 -0
  42. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTrace.js +4 -0
  43. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceImpl.js +67 -0
  44. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceModel.js +97 -0
  45. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/Trie.js +113 -0
  46. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/stack_trace.js +5 -0
  47. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/stack_trace_impl.js +7 -0
  48. package/build/node_modules/chrome-devtools-frontend/front_end/models/text_utils/TextUtils.js +23 -0
  49. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Processor.js +1 -1
  50. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/helpers/Trace.js +1 -1
  51. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DocumentLatency.js +5 -4
  52. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace_source_maps_resolver/SourceMapsResolver.js +199 -0
  53. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace_source_maps_resolver/trace_source_maps_resolver.js +4 -0
  54. package/build/node_modules/chrome-devtools-frontend/front_end/models/workspace/FileManager.js +64 -0
  55. package/build/node_modules/chrome-devtools-frontend/front_end/models/workspace/IgnoreListManager.js +511 -0
  56. package/build/node_modules/chrome-devtools-frontend/front_end/models/workspace/SearchConfig.js +113 -0
  57. package/build/node_modules/chrome-devtools-frontend/front_end/models/workspace/UISourceCode.js +563 -0
  58. package/build/node_modules/chrome-devtools-frontend/front_end/models/workspace/WorkspaceImpl.js +204 -0
  59. package/build/node_modules/chrome-devtools-frontend/front_end/models/workspace/workspace.js +9 -0
  60. package/build/src/McpContext.js +24 -9
  61. package/build/src/McpResponse.js +3 -3
  62. package/build/src/browser.js +3 -1
  63. package/build/src/index.js +1 -1
  64. package/build/src/tools/input.js +7 -7
  65. package/build/src/tools/performance.js +29 -2
  66. package/build/src/tools/screenshot.js +1 -1
  67. package/build/src/tools/script.js +40 -14
  68. package/build/src/trace-processing/parse.js +26 -22
  69. package/package.json +9 -7
@@ -0,0 +1,1706 @@
1
+ // Copyright 2014 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+ // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
5
+ /* eslint-disable @typescript-eslint/no-explicit-any */
6
+ import * as Common from '../../core/common/common.js';
7
+ import * as i18n from '../../core/i18n/i18n.js';
8
+ import * as SDK from '../../core/sdk/sdk.js';
9
+ import { Insets, MaxDeviceSize, MinDeviceSize } from './DeviceModeModel.js';
10
+ const UIStrings = {
11
+ /**
12
+ * @description Title of the Laptop with touch device
13
+ */
14
+ laptopWithTouch: 'Laptop with touch',
15
+ /**
16
+ * @description Title of the Laptop with HiDPI screen device
17
+ */
18
+ laptopWithHiDPIScreen: 'Laptop with HiDPI screen',
19
+ /**
20
+ * @description Title of the Laptop with MDPI screen device
21
+ */
22
+ laptopWithMDPIScreen: 'Laptop with MDPI screen',
23
+ };
24
+ const str_ = i18n.i18n.registerUIStrings('models/emulation/EmulatedDevices.ts', UIStrings);
25
+ const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
26
+ export function computeRelativeImageURL(cssURLValue) {
27
+ return cssURLValue.replace(/@url\(([^\)]*?)\)/g, (_match, url) => {
28
+ return new URL(`../../emulated_devices/${url}`, import.meta.url).toString();
29
+ });
30
+ }
31
+ export class EmulatedDevice {
32
+ title;
33
+ type;
34
+ order;
35
+ vertical;
36
+ horizontal;
37
+ deviceScaleFactor;
38
+ capabilities;
39
+ userAgent;
40
+ userAgentMetadata;
41
+ modes;
42
+ isDualScreen;
43
+ isFoldableScreen;
44
+ verticalSpanned;
45
+ horizontalSpanned;
46
+ #show;
47
+ #showByDefault;
48
+ constructor() {
49
+ this.title = '';
50
+ this.type = Type.Unknown;
51
+ this.vertical = { width: 0, height: 0, outlineInsets: null, outlineImage: null, hinge: null };
52
+ this.horizontal = { width: 0, height: 0, outlineInsets: null, outlineImage: null, hinge: null };
53
+ this.deviceScaleFactor = 1;
54
+ this.capabilities = ["touch" /* Capability.TOUCH */, "mobile" /* Capability.MOBILE */];
55
+ this.userAgent = '';
56
+ this.userAgentMetadata = null;
57
+ this.modes = [];
58
+ this.isDualScreen = false;
59
+ this.isFoldableScreen = false;
60
+ this.verticalSpanned = { width: 0, height: 0, outlineInsets: null, outlineImage: null, hinge: null };
61
+ this.horizontalSpanned = { width: 0, height: 0, outlineInsets: null, outlineImage: null, hinge: null };
62
+ this.#show = Show.Default;
63
+ this.#showByDefault = true;
64
+ }
65
+ static fromJSONV1(json) {
66
+ try {
67
+ function parseValue(object, key, type, defaultValue) {
68
+ if (typeof object !== 'object' || object === null || !object.hasOwnProperty(key)) {
69
+ if (typeof defaultValue !== 'undefined') {
70
+ return defaultValue;
71
+ }
72
+ throw new Error('Emulated device is missing required property \'' + key + '\'');
73
+ }
74
+ const value = object[key];
75
+ if (typeof value !== type || value === null) {
76
+ throw new Error('Emulated device property \'' + key + '\' has wrong type \'' + typeof value + '\'');
77
+ }
78
+ return value;
79
+ }
80
+ function parseIntValue(object, key) {
81
+ const value = parseValue(object, key, 'number');
82
+ if (value !== Math.abs(value)) {
83
+ throw new Error('Emulated device value \'' + key + '\' must be integer');
84
+ }
85
+ return value;
86
+ }
87
+ function parseInsets(json) {
88
+ return new Insets(parseIntValue(json, 'left'), parseIntValue(json, 'top'), parseIntValue(json, 'right'), parseIntValue(json, 'bottom'));
89
+ }
90
+ function parseRGBA(json) {
91
+ const result = {};
92
+ result.r = parseIntValue(json, 'r');
93
+ if (result.r < 0 || result.r > 255) {
94
+ throw new Error('color has wrong r value: ' + result.r);
95
+ }
96
+ result.g = parseIntValue(json, 'g');
97
+ if (result.g < 0 || result.g > 255) {
98
+ throw new Error('color has wrong g value: ' + result.g);
99
+ }
100
+ result.b = parseIntValue(json, 'b');
101
+ if (result.b < 0 || result.b > 255) {
102
+ throw new Error('color has wrong b value: ' + result.b);
103
+ }
104
+ result.a = parseValue(json, 'a', 'number');
105
+ if (result.a < 0 || result.a > 1) {
106
+ throw new Error('color has wrong a value: ' + result.a);
107
+ }
108
+ return result;
109
+ }
110
+ function parseHinge(json) {
111
+ const result = {};
112
+ result.width = parseIntValue(json, 'width');
113
+ if (result.width < 0 || result.width > MaxDeviceSize) {
114
+ throw new Error('Emulated device has wrong hinge width: ' + result.width);
115
+ }
116
+ result.height = parseIntValue(json, 'height');
117
+ if (result.height < 0 || result.height > MaxDeviceSize) {
118
+ throw new Error('Emulated device has wrong hinge height: ' + result.height);
119
+ }
120
+ result.x = parseIntValue(json, 'x');
121
+ if (result.x < 0 || result.x > MaxDeviceSize) {
122
+ throw new Error('Emulated device has wrong x offset: ' + result.height);
123
+ }
124
+ result.y = parseIntValue(json, 'y');
125
+ if (result.x < 0 || result.x > MaxDeviceSize) {
126
+ throw new Error('Emulated device has wrong y offset: ' + result.height);
127
+ }
128
+ if (json['contentColor']) {
129
+ result.contentColor = parseRGBA(json['contentColor']);
130
+ }
131
+ if (json['outlineColor']) {
132
+ result.outlineColor = parseRGBA(json['outlineColor']);
133
+ }
134
+ return result;
135
+ }
136
+ function parseOrientation(json) {
137
+ const result = {};
138
+ result.width = parseIntValue(json, 'width');
139
+ if (result.width < 0 || result.width > MaxDeviceSize || result.width < MinDeviceSize) {
140
+ throw new Error('Emulated device has wrong width: ' + result.width);
141
+ }
142
+ result.height = parseIntValue(json, 'height');
143
+ if (result.height < 0 || result.height > MaxDeviceSize || result.height < MinDeviceSize) {
144
+ throw new Error('Emulated device has wrong height: ' + result.height);
145
+ }
146
+ const outlineInsets = parseValue(json['outline'], 'insets', 'object', null);
147
+ if (outlineInsets) {
148
+ result.outlineInsets = parseInsets(outlineInsets);
149
+ if (result.outlineInsets.left < 0 || result.outlineInsets.top < 0) {
150
+ throw new Error('Emulated device has wrong outline insets');
151
+ }
152
+ result.outlineImage = parseValue(json['outline'], 'image', 'string');
153
+ }
154
+ if (json['hinge']) {
155
+ result.hinge = parseHinge(parseValue(json, 'hinge', 'object', undefined));
156
+ }
157
+ return result;
158
+ }
159
+ const result = new EmulatedDevice();
160
+ result.title = parseValue(json, 'title', 'string');
161
+ const type = parseValue(json, 'type', 'string');
162
+ if (!Object.values(Type).includes(type)) {
163
+ throw new Error('Emulated device has wrong type: ' + type);
164
+ }
165
+ result.type = type;
166
+ result.order = parseValue(json, 'order', 'number', 0);
167
+ const rawUserAgent = parseValue(json, 'user-agent', 'string');
168
+ result.userAgent = SDK.NetworkManager.MultitargetNetworkManager.patchUserAgentWithChromeVersion(rawUserAgent);
169
+ result.userAgentMetadata = parseValue(json, 'user-agent-metadata', 'object', null);
170
+ const capabilities = parseValue(json, 'capabilities', 'object', []);
171
+ if (!Array.isArray(capabilities)) {
172
+ throw new Error('Emulated device capabilities must be an array');
173
+ }
174
+ result.capabilities = [];
175
+ for (let i = 0; i < capabilities.length; ++i) {
176
+ if (typeof capabilities[i] !== 'string') {
177
+ throw new Error('Emulated device capability must be a string');
178
+ }
179
+ result.capabilities.push(capabilities[i]);
180
+ }
181
+ result.deviceScaleFactor = parseValue(json['screen'], 'device-pixel-ratio', 'number');
182
+ if (result.deviceScaleFactor < 0 || result.deviceScaleFactor > 100) {
183
+ throw new Error('Emulated device has wrong deviceScaleFactor: ' + result.deviceScaleFactor);
184
+ }
185
+ result.vertical = parseOrientation(parseValue(json['screen'], 'vertical', 'object'));
186
+ result.horizontal = parseOrientation(parseValue(json['screen'], 'horizontal', 'object'));
187
+ result.isDualScreen = parseValue(json, 'dual-screen', 'boolean', false);
188
+ result.isFoldableScreen = parseValue(json, 'foldable-screen', 'boolean', false);
189
+ if (result.isDualScreen || result.isFoldableScreen) {
190
+ result.verticalSpanned = parseOrientation(parseValue(json['screen'], 'vertical-spanned', 'object', null));
191
+ result.horizontalSpanned = parseOrientation(parseValue(json['screen'], 'horizontal-spanned', 'object', null));
192
+ }
193
+ if ((result.isDualScreen || result.isFoldableScreen) && (!result.verticalSpanned || !result.horizontalSpanned)) {
194
+ throw new Error('Emulated device \'' + result.title + '\'has dual screen without spanned orientations');
195
+ }
196
+ const modes = parseValue(json, 'modes', 'object', [
197
+ { title: 'default', orientation: 'vertical' },
198
+ { title: 'default', orientation: 'horizontal' },
199
+ ]);
200
+ if (!Array.isArray(modes)) {
201
+ throw new Error('Emulated device modes must be an array');
202
+ }
203
+ result.modes = [];
204
+ for (let i = 0; i < modes.length; ++i) {
205
+ const mode = {};
206
+ mode.title = parseValue(modes[i], 'title', 'string');
207
+ mode.orientation = parseValue(modes[i], 'orientation', 'string');
208
+ if (mode.orientation !== Vertical && mode.orientation !== Horizontal && mode.orientation !== VerticalSpanned &&
209
+ mode.orientation !== HorizontalSpanned) {
210
+ throw new Error('Emulated device mode has wrong orientation \'' + mode.orientation + '\'');
211
+ }
212
+ const orientation = result.orientationByName(mode.orientation);
213
+ mode.insets = parseInsets(parseValue(modes[i], 'insets', 'object', { left: 0, top: 0, right: 0, bottom: 0 }));
214
+ if (mode.insets.top < 0 || mode.insets.left < 0 || mode.insets.right < 0 || mode.insets.bottom < 0 ||
215
+ mode.insets.top + mode.insets.bottom > orientation.height ||
216
+ mode.insets.left + mode.insets.right > orientation.width) {
217
+ throw new Error('Emulated device mode \'' + mode.title + '\'has wrong mode insets');
218
+ }
219
+ mode.image = parseValue(modes[i], 'image', 'string', null);
220
+ result.modes.push(mode);
221
+ }
222
+ result.#showByDefault = parseValue(json, 'show-by-default', 'boolean', undefined);
223
+ const show = parseValue(json, 'show', 'string', Show.Default);
224
+ if (!Object.values(Show).includes(show)) {
225
+ throw new Error('Emulated device has wrong show mode: ' + show);
226
+ }
227
+ result.#show = show;
228
+ return result;
229
+ }
230
+ catch {
231
+ return null;
232
+ }
233
+ }
234
+ static deviceComparator(device1, device2) {
235
+ const order1 = device1.order || 0;
236
+ const order2 = device2.order || 0;
237
+ if (order1 > order2) {
238
+ return 1;
239
+ }
240
+ if (order2 > order1) {
241
+ return -1;
242
+ }
243
+ return device1.title < device2.title ? -1 : (device1.title > device2.title ? 1 : 0);
244
+ }
245
+ modesForOrientation(orientation) {
246
+ const result = [];
247
+ for (let index = 0; index < this.modes.length; index++) {
248
+ if (this.modes[index].orientation === orientation) {
249
+ result.push(this.modes[index]);
250
+ }
251
+ }
252
+ return result;
253
+ }
254
+ getSpanPartner(mode) {
255
+ switch (mode.orientation) {
256
+ case Vertical:
257
+ return this.modesForOrientation(VerticalSpanned)[0];
258
+ case Horizontal:
259
+ return this.modesForOrientation(HorizontalSpanned)[0];
260
+ case VerticalSpanned:
261
+ return this.modesForOrientation(Vertical)[0];
262
+ default:
263
+ return this.modesForOrientation(Horizontal)[0];
264
+ }
265
+ }
266
+ getRotationPartner(mode) {
267
+ switch (mode.orientation) {
268
+ case HorizontalSpanned:
269
+ return this.modesForOrientation(VerticalSpanned)[0];
270
+ case VerticalSpanned:
271
+ return this.modesForOrientation(HorizontalSpanned)[0];
272
+ case Horizontal:
273
+ return this.modesForOrientation(Vertical)[0];
274
+ default:
275
+ return this.modesForOrientation(Horizontal)[0];
276
+ }
277
+ }
278
+ toJSON() {
279
+ const json = {};
280
+ json['title'] = this.title;
281
+ json['type'] = this.type;
282
+ json['user-agent'] = this.userAgent;
283
+ json['capabilities'] = this.capabilities;
284
+ json['screen'] = {
285
+ 'device-pixel-ratio': this.deviceScaleFactor,
286
+ vertical: this.orientationToJSON(this.vertical),
287
+ horizontal: this.orientationToJSON(this.horizontal),
288
+ 'vertical-spanned': undefined,
289
+ 'horizontal-spanned': undefined,
290
+ };
291
+ if (this.isDualScreen || this.isFoldableScreen) {
292
+ json['screen']['vertical-spanned'] = this.orientationToJSON(this.verticalSpanned);
293
+ json['screen']['horizontal-spanned'] = this.orientationToJSON(this.horizontalSpanned);
294
+ }
295
+ json['modes'] = [];
296
+ for (let i = 0; i < this.modes.length; ++i) {
297
+ const mode = {
298
+ title: this.modes[i].title,
299
+ orientation: this.modes[i].orientation,
300
+ insets: {
301
+ left: this.modes[i].insets.left,
302
+ top: this.modes[i].insets.top,
303
+ right: this.modes[i].insets.right,
304
+ bottom: this.modes[i].insets.bottom,
305
+ },
306
+ image: this.modes[i].image || undefined,
307
+ };
308
+ json['modes'].push(mode);
309
+ }
310
+ json['show-by-default'] = this.#showByDefault;
311
+ json['dual-screen'] = this.isDualScreen;
312
+ json['foldable-screen'] = this.isFoldableScreen;
313
+ json['show'] = this.#show;
314
+ if (this.userAgentMetadata) {
315
+ json['user-agent-metadata'] = this.userAgentMetadata;
316
+ }
317
+ return json;
318
+ }
319
+ orientationToJSON(orientation) {
320
+ const json = {};
321
+ json['width'] = orientation.width;
322
+ json['height'] = orientation.height;
323
+ if (orientation.outlineInsets) {
324
+ json.outline = {
325
+ insets: {
326
+ left: orientation.outlineInsets.left,
327
+ top: orientation.outlineInsets.top,
328
+ right: orientation.outlineInsets.right,
329
+ bottom: orientation.outlineInsets.bottom,
330
+ },
331
+ image: orientation.outlineImage,
332
+ };
333
+ }
334
+ if (orientation.hinge) {
335
+ json.hinge = {
336
+ width: orientation.hinge.width,
337
+ height: orientation.hinge.height,
338
+ x: orientation.hinge.x,
339
+ y: orientation.hinge.y,
340
+ contentColor: undefined,
341
+ outlineColor: undefined,
342
+ };
343
+ if (orientation.hinge.contentColor) {
344
+ json.hinge.contentColor = {
345
+ r: orientation.hinge.contentColor.r,
346
+ g: orientation.hinge.contentColor.g,
347
+ b: orientation.hinge.contentColor.b,
348
+ a: orientation.hinge.contentColor.a,
349
+ };
350
+ }
351
+ if (orientation.hinge.outlineColor) {
352
+ json.hinge.outlineColor = {
353
+ r: orientation.hinge.outlineColor.r,
354
+ g: orientation.hinge.outlineColor.g,
355
+ b: orientation.hinge.outlineColor.b,
356
+ a: orientation.hinge.outlineColor.a,
357
+ };
358
+ }
359
+ }
360
+ return json;
361
+ }
362
+ modeImage(mode) {
363
+ if (!mode.image) {
364
+ return '';
365
+ }
366
+ return computeRelativeImageURL(mode.image);
367
+ }
368
+ outlineImage(mode) {
369
+ const orientation = this.orientationByName(mode.orientation);
370
+ if (!orientation.outlineImage) {
371
+ return '';
372
+ }
373
+ return computeRelativeImageURL(orientation.outlineImage);
374
+ }
375
+ orientationByName(name) {
376
+ switch (name) {
377
+ case VerticalSpanned:
378
+ return this.verticalSpanned;
379
+ case HorizontalSpanned:
380
+ return this.horizontalSpanned;
381
+ case Vertical:
382
+ return this.vertical;
383
+ default:
384
+ return this.horizontal;
385
+ }
386
+ }
387
+ show() {
388
+ if (this.#show === Show.Default) {
389
+ return this.#showByDefault;
390
+ }
391
+ return this.#show === Show.Always;
392
+ }
393
+ setShow(show) {
394
+ this.#show = show ? Show.Always : Show.Never;
395
+ }
396
+ copyShowFrom(other) {
397
+ this.#show = other.#show;
398
+ }
399
+ touch() {
400
+ return this.capabilities.indexOf("touch" /* Capability.TOUCH */) !== -1;
401
+ }
402
+ mobile() {
403
+ return this.capabilities.indexOf("mobile" /* Capability.MOBILE */) !== -1;
404
+ }
405
+ }
406
+ export const Horizontal = 'horizontal';
407
+ export const Vertical = 'vertical';
408
+ export const HorizontalSpanned = 'horizontal-spanned';
409
+ export const VerticalSpanned = 'vertical-spanned';
410
+ var Type;
411
+ (function (Type) {
412
+ /* eslint-disable @typescript-eslint/naming-convention -- Indexed access. */
413
+ Type["Phone"] = "phone";
414
+ Type["Tablet"] = "tablet";
415
+ Type["Notebook"] = "notebook";
416
+ Type["Desktop"] = "desktop";
417
+ Type["Unknown"] = "unknown";
418
+ /* eslint-enable @typescript-eslint/naming-convention */
419
+ })(Type || (Type = {}));
420
+ var Show;
421
+ (function (Show) {
422
+ /* eslint-disable @typescript-eslint/naming-convention -- Indexed access. */
423
+ Show["Always"] = "Always";
424
+ Show["Default"] = "Default";
425
+ Show["Never"] = "Never";
426
+ /* eslint-enable @typescript-eslint/naming-convention */
427
+ })(Show || (Show = {}));
428
+ let emulatedDevicesListInstance;
429
+ export class EmulatedDevicesList extends Common.ObjectWrapper.ObjectWrapper {
430
+ #standardSetting;
431
+ #standard;
432
+ #customSetting;
433
+ #custom;
434
+ constructor() {
435
+ super();
436
+ this.#standardSetting = Common.Settings.Settings.instance().createSetting('standard-emulated-device-list', []);
437
+ this.#standard = new Set();
438
+ this.listFromJSONV1(this.#standardSetting.get(), this.#standard);
439
+ this.updateStandardDevices();
440
+ this.#customSetting = Common.Settings.Settings.instance().createSetting('custom-emulated-device-list', []);
441
+ this.#custom = new Set();
442
+ if (!this.listFromJSONV1(this.#customSetting.get(), this.#custom)) {
443
+ this.saveCustomDevices();
444
+ }
445
+ }
446
+ static instance() {
447
+ if (!emulatedDevicesListInstance) {
448
+ emulatedDevicesListInstance = new EmulatedDevicesList();
449
+ }
450
+ return emulatedDevicesListInstance;
451
+ }
452
+ updateStandardDevices() {
453
+ const devices = new Set();
454
+ for (const emulatedDevice of emulatedDevices) {
455
+ const device = EmulatedDevice.fromJSONV1(emulatedDevice);
456
+ if (device) {
457
+ devices.add(device);
458
+ }
459
+ }
460
+ this.copyShowValues(this.#standard, devices);
461
+ this.#standard = devices;
462
+ this.saveStandardDevices();
463
+ }
464
+ listFromJSONV1(jsonArray, result) {
465
+ if (!Array.isArray(jsonArray)) {
466
+ return false;
467
+ }
468
+ let success = true;
469
+ for (let i = 0; i < jsonArray.length; ++i) {
470
+ const device = EmulatedDevice.fromJSONV1(jsonArray[i]);
471
+ if (device) {
472
+ result.add(device);
473
+ if (!device.modes.length) {
474
+ device.modes.push({ title: '', orientation: Horizontal, insets: new Insets(0, 0, 0, 0), image: null });
475
+ device.modes.push({ title: '', orientation: Vertical, insets: new Insets(0, 0, 0, 0), image: null });
476
+ }
477
+ }
478
+ else {
479
+ success = false;
480
+ }
481
+ }
482
+ return success;
483
+ }
484
+ static rawEmulatedDevicesForTest() {
485
+ return emulatedDevices;
486
+ }
487
+ standard() {
488
+ return [...this.#standard];
489
+ }
490
+ custom() {
491
+ return [...this.#custom];
492
+ }
493
+ revealCustomSetting() {
494
+ void Common.Revealer.reveal(this.#customSetting);
495
+ }
496
+ addCustomDevice(device) {
497
+ this.#custom.add(device);
498
+ this.saveCustomDevices();
499
+ }
500
+ removeCustomDevice(device) {
501
+ this.#custom.delete(device);
502
+ this.saveCustomDevices();
503
+ }
504
+ saveCustomDevices() {
505
+ const json = [];
506
+ this.#custom.forEach(device => json.push(device.toJSON()));
507
+ this.#customSetting.set(json);
508
+ this.dispatchEventToListeners("CustomDevicesUpdated" /* Events.CUSTOM_DEVICES_UPDATED */);
509
+ }
510
+ saveStandardDevices() {
511
+ const json = [];
512
+ this.#standard.forEach(device => json.push(device.toJSON()));
513
+ this.#standardSetting.set(json);
514
+ this.dispatchEventToListeners("StandardDevicesUpdated" /* Events.STANDARD_DEVICES_UPDATED */);
515
+ }
516
+ copyShowValues(from, to) {
517
+ const fromDeviceById = new Map();
518
+ for (const device of from) {
519
+ fromDeviceById.set(device.title, device);
520
+ }
521
+ for (const toDevice of to) {
522
+ const fromDevice = fromDeviceById.get(toDevice.title);
523
+ if (fromDevice) {
524
+ toDevice.copyShowFrom(fromDevice);
525
+ }
526
+ }
527
+ }
528
+ }
529
+ // These props should quoted for the script to work properly
530
+ /* eslint-disable @stylistic/quote-props */
531
+ const emulatedDevices = [
532
+ // This is used by a python script to keep this list up-to-date with
533
+ // chromedriver native code.
534
+ // See //chrome/test/chromedriver/embed_mobile_devices_in_cpp.py in Chromium.
535
+ // DEVICE-LIST-BEGIN
536
+ {
537
+ 'order': 10,
538
+ 'show-by-default': true,
539
+ 'title': 'iPhone SE',
540
+ 'screen': {
541
+ 'horizontal': {
542
+ 'width': 667,
543
+ 'height': 375,
544
+ },
545
+ 'device-pixel-ratio': 2,
546
+ 'vertical': {
547
+ 'width': 375,
548
+ 'height': 667,
549
+ },
550
+ },
551
+ 'capabilities': ['touch', 'mobile'],
552
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
553
+ 'type': 'phone',
554
+ },
555
+ {
556
+ 'order': 12,
557
+ 'show-by-default': true,
558
+ 'title': 'iPhone XR',
559
+ 'screen': {
560
+ 'horizontal': {
561
+ 'width': 896,
562
+ 'height': 414,
563
+ },
564
+ 'device-pixel-ratio': 2,
565
+ 'vertical': {
566
+ 'width': 414,
567
+ 'height': 896,
568
+ },
569
+ },
570
+ 'capabilities': ['touch', 'mobile'],
571
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
572
+ 'type': 'phone',
573
+ },
574
+ {
575
+ 'order': 14,
576
+ 'show-by-default': true,
577
+ 'title': 'iPhone 12 Pro',
578
+ 'screen': {
579
+ 'horizontal': {
580
+ 'width': 844,
581
+ 'height': 390,
582
+ },
583
+ 'device-pixel-ratio': 3,
584
+ 'vertical': {
585
+ 'width': 390,
586
+ 'height': 844,
587
+ },
588
+ },
589
+ 'capabilities': ['touch', 'mobile'],
590
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
591
+ 'type': 'phone',
592
+ },
593
+ {
594
+ 'order': 15,
595
+ 'show-by-default': true,
596
+ 'title': 'iPhone 14 Pro Max',
597
+ 'screen': {
598
+ 'horizontal': {
599
+ 'width': 932,
600
+ 'height': 430,
601
+ },
602
+ 'device-pixel-ratio': 3,
603
+ 'vertical': {
604
+ 'width': 430,
605
+ 'height': 932,
606
+ },
607
+ },
608
+ 'capabilities': ['touch', 'mobile'],
609
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
610
+ 'type': 'phone',
611
+ },
612
+ {
613
+ 'order': 16,
614
+ 'show-by-default': false,
615
+ 'title': 'Pixel 3 XL',
616
+ 'screen': {
617
+ 'horizontal': {
618
+ 'width': 786,
619
+ 'height': 393,
620
+ },
621
+ 'device-pixel-ratio': 2.75,
622
+ 'vertical': {
623
+ 'width': 393,
624
+ 'height': 786,
625
+ },
626
+ },
627
+ 'capabilities': ['touch', 'mobile'],
628
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 11; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
629
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '11', 'architecture': '', 'model': 'Pixel 3', 'mobile': true },
630
+ 'type': 'phone',
631
+ },
632
+ {
633
+ 'order': 18,
634
+ 'show-by-default': true,
635
+ 'title': 'Pixel 7',
636
+ 'screen': {
637
+ 'horizontal': {
638
+ 'width': 915,
639
+ 'height': 412,
640
+ },
641
+ 'device-pixel-ratio': 2.625,
642
+ 'vertical': {
643
+ 'width': 412,
644
+ 'height': 915,
645
+ },
646
+ },
647
+ 'capabilities': ['touch', 'mobile'],
648
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
649
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '13', 'architecture': '', 'model': 'Pixel 5', 'mobile': true },
650
+ 'type': 'phone',
651
+ },
652
+ {
653
+ 'order': 20,
654
+ 'show-by-default': true,
655
+ 'title': 'Samsung Galaxy S8+',
656
+ 'screen': {
657
+ 'horizontal': {
658
+ 'width': 740,
659
+ 'height': 360,
660
+ },
661
+ 'device-pixel-ratio': 4,
662
+ 'vertical': {
663
+ 'width': 360,
664
+ 'height': 740,
665
+ },
666
+ },
667
+ 'capabilities': ['touch', 'mobile'],
668
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
669
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '8.0.0', 'architecture': '', 'model': 'SM-G955U', 'mobile': true },
670
+ 'type': 'phone',
671
+ },
672
+ {
673
+ 'order': 24,
674
+ 'show-by-default': true,
675
+ 'title': 'Samsung Galaxy S20 Ultra',
676
+ 'screen': {
677
+ 'horizontal': {
678
+ 'width': 915,
679
+ 'height': 412,
680
+ },
681
+ 'device-pixel-ratio': 3.5,
682
+ 'vertical': {
683
+ 'width': 412,
684
+ 'height': 915,
685
+ },
686
+ },
687
+ 'capabilities': ['touch', 'mobile'],
688
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 13; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
689
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '13', 'architecture': '', 'model': 'SM-G981B', 'mobile': true },
690
+ 'type': 'phone',
691
+ },
692
+ {
693
+ 'order': 26,
694
+ 'show-by-default': true,
695
+ 'title': 'iPad Mini',
696
+ 'screen': {
697
+ 'horizontal': {
698
+ 'width': 1024,
699
+ 'height': 768,
700
+ },
701
+ 'device-pixel-ratio': 2,
702
+ 'vertical': {
703
+ 'width': 768,
704
+ 'height': 1024,
705
+ },
706
+ },
707
+ 'capabilities': ['touch', 'mobile'],
708
+ 'user-agent': 'Mozilla/5.0 (iPad; CPU OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
709
+ 'type': 'tablet',
710
+ },
711
+ {
712
+ 'order': 28,
713
+ 'show-by-default': true,
714
+ 'title': 'iPad Air',
715
+ 'screen': {
716
+ 'horizontal': {
717
+ 'width': 1180,
718
+ 'height': 820,
719
+ },
720
+ 'device-pixel-ratio': 2,
721
+ 'vertical': {
722
+ 'width': 820,
723
+ 'height': 1180,
724
+ },
725
+ },
726
+ 'capabilities': ['touch', 'mobile'],
727
+ 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15',
728
+ 'type': 'tablet',
729
+ },
730
+ {
731
+ 'order': 29,
732
+ 'show-by-default': true,
733
+ 'title': 'iPad Pro',
734
+ 'screen': {
735
+ 'horizontal': {
736
+ 'width': 1366,
737
+ 'height': 1024,
738
+ },
739
+ 'device-pixel-ratio': 2,
740
+ 'vertical': {
741
+ 'width': 1024,
742
+ 'height': 1366,
743
+ },
744
+ },
745
+ 'capabilities': ['touch', 'mobile'],
746
+ 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15',
747
+ 'type': 'tablet',
748
+ },
749
+ {
750
+ 'order': 30,
751
+ 'show-by-default': true,
752
+ 'title': 'Surface Pro 7',
753
+ 'screen': {
754
+ 'horizontal': {
755
+ 'width': 1368,
756
+ 'height': 912,
757
+ },
758
+ 'device-pixel-ratio': 2,
759
+ 'vertical': {
760
+ 'width': 912,
761
+ 'height': 1368,
762
+ },
763
+ },
764
+ 'capabilities': ['touch', 'mobile'],
765
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36',
766
+ 'type': 'tablet',
767
+ },
768
+ {
769
+ 'order': 32,
770
+ 'show-by-default': true,
771
+ 'dual-screen': true,
772
+ 'title': 'Surface Duo',
773
+ 'screen': {
774
+ 'horizontal': { 'width': 720, 'height': 540 },
775
+ 'device-pixel-ratio': 2.5,
776
+ 'vertical': { 'width': 540, 'height': 720 },
777
+ 'vertical-spanned': {
778
+ 'width': 1114,
779
+ 'height': 720,
780
+ 'hinge': { 'width': 34, 'height': 720, 'x': 540, 'y': 0, 'contentColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 1 } },
781
+ },
782
+ 'horizontal-spanned': {
783
+ 'width': 720,
784
+ 'height': 1114,
785
+ 'hinge': { 'width': 720, 'height': 34, 'x': 0, 'y': 540, 'contentColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 1 } },
786
+ },
787
+ },
788
+ 'capabilities': ['touch', 'mobile'],
789
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 11.0; Surface Duo) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
790
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '11.0', 'architecture': '', 'model': 'Surface Duo', 'mobile': true },
791
+ 'type': 'phone',
792
+ 'modes': [
793
+ { 'title': 'default', 'orientation': 'vertical', 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 } },
794
+ { 'title': 'default', 'orientation': 'horizontal', 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 } },
795
+ { 'title': 'spanned', 'orientation': 'vertical-spanned', 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 } },
796
+ {
797
+ 'title': 'spanned',
798
+ 'orientation': 'horizontal-spanned',
799
+ 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 },
800
+ },
801
+ ],
802
+ },
803
+ {
804
+ 'order': 34,
805
+ 'show-by-default': true,
806
+ 'foldable-screen': true,
807
+ 'title': 'Galaxy Z Fold 5',
808
+ 'screen': {
809
+ 'horizontal': { 'width': 882, 'height': 344 },
810
+ 'device-pixel-ratio': 2.625,
811
+ 'vertical': { 'width': 344, 'height': 882 },
812
+ 'vertical-spanned': {
813
+ 'width': 690,
814
+ 'height': 829,
815
+ 'hinge': {
816
+ 'width': 0,
817
+ 'height': 829,
818
+ 'x': 345,
819
+ 'y': 0,
820
+ 'contentColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 0.2 },
821
+ 'outlineColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 0.7 },
822
+ },
823
+ },
824
+ 'horizontal-spanned': {
825
+ 'width': 829,
826
+ 'height': 690,
827
+ 'hinge': {
828
+ 'width': 829,
829
+ 'height': 0,
830
+ 'x': 0,
831
+ 'y': 345,
832
+ 'contentColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 0.2 },
833
+ 'outlineColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 0.7 },
834
+ },
835
+ },
836
+ },
837
+ 'capabilities': ['touch', 'mobile'],
838
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
839
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '10.0', 'architecture': '', 'model': 'SM-F946U', 'mobile': true },
840
+ 'type': 'phone',
841
+ 'modes': [
842
+ { 'title': 'default', 'orientation': 'vertical', 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 } },
843
+ { 'title': 'default', 'orientation': 'horizontal', 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 } },
844
+ { 'title': 'spanned', 'orientation': 'vertical-spanned', 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 } },
845
+ {
846
+ 'title': 'spanned',
847
+ 'orientation': 'horizontal-spanned',
848
+ 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 },
849
+ },
850
+ ],
851
+ },
852
+ {
853
+ 'order': 35,
854
+ 'show-by-default': true,
855
+ 'foldable-screen': true,
856
+ 'title': 'Asus Zenbook Fold',
857
+ 'screen': {
858
+ 'horizontal': { 'width': 1280, 'height': 853 },
859
+ 'device-pixel-ratio': 1.5,
860
+ 'vertical': { 'width': 853, 'height': 1280 },
861
+ 'vertical-spanned': {
862
+ 'width': 1706,
863
+ 'height': 1280,
864
+ 'hinge': {
865
+ 'width': 107,
866
+ 'height': 1280,
867
+ 'x': 800,
868
+ 'y': 0,
869
+ 'contentColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 0.2 },
870
+ 'outlineColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 0.7 },
871
+ },
872
+ },
873
+ 'horizontal-spanned': {
874
+ 'width': 1280,
875
+ 'height': 1706,
876
+ 'hinge': {
877
+ 'width': 1706,
878
+ 'height': 107,
879
+ 'x': 0,
880
+ 'y': 800,
881
+ 'contentColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 0.2 },
882
+ 'outlineColor': { 'r': 38, 'g': 38, 'b': 38, 'a': 0.7 },
883
+ },
884
+ },
885
+ },
886
+ 'capabilities': ['touch'],
887
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36',
888
+ 'user-agent-metadata': { 'platform': 'Windows', 'platformVersion': '11.0', 'architecture': '', 'model': 'UX9702AA', 'mobile': false },
889
+ 'type': 'tablet',
890
+ 'modes': [
891
+ { 'title': 'default', 'orientation': 'vertical', 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 } },
892
+ { 'title': 'default', 'orientation': 'horizontal', 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 } },
893
+ {
894
+ 'title': 'spanned',
895
+ 'orientation': 'vertical-spanned',
896
+ 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 },
897
+ },
898
+ {
899
+ 'title': 'spanned',
900
+ 'orientation': 'horizontal-spanned',
901
+ 'insets': { 'left': 0, 'top': 0, 'right': 0, 'bottom': 0 },
902
+ },
903
+ ],
904
+ },
905
+ {
906
+ 'order': 36,
907
+ 'show-by-default': true,
908
+ 'title': 'Samsung Galaxy A51/71',
909
+ 'screen': {
910
+ 'horizontal': {
911
+ 'width': 914,
912
+ 'height': 412,
913
+ },
914
+ 'device-pixel-ratio': 2.625,
915
+ 'vertical': {
916
+ 'width': 412,
917
+ 'height': 914,
918
+ },
919
+ },
920
+ 'capabilities': ['touch', 'mobile'],
921
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
922
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '8.0.0', 'architecture': '', 'model': 'SM-G955U', 'mobile': true },
923
+ 'type': 'phone',
924
+ },
925
+ {
926
+ 'order': 52,
927
+ 'show-by-default': true,
928
+ 'title': 'Nest Hub Max',
929
+ 'screen': {
930
+ 'horizontal': {
931
+ 'outline': {
932
+ 'image': '@url(optimized/google-nest-hub-max-horizontal.avif)',
933
+ 'insets': { 'left': 92, 'top': 96, 'right': 91, 'bottom': 248 },
934
+ },
935
+ 'width': 1280,
936
+ 'height': 800,
937
+ },
938
+ 'device-pixel-ratio': 2,
939
+ 'vertical': {
940
+ 'width': 1280,
941
+ 'height': 800,
942
+ },
943
+ },
944
+ 'capabilities': ['touch', 'mobile'],
945
+ 'user-agent': 'Mozilla/5.0 (X11; Linux aarch64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36 CrKey/1.54.250320',
946
+ 'type': 'tablet',
947
+ 'modes': [{ 'title': 'default', 'orientation': 'horizontal' }],
948
+ },
949
+ {
950
+ 'order': 50,
951
+ 'show-by-default': true,
952
+ 'title': 'Nest Hub',
953
+ 'screen': {
954
+ 'horizontal': {
955
+ 'outline': {
956
+ 'image': '@url(optimized/google-nest-hub-horizontal.avif)',
957
+ 'insets': { 'left': 82, 'top': 74, 'right': 83, 'bottom': 222 },
958
+ },
959
+ 'width': 1024,
960
+ 'height': 600,
961
+ },
962
+ 'device-pixel-ratio': 2,
963
+ 'vertical': {
964
+ 'width': 1024,
965
+ 'height': 600,
966
+ },
967
+ },
968
+ 'capabilities': ['touch', 'mobile'],
969
+ 'user-agent': 'Mozilla/5.0 (Linux; Android) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36 CrKey/1.54.248666',
970
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '', 'architecture': '', 'model': '', 'mobile': false },
971
+ 'type': 'tablet',
972
+ 'modes': [{ 'title': 'default', 'orientation': 'horizontal' }],
973
+ },
974
+ {
975
+ 'order': 129,
976
+ 'show-by-default': false,
977
+ 'title': 'iPhone 4',
978
+ 'screen': {
979
+ 'horizontal': { 'width': 480, 'height': 320 },
980
+ 'device-pixel-ratio': 2,
981
+ 'vertical': { 'width': 320, 'height': 480 },
982
+ },
983
+ 'capabilities': ['touch', 'mobile'],
984
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53',
985
+ 'type': 'phone',
986
+ },
987
+ {
988
+ 'order': 130,
989
+ 'show-by-default': false,
990
+ 'title': 'iPhone 5/SE',
991
+ 'screen': {
992
+ 'horizontal': {
993
+ 'outline': {
994
+ 'image': '@url(optimized/iPhone5-landscape.avif)',
995
+ 'insets': { 'left': 115, 'top': 25, 'right': 115, 'bottom': 28 },
996
+ },
997
+ 'width': 568,
998
+ 'height': 320,
999
+ },
1000
+ 'device-pixel-ratio': 2,
1001
+ 'vertical': {
1002
+ 'outline': {
1003
+ 'image': '@url(optimized/iPhone5-portrait.avif)',
1004
+ 'insets': { 'left': 29, 'top': 105, 'right': 25, 'bottom': 111 },
1005
+ },
1006
+ 'width': 320,
1007
+ 'height': 568,
1008
+ },
1009
+ },
1010
+ 'capabilities': ['touch', 'mobile'],
1011
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1',
1012
+ 'type': 'phone',
1013
+ },
1014
+ {
1015
+ 'order': 131,
1016
+ 'show-by-default': false,
1017
+ 'title': 'iPhone 6/7/8',
1018
+ 'screen': {
1019
+ 'horizontal': {
1020
+ 'outline': {
1021
+ 'image': '@url(optimized/iPhone6-landscape.avif)',
1022
+ 'insets': { 'left': 106, 'top': 28, 'right': 106, 'bottom': 28 },
1023
+ },
1024
+ 'width': 667,
1025
+ 'height': 375,
1026
+ },
1027
+ 'device-pixel-ratio': 2,
1028
+ 'vertical': {
1029
+ 'outline': {
1030
+ 'image': '@url(optimized/iPhone6-portrait.avif)',
1031
+ 'insets': { 'left': 28, 'top': 105, 'right': 28, 'bottom': 105 },
1032
+ },
1033
+ 'width': 375,
1034
+ 'height': 667,
1035
+ },
1036
+ },
1037
+ 'capabilities': ['touch', 'mobile'],
1038
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
1039
+ 'type': 'phone',
1040
+ },
1041
+ {
1042
+ 'order': 132,
1043
+ 'show-by-default': false,
1044
+ 'title': 'iPhone 6/7/8 Plus',
1045
+ 'screen': {
1046
+ 'horizontal': {
1047
+ 'outline': {
1048
+ 'image': '@url(optimized/iPhone6Plus-landscape.avif)',
1049
+ 'insets': { 'left': 109, 'top': 29, 'right': 109, 'bottom': 27 },
1050
+ },
1051
+ 'width': 736,
1052
+ 'height': 414,
1053
+ },
1054
+ 'device-pixel-ratio': 3,
1055
+ 'vertical': {
1056
+ 'outline': {
1057
+ 'image': '@url(optimized/iPhone6Plus-portrait.avif)',
1058
+ 'insets': { 'left': 26, 'top': 107, 'right': 30, 'bottom': 111 },
1059
+ },
1060
+ 'width': 414,
1061
+ 'height': 736,
1062
+ },
1063
+ },
1064
+ 'capabilities': ['touch', 'mobile'],
1065
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
1066
+ 'type': 'phone',
1067
+ },
1068
+ {
1069
+ 'order': 133,
1070
+ 'show-by-default': false,
1071
+ 'title': 'iPhone X',
1072
+ 'screen': {
1073
+ 'horizontal': { 'width': 812, 'height': 375 },
1074
+ 'device-pixel-ratio': 3,
1075
+ 'vertical': { 'width': 375, 'height': 812 },
1076
+ },
1077
+ 'capabilities': ['touch', 'mobile'],
1078
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
1079
+ 'type': 'phone',
1080
+ },
1081
+ {
1082
+ 'show-by-default': false,
1083
+ 'title': 'BlackBerry Z30',
1084
+ 'screen': {
1085
+ 'horizontal': { 'width': 640, 'height': 360 },
1086
+ 'device-pixel-ratio': 2,
1087
+ 'vertical': { 'width': 360, 'height': 640 },
1088
+ },
1089
+ 'capabilities': ['touch', 'mobile'],
1090
+ 'user-agent': 'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+',
1091
+ 'type': 'phone',
1092
+ },
1093
+ {
1094
+ 'show-by-default': false,
1095
+ 'title': 'Nexus 4',
1096
+ 'screen': {
1097
+ 'horizontal': { 'width': 640, 'height': 384 },
1098
+ 'device-pixel-ratio': 2,
1099
+ 'vertical': { 'width': 384, 'height': 640 },
1100
+ },
1101
+ 'capabilities': ['touch', 'mobile'],
1102
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1103
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '4.4.2', 'architecture': '', 'model': 'Nexus 4', 'mobile': true },
1104
+ 'type': 'phone',
1105
+ },
1106
+ {
1107
+ 'title': 'Nexus 5',
1108
+ 'type': 'phone',
1109
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1110
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '6.0', 'architecture': '', 'model': 'Nexus 5', 'mobile': true },
1111
+ 'capabilities': ['touch', 'mobile'],
1112
+ 'show-by-default': false,
1113
+ 'screen': {
1114
+ 'device-pixel-ratio': 3,
1115
+ 'vertical': { 'width': 360, 'height': 640 },
1116
+ 'horizontal': { 'width': 640, 'height': 360 },
1117
+ },
1118
+ 'modes': [
1119
+ {
1120
+ 'title': 'default',
1121
+ 'orientation': 'vertical',
1122
+ 'insets': { 'left': 0, 'top': 25, 'right': 0, 'bottom': 48 },
1123
+ 'image': '@url(optimized/google-nexus-5-vertical-default-1x.avif) 1x, @url(optimized/google-nexus-5-vertical-default-2x.avif) 2x',
1124
+ },
1125
+ {
1126
+ 'title': 'navigation bar',
1127
+ 'orientation': 'vertical',
1128
+ 'insets': { 'left': 0, 'top': 80, 'right': 0, 'bottom': 48 },
1129
+ 'image': '@url(optimized/google-nexus-5-vertical-navigation-1x.avif) 1x, @url(optimized/google-nexus-5-vertical-navigation-2x.avif) 2x',
1130
+ },
1131
+ {
1132
+ 'title': 'keyboard',
1133
+ 'orientation': 'vertical',
1134
+ 'insets': { 'left': 0, 'top': 80, 'right': 0, 'bottom': 312 },
1135
+ 'image': '@url(optimized/google-nexus-5-vertical-keyboard-1x.avif) 1x, @url(optimized/google-nexus-5-vertical-keyboard-2x.avif) 2x',
1136
+ },
1137
+ {
1138
+ 'title': 'default',
1139
+ 'orientation': 'horizontal',
1140
+ 'insets': { 'left': 0, 'top': 25, 'right': 42, 'bottom': 0 },
1141
+ 'image': '@url(optimized/google-nexus-5-horizontal-default-1x.avif) 1x, @url(optimized/google-nexus-5-horizontal-default-2x.avif) 2x',
1142
+ },
1143
+ {
1144
+ 'title': 'navigation bar',
1145
+ 'orientation': 'horizontal',
1146
+ 'insets': { 'left': 0, 'top': 80, 'right': 42, 'bottom': 0 },
1147
+ 'image': '@url(optimized/google-nexus-5-horizontal-navigation-1x.avif) 1x, @url(optimized/google-nexus-5-horizontal-navigation-2x.avif) 2x',
1148
+ },
1149
+ {
1150
+ 'title': 'keyboard',
1151
+ 'orientation': 'horizontal',
1152
+ 'insets': { 'left': 0, 'top': 80, 'right': 42, 'bottom': 202 },
1153
+ 'image': '@url(optimized/google-nexus-5-horizontal-keyboard-1x.avif) 1x, @url(optimized/google-nexus-5-horizontal-keyboard-2x.avif) 2x',
1154
+ },
1155
+ ],
1156
+ },
1157
+ {
1158
+ 'title': 'Nexus 5X',
1159
+ 'type': 'phone',
1160
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1161
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '8.0.0', 'architecture': '', 'model': 'Nexus 5X', 'mobile': true },
1162
+ 'capabilities': ['touch', 'mobile'],
1163
+ 'show-by-default': false,
1164
+ 'screen': {
1165
+ 'device-pixel-ratio': 2.625,
1166
+ 'vertical': {
1167
+ 'outline': {
1168
+ 'image': '@url(optimized/Nexus5X-portrait.avif)',
1169
+ 'insets': { 'left': 18, 'top': 88, 'right': 22, 'bottom': 98 },
1170
+ },
1171
+ 'width': 412,
1172
+ 'height': 732,
1173
+ },
1174
+ 'horizontal': {
1175
+ 'outline': {
1176
+ 'image': '@url(optimized/Nexus5X-landscape.avif)',
1177
+ 'insets': { 'left': 88, 'top': 21, 'right': 98, 'bottom': 19 },
1178
+ },
1179
+ 'width': 732,
1180
+ 'height': 412,
1181
+ },
1182
+ },
1183
+ 'modes': [
1184
+ {
1185
+ 'title': 'default',
1186
+ 'orientation': 'vertical',
1187
+ 'insets': { 'left': 0, 'top': 24, 'right': 0, 'bottom': 48 },
1188
+ 'image': '@url(optimized/google-nexus-5x-vertical-default-1x.avif) 1x, @url(optimized/google-nexus-5x-vertical-default-2x.avif) 2x',
1189
+ },
1190
+ {
1191
+ 'title': 'navigation bar',
1192
+ 'orientation': 'vertical',
1193
+ 'insets': { 'left': 0, 'top': 80, 'right': 0, 'bottom': 48 },
1194
+ 'image': '@url(optimized/google-nexus-5x-vertical-navigation-1x.avif) 1x, @url(optimized/google-nexus-5x-vertical-navigation-2x.avif) 2x',
1195
+ },
1196
+ {
1197
+ 'title': 'keyboard',
1198
+ 'orientation': 'vertical',
1199
+ 'insets': { 'left': 0, 'top': 80, 'right': 0, 'bottom': 342 },
1200
+ 'image': '@url(optimized/google-nexus-5x-vertical-keyboard-1x.avif) 1x, @url(optimized/google-nexus-5x-vertical-keyboard-2x.avif) 2x',
1201
+ },
1202
+ {
1203
+ 'title': 'default',
1204
+ 'orientation': 'horizontal',
1205
+ 'insets': { 'left': 0, 'top': 24, 'right': 48, 'bottom': 0 },
1206
+ 'image': '@url(optimized/google-nexus-5x-horizontal-default-1x.avif) 1x, @url(optimized/google-nexus-5x-horizontal-default-2x.avif) 2x',
1207
+ },
1208
+ {
1209
+ 'title': 'navigation bar',
1210
+ 'orientation': 'horizontal',
1211
+ 'insets': { 'left': 0, 'top': 80, 'right': 48, 'bottom': 0 },
1212
+ 'image': '@url(optimized/google-nexus-5x-horizontal-navigation-1x.avif) 1x, @url(optimized/google-nexus-5x-horizontal-navigation-2x.avif) 2x',
1213
+ },
1214
+ {
1215
+ 'title': 'keyboard',
1216
+ 'orientation': 'horizontal',
1217
+ 'insets': { 'left': 0, 'top': 80, 'right': 48, 'bottom': 222 },
1218
+ 'image': '@url(optimized/google-nexus-5x-horizontal-keyboard-1x.avif) 1x, @url(optimized/google-nexus-5x-horizontal-keyboard-2x.avif) 2x',
1219
+ },
1220
+ ],
1221
+ },
1222
+ {
1223
+ 'show-by-default': false,
1224
+ 'title': 'Nexus 6',
1225
+ 'screen': {
1226
+ 'horizontal': { 'width': 732, 'height': 412 },
1227
+ 'device-pixel-ratio': 3.5,
1228
+ 'vertical': { 'width': 412, 'height': 732 },
1229
+ },
1230
+ 'capabilities': ['touch', 'mobile'],
1231
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1232
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '7.1.1', 'architecture': '', 'model': 'Nexus 6', 'mobile': true },
1233
+ 'type': 'phone',
1234
+ },
1235
+ {
1236
+ 'show-by-default': false,
1237
+ 'title': 'Nexus 6P',
1238
+ 'screen': {
1239
+ 'horizontal': {
1240
+ 'outline': {
1241
+ 'image': '@url(optimized/Nexus6P-landscape.avif)',
1242
+ 'insets': { 'left': 94, 'top': 17, 'right': 88, 'bottom': 17 },
1243
+ },
1244
+ 'width': 732,
1245
+ 'height': 412,
1246
+ },
1247
+ 'device-pixel-ratio': 3.5,
1248
+ 'vertical': {
1249
+ 'outline': {
1250
+ 'image': '@url(optimized/Nexus6P-portrait.avif)',
1251
+ 'insets': { 'left': 16, 'top': 94, 'right': 16, 'bottom': 88 },
1252
+ },
1253
+ 'width': 412,
1254
+ 'height': 732,
1255
+ },
1256
+ },
1257
+ 'capabilities': ['touch', 'mobile'],
1258
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1259
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '8.0.0', 'architecture': '', 'model': 'Nexus 6P', 'mobile': true },
1260
+ 'type': 'phone',
1261
+ },
1262
+ {
1263
+ 'order': 120,
1264
+ 'show-by-default': false,
1265
+ 'title': 'Pixel 2',
1266
+ 'screen': {
1267
+ 'horizontal': { 'width': 731, 'height': 411 },
1268
+ 'device-pixel-ratio': 2.625,
1269
+ 'vertical': { 'width': 411, 'height': 731 },
1270
+ },
1271
+ 'capabilities': ['touch', 'mobile'],
1272
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1273
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '8.0', 'architecture': '', 'model': 'Pixel 2', 'mobile': true },
1274
+ 'type': 'phone',
1275
+ },
1276
+ {
1277
+ 'order': 121,
1278
+ 'show-by-default': false,
1279
+ 'title': 'Pixel 2 XL',
1280
+ 'screen': {
1281
+ 'horizontal': { 'width': 823, 'height': 411 },
1282
+ 'device-pixel-ratio': 3.5,
1283
+ 'vertical': { 'width': 411, 'height': 823 },
1284
+ },
1285
+ 'capabilities': ['touch', 'mobile'],
1286
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1287
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '8.0.0', 'architecture': '', 'model': 'Pixel 2 XL', 'mobile': true },
1288
+ 'type': 'phone',
1289
+ },
1290
+ {
1291
+ 'show-by-default': false,
1292
+ 'title': 'Pixel 3',
1293
+ 'screen': {
1294
+ 'horizontal': { 'width': 786, 'height': 393 },
1295
+ 'device-pixel-ratio': 2.75,
1296
+ 'vertical': { 'width': 393, 'height': 786 },
1297
+ },
1298
+ 'capabilities': ['touch', 'mobile'],
1299
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1300
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '9', 'architecture': '', 'model': 'Pixel 3', 'mobile': true },
1301
+ 'type': 'phone',
1302
+ },
1303
+ {
1304
+ 'show-by-default': false,
1305
+ 'title': 'Pixel 4',
1306
+ 'screen': {
1307
+ 'horizontal': { 'width': 745, 'height': 353 },
1308
+ 'device-pixel-ratio': 3,
1309
+ 'vertical': { 'width': 353, 'height': 745 },
1310
+ },
1311
+ 'capabilities': ['touch', 'mobile'],
1312
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1313
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '10', 'architecture': '', 'model': 'Pixel 4', 'mobile': true },
1314
+ 'type': 'phone',
1315
+ },
1316
+ {
1317
+ 'show-by-default': false,
1318
+ 'title': 'LG Optimus L70',
1319
+ 'screen': {
1320
+ 'horizontal': { 'width': 640, 'height': 384 },
1321
+ 'device-pixel-ratio': 1.25,
1322
+ 'vertical': { 'width': 384, 'height': 640 },
1323
+ },
1324
+ 'capabilities': ['touch', 'mobile'],
1325
+ 'user-agent': '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/%s Mobile Safari/537.36',
1326
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '4.4.2', 'architecture': '', 'model': 'LGMS323', 'mobile': true },
1327
+ 'type': 'phone',
1328
+ },
1329
+ {
1330
+ 'show-by-default': false,
1331
+ 'title': 'Nokia N9',
1332
+ 'screen': {
1333
+ 'horizontal': { 'width': 854, 'height': 480 },
1334
+ 'device-pixel-ratio': 1,
1335
+ 'vertical': { 'width': 480, 'height': 854 },
1336
+ },
1337
+ 'capabilities': ['touch', 'mobile'],
1338
+ 'user-agent': 'Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13',
1339
+ 'type': 'phone',
1340
+ },
1341
+ {
1342
+ 'show-by-default': false,
1343
+ 'title': 'Nokia Lumia 520',
1344
+ 'screen': {
1345
+ 'horizontal': { 'width': 533, 'height': 320 },
1346
+ 'device-pixel-ratio': 1.5,
1347
+ 'vertical': { 'width': 320, 'height': 533 },
1348
+ },
1349
+ 'capabilities': ['touch', 'mobile'],
1350
+ 'user-agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)',
1351
+ 'type': 'phone',
1352
+ },
1353
+ {
1354
+ 'show-by-default': false,
1355
+ 'title': 'Microsoft Lumia 550',
1356
+ 'screen': {
1357
+ 'horizontal': { 'width': 640, 'height': 360 },
1358
+ 'device-pixel-ratio': 2,
1359
+ 'vertical': { 'width': 640, 'height': 360 },
1360
+ },
1361
+ 'capabilities': ['touch', 'mobile'],
1362
+ 'user-agent': 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36 Edge/14.14263',
1363
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '4.2.1', 'architecture': '', 'model': 'Lumia 550', 'mobile': true },
1364
+ 'type': 'phone',
1365
+ },
1366
+ {
1367
+ 'show-by-default': false,
1368
+ 'title': 'Microsoft Lumia 950',
1369
+ 'screen': {
1370
+ 'horizontal': { 'width': 640, 'height': 360 },
1371
+ 'device-pixel-ratio': 4,
1372
+ 'vertical': { 'width': 360, 'height': 640 },
1373
+ },
1374
+ 'capabilities': ['touch', 'mobile'],
1375
+ 'user-agent': 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36 Edge/14.14263',
1376
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '4.2.1', 'architecture': '', 'model': 'Lumia 950', 'mobile': true },
1377
+ 'type': 'phone',
1378
+ },
1379
+ {
1380
+ 'show-by-default': false,
1381
+ 'title': 'Galaxy S III',
1382
+ 'screen': {
1383
+ 'horizontal': { 'width': 640, 'height': 360 },
1384
+ 'device-pixel-ratio': 2,
1385
+ 'vertical': { 'width': 360, 'height': 640 },
1386
+ },
1387
+ 'capabilities': ['touch', 'mobile'],
1388
+ 'user-agent': 'Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
1389
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '4.0', 'architecture': '', 'model': 'GT-I9300', 'mobile': true },
1390
+ 'type': 'phone',
1391
+ },
1392
+ {
1393
+ 'order': 110,
1394
+ 'show-by-default': false,
1395
+ 'title': 'Galaxy S5',
1396
+ 'screen': {
1397
+ 'horizontal': { 'width': 640, 'height': 360 },
1398
+ 'device-pixel-ratio': 3,
1399
+ 'vertical': { 'width': 360, 'height': 640 },
1400
+ },
1401
+ 'capabilities': ['touch', 'mobile'],
1402
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1403
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '5.0', 'architecture': '', 'model': 'SM-G900P', 'mobile': true },
1404
+ 'type': 'phone',
1405
+ },
1406
+ {
1407
+ 'show-by-default': false,
1408
+ 'title': 'Galaxy S8',
1409
+ 'screen': {
1410
+ 'horizontal': { 'width': 740, 'height': 360 },
1411
+ 'device-pixel-ratio': 3,
1412
+ 'vertical': { 'width': 360, 'height': 740 },
1413
+ },
1414
+ 'capabilities': ['touch', 'mobile'],
1415
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1416
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '7.0', 'architecture': '', 'model': 'SM-G950U', 'mobile': true },
1417
+ 'type': 'phone',
1418
+ },
1419
+ {
1420
+ 'show-by-default': false,
1421
+ 'title': 'Galaxy S9+',
1422
+ 'screen': {
1423
+ 'horizontal': { 'width': 658, 'height': 320 },
1424
+ 'device-pixel-ratio': 4.5,
1425
+ 'vertical': { 'width': 320, 'height': 658 },
1426
+ },
1427
+ 'capabilities': ['touch', 'mobile'],
1428
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1429
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '8.0.0', 'architecture': '', 'model': 'SM-G965U', 'mobile': true },
1430
+ 'type': 'phone',
1431
+ },
1432
+ {
1433
+ 'show-by-default': false,
1434
+ 'title': 'Galaxy Tab S4',
1435
+ 'screen': {
1436
+ 'horizontal': { 'width': 1138, 'height': 712 },
1437
+ 'device-pixel-ratio': 2.25,
1438
+ 'vertical': { 'width': 712, 'height': 1138 },
1439
+ },
1440
+ 'capabilities': ['touch', 'mobile'],
1441
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36',
1442
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '8.1.0', 'architecture': '', 'model': 'SM-T837A', 'mobile': false },
1443
+ 'type': 'phone',
1444
+ },
1445
+ {
1446
+ 'order': 1,
1447
+ 'show-by-default': false,
1448
+ 'title': 'JioPhone 2',
1449
+ 'screen': {
1450
+ 'horizontal': { 'width': 320, 'height': 240 },
1451
+ 'device-pixel-ratio': 1,
1452
+ 'vertical': { 'width': 240, 'height': 320 },
1453
+ },
1454
+ 'capabilities': ['touch', 'mobile'],
1455
+ 'user-agent': 'Mozilla/5.0 (Mobile; LYF/F300B/LYF-F300B-001-01-15-130718-i;Android; rv:48.0) Gecko/48.0 Firefox/48.0 KAIOS/2.5',
1456
+ 'user-agent-metadata': {
1457
+ 'platform': 'Android',
1458
+ 'platformVersion': '',
1459
+ 'architecture': '',
1460
+ 'model': 'LYF/F300B/LYF-F300B-001-01-15-130718-i',
1461
+ 'mobile': true,
1462
+ },
1463
+ 'type': 'phone',
1464
+ },
1465
+ {
1466
+ 'show-by-default': false,
1467
+ 'title': 'Kindle Fire HDX',
1468
+ 'screen': {
1469
+ 'horizontal': { 'width': 1280, 'height': 800 },
1470
+ 'device-pixel-ratio': 2,
1471
+ 'vertical': { 'width': 800, 'height': 1280 },
1472
+ },
1473
+ 'capabilities': ['touch', 'mobile'],
1474
+ 'user-agent': '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',
1475
+ 'type': 'tablet',
1476
+ },
1477
+ {
1478
+ 'order': 140,
1479
+ 'show-by-default': false,
1480
+ 'title': 'iPad',
1481
+ 'screen': {
1482
+ 'horizontal': {
1483
+ 'outline': {
1484
+ 'image': '@url(optimized/iPad-landscape.avif)',
1485
+ 'insets': { 'left': 112, 'top': 56, 'right': 116, 'bottom': 52 },
1486
+ },
1487
+ 'width': 1024,
1488
+ 'height': 768,
1489
+ },
1490
+ 'device-pixel-ratio': 2,
1491
+ 'vertical': {
1492
+ 'outline': {
1493
+ 'image': '@url(optimized/iPad-portrait.avif)',
1494
+ 'insets': { 'left': 52, 'top': 114, 'right': 55, 'bottom': 114 },
1495
+ },
1496
+ 'width': 768,
1497
+ 'height': 1024,
1498
+ },
1499
+ },
1500
+ 'capabilities': ['touch', 'mobile'],
1501
+ 'user-agent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
1502
+ 'type': 'tablet',
1503
+ },
1504
+ {
1505
+ 'order': 141,
1506
+ 'show-by-default': false,
1507
+ 'title': 'iPad Pro',
1508
+ 'screen': {
1509
+ 'horizontal': { 'width': 1366, 'height': 1024 },
1510
+ 'device-pixel-ratio': 2,
1511
+ 'vertical': { 'width': 1024, 'height': 1366 },
1512
+ },
1513
+ 'capabilities': ['touch', 'mobile'],
1514
+ 'user-agent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
1515
+ 'type': 'tablet',
1516
+ },
1517
+ {
1518
+ 'show-by-default': false,
1519
+ 'title': 'Blackberry PlayBook',
1520
+ 'screen': {
1521
+ 'horizontal': { 'width': 1024, 'height': 600 },
1522
+ 'device-pixel-ratio': 1,
1523
+ 'vertical': { 'width': 600, 'height': 1024 },
1524
+ },
1525
+ 'capabilities': ['touch', 'mobile'],
1526
+ 'user-agent': 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+',
1527
+ 'type': 'tablet',
1528
+ },
1529
+ {
1530
+ 'show-by-default': false,
1531
+ 'title': 'Nexus 10',
1532
+ 'screen': {
1533
+ 'horizontal': { 'width': 1280, 'height': 800 },
1534
+ 'device-pixel-ratio': 2,
1535
+ 'vertical': { 'width': 800, 'height': 1280 },
1536
+ },
1537
+ 'capabilities': ['touch', 'mobile'],
1538
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36',
1539
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '6.0.1', 'architecture': '', 'model': 'Nexus 10', 'mobile': false },
1540
+ 'type': 'tablet',
1541
+ },
1542
+ {
1543
+ 'show-by-default': false,
1544
+ 'title': 'Nexus 7',
1545
+ 'screen': {
1546
+ 'horizontal': { 'width': 960, 'height': 600 },
1547
+ 'device-pixel-ratio': 2,
1548
+ 'vertical': { 'width': 600, 'height': 960 },
1549
+ },
1550
+ 'capabilities': ['touch', 'mobile'],
1551
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36',
1552
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '6.0.1', 'architecture': '', 'model': 'Nexus 7', 'mobile': false },
1553
+ 'type': 'tablet',
1554
+ },
1555
+ {
1556
+ 'show-by-default': false,
1557
+ 'title': 'Galaxy Note 3',
1558
+ 'screen': {
1559
+ 'horizontal': { 'width': 640, 'height': 360 },
1560
+ 'device-pixel-ratio': 3,
1561
+ 'vertical': { 'width': 360, 'height': 640 },
1562
+ },
1563
+ 'capabilities': ['touch', 'mobile'],
1564
+ 'user-agent': 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
1565
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '4.3', 'architecture': '', 'model': 'SM-N900T', 'mobile': true },
1566
+ 'type': 'phone',
1567
+ },
1568
+ {
1569
+ 'show-by-default': false,
1570
+ 'title': 'Galaxy Note II',
1571
+ 'screen': {
1572
+ 'horizontal': { 'width': 640, 'height': 360 },
1573
+ 'device-pixel-ratio': 2,
1574
+ 'vertical': { 'width': 360, 'height': 640 },
1575
+ },
1576
+ 'capabilities': ['touch', 'mobile'],
1577
+ 'user-agent': 'Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
1578
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '4.1', 'architecture': '', 'model': 'GT-N7100', 'mobile': true },
1579
+ 'type': 'phone',
1580
+ },
1581
+ {
1582
+ 'show-by-default': false,
1583
+ /* DEVICE-LIST-IF-JS */
1584
+ 'title': i18nLazyString(UIStrings.laptopWithTouch),
1585
+ /* DEVICE-LIST-ELSE
1586
+ 'title': 'Laptop with touch',
1587
+ DEVICE-LIST-END-IF */
1588
+ 'screen': {
1589
+ 'horizontal': { 'width': 1280, 'height': 950 },
1590
+ 'device-pixel-ratio': 1,
1591
+ 'vertical': { 'width': 950, 'height': 1280 },
1592
+ },
1593
+ 'capabilities': ['touch'],
1594
+ 'user-agent': '',
1595
+ 'type': 'notebook',
1596
+ 'modes': [{ 'title': 'default', 'orientation': 'horizontal' }],
1597
+ },
1598
+ {
1599
+ 'show-by-default': false,
1600
+ /* DEVICE-LIST-IF-JS */
1601
+ 'title': i18nLazyString(UIStrings.laptopWithHiDPIScreen),
1602
+ /* DEVICE-LIST-ELSE
1603
+ 'title': 'Laptop with HiDPI screen',
1604
+ DEVICE-LIST-END-IF */
1605
+ 'screen': {
1606
+ 'horizontal': { 'width': 1440, 'height': 900 },
1607
+ 'device-pixel-ratio': 2,
1608
+ 'vertical': { 'width': 900, 'height': 1440 },
1609
+ },
1610
+ 'capabilities': [],
1611
+ 'user-agent': '',
1612
+ 'type': 'notebook',
1613
+ 'modes': [{ 'title': 'default', 'orientation': 'horizontal' }],
1614
+ },
1615
+ {
1616
+ 'show-by-default': false,
1617
+ /* DEVICE-LIST-IF-JS */
1618
+ 'title': i18nLazyString(UIStrings.laptopWithMDPIScreen),
1619
+ /* DEVICE-LIST-ELSE
1620
+ 'title': 'Laptop with MDPI screen',
1621
+ DEVICE-LIST-END-IF */
1622
+ 'screen': {
1623
+ 'horizontal': { 'width': 1280, 'height': 800 },
1624
+ 'device-pixel-ratio': 1,
1625
+ 'vertical': { 'width': 800, 'height': 1280 },
1626
+ },
1627
+ 'capabilities': [],
1628
+ 'user-agent': '',
1629
+ 'type': 'notebook',
1630
+ 'modes': [{ 'title': 'default', 'orientation': 'horizontal' }],
1631
+ },
1632
+ {
1633
+ 'show-by-default': false,
1634
+ 'title': 'Moto G4',
1635
+ 'screen': {
1636
+ 'horizontal': {
1637
+ 'outline': {
1638
+ 'image': '@url(optimized/MotoG4-landscape.avif)',
1639
+ 'insets': { 'left': 91, 'top': 30, 'right': 74, 'bottom': 30 },
1640
+ },
1641
+ 'width': 640,
1642
+ 'height': 360,
1643
+ },
1644
+ 'device-pixel-ratio': 3,
1645
+ 'vertical': {
1646
+ 'outline': {
1647
+ 'image': '@url(optimized/MotoG4-portrait.avif)',
1648
+ 'insets': { 'left': 30, 'top': 91, 'right': 30, 'bottom': 74 },
1649
+ },
1650
+ 'width': 360,
1651
+ 'height': 640,
1652
+ },
1653
+ },
1654
+ 'capabilities': ['touch', 'mobile'],
1655
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1656
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '6.0.1', 'architecture': '', 'model': 'Moto G (4)', 'mobile': true },
1657
+ 'type': 'phone',
1658
+ },
1659
+ {
1660
+ 'show-by-default': false,
1661
+ 'title': 'Moto G Power',
1662
+ 'screen': {
1663
+ 'device-pixel-ratio': 1.75,
1664
+ 'horizontal': {
1665
+ 'width': 823,
1666
+ 'height': 412,
1667
+ },
1668
+ 'vertical': {
1669
+ 'width': 412,
1670
+ 'height': 823,
1671
+ },
1672
+ },
1673
+ 'capabilities': ['touch', 'mobile'],
1674
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 11; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile Safari/537.36',
1675
+ 'user-agent-metadata': {
1676
+ 'platform': 'Android',
1677
+ 'platformVersion': '11',
1678
+ 'architecture': '',
1679
+ 'model': 'moto g power (2022)',
1680
+ 'mobile': true,
1681
+ },
1682
+ 'type': 'phone',
1683
+ },
1684
+ {
1685
+ 'order': 200,
1686
+ 'show-by-default': false,
1687
+ 'title': 'Facebook on Android',
1688
+ 'screen': {
1689
+ 'horizontal': {
1690
+ 'width': 892,
1691
+ 'height': 412,
1692
+ },
1693
+ 'device-pixel-ratio': 3.5,
1694
+ 'vertical': {
1695
+ 'width': 412,
1696
+ 'height': 892,
1697
+ },
1698
+ },
1699
+ 'capabilities': ['touch', 'mobile'],
1700
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 12; Pixel 6 Build/SQ3A.220705.004; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/%s Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/407.0.0.0.65;]',
1701
+ 'user-agent-metadata': { 'platform': 'Android', 'platformVersion': '12', 'architecture': '', 'model': 'Pixel 6', 'mobile': true },
1702
+ 'type': 'phone',
1703
+ },
1704
+ // DEVICE-LIST-END
1705
+ ];
1706
+ /* eslint-enable @stylistic/quote-props */