chrome-devtools-frontend 1.0.1534251 → 1.0.1535712

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 (44) hide show
  1. package/docs/contributing/infrastructure.md +32 -0
  2. package/docs/contributing/issues.md +15 -37
  3. package/eslint.config.mjs +1 -0
  4. package/front_end/core/host/InspectorFrontendHost.ts +2 -0
  5. package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
  6. package/front_end/core/host/UserMetrics.ts +29 -1
  7. package/front_end/core/protocol_client/CDPConnection.ts +53 -5
  8. package/front_end/core/protocol_client/InspectorBackend.ts +0 -89
  9. package/front_end/core/protocol_client/protocol_client.ts +2 -0
  10. package/front_end/core/root/Runtime.ts +1 -0
  11. package/front_end/core/sdk/RehydratingConnection.ts +1 -1
  12. package/front_end/devtools_compatibility.js +230 -32
  13. package/front_end/generated/SupportedCSSProperties.js +38 -0
  14. package/front_end/models/ai_assistance/BuiltInAi.ts +141 -39
  15. package/front_end/panels/ai_assistance/PatchWidget.ts +39 -40
  16. package/front_end/panels/ai_assistance/components/ExploreWidget.ts +0 -2
  17. package/front_end/panels/autofill/AutofillView.ts +2 -3
  18. package/front_end/panels/changes/CombinedDiffView.ts +13 -14
  19. package/front_end/panels/common/BadgeNotification.ts +1 -3
  20. package/front_end/panels/console/ConsoleInsightTeaser.ts +8 -1
  21. package/front_end/panels/console/ConsoleView.ts +1 -0
  22. package/front_end/panels/console/consoleView.css +0 -1
  23. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
  24. package/front_end/panels/network/components/DirectSocketConnectionView.ts +4 -6
  25. package/front_end/panels/network/components/ResponseHeaderSection.ts +1 -2
  26. package/front_end/panels/security/CookieControlsView.ts +72 -66
  27. package/front_end/panels/security/CookieReportView.ts +15 -14
  28. package/front_end/panels/security/IPProtectionView.ts +1 -2
  29. package/front_end/panels/security/SecurityPanel.ts +19 -19
  30. package/front_end/panels/timeline/TimelineSelectorStatsView.ts +36 -36
  31. package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +1 -2
  32. package/front_end/third_party/chromium/README.chromium +1 -1
  33. package/front_end/ui/components/dialogs/Dialog.ts +7 -17
  34. package/front_end/ui/components/text_editor/TextEditor.ts +2 -3
  35. package/front_end/ui/components/text_editor/config.ts +1 -3
  36. package/front_end/ui/legacy/UIUtils.ts +5 -0
  37. package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +1 -1
  38. package/front_end/ui/legacy/components/perf_ui/BrickBreaker.ts +2 -2
  39. package/front_end/ui/legacy/components/perf_ui/Font.ts +1 -14
  40. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  41. package/inspector_overlay/testing/InspectorOverlayHelpers.ts +2 -10
  42. package/package.json +1 -1
  43. package/front_end/services/window_bounds/WindowBoundsService.ts +0 -27
  44. package/front_end/services/window_bounds/window_bounds.ts +0 -9
@@ -68,6 +68,27 @@ https://chromium.googlesource.com/chromium/tools/build/+/refs/heads/main/recipes
68
68
  and upload a CL for
69
69
  [`chromium/tools/build`](https://chromium.googlesource.com/chromium/tools/build/+/refs/heads/main).
70
70
 
71
+ It's good practice to also manually test your recipes. You can test your recipe
72
+ changes against a build that was performed with the same recipes. To do so
73
+ follow these steps:
74
+ - authenticate with `led auth-login`
75
+ - select a particular build that ran with your target recipe ([example](https://ci.chromium.org/ui/p/devtools-frontend/builders/try/dtf_linux_dbg/14161))
76
+ - got to Infra tab and collect the Buildbucket id (8700153319150087425 for the example above)
77
+ - run `led get-build --real-build 8700153319150087425 | led edit-recipe-bundle | led edit-system -p 25 | led launch` while in your local recipe checkout
78
+ - collect the output link to your test build and verify that you got the expected result
79
+
80
+ ## Pin older version of DevTools recipes to a branch
81
+
82
+ Updating a recipe that depends on DevTools repo recent changes can break the
83
+ build in beta/stable/extended branches. If those changes cannot be back-merged
84
+ into the branches you can pin the older version of the recipe to the branches in
85
+ infra/config.
86
+
87
+ To do so update the `legacy_recipe` config in `definitions.star` with the number
88
+ of the last branch you need the old version of the recipe to run on and with the
89
+ revision hash of that version. Branches with number higher than the one you
90
+ configured will run ToT recipe version. [Example](https://crrev.com/c/7003685)
91
+
71
92
  ## Updating test commands in the infrastructure
72
93
 
73
94
  The DevTools recipes are defined in
@@ -228,6 +249,17 @@ Below is a detailed description of what happens in such a build:
228
249
  - fail the builder if tests failed in the deflaking phase
229
250
  - otherwise report build as passing
230
251
 
252
+ ## Skip flake detection
253
+
254
+ Test that are already flaky can end up being updated in CLs that do not deal
255
+ with the original flakiness nor can be blamed for introducing or increasing the
256
+ flakiness of the test. However CQ builder will fail in Flake Detection steps
257
+ because they picked up the test as it was being touched.
258
+
259
+ You can skip Flake Detection for your tests by adding the `Skip-Flake-Detection`
260
+ CL footer (see example [CL](https://crrev.com/c/6994031)). Make sure you use the
261
+ full path to your test.
262
+
231
263
  ### Common build failures
232
264
 
233
265
  The first place where a build usually fails is on `bot_update` and this usually
@@ -61,53 +61,29 @@ Tracker]. This section provides an overview of the Chromium DevTools specifics.
61
61
  ### Issue types
62
62
 
63
63
  [crbug] supports a wide range of different issue types, with ambiguous semantics.
64
- For Chromium DevTools we explicitly limit the set of types we use and give them
65
- well-defined semantics:
64
+ For the Chromium DevTools component tree ([Chromium>Platform>DevTools]) we
65
+ explicitly limit the set of types we use and give them well-defined semantics:
66
66
 
67
67
  | Issue Type | Meaning |
68
68
  | -------------------- | ------------------------------------------ |
69
69
  | **Bug** | The behavior does not match what is supposed to occur or what is documented. The product does not work as expected. |
70
70
  | **Feature Request** | The product works as intended but could be improved. |
71
71
  | **Internal Cleanup** | This is typically a maintenance issue. The issue has no effect on the behavior of a product, but addressing it may allow more intuitive interaction. |
72
- | **Vulnerability** | Security vulnerabilities subject to the handling outlined in Google's [Vulnerability Priority Guidelines](http://go/vulnerability-slo). |
73
72
  | **Privacy Issue** | Privacy issues subject to the handling outlined in Google's [Privacy Issue Bugs](http://go/pib-slo). |
74
73
  | **Task** | A small unit of work. |
75
- | **Project** | A goal-driven effort with a finite start and end, focused on creating a unique product, service, or result. |
76
- | **Feature** | A collection of work that provides a specific value to the user. |
77
-
78
- The first 6 (**Bug** to **Task**) are used for day-to-day work and for issues
79
- reported by users. The last 2 (**Project** and **Feature**) are used to organize
80
- the other types of issues for the purpose of planning (ahead). We explicitly
81
- don't use Customer Issue, Process, Milestone, Epic, and Story within Chrome DevTools.
82
-
83
- *** promo
84
- **BEST PRACTICE:** Limit the nesting of **Project** and **Feature** to the bare
85
- minimum needed, and use **Task** for small chunks of work.
86
- ***
87
-
88
- ### Parent-Child Relationships and Blocking
89
-
90
- *** note
91
- **TL;DR:**
92
-
93
- - Prefer parent-child relationships to split work into smaller chunks.
94
- - Prefer blocking to express dependencies between independent / adjacent
95
- issues.
96
- ***
74
+ | **Vulnerability** | Security vulnerabilities subject to the handling outlined in Google's [Vulnerability Priority Guidelines](http://go/vulnerability-slo). |
97
75
 
98
- When splitting up work into smaller chunks or when scoping a project that
99
- encompasses multiple bugs or feature requests, favor to express this via a
100
- parent-child relationship. Consider the example of a CSS Nesting:
76
+ These are used to track day-to-day work, primarily issues reported by users. We
77
+ explicitly don't use the Customer Issue, Process, and Story types, because the
78
+ former is already sufficiently covered with **Bug**, **Privacy Issue** and
79
+ **Vulnerability**, while the latter two are basically just special sub types of
80
+ **Task** and this fine-grained distinction would add more confusion than good.
81
+ Any use of the disallowed issue types will be corrected automatically by the
82
+ [Blunderbuss](http://go/blunderbuss) bot.
101
83
 
102
- 1. This should start with an issue of type Feature which is about adding CSS
103
- Nesting support to Chromium DevTools.
104
- 1. This Feature has child issues of type Task, which are concerned with adding
105
- CSS Nesting support to the various parts of DevTools involved, for example
106
- the CDP (Chrome DevTools Protocol), the Elements panel, the Sources panel,
107
- and so forth.
108
- 1. Over the course of the project there'll likely also be Feature Requests and
109
- Bugs from internal and external developers, which should also be parented
110
- under the CSS Nesting Feature issue.
84
+ We also explicitly disallow goal-type issues in the [Chromium>Platform>DevTools]
85
+ component tree. Check out [go/chrome-tooling/project-management] for guidance
86
+ how to manage goals using **Feature** and **Project** (_Googlers-only_).
111
87
 
112
88
  ### Priorities
113
89
 
@@ -265,6 +241,8 @@ refreshed every 2-4 hours, to see SLO compliance for a given lead.
265
241
  [Chrome SLO Policy]: https://b.corp.google.com/slos/1834
266
242
  [go/chrome-slo]: http://go/chrome-slo
267
243
  [go/chrome-release-slos]: http://go/chrome-release-slos
244
+ [go/chrome-tooling/project-management]: http://go/chrome-tooling/project-management
268
245
  [Buganizer SLO Compliance]: go/b-slo-compliance
269
246
  [TaskFlow]: http://go/chrome-devtools:taskflow
270
247
  [TaskFlow Inbox]: http://go/chrome-devtools:taskflow/inbox
248
+ [Chromium>Platform>DevTools]: https://issues.chromium.org/components/1457055
package/eslint.config.mjs CHANGED
@@ -84,6 +84,7 @@ export default defineConfig([
84
84
 
85
85
  linterOptions: {
86
86
  reportUnusedDisableDirectives: 'error',
87
+ reportUnusedInlineConfigs: 'error',
87
88
  },
88
89
 
89
90
  rules: {
@@ -600,6 +600,7 @@ class InspectorFrontendAPIImpl {
600
600
  resourceLoaderStreamWrite(id, chunk);
601
601
  }
602
602
  }
603
+
603
604
  /**
604
605
  * Used in `front_end/devtools_compatibility.js` to verify that calls from there
605
606
  * are valid.
@@ -607,6 +608,7 @@ class InspectorFrontendAPIImpl {
607
608
  export type InspectorFrontendAPIImplMethods = keyof InspectorFrontendAPIImpl;
608
609
 
609
610
  (function(): void {
611
+
610
612
  function initializeInspectorFrontendHost(): void {
611
613
  if (!InspectorFrontendHostInstance) {
612
614
  // Instantiate stub for web-hosted mode if necessary.
@@ -550,5 +550,6 @@ export const enum EnumeratedHistogram {
550
550
  LighthouseCategoryUsed = 'DevTools.LighthouseCategoryUsed',
551
551
  SwatchActivated = 'DevTools.SwatchActivated',
552
552
  AnimationPlaybackRateChanged = 'DevTools.AnimationPlaybackRateChanged',
553
+ BuiltInAiAvailability = 'DevTools.BuiltInAiAvailability',
553
554
  // LINT.ThenChange(/front_end/devtools_compatibility.js:EnumeratedHistogram)
554
555
  }
@@ -307,6 +307,16 @@ export class UserMetrics {
307
307
  InspectorFrontendHostInstance.recordCountHistogram(
308
308
  'DevTools.PerformanceAI.MainThreadActivityResponseSize', bytes, 0, 100_000, 100);
309
309
  }
310
+
311
+ builtInAiAvailability(availability: BuiltInAiAvailability): void {
312
+ InspectorFrontendHostInstance.recordEnumeratedHistogram(
313
+ EnumeratedHistogram.BuiltInAiAvailability, availability, BuiltInAiAvailability.MAX_VALUE);
314
+ }
315
+
316
+ consoleInsightTeaserGenerated(timeInMilliseconds: number): void {
317
+ InspectorFrontendHostInstance.recordPerformanceHistogram(
318
+ 'DevTools.Insights.TeaserGenerationTime', timeInMilliseconds);
319
+ }
310
320
  }
311
321
 
312
322
  /**
@@ -513,7 +523,11 @@ export enum Action {
513
523
  AiCodeCompletionError = 188,
514
524
  AttributeLinkClicked = 189,
515
525
  InsightRequestedViaTeaser = 190,
516
- MAX_VALUE = 191,
526
+ InsightTeaserGenerationStarted = 191,
527
+ InsightTeaserGenerationCompleted = 192,
528
+ InsightTeaserGenerationAborted = 193,
529
+ InsightTeaserGenerationErrored = 194,
530
+ MAX_VALUE = 195,
517
531
  /* eslint-enable @typescript-eslint/naming-convention */
518
532
  }
519
533
 
@@ -1229,3 +1243,17 @@ export const enum TimelineNavigationSetting {
1229
1243
  SWITCHED_TO_MODERN = 3,
1230
1244
  MAX_VALUE = 4,
1231
1245
  }
1246
+
1247
+ export const enum BuiltInAiAvailability {
1248
+ UNAVAILABLE_HAS_GPU = 0,
1249
+ DOWNLOADABLE_HAS_GPU = 1,
1250
+ DOWNLOADING_HAS_GPU = 2,
1251
+ AVAILABLE_HAS_GPU = 3,
1252
+ DISABLED_HAS_GPU = 4,
1253
+ UNAVAILABLE_NO_GPU = 5,
1254
+ DOWNLOADABLE_NO_GPU = 6,
1255
+ DOWNLOADING_NO_GPU = 7,
1256
+ AVAILABLE_NO_GPU = 8,
1257
+ DISABLED_NO_GPU = 9,
1258
+ MAX_VALUE = 10,
1259
+ }
@@ -4,6 +4,55 @@
4
4
 
5
5
  import type {ProtocolMapping} from '../../generated/protocol-mapping.js';
6
6
 
7
+ export type CommandParams<T extends keyof ProtocolMapping.Commands> = ProtocolMapping.Commands[T]['paramsType'][0];
8
+ export type CommandResult<T extends keyof ProtocolMapping.Commands> = ProtocolMapping.Commands[T]['returnType'];
9
+ export type EventParams<T extends keyof ProtocolMapping.Events> = ProtocolMapping.Events[T];
10
+
11
+ export interface CDPBaseMessage {
12
+ sessionId?: string;
13
+ }
14
+
15
+ export interface CDPCommandRequest<T extends keyof ProtocolMapping.Commands> extends CDPBaseMessage {
16
+ id: number;
17
+ method: T;
18
+ params: CommandParams<T>;
19
+ }
20
+
21
+ export interface CDPCommandResponse<T extends keyof ProtocolMapping.Commands> extends CDPBaseMessage {
22
+ id: number;
23
+ result: CommandResult<T>;
24
+ }
25
+
26
+ export interface CDPEvent<T extends keyof ProtocolMapping.Events> extends CDPBaseMessage {
27
+ method: T;
28
+ params: EventParams<T>;
29
+ }
30
+
31
+ /**
32
+ * Keep this in sync with https://source.chromium.org/chromium/chromium/src/+/main:third_party/inspector_protocol/crdtp/dispatch.h.
33
+ */
34
+ export const enum CDPErrorStatus {
35
+ PARSE_ERROR = -32700,
36
+ INVALID_REQUEST = -32600,
37
+ METHOD_NOT_FOUND = -32601,
38
+ INVALID_PARAMS = -32602,
39
+ INTERNAL_ERROR = -32603,
40
+ SERVER_ERROR = -32000,
41
+ SESSION_NOT_FOUND = SERVER_ERROR - 1,
42
+ }
43
+
44
+ export interface CDPError extends CDPBaseMessage {
45
+ id?: number;
46
+ error: {
47
+ code: CDPErrorStatus,
48
+ message: string,
49
+ data?: string,
50
+ };
51
+ }
52
+
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
+ export type CDPMessage = CDPCommandRequest<any>|CDPCommandResponse<any>|CDPEvent<any>|CDPError;
55
+
7
56
  /**
8
57
  * Allows the sending and receiving of CDP commands and the notification of CDP events to observers.
9
58
  *
@@ -12,9 +61,8 @@ import type {ProtocolMapping} from '../../generated/protocol-mapping.js';
12
61
  * would conflict with any other shared traffic.
13
62
  */
14
63
  export interface CDPConnection {
15
- send<T extends keyof ProtocolMapping.Commands>(
16
- method: T, params: ProtocolMapping.Commands[T]['paramsType'][0],
17
- sessionId: string|undefined): Promise<ProtocolMapping.Commands[T]['returnType']|{getError(): string}>;
64
+ send<T extends keyof ProtocolMapping.Commands>(method: T, params: CommandParams<T>, sessionId: string|undefined):
65
+ Promise<CommandResult<T>|{getError(): string}>;
18
66
 
19
67
  observe(observer: CDPConnectionObserver): void;
20
68
  unobserve(observer: CDPConnectionObserver): void;
@@ -34,6 +82,6 @@ export interface DebuggableCDPConnection extends CDPConnection {
34
82
  }
35
83
 
36
84
  export interface RawMessageObserver {
37
- onMessageReceived(message: unknown): void;
38
- onMessageSent(message: unknown): void;
85
+ onMessageReceived(message: CDPMessage): void;
86
+ onMessageSent(message: CDPMessage): void;
39
87
  }
@@ -855,13 +855,11 @@ export class TargetBase {
855
855
  * of the invoke_enable, etc. methods that the front-end uses.
856
856
  */
857
857
  class AgentPrototype {
858
- replyArgs: Record<string, string[]>;
859
858
  description = '';
860
859
  metadata: Record<string, {parameters: CommandParameter[], description: string, replyArgs: string[]}>;
861
860
  readonly domain: string;
862
861
  target!: TargetBase;
863
862
  constructor(domain: string) {
864
- this.replyArgs = {};
865
863
  this.domain = domain;
866
864
  this.metadata = {};
867
865
  }
@@ -869,11 +867,6 @@ class AgentPrototype {
869
867
  registerCommand(
870
868
  methodName: UnqualifiedName, parameters: CommandParameter[], replyArgs: string[], description: string): void {
871
869
  const domainAndMethod = qualifyName(this.domain, methodName);
872
- function sendMessagePromise(this: AgentPrototype, ...args: unknown[]): Promise<unknown> {
873
- return AgentPrototype.prototype.sendMessageToBackendPromise.call(this, domainAndMethod, parameters, args);
874
- }
875
- // @ts-expect-error Method code generation
876
- this[methodName] = sendMessagePromise;
877
870
  this.metadata[domainAndMethod] = {parameters, description, replyArgs};
878
871
 
879
872
  function invoke(this: AgentPrototype, request: Object|undefined = {}): Promise<Protocol.ProtocolResponseWithError> {
@@ -882,88 +875,6 @@ class AgentPrototype {
882
875
 
883
876
  // @ts-expect-error Method code generation
884
877
  this['invoke_' + methodName] = invoke;
885
- this.replyArgs[domainAndMethod] = replyArgs;
886
- }
887
-
888
- private prepareParameters(
889
- method: string, parameters: CommandParameter[], args: unknown[], errorCallback: (arg0: string) => void): Object
890
- |null {
891
- const params: Record<string, unknown> = {};
892
- let hasParams = false;
893
-
894
- for (const param of parameters) {
895
- const paramName = param.name;
896
- const typeName = param.type;
897
- const optionalFlag = param.optional;
898
-
899
- if (!args.length && !optionalFlag) {
900
- errorCallback(
901
- `Protocol Error: Invalid number of arguments for method '${method}' call. ` +
902
- `It must have the following arguments ${JSON.stringify(parameters)}'.`);
903
- return null;
904
- }
905
-
906
- const value = args.shift();
907
- if (optionalFlag && typeof value === 'undefined') {
908
- continue;
909
- }
910
- const expectedJSType = typeName === 'array' ? 'object' : typeName;
911
- if (typeof value !== expectedJSType) {
912
- errorCallback(
913
- `Protocol Error: Invalid type of argument '${paramName}' for method '${method}' call. ` +
914
- `It must be '${typeName}' but it is '${typeof value}'.`);
915
- return null;
916
- }
917
-
918
- params[paramName] = value;
919
- hasParams = true;
920
- }
921
-
922
- if (args.length) {
923
- errorCallback(`Protocol Error: Extra ${args.length} arguments in a call to method '${method}'.`);
924
- return null;
925
- }
926
-
927
- return hasParams ? params : null;
928
- }
929
-
930
- private sendMessageToBackendPromise(method: QualifiedName, parameters: CommandParameter[], args: unknown[]):
931
- Promise<unknown> {
932
- let errorMessage;
933
- function onError(message: string): void {
934
- console.error(message);
935
- errorMessage = message;
936
- }
937
- const params = this.prepareParameters(method, parameters, args, onError);
938
- if (errorMessage) {
939
- return Promise.resolve(null);
940
- }
941
-
942
- return new Promise(resolve => {
943
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
944
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
945
- const callback: Callback = (error: MessageError|null, result: any|null): void => {
946
- if (error) {
947
- if (!test.suppressRequestErrors && error.code !== DevToolsStubErrorCode && error.code !== GenericErrorCode &&
948
- error.code !== ConnectionClosedErrorCode) {
949
- console.error('Request ' + method + ' failed. ' + JSON.stringify(error));
950
- }
951
-
952
- resolve(null);
953
- return;
954
- }
955
-
956
- const args = this.replyArgs[method];
957
- resolve(result && args.length ? result[args[0]] : undefined);
958
- };
959
-
960
- const router = this.target.router();
961
- if (!router) {
962
- SessionRouter.dispatchConnectionError(callback, method);
963
- } else {
964
- router.sendMessage(this.target.sessionId, this.domain, method, params, callback);
965
- }
966
- });
967
878
  }
968
879
 
969
880
  private invoke(method: QualifiedName, request: Object|null): Promise<Protocol.ProtocolResponseWithError> {
@@ -2,11 +2,13 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ import * as CDPConnection from './CDPConnection.js';
5
6
  import * as ConnectionTransport from './ConnectionTransport.js';
6
7
  import * as InspectorBackend from './InspectorBackend.js';
7
8
  import * as NodeURL from './NodeURL.js';
8
9
 
9
10
  export {
11
+ CDPConnection,
10
12
  ConnectionTransport,
11
13
  InspectorBackend,
12
14
  NodeURL,
@@ -521,6 +521,7 @@ interface DevToolsStartingStyleDebugging {
521
521
 
522
522
  interface AiPromptApi {
523
523
  enabled: boolean;
524
+ allowWithoutGpu: boolean;
524
525
  }
525
526
 
526
527
  interface DevToolsIndividualRequestThrottling {
@@ -109,7 +109,7 @@ export class RehydratingConnection implements ProtocolClient.ConnectionTransport
109
109
  if (this.#rehydratingWindow.opener) {
110
110
  this.#rehydratingWindow.opener.postMessage({type: 'REHYDRATING_WINDOW_READY'});
111
111
  } else if (this.#rehydratingWindow !== window.top) {
112
- this.#rehydratingWindow.parent.postMessage({type: 'REHYDRATING_IFRAME_READY'});
112
+ this.#rehydratingWindow.parent.postMessage({type: 'REHYDRATING_IFRAME_READY'}, '*');
113
113
  } else {
114
114
  this.#onConnectionLost(i18nString(UIStrings.noHostWindow));
115
115
  }