chrome-devtools-frontend 1.0.1029795 → 1.0.1030946
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.
- package/config/gni/devtools_grd_files.gni +3 -0
- package/config/gni/devtools_image_files.gni +2 -0
- package/docs/workflows.md +1 -1
- package/front_end/Images/src/file-sync_icon.svg +62 -0
- package/front_end/Images/src/file_icon.svg +52 -0
- package/front_end/Tests.js +0 -28
- package/front_end/core/host/UserMetrics.ts +2 -1
- package/front_end/core/i18n/locales/en-US.json +16 -7
- package/front_end/core/i18n/locales/en-XL.json +16 -7
- package/front_end/core/root/Runtime.ts +1 -0
- package/front_end/core/sdk/CSSStyleSheetHeader.ts +0 -4
- package/front_end/core/sdk/CompilerSourceMappingContentProvider.ts +0 -4
- package/front_end/core/sdk/NetworkRequest.ts +0 -4
- package/front_end/core/sdk/Resource.ts +0 -5
- package/front_end/core/sdk/Script.ts +71 -76
- package/front_end/entrypoints/main/MainImpl.ts +4 -0
- package/front_end/generated/InspectorBackendCommands.js +10 -8
- package/front_end/generated/protocol-mapping.d.ts +16 -2
- package/front_end/generated/protocol-proxy-api.d.ts +11 -1
- package/front_end/generated/protocol.ts +75 -1
- package/front_end/models/bindings/CompilerScriptMapping.ts +6 -3
- package/front_end/models/bindings/ContentProviderBasedProject.ts +2 -3
- package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +1 -4
- package/front_end/models/bindings/IgnoreListManager.ts +10 -8
- package/front_end/models/bindings/ResourceMapping.ts +0 -4
- package/front_end/models/bindings/StylesSourceMapping.ts +0 -5
- package/front_end/models/extensions/ExtensionServer.ts +2 -3
- package/front_end/models/issues_manager/AttributionReportingIssue.ts +8 -0
- package/front_end/models/issues_manager/DeprecationIssue.ts +5 -1
- package/front_end/models/issues_manager/descriptions/arTooManyConcurrentRequests.md +5 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +6 -2
- package/front_end/models/persistence/NetworkPersistenceManager.ts +4 -6
- package/front_end/models/persistence/PersistenceActions.ts +5 -4
- package/front_end/models/text_utils/CodeMirrorUtils.ts +17 -4
- package/front_end/models/text_utils/ContentProvider.ts +0 -1
- package/front_end/models/text_utils/StaticContentProvider.ts +0 -4
- package/front_end/models/workspace/UISourceCode.ts +10 -5
- package/front_end/panels/elements/CSSRuleValidator.ts +382 -63
- package/front_end/panels/elements/CSSRuleValidatorHelper.ts +34 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
- package/front_end/panels/elements/components/CSSHintDetailsView.ts +23 -20
- package/front_end/panels/elements/components/cssHintDetailsView.css +2 -0
- package/front_end/panels/issues/AttributionReportingIssueDetailsView.ts +12 -0
- package/front_end/panels/network/components/RequestHeadersView.css +41 -8
- package/front_end/panels/network/components/RequestHeadersView.ts +102 -12
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -0
- package/front_end/panels/sources/NavigatorView.ts +22 -0
- package/front_end/third_party/codemirror.next/bundle.ts +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -2
- package/front_end/third_party/codemirror.next/chunk/java.js +1 -2
- package/front_end/third_party/codemirror.next/chunk/json.js +1 -2
- package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -2
- package/front_end/third_party/codemirror.next/chunk/php.js +1 -2
- package/front_end/third_party/codemirror.next/chunk/python.js +1 -2
- package/front_end/third_party/codemirror.next/chunk/wast.js +1 -2
- package/front_end/third_party/codemirror.next/chunk/xml.js +1 -2
- package/front_end/third_party/codemirror.next/codemirror.next.d.ts +1247 -116
- package/front_end/third_party/codemirror.next/codemirror.next.js +1 -2
- package/front_end/ui/components/data_grid/DataGrid.ts +15 -10
- package/front_end/ui/components/data_grid/DataGridController.ts +7 -0
- package/front_end/ui/components/docs/building-ui-documentation/StylingComponents.md +64 -0
- package/front_end/ui/legacy/components/source_frame/ImageView.ts +10 -11
- package/front_end/ui/legacy/components/source_frame/PreviewFactory.ts +1 -1
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +49 -0
- package/package.json +6 -5
@@ -1,2 +1 @@
|
|
1
|
-
export{
|
2
|
-
|
1
|
+
export{aw as Annotation,ax as AnnotationType,ay as ChangeDesc,az as ChangeSet,aA as Compartment,W as CompletionContext,aO as Decoration,m as EditorSelection,aB as EditorState,aQ as EditorView,aC as Facet,aS as GutterMarker,ao as HighlightStyle,L as LRParser,k as Language,e as LanguageSupport,aD as Line,aE as MapMode,aX as MatchDecorator,g as NodeProp,h as NodeSet,N as NodeType,P as Parser,n as Prec,aF as Range,aG as RangeSet,aH as RangeSetBuilder,aI as SelectionRange,aJ as StateEffect,aK as StateEffectType,aL as StateField,ar as StreamLanguage,as as StringStream,b7 as StyleModule,T as Tag,aM as Text,aN as Transaction,j as Tree,b5 as TreeCursor,b2 as ViewPlugin,b3 as ViewUpdate,b4 as WidgetType,O as acceptCompletion,Q as autocompletion,aj as bracketMatching,y as clojure,R as closeBrackets,S as closeBracketsKeymap,U as closeCompletion,ak as codeFolding,z as coffeescript,V as completeAnyWord,A as cpp,ag as css,J as cssStreamParser,X as currentCompletions,$ as cursorMatchingBracket,a0 as cursorSubwordBackward,a1 as cursorSubwordForward,aP as drawSelection,al as ensureSyntaxTree,am as foldGutter,an as foldKeymap,aR as gutter,aT as gutters,au as highlightSelectionMatches,aU as highlightSpecialChars,b6 as highlightTree,a2 as history,a3 as historyKeymap,ah as html,Y as ifNotIn,a4 as indentLess,a5 as indentMore,ap as indentOnInput,aq as indentUnit,a6 as insertNewlineAndIndent,B as java,ai as javascript,D as json,o as keymap,aV as lineNumberMarkers,aW as lineNumbers,F as markdown,G as php,aY as placeholder,H as python,a7 as redo,a8 as redoSelection,aZ as repositionTooltips,a_ as scrollPastEnd,a9 as selectMatchingBracket,av as selectNextOccurrence,aa as selectSubwordBackward,ab as selectSubwordForward,Z as selectedCompletion,I as shell,a$ as showPanel,b0 as showTooltip,ac as standardKeymap,_ as startCompletion,at as syntaxHighlighting,l as syntaxTree,t as tags,ad as toggleComment,b1 as tooltips,ae as undo,af as undoSelection,K as wast,M as xml}from"./chunk/codemirror.js";
|
@@ -58,6 +58,7 @@ export interface DataGridData {
|
|
58
58
|
activeSort: SortState|null;
|
59
59
|
contextMenus?: DataGridContextMenusConfiguration;
|
60
60
|
label?: string;
|
61
|
+
paddingRowsCount?: number;
|
61
62
|
}
|
62
63
|
|
63
64
|
const enum UserScrollState {
|
@@ -69,7 +70,6 @@ const enum UserScrollState {
|
|
69
70
|
const KEYS_TREATED_AS_CLICKS = new Set([' ', 'Enter']);
|
70
71
|
|
71
72
|
const ROW_HEIGHT_PIXELS = 18;
|
72
|
-
const PADDING_ROWS_COUNT = 10;
|
73
73
|
|
74
74
|
export class DataGrid extends HTMLElement {
|
75
75
|
static readonly litTagName = LitHtml.literal`devtools-data-grid`;
|
@@ -82,6 +82,7 @@ export class DataGrid extends HTMLElement {
|
|
82
82
|
#userScrollState: UserScrollState = UserScrollState.NOT_SCROLLED;
|
83
83
|
#contextMenus?: DataGridContextMenusConfiguration = undefined;
|
84
84
|
#label?: string = undefined;
|
85
|
+
#paddingRowsCount = 10;
|
85
86
|
#currentResize: {
|
86
87
|
rightCellCol: HTMLTableColElement,
|
87
88
|
leftCellCol: HTMLTableColElement,
|
@@ -139,6 +140,7 @@ export class DataGrid extends HTMLElement {
|
|
139
140
|
activeSort: this.#sortState,
|
140
141
|
contextMenus: this.#contextMenus,
|
141
142
|
label: this.#label,
|
143
|
+
paddingRowsCount: this.#paddingRowsCount,
|
142
144
|
};
|
143
145
|
}
|
144
146
|
|
@@ -171,6 +173,10 @@ export class DataGrid extends HTMLElement {
|
|
171
173
|
this.#cellToFocusIfUserTabsIn = calculateFirstFocusableCell({columns: this.#columns, rows: this.#rows});
|
172
174
|
}
|
173
175
|
|
176
|
+
if (data.paddingRowsCount !== undefined) {
|
177
|
+
this.#paddingRowsCount = data.paddingRowsCount;
|
178
|
+
}
|
179
|
+
|
174
180
|
if (this.#hasRenderedAtLeastOnce && this.#userHasCellFocused()) {
|
175
181
|
const [selectedColIndex, selectedRowIndex] = this.#tabbableCell();
|
176
182
|
const columnOutOfBounds = selectedColIndex > this.#columns.length;
|
@@ -220,15 +226,14 @@ export class DataGrid extends HTMLElement {
|
|
220
226
|
return;
|
221
227
|
}
|
222
228
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
229
|
+
const wrapper = this.#shadow.querySelector('.wrapping-container');
|
230
|
+
if (!wrapper) {
|
231
|
+
return;
|
232
|
+
}
|
233
|
+
|
234
|
+
void coordinator.scroll(() => {
|
228
235
|
const scrollHeight = wrapper.scrollHeight;
|
229
|
-
|
230
|
-
wrapper.scrollTo(0, scrollHeight);
|
231
|
-
});
|
236
|
+
wrapper.scrollTo(0, scrollHeight);
|
232
237
|
});
|
233
238
|
}
|
234
239
|
|
@@ -643,7 +648,7 @@ export class DataGrid extends HTMLElement {
|
|
643
648
|
scrollTop = wrapper.scrollTop;
|
644
649
|
clientHeight = wrapper.clientHeight;
|
645
650
|
}
|
646
|
-
const padding = ROW_HEIGHT_PIXELS *
|
651
|
+
const padding = ROW_HEIGHT_PIXELS * this.#paddingRowsCount;
|
647
652
|
let topVisibleRow = Math.floor((scrollTop - padding) / ROW_HEIGHT_PIXELS);
|
648
653
|
let bottomVisibleRow = Math.ceil((scrollTop + clientHeight + padding) / ROW_HEIGHT_PIXELS);
|
649
654
|
|
@@ -31,6 +31,7 @@ export interface DataGridControllerData {
|
|
31
31
|
initialSort?: SortState;
|
32
32
|
contextMenus?: DataGridContextMenusConfiguration;
|
33
33
|
label?: string;
|
34
|
+
paddingRowsCount?: number;
|
34
35
|
}
|
35
36
|
|
36
37
|
export class DataGridController extends HTMLElement {
|
@@ -55,6 +56,8 @@ export class DataGridController extends HTMLElement {
|
|
55
56
|
#sortState: Readonly<SortState>|null = null;
|
56
57
|
#filters: readonly TextUtils.TextUtils.ParsedFilter[] = [];
|
57
58
|
|
59
|
+
#paddingRowsCount?: number;
|
60
|
+
|
58
61
|
connectedCallback(): void {
|
59
62
|
this.#shadow.adoptedStyleSheets = [dataGridControllerStyles];
|
60
63
|
}
|
@@ -66,6 +69,7 @@ export class DataGridController extends HTMLElement {
|
|
66
69
|
filters: this.#filters,
|
67
70
|
contextMenus: this.#contextMenus,
|
68
71
|
label: this.#label,
|
72
|
+
paddingRowsCount: this.#paddingRowsCount,
|
69
73
|
};
|
70
74
|
}
|
71
75
|
|
@@ -88,6 +92,8 @@ export class DataGridController extends HTMLElement {
|
|
88
92
|
this.#sortRows(this.#sortState);
|
89
93
|
}
|
90
94
|
|
95
|
+
this.#paddingRowsCount = data.paddingRowsCount;
|
96
|
+
|
91
97
|
this.#render();
|
92
98
|
}
|
93
99
|
|
@@ -222,6 +228,7 @@ export class DataGridController extends HTMLElement {
|
|
222
228
|
activeSort: this.#sortState,
|
223
229
|
contextMenus: this.#contextMenus,
|
224
230
|
label: this.#label,
|
231
|
+
paddingRowsCount: this.#paddingRowsCount,
|
225
232
|
} as DataGridData}
|
226
233
|
@columnheaderclick=${this.#onColumnHeaderClick}
|
227
234
|
@contextmenucolumnsortclick=${this.#onContextMenuColumnSortClick}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Styling Components
|
2
|
+
|
3
|
+
Components are styled by a CSS file that is co-located next to the TypeScript source file. The only difference in file name is the extension and that for CSS files, the first letter is lowercase:
|
4
|
+
|
5
|
+
```
|
6
|
+
- ElementsBreadcrumbs.ts
|
7
|
+
- elementsBreadcrumbs.css
|
8
|
+
```
|
9
|
+
|
10
|
+
To import this file you use a regular `import` statement, and import the filename with `.js` appended:
|
11
|
+
|
12
|
+
```ts
|
13
|
+
import elementsBreadcrumbsStyles from './elementsBreadcrumbs.css.js';
|
14
|
+
```
|
15
|
+
|
16
|
+
As part of the build tool step, each CSS file is converted into a JS file that exports a `CSSStyleSheet` instance. This is done by Rollup in [`generate_css_js_files`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/devtools-frontend/src/scripts/build/generate_css_js_files.js;l=1;drc=28af9fbe783d82aa64bfa5f9b9509572dc2b3efe).
|
17
|
+
|
18
|
+
## `BUILD.gn` changes
|
19
|
+
|
20
|
+
Use the `generate_css` action (`scripts/build/ninja/generate_css.gni`) to declare stylesheets:
|
21
|
+
|
22
|
+
```gn
|
23
|
+
import("scripts/build/ninja/generate_css.gni") // Edit path correctly: this must be relative
|
24
|
+
|
25
|
+
generate_css("css_files") {
|
26
|
+
sources = [ "elementsBreadcrumbs.css"]
|
27
|
+
}
|
28
|
+
```
|
29
|
+
|
30
|
+
And then add `:css_files` as a dependency to the `devtools_entrypoint`:
|
31
|
+
|
32
|
+
```gn
|
33
|
+
devtools_entrypoint("bundle") {
|
34
|
+
deps = [ ":css_files" , "..."]
|
35
|
+
}
|
36
|
+
```
|
37
|
+
|
38
|
+
## Adopting the stylesheet
|
39
|
+
|
40
|
+
Importing the stylesheet is not enough to have it apply to the component's ShadowDOM, it must be adopted. The `connectedCallback` method is the best place for this:
|
41
|
+
|
42
|
+
```ts
|
43
|
+
connectedCallback() {
|
44
|
+
this.#shadow.adoptedStyleSheets = [elementsBreadcrumbs];
|
45
|
+
}
|
46
|
+
```
|
47
|
+
|
48
|
+
## Tips for writing CSS.
|
49
|
+
|
50
|
+
Use `:host` to style the component itself. By default elements are `display: inline`. Often it can be useful to set `display: block`.
|
51
|
+
|
52
|
+
Remember to use theme colors (`var(--color-text-primary)`) when styling elements to ensure consistency across DevTools.
|
53
|
+
|
54
|
+
If you want your component to have its colors configurable by users, consider defining `--override` variables. In your component's CSS, you would have something like:
|
55
|
+
|
56
|
+
```css
|
57
|
+
:host {
|
58
|
+
color: var(--override-custom-color, var(--color-text-primary));
|
59
|
+
}
|
60
|
+
```
|
61
|
+
|
62
|
+
This allows someone to define that `--override-custom-color` variable, but also ensures if it isn't defined that the default `color-text-primary` will be used. **Be careful with this!** We try to ensure consistent colors across DevTools; so most of the time you shouldn't allow configurable colors and should use the correct theme variables.
|
63
|
+
|
64
|
+
|
@@ -95,7 +95,7 @@ export class ImageView extends UI.View.SimpleView {
|
|
95
95
|
private readonly mimeTypeLabel: UI.Toolbar.ToolbarText;
|
96
96
|
private readonly container: HTMLElement;
|
97
97
|
private imagePreviewElement: HTMLImageElement;
|
98
|
-
private cachedContent?:
|
98
|
+
private cachedContent?: TextUtils.ContentProvider.DeferredContent;
|
99
99
|
constructor(mimeType: string, contentProvider: TextUtils.ContentProvider.ContentProvider) {
|
100
100
|
super(i18nString(UIStrings.image));
|
101
101
|
this.registerRequiredCSS(imageViewStyles);
|
@@ -153,20 +153,21 @@ export class ImageView extends UI.View.SimpleView {
|
|
153
153
|
}
|
154
154
|
|
155
155
|
private async updateContentIfNeeded(): Promise<void> {
|
156
|
-
const
|
157
|
-
if (this.cachedContent === content) {
|
156
|
+
const content = await this.contentProvider.requestContent();
|
157
|
+
if (this.cachedContent?.content === content.content) {
|
158
158
|
return;
|
159
159
|
}
|
160
160
|
|
161
|
-
const contentEncoded = await this.contentProvider.contentEncoded();
|
162
161
|
this.cachedContent = content;
|
163
|
-
const imageSrc =
|
162
|
+
const imageSrc =
|
163
|
+
TextUtils.ContentProvider.contentAsDataURL(content.content, this.mimeType, content.isEncoded) || this.url;
|
164
164
|
const loadPromise = new Promise(x => {
|
165
165
|
this.imagePreviewElement.onload = x;
|
166
166
|
});
|
167
167
|
this.imagePreviewElement.src = imageSrc;
|
168
168
|
this.imagePreviewElement.alt = i18nString(UIStrings.imageFromS, {PH1: this.url});
|
169
|
-
const size = content && !
|
169
|
+
const size = content.content && !content.isEncoded ? content.content.length :
|
170
|
+
Platform.StringUtilities.base64ToSize(content.content);
|
170
171
|
this.sizeLabel.setText(Platform.NumberUtilities.bytesToString(size));
|
171
172
|
await loadPromise;
|
172
173
|
this.dimensionsLabel.setText(i18nString(
|
@@ -203,13 +204,11 @@ export class ImageView extends UI.View.SimpleView {
|
|
203
204
|
}
|
204
205
|
|
205
206
|
private async saveImage(): Promise<void> {
|
206
|
-
|
207
|
-
if (!this.cachedContent) {
|
207
|
+
if (!this.cachedContent || !this.cachedContent.content) {
|
208
208
|
return;
|
209
209
|
}
|
210
|
-
const
|
211
|
-
|
212
|
-
TextUtils.ContentProvider.contentAsDataURL(cachedContent, this.mimeType, contentEncoded, '', false);
|
210
|
+
const imageDataURL = TextUtils.ContentProvider.contentAsDataURL(
|
211
|
+
this.cachedContent.content, this.mimeType, this.cachedContent.isEncoded, '', false);
|
213
212
|
|
214
213
|
if (!imageDataURL) {
|
215
214
|
return;
|
@@ -460,6 +460,55 @@ export class SourceFrameImpl extends Common.ObjectWrapper.eventMixin<EventTypes,
|
|
460
460
|
}
|
461
461
|
}
|
462
462
|
|
463
|
+
// If the input is wasm but v8-based wasm disassembly failed, fall back to wasmparser for backwards compatibility.
|
464
|
+
if (content && this.contentType === 'application/wasm' && !this.wasmDisassemblyInternal) {
|
465
|
+
const worker = Common.Worker.WorkerWrapper.fromURL(
|
466
|
+
new URL('../../../../entrypoints/wasmparser_worker/wasmparser_worker-entrypoint.js', import.meta.url));
|
467
|
+
const promise = new Promise<{
|
468
|
+
lines: string[],
|
469
|
+
offsets: number[],
|
470
|
+
functionBodyOffsets: {
|
471
|
+
start: number,
|
472
|
+
end: number,
|
473
|
+
}[],
|
474
|
+
}>((resolve, reject) => {
|
475
|
+
worker.onmessage =
|
476
|
+
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
477
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
478
|
+
({data}: MessageEvent<any>): void => {
|
479
|
+
if ('event' in data) {
|
480
|
+
switch (data.event) {
|
481
|
+
case 'progress':
|
482
|
+
progressIndicator.setWorked(data.params.percentage);
|
483
|
+
break;
|
484
|
+
}
|
485
|
+
} else if ('method' in data) {
|
486
|
+
switch (data.method) {
|
487
|
+
case 'disassemble':
|
488
|
+
if ('error' in data) {
|
489
|
+
reject(data.error);
|
490
|
+
} else if ('result' in data) {
|
491
|
+
resolve(data.result);
|
492
|
+
}
|
493
|
+
break;
|
494
|
+
}
|
495
|
+
}
|
496
|
+
};
|
497
|
+
worker.onerror = reject;
|
498
|
+
});
|
499
|
+
worker.postMessage({method: 'disassemble', params: {content}});
|
500
|
+
try {
|
501
|
+
const {lines, offsets, functionBodyOffsets} = await promise;
|
502
|
+
this.rawContent = content = CodeMirror.Text.of(lines);
|
503
|
+
this.wasmDisassemblyInternal =
|
504
|
+
new Common.WasmDisassembly.WasmDisassembly(lines, offsets, functionBodyOffsets);
|
505
|
+
} catch (e) {
|
506
|
+
this.rawContent = content = error = e.message;
|
507
|
+
} finally {
|
508
|
+
worker.terminate();
|
509
|
+
}
|
510
|
+
}
|
511
|
+
|
463
512
|
progressIndicator.setWorked(100);
|
464
513
|
progressIndicator.done();
|
465
514
|
|
package/package.json
CHANGED
@@ -19,12 +19,13 @@
|
|
19
19
|
"url": "git+https://github.com/ChromeDevTools/devtools-frontend.git"
|
20
20
|
},
|
21
21
|
"scripts": {
|
22
|
-
"auto-debug-e2etest": "
|
23
|
-
"auto-debug-interactionstest": "
|
22
|
+
"auto-debug-e2etest": "npm run build && npm run debug-e2etest --",
|
23
|
+
"auto-debug-interactionstest": "npm run build && npm run debug-interactionstest --",
|
24
24
|
"auto-debug-unittest": "DEBUG_TEST=1 npm run auto-unittest --",
|
25
|
-
"auto-e2etest": "
|
26
|
-
"auto-interactionstest": "
|
25
|
+
"auto-e2etest": "npm run build && npm run e2etest --",
|
26
|
+
"auto-interactionstest": "npm run build && npm run interactionstest --",
|
27
27
|
"auto-unittest": "scripts/test/run_auto_unittests.py --no-text-coverage",
|
28
|
+
"prebuild": "gn gen out/Default",
|
28
29
|
"build": "autoninja -C out/Default",
|
29
30
|
"build-release": "autoninja -C out/Release",
|
30
31
|
"check": "npm run check-lint && npm run check-loc",
|
@@ -55,5 +56,5 @@
|
|
55
56
|
"unittest": "scripts/test/run_unittests.py --no-text-coverage",
|
56
57
|
"watch": "vpython third_party/node/node.py --output scripts/watch_build.js"
|
57
58
|
},
|
58
|
-
"version": "1.0.
|
59
|
+
"version": "1.0.1030946"
|
59
60
|
}
|