@myrmidon/gve-core 0.0.6 → 1.0.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.
- package/fesm2022/myrmidon-gve-core.mjs +134 -136
- package/fesm2022/myrmidon-gve-core.mjs.map +1 -1
- package/lib/components/feature-editor/feature-editor.component.d.ts +1 -1
- package/package.json +6 -8
- package/esm2022/lib/components/animation-timeline/animation-timeline.component.mjs +0 -207
- package/esm2022/lib/components/animation-timeline-set/animation-timeline-set.component.mjs +0 -154
- package/esm2022/lib/components/animation-tween/animation-tween.component.mjs +0 -184
- package/esm2022/lib/components/base-text-char/base-text-char.component.mjs +0 -46
- package/esm2022/lib/components/base-text-editor/base-text-editor.component.mjs +0 -115
- package/esm2022/lib/components/base-text-view/base-text-view.component.mjs +0 -159
- package/esm2022/lib/components/batch-operation-editor/batch-operation-editor.component.mjs +0 -111
- package/esm2022/lib/components/chain-operation-editor/chain-operation-editor.component.mjs +0 -570
- package/esm2022/lib/components/chain-result-view/chain-result-view.component.mjs +0 -225
- package/esm2022/lib/components/feature-editor/feature-editor.component.mjs +0 -200
- package/esm2022/lib/components/feature-set-editor/feature-set-editor.component.mjs +0 -175
- package/esm2022/lib/components/feature-set-view/feature-set-view.component.mjs +0 -100
- package/esm2022/lib/components/ln-heights-editor/ln-heights-editor.component.mjs +0 -126
- package/esm2022/lib/components/operation-source-editor/operation-source-editor.component.mjs +0 -131
- package/esm2022/lib/components/simple-tree/simple-tree.component.mjs +0 -72
- package/esm2022/lib/components/snapshot-editor/snapshot-editor.component.mjs +0 -870
- package/esm2022/lib/components/steps-map/steps-map.component.mjs +0 -83
- package/esm2022/lib/models.mjs +0 -2
- package/esm2022/lib/services/gve-api.service.mjs +0 -65
- package/esm2022/lib/services/settings.service.mjs +0 -87
- package/esm2022/lib/validators/svg-validators.mjs +0 -34
- package/esm2022/myrmidon-gve-core.mjs +0 -5
- package/esm2022/public-api.mjs +0 -23
|
@@ -1,870 +0,0 @@
|
|
|
1
|
-
import { CUSTOM_ELEMENTS_SCHEMA, Component, EventEmitter, Input, Output, ViewChild, } from '@angular/core';
|
|
2
|
-
import { FormControl, FormsModule, ReactiveFormsModule, Validators, } from '@angular/forms';
|
|
3
|
-
import { CommonModule } from '@angular/common';
|
|
4
|
-
import { MatButtonModule } from '@angular/material/button';
|
|
5
|
-
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
6
|
-
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
7
|
-
import { MatExpansionModule } from '@angular/material/expansion';
|
|
8
|
-
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
9
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
10
|
-
import { MatInputModule } from '@angular/material/input';
|
|
11
|
-
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
12
|
-
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
13
|
-
import { MatTabsModule } from '@angular/material/tabs';
|
|
14
|
-
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
15
|
-
import { customAlphabet } from 'nanoid';
|
|
16
|
-
import { NgToolsModule, deepCopy } from '@myrmidon/ng-tools';
|
|
17
|
-
import { DEFAULT_SVG_BASE_TEXT_OPTIONS, } from '@myrmidon/gve-snapshot-view';
|
|
18
|
-
import { BaseTextViewComponent, } from '../base-text-view/base-text-view.component';
|
|
19
|
-
import { ChainOperationEditorComponent } from '../chain-operation-editor/chain-operation-editor.component';
|
|
20
|
-
import { ChainResultViewComponent } from '../chain-result-view/chain-result-view.component';
|
|
21
|
-
import { LnHeightsEditorComponent } from '../ln-heights-editor/ln-heights-editor.component';
|
|
22
|
-
import { BaseTextEditorComponent } from '../base-text-editor/base-text-editor.component';
|
|
23
|
-
import { AnimationTimelineSetComponent } from '../animation-timeline-set/animation-timeline-set.component';
|
|
24
|
-
import { BatchOperationEditorComponent } from '../batch-operation-editor/batch-operation-editor.component';
|
|
25
|
-
import * as i0 from "@angular/core";
|
|
26
|
-
import * as i1 from "@angular/forms";
|
|
27
|
-
import * as i2 from "../../services/gve-api.service";
|
|
28
|
-
import * as i3 from "@angular/material/dialog";
|
|
29
|
-
import * as i4 from "@myrmidon/ng-mat-tools";
|
|
30
|
-
import * as i5 from "@angular/material/snack-bar";
|
|
31
|
-
import * as i6 from "@angular/common";
|
|
32
|
-
import * as i7 from "@angular/material/button";
|
|
33
|
-
import * as i8 from "@angular/material/button-toggle";
|
|
34
|
-
import * as i9 from "@angular/material/expansion";
|
|
35
|
-
import * as i10 from "@angular/material/form-field";
|
|
36
|
-
import * as i11 from "@angular/material/icon";
|
|
37
|
-
import * as i12 from "@angular/material/input";
|
|
38
|
-
import * as i13 from "@angular/material/progress-bar";
|
|
39
|
-
import * as i14 from "@angular/material/tabs";
|
|
40
|
-
import * as i15 from "@angular/material/tooltip";
|
|
41
|
-
import * as i16 from "@myrmidon/ng-tools";
|
|
42
|
-
// default snapshot view title
|
|
43
|
-
const VIEW_TITLE = 'preview';
|
|
44
|
-
// suffix for IDs of SVG elements to be made transparent at first rendition
|
|
45
|
-
const SVG_TRANSP_SUFFIX = '_t';
|
|
46
|
-
/**
|
|
47
|
-
* 🔑 `gve-snapshot-editor`
|
|
48
|
-
*
|
|
49
|
-
* A component to edit a text snapshot. This is the top level component in the GVE core
|
|
50
|
-
* library.
|
|
51
|
-
*
|
|
52
|
-
* - ▶️ `snapshot` (`Snapshot`): the snapshot to edit.
|
|
53
|
-
* - ▶️ `batchOps` (`string`): the batch operations text to set for the editor.
|
|
54
|
-
* - ▶️ `noSave` (`boolean`): true to disable saving.
|
|
55
|
-
* - 🔥 `snapshotChange` (`Snapshot`): emitted when the user saves the edited snapshot.
|
|
56
|
-
* - 🔥 `snapshotCancel` (`void`): emitted when the user cancels the snapshot editing.
|
|
57
|
-
*/
|
|
58
|
-
export class SnapshotEditorComponent {
|
|
59
|
-
/**
|
|
60
|
-
* The snapshot to edit.
|
|
61
|
-
*/
|
|
62
|
-
get snapshot() {
|
|
63
|
-
return this._snapshot;
|
|
64
|
-
}
|
|
65
|
-
set snapshot(value) {
|
|
66
|
-
if (this._snapshot === value) {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
this._snapshot = value || undefined;
|
|
70
|
-
this.updateForm(this._snapshot);
|
|
71
|
-
setTimeout(() => {
|
|
72
|
-
this.runToLast();
|
|
73
|
-
}, 0);
|
|
74
|
-
}
|
|
75
|
-
constructor(formBuilder, _api, _dialog, _dialogService, _snackbar) {
|
|
76
|
-
this._api = _api;
|
|
77
|
-
this._dialog = _dialog;
|
|
78
|
-
this._dialogService = _dialogService;
|
|
79
|
-
this._snackbar = _snackbar;
|
|
80
|
-
this._nanoid = customAlphabet('1234567890abcdef', 10);
|
|
81
|
-
/**
|
|
82
|
-
* Emitted when the user saves the edited snapshot.
|
|
83
|
-
*/
|
|
84
|
-
this.snapshotChange = new EventEmitter();
|
|
85
|
-
/**
|
|
86
|
-
* Emitted when the user cancels the snapshot editing.
|
|
87
|
-
*/
|
|
88
|
-
this.snapshotCancel = new EventEmitter();
|
|
89
|
-
// list of operations output tags
|
|
90
|
-
this.opTags = [];
|
|
91
|
-
// list of operation diplomatic.g element IDs
|
|
92
|
-
this.opElementIds = [];
|
|
93
|
-
// the lines count for the current base text
|
|
94
|
-
this.lineCount = 0;
|
|
95
|
-
this.editedOpIndex = -1;
|
|
96
|
-
this.opTypeMap = {
|
|
97
|
-
0: 'replace',
|
|
98
|
-
1: 'delete',
|
|
99
|
-
2: 'add-before',
|
|
100
|
-
3: 'add-after',
|
|
101
|
-
4: 'move-before',
|
|
102
|
-
5: 'move-after',
|
|
103
|
-
6: 'swap',
|
|
104
|
-
7: 'annotate',
|
|
105
|
-
};
|
|
106
|
-
// snapshot view data
|
|
107
|
-
this.viewTitle = VIEW_TITLE;
|
|
108
|
-
this.rulers = true;
|
|
109
|
-
this.initialStepIndex = -1;
|
|
110
|
-
// general
|
|
111
|
-
this.width = new FormControl(800, { nonNullable: true });
|
|
112
|
-
this.height = new FormControl(600, { nonNullable: true });
|
|
113
|
-
this.style = new FormControl(null);
|
|
114
|
-
// base text
|
|
115
|
-
this.baseText = new FormControl([], {
|
|
116
|
-
nonNullable: true,
|
|
117
|
-
validators: [Validators.required],
|
|
118
|
-
});
|
|
119
|
-
this.offsetX = new FormControl(0, { nonNullable: true });
|
|
120
|
-
this.offsetY = new FormControl(0, { nonNullable: true });
|
|
121
|
-
this.lineHeightOffset = new FormControl(DEFAULT_SVG_BASE_TEXT_OPTIONS.lineHeightOffset, { nonNullable: true });
|
|
122
|
-
this.lnHeights = new FormControl(null);
|
|
123
|
-
this.charSpacingOffset = new FormControl(0, { nonNullable: true });
|
|
124
|
-
this.spcWidthOffset = new FormControl(0, { nonNullable: true });
|
|
125
|
-
this.textStyle = new FormControl(null);
|
|
126
|
-
// operations
|
|
127
|
-
this.operations = new FormControl([], {
|
|
128
|
-
nonNullable: true,
|
|
129
|
-
});
|
|
130
|
-
this.opStyle = new FormControl(null);
|
|
131
|
-
// image
|
|
132
|
-
this.imageUrl = new FormControl(null);
|
|
133
|
-
this.imageOpacity = new FormControl(1, { nonNullable: true });
|
|
134
|
-
this.imageX = new FormControl(0, { nonNullable: true });
|
|
135
|
-
this.imageY = new FormControl(0, { nonNullable: true });
|
|
136
|
-
this.imageWidth = new FormControl(0, { nonNullable: true });
|
|
137
|
-
this.imageHeight = new FormControl(0, { nonNullable: true });
|
|
138
|
-
this.defs = new FormControl(null);
|
|
139
|
-
// timelines
|
|
140
|
-
this.timelines = new FormControl([], {
|
|
141
|
-
nonNullable: true,
|
|
142
|
-
});
|
|
143
|
-
// form
|
|
144
|
-
this.form = formBuilder.group({
|
|
145
|
-
width: this.width,
|
|
146
|
-
height: this.height,
|
|
147
|
-
style: this.style,
|
|
148
|
-
baseText: this.baseText,
|
|
149
|
-
offsetX: this.offsetX,
|
|
150
|
-
offsetY: this.offsetY,
|
|
151
|
-
lineHeightOffset: this.lineHeightOffset,
|
|
152
|
-
lnHeights: this.lnHeights,
|
|
153
|
-
charSpacingOffset: this.charSpacingOffset,
|
|
154
|
-
spcWidthOffset: this.spcWidthOffset,
|
|
155
|
-
textStyle: this.textStyle,
|
|
156
|
-
operations: this.operations,
|
|
157
|
-
opStyle: this.opStyle,
|
|
158
|
-
// image
|
|
159
|
-
imageUrl: this.imageUrl,
|
|
160
|
-
imageOpacity: this.imageOpacity,
|
|
161
|
-
imageX: this.imageX,
|
|
162
|
-
imageY: this.imageY,
|
|
163
|
-
imageWidth: this.imageWidth,
|
|
164
|
-
imageHeight: this.imageHeight,
|
|
165
|
-
defs: this.defs,
|
|
166
|
-
// timelines
|
|
167
|
-
timelines: this.timelines,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Set the view data for the snapshot view.
|
|
172
|
-
*
|
|
173
|
-
* @param snapshot The optional snapshot data to use. If not provided,
|
|
174
|
-
* a snapshot will be created from the form data.
|
|
175
|
-
* @param title The optional title to set for the view.
|
|
176
|
-
*/
|
|
177
|
-
setViewData(snapshot, title = VIEW_TITLE) {
|
|
178
|
-
console.log('set view data');
|
|
179
|
-
// get the snapshot to use
|
|
180
|
-
if (!snapshot) {
|
|
181
|
-
snapshot = this.getSnapshot();
|
|
182
|
-
}
|
|
183
|
-
// update view data
|
|
184
|
-
this.viewTitle = title;
|
|
185
|
-
this.visualInfo = undefined;
|
|
186
|
-
this.viewData = {
|
|
187
|
-
snapshot: snapshot,
|
|
188
|
-
options: {
|
|
189
|
-
debug: this.debug,
|
|
190
|
-
delayedRender: true,
|
|
191
|
-
showRulers: true,
|
|
192
|
-
showGrid: true,
|
|
193
|
-
panZoom: true,
|
|
194
|
-
transparentIds: this._transparentIds,
|
|
195
|
-
},
|
|
196
|
-
};
|
|
197
|
-
console.log('view data: ', this.viewData);
|
|
198
|
-
}
|
|
199
|
-
updateForm(snapshot) {
|
|
200
|
-
this._transparentIds = undefined;
|
|
201
|
-
this.initialStepIndex = -1;
|
|
202
|
-
if (!snapshot) {
|
|
203
|
-
this.form.reset();
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
this.width.setValue(snapshot.size.width);
|
|
207
|
-
this.height.setValue(snapshot.size.height);
|
|
208
|
-
this.style.setValue(snapshot.style || null);
|
|
209
|
-
this.imageUrl.setValue(snapshot.image?.url || null);
|
|
210
|
-
this.imageOpacity.setValue(snapshot.image?.opacity || 0);
|
|
211
|
-
this.imageX.setValue(snapshot.image?.canvas?.x || 0);
|
|
212
|
-
this.imageY.setValue(snapshot.image?.canvas?.y || 0);
|
|
213
|
-
this.imageWidth.setValue(snapshot.image?.canvas?.width || 0);
|
|
214
|
-
this.imageHeight.setValue(snapshot.image?.canvas?.height || 0);
|
|
215
|
-
this.defs.setValue(snapshot.defs || null);
|
|
216
|
-
this.baseText.setValue(snapshot.text);
|
|
217
|
-
this.offsetX.setValue(snapshot.textOptions?.offset?.x || 0);
|
|
218
|
-
this.offsetY.setValue(snapshot.textOptions?.offset?.y || 0);
|
|
219
|
-
this.lineHeightOffset.setValue(snapshot.textOptions?.lineHeightOffset);
|
|
220
|
-
this.lnHeights.setValue(snapshot.textOptions?.minLineHeights || null);
|
|
221
|
-
this.charSpacingOffset.setValue(snapshot.textOptions?.charSpacingOffset);
|
|
222
|
-
this.spcWidthOffset.setValue(snapshot.textOptions?.spcWidthOffset);
|
|
223
|
-
this.textStyle.setValue(snapshot.textStyle || null);
|
|
224
|
-
this.operations.setValue(snapshot.operations);
|
|
225
|
-
this.opStyle.setValue(snapshot.opStyle || null);
|
|
226
|
-
// timelines
|
|
227
|
-
const timelines = [];
|
|
228
|
-
if (snapshot.timelines) {
|
|
229
|
-
for (let tag in snapshot.timelines) {
|
|
230
|
-
timelines.push(snapshot.timelines[tag]);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
this.timelines.setValue(timelines);
|
|
234
|
-
}
|
|
235
|
-
this.updateLineCount(this.baseText.value);
|
|
236
|
-
this.updateOpLists();
|
|
237
|
-
this.form.markAsPristine();
|
|
238
|
-
}
|
|
239
|
-
// #region base text
|
|
240
|
-
/**
|
|
241
|
-
* Update the line count based on the received text.
|
|
242
|
-
* @param text The text to use for counting lines.
|
|
243
|
-
*/
|
|
244
|
-
updateLineCount(text) {
|
|
245
|
-
if (!text.length) {
|
|
246
|
-
this.lineCount = 0;
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
this.lineCount = text.filter((c) => c.data === '\n').length + 1;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Handle the event fired by the base text editor to pick a text range.
|
|
254
|
-
* @param range The picked range.
|
|
255
|
-
*/
|
|
256
|
-
onRangePick(range) {
|
|
257
|
-
this.textRange = range;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Handle the event fired by the base text editor to change the base text.
|
|
261
|
-
* @param text The text to set.
|
|
262
|
-
*/
|
|
263
|
-
onTextChange(text) {
|
|
264
|
-
console.log('text change', text);
|
|
265
|
-
// update the form control and reset the current text range
|
|
266
|
-
this.baseText.setValue(text);
|
|
267
|
-
this.baseText.updateValueAndValidity();
|
|
268
|
-
this.baseText.markAsDirty();
|
|
269
|
-
this.textRange = undefined;
|
|
270
|
-
// update the line count
|
|
271
|
-
this.updateLineCount(text);
|
|
272
|
-
// remove all operations and update the view data
|
|
273
|
-
this.removeAllOperations();
|
|
274
|
-
// remove all timelines
|
|
275
|
-
this.timelines.reset();
|
|
276
|
-
}
|
|
277
|
-
// #endregion
|
|
278
|
-
// #region operations
|
|
279
|
-
/**
|
|
280
|
-
* Update the lists of operation output tags and element IDs by collecting
|
|
281
|
-
* all the operation tags and the IDs of the elements in their diplomatic.g
|
|
282
|
-
* SVG code if any.
|
|
283
|
-
*/
|
|
284
|
-
updateOpLists() {
|
|
285
|
-
const tags = new Set();
|
|
286
|
-
const ids = new Set();
|
|
287
|
-
let n = 0;
|
|
288
|
-
for (const op of this.operations.value) {
|
|
289
|
-
// output tag
|
|
290
|
-
n++;
|
|
291
|
-
tags.add(op.outputTag || `v${n}`);
|
|
292
|
-
// element IDs
|
|
293
|
-
if (op.diplomatics?.g) {
|
|
294
|
-
this.parseSvgIds(op.diplomatics.g)?.forEach((id) => ids.add(id));
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
this.opTags = [...tags];
|
|
298
|
-
this.opElementIds = [...ids];
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Edit a new operation.
|
|
302
|
-
*/
|
|
303
|
-
editNewOperation() {
|
|
304
|
-
// create a new operation and edit it
|
|
305
|
-
this.editedOp = {
|
|
306
|
-
id: this._nanoid(),
|
|
307
|
-
type: 0,
|
|
308
|
-
at: this.textRange?.at || 0,
|
|
309
|
-
run: this.textRange?.run || 1,
|
|
310
|
-
};
|
|
311
|
-
this.editedOpIndex = -1;
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Edit (a copy of) the operation at the specified index.
|
|
315
|
-
* @param index The operation index.
|
|
316
|
-
*/
|
|
317
|
-
editOperation(index) {
|
|
318
|
-
this.editedOpIndex = index;
|
|
319
|
-
this.editedOp = deepCopy(this.operations.value[index]);
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Close the currently edited operation.
|
|
323
|
-
*/
|
|
324
|
-
closeEditedOperation() {
|
|
325
|
-
this.editedOpIndex = -1;
|
|
326
|
-
this.editedOp = undefined;
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Handle the event fired by the operation editor to cancel
|
|
330
|
-
* the current operation edits.
|
|
331
|
-
*/
|
|
332
|
-
onOperationCancel() {
|
|
333
|
-
this.closeEditedOperation();
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Handle the event fired by the operation editor to change
|
|
337
|
-
* the currently edited operation, or add a new one if that
|
|
338
|
-
* was a new operation.
|
|
339
|
-
* @param op The changed operation.
|
|
340
|
-
*/
|
|
341
|
-
async onOperationChange(op) {
|
|
342
|
-
console.log('operation change');
|
|
343
|
-
const operations = [...this.operations.value];
|
|
344
|
-
// replace or add the operation
|
|
345
|
-
let i = this.editedOpIndex;
|
|
346
|
-
if (this.editedOpIndex > -1) {
|
|
347
|
-
operations.splice(this.editedOpIndex, 1, op);
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
operations.push(op);
|
|
351
|
-
i = operations.length - 1;
|
|
352
|
-
}
|
|
353
|
-
// update the operations form control
|
|
354
|
-
this.operations.setValue(operations);
|
|
355
|
-
this.operations.markAsDirty();
|
|
356
|
-
this.operations.updateValueAndValidity();
|
|
357
|
-
// update the operation lists
|
|
358
|
-
this.updateOpLists();
|
|
359
|
-
// update the view data
|
|
360
|
-
this.result = await this.runTo(i);
|
|
361
|
-
// close the edited operation
|
|
362
|
-
this.closeEditedOperation();
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Delete the operation at the specified index.
|
|
366
|
-
* @param index The index of the operation to delete.
|
|
367
|
-
*/
|
|
368
|
-
deleteOperation(index) {
|
|
369
|
-
this._dialogService
|
|
370
|
-
.confirm('Confirm Deletion', `Delete operation "${this.operations.value[index].id}"?`)
|
|
371
|
-
.subscribe((yes) => {
|
|
372
|
-
if (yes) {
|
|
373
|
-
// close the edited operation if it is the one being deleted
|
|
374
|
-
if (this.editedOpIndex === index) {
|
|
375
|
-
this.closeEditedOperation();
|
|
376
|
-
}
|
|
377
|
-
// reset the result operation ID if it is the one being deleted
|
|
378
|
-
if (this.resultOperationId === this.operations.value[index].id) {
|
|
379
|
-
this.resultOperationId = undefined;
|
|
380
|
-
}
|
|
381
|
-
// delete the operation and update the form control
|
|
382
|
-
const operations = [...this.operations.value];
|
|
383
|
-
operations.splice(index, 1);
|
|
384
|
-
this.operations.setValue(operations);
|
|
385
|
-
this.operations.markAsDirty();
|
|
386
|
-
this.operations.updateValueAndValidity();
|
|
387
|
-
// update the operation lists
|
|
388
|
-
this.updateOpLists();
|
|
389
|
-
// update the view data
|
|
390
|
-
setTimeout(() => {
|
|
391
|
-
this.runToLast();
|
|
392
|
-
}, 0);
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* Parse the operations from their text and append them to the current
|
|
398
|
-
* snapshot operations.
|
|
399
|
-
*/
|
|
400
|
-
parseOperations() {
|
|
401
|
-
if (this.busy) {
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
const dialogRef = this._dialog.open(BatchOperationEditorComponent, {
|
|
405
|
-
data: { preset: this.batchOps },
|
|
406
|
-
});
|
|
407
|
-
dialogRef.afterClosed().subscribe((batchOps) => {
|
|
408
|
-
if (batchOps) {
|
|
409
|
-
const operations = [...this.operations.value];
|
|
410
|
-
operations.push(...batchOps);
|
|
411
|
-
this.operations.setValue(operations);
|
|
412
|
-
this.operations.markAsDirty();
|
|
413
|
-
this.operations.updateValueAndValidity();
|
|
414
|
-
// update the operation lists
|
|
415
|
-
this.updateOpLists();
|
|
416
|
-
// update the view data
|
|
417
|
-
setTimeout(() => {
|
|
418
|
-
this.runToLast();
|
|
419
|
-
}, 0);
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
removeAllOperations() {
|
|
424
|
-
this.resultOperationId = undefined;
|
|
425
|
-
this.closeEditedOperation();
|
|
426
|
-
this.operations.reset();
|
|
427
|
-
this.operations.markAsDirty();
|
|
428
|
-
this.operations.updateValueAndValidity();
|
|
429
|
-
this.opTags = [];
|
|
430
|
-
this.opElementIds = [];
|
|
431
|
-
this.setViewData();
|
|
432
|
-
this.result = undefined;
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Remove all the operations.
|
|
436
|
-
*/
|
|
437
|
-
clearOperations() {
|
|
438
|
-
this._dialogService
|
|
439
|
-
.confirm('Confirm', 'Remove all operations?')
|
|
440
|
-
.subscribe((yes) => {
|
|
441
|
-
if (yes) {
|
|
442
|
-
this.removeAllOperations();
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Parse all the id attributes from the received SVG code and
|
|
448
|
-
* return them as an array.
|
|
449
|
-
*
|
|
450
|
-
* @param svg The SVG content to parse or undefined.
|
|
451
|
-
* @returns Array of IDs found in the SVG content or undefined.
|
|
452
|
-
*/
|
|
453
|
-
parseSvgIds(svg) {
|
|
454
|
-
if (!svg) {
|
|
455
|
-
return undefined;
|
|
456
|
-
}
|
|
457
|
-
const regex = /<[^>]+\bid=(["'])(.*?)\1/g;
|
|
458
|
-
const ids = [];
|
|
459
|
-
let match;
|
|
460
|
-
while ((match = regex.exec(svg)) !== null) {
|
|
461
|
-
ids.push(match[2]);
|
|
462
|
-
}
|
|
463
|
-
return ids;
|
|
464
|
-
}
|
|
465
|
-
getTransparentIds(g) {
|
|
466
|
-
if (!g) {
|
|
467
|
-
return undefined;
|
|
468
|
-
}
|
|
469
|
-
return this.parseSvgIds(g)?.filter((id) => id.endsWith(SVG_TRANSP_SUFFIX));
|
|
470
|
-
}
|
|
471
|
-
/**
|
|
472
|
-
* Run the operations up to the specified index (included).
|
|
473
|
-
* This is called when:
|
|
474
|
-
* - a preview is requested by the operation editor.
|
|
475
|
-
* - the currently edited operation is saved.
|
|
476
|
-
* - the user picks a step in the chain result view.
|
|
477
|
-
* - runToLast is called, which happens when:
|
|
478
|
-
* - setting the snapshot.
|
|
479
|
-
* - parsing a batch of operations.
|
|
480
|
-
* - deleting an operation.
|
|
481
|
-
*
|
|
482
|
-
* @param index The index of the operation to run to.
|
|
483
|
-
* @param lastOperation The operation to use in place of the existing
|
|
484
|
-
* operation in the snapshot at index. This is used when previewing
|
|
485
|
-
* the edited operation from within the operation editor.
|
|
486
|
-
*/
|
|
487
|
-
runTo(index, lastOperation) {
|
|
488
|
-
return new Promise((resolve, reject) => {
|
|
489
|
-
if (this.busy) {
|
|
490
|
-
return reject('Busy');
|
|
491
|
-
}
|
|
492
|
-
console.log('run to: ' + index);
|
|
493
|
-
// get the snapshot (=text and ops) to run operations on
|
|
494
|
-
const snapshot = this.getSnapshot();
|
|
495
|
-
if (!snapshot.text) {
|
|
496
|
-
return reject('No snapshot text');
|
|
497
|
-
}
|
|
498
|
-
// remove from the snapshot the operations past the specified index,
|
|
499
|
-
// also replacing the last operation when this was received as a parameter
|
|
500
|
-
snapshot.operations = [...this.operations.value];
|
|
501
|
-
if (lastOperation) {
|
|
502
|
-
snapshot.operations = snapshot.operations.slice(0, index);
|
|
503
|
-
snapshot.operations.push(lastOperation);
|
|
504
|
-
}
|
|
505
|
-
else {
|
|
506
|
-
snapshot.operations = snapshot.operations.slice(0, index + 1);
|
|
507
|
-
}
|
|
508
|
-
// run the operations
|
|
509
|
-
this.busy = true;
|
|
510
|
-
this.initialStepIndex = index;
|
|
511
|
-
this._api
|
|
512
|
-
.runOperations(snapshot.text, snapshot.operations)
|
|
513
|
-
.subscribe({
|
|
514
|
-
next: (wrapper) => {
|
|
515
|
-
// handle operation (non-fatal) error or result
|
|
516
|
-
if (wrapper.error) {
|
|
517
|
-
this._snackbar.open(wrapper.error, 'OK');
|
|
518
|
-
reject(wrapper.error);
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
// extract the IDs from the last operation's diplomatics and filter
|
|
522
|
-
// them so that only the ones ending with _t are kept. By convention,
|
|
523
|
-
// all the IDs ending with this suffix are to be made invisible at
|
|
524
|
-
// their first rendition (opacity=0). An animation will then make
|
|
525
|
-
// them visible.
|
|
526
|
-
const lastOp = snapshot.operations[snapshot.operations.length - 1];
|
|
527
|
-
this._transparentIds = this.getTransparentIds(lastOp.diplomatics?.g);
|
|
528
|
-
// update the view data
|
|
529
|
-
this.setViewData(snapshot, lastOp.outputTag);
|
|
530
|
-
// return the result
|
|
531
|
-
resolve(wrapper.result);
|
|
532
|
-
},
|
|
533
|
-
error: (error) => {
|
|
534
|
-
console.error(error);
|
|
535
|
-
this._transparentIds = undefined;
|
|
536
|
-
this._snackbar.open('Error running operations', 'OK');
|
|
537
|
-
reject(error);
|
|
538
|
-
},
|
|
539
|
-
complete: () => {
|
|
540
|
-
this.busy = false;
|
|
541
|
-
},
|
|
542
|
-
});
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Run the operations up to the last operation if any, updating the
|
|
547
|
-
* execution result. The execution result is always the result from
|
|
548
|
-
* all the operations, as users must be able to browse across its steps.
|
|
549
|
-
*/
|
|
550
|
-
async runToLast() {
|
|
551
|
-
if (this.operations.value.length) {
|
|
552
|
-
this.result = await this.runTo(this.operations.value.length - 1);
|
|
553
|
-
}
|
|
554
|
-
else {
|
|
555
|
-
this.setViewData();
|
|
556
|
-
this.result = undefined;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Update the snapshot view by running the operations up to the
|
|
561
|
-
* currently edited operation if any.
|
|
562
|
-
*
|
|
563
|
-
* @param operation The operation being previewed.
|
|
564
|
-
*/
|
|
565
|
-
onOperationPreview(operation) {
|
|
566
|
-
// no multiple previews or previewing a new operation
|
|
567
|
-
if (this._previewing || this.editedOpIndex < 0) {
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
this._previewing = true;
|
|
571
|
-
setTimeout(() => {
|
|
572
|
-
this.runTo(this.editedOpIndex, operation);
|
|
573
|
-
this._previewing = false;
|
|
574
|
-
}, 0);
|
|
575
|
-
}
|
|
576
|
-
// #endregion
|
|
577
|
-
/**
|
|
578
|
-
* Build the snapshot at the specified execution step. This implies adding
|
|
579
|
-
* the nodes introduced by the operations up to the specified step, and
|
|
580
|
-
* updating the features of the nodes introduced by the specified step.
|
|
581
|
-
* Also, the operations after the specified step are removed from the
|
|
582
|
-
* snapshot.
|
|
583
|
-
*
|
|
584
|
-
* @param step The step to build the snapshot at.
|
|
585
|
-
* @returns The snapshot at the specified step.
|
|
586
|
-
*/
|
|
587
|
-
buildSnapshotAtStep(step) {
|
|
588
|
-
// no result, nothing to do
|
|
589
|
-
if (!this.result) {
|
|
590
|
-
return null;
|
|
591
|
-
}
|
|
592
|
-
// get the currently edited snapshot
|
|
593
|
-
const snapshot = this.getSnapshot();
|
|
594
|
-
// find the max ID in snapshot.text (=original) nodes,
|
|
595
|
-
// so that any ID greater than it belongs to new nodes
|
|
596
|
-
const maxOriginalId = snapshot.text.reduce((max, n) => Math.max(max, n.id), 0);
|
|
597
|
-
// get a copy of the nodes of the snapshot base text
|
|
598
|
-
const snapNodes = deepCopy(snapshot.text);
|
|
599
|
-
// get the nodes of the picked step
|
|
600
|
-
const stepNodes = this.result.taggedNodes[step.outputTag];
|
|
601
|
-
// update the snapshot text nodes copies with the picked step nodes,
|
|
602
|
-
// by updating their features if existing, or adding new nodes if not.
|
|
603
|
-
for (const sn of stepNodes) {
|
|
604
|
-
// find the node in the original snapshot text
|
|
605
|
-
const i = snapNodes.findIndex((n) => n.id === sn.id);
|
|
606
|
-
// if found, update its features, else add it
|
|
607
|
-
if (i > -1) {
|
|
608
|
-
snapNodes[i].features = sn.features;
|
|
609
|
-
}
|
|
610
|
-
else {
|
|
611
|
-
// new node: we assume that it has a manually set position (x,y features)
|
|
612
|
-
snapNodes.push(sn);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
// append nodes introduced *before* the picked step, if any
|
|
616
|
-
// (those introduced by the picked step have already been added)
|
|
617
|
-
const stepIndex = this.result.steps.indexOf(step);
|
|
618
|
-
for (let i = 0; i < stepIndex; i++) {
|
|
619
|
-
const stepNodes = this.result.taggedNodes[this.result.steps[i].outputTag];
|
|
620
|
-
for (const n of stepNodes) {
|
|
621
|
-
if (n.id > maxOriginalId && !snapNodes.find((x) => x.id === n.id)) {
|
|
622
|
-
snapNodes.push(n);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
// update the snapshot text nodes
|
|
627
|
-
snapshot.text = snapNodes;
|
|
628
|
-
// remove from the snapshot the operations after the picked step
|
|
629
|
-
const i = snapshot.operations.findIndex((o) => o.id === step.operation.id);
|
|
630
|
-
if (i > -1) {
|
|
631
|
-
snapshot.operations = snapshot.operations.slice(0, i + 1);
|
|
632
|
-
}
|
|
633
|
-
return snapshot;
|
|
634
|
-
}
|
|
635
|
-
playTimeline(tl) {
|
|
636
|
-
const shadowRoot = this.snapshotView?.nativeElement?.shadowRoot;
|
|
637
|
-
if (tl && shadowRoot) {
|
|
638
|
-
console.log('play timeline', tl);
|
|
639
|
-
this._renderer?.playTimeline(tl, undefined, shadowRoot);
|
|
640
|
-
}
|
|
641
|
-
else {
|
|
642
|
-
if (!this.snapshotView) {
|
|
643
|
-
console.warn('no snapshotView for timeline');
|
|
644
|
-
}
|
|
645
|
-
else {
|
|
646
|
-
console.warn('no shadowRoot for timeline');
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* Handle the event fired by the chain result view to pick a step.
|
|
652
|
-
*
|
|
653
|
-
* @param step The step to pick.
|
|
654
|
-
*/
|
|
655
|
-
async onStepPick(step) {
|
|
656
|
-
if (!this.result || this._stepPickFrozen) {
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
// get the currently edited snapshot
|
|
660
|
-
const snapshot = this.buildSnapshotAtStep(step);
|
|
661
|
-
// update result operation ID
|
|
662
|
-
this.resultOperationId = step.operation.id;
|
|
663
|
-
// update transparent IDs
|
|
664
|
-
this._transparentIds = this.getTransparentIds(step.operation.diplomatics?.g);
|
|
665
|
-
// update view data
|
|
666
|
-
this.setViewData(snapshot, step.outputTag);
|
|
667
|
-
// play animation if any
|
|
668
|
-
const tl = this.timelines.value.find((t) => t.tag === step.outputTag);
|
|
669
|
-
if (tl) {
|
|
670
|
-
this._stepPickFrozen = true;
|
|
671
|
-
// find the index of the picked step in the snapshot operations
|
|
672
|
-
const i = snapshot.operations.findIndex((o) => o.id === step.operation.id);
|
|
673
|
-
// run the operations up to the picked step as we need to hide
|
|
674
|
-
// those visuals to be revealed by the animation
|
|
675
|
-
await this.runTo(i);
|
|
676
|
-
this._stepPickFrozen = false;
|
|
677
|
-
// play the timeline
|
|
678
|
-
setTimeout(() => {
|
|
679
|
-
this.playTimeline(tl);
|
|
680
|
-
}, 0);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
/**
|
|
684
|
-
* Handle the event fired by a visual in the snapshot view.
|
|
685
|
-
*
|
|
686
|
-
* @param event The event.
|
|
687
|
-
*/
|
|
688
|
-
onVisualEvent(event) {
|
|
689
|
-
const d = event.detail;
|
|
690
|
-
if (d.event.type === 'mouseover') {
|
|
691
|
-
const visual = d.source;
|
|
692
|
-
const sb = [];
|
|
693
|
-
// id (type)
|
|
694
|
-
sb.push('#' + visual.id);
|
|
695
|
-
sb.push(` (${visual.type})`);
|
|
696
|
-
// : label and features
|
|
697
|
-
if (visual.data?.label) {
|
|
698
|
-
sb.push(': ');
|
|
699
|
-
sb.push(visual.data.label);
|
|
700
|
-
}
|
|
701
|
-
if (visual.data?.features?.length) {
|
|
702
|
-
sb.push(' ');
|
|
703
|
-
sb.push(visual.data.features
|
|
704
|
-
.map((f) => `${f.name}=${f.value}`)
|
|
705
|
-
.join('\n'));
|
|
706
|
-
}
|
|
707
|
-
// (@x,y width×height)
|
|
708
|
-
sb.push(` (@${visual.x.toFixed(1)},${visual.y.toFixed(1)} ` +
|
|
709
|
-
`◻${visual.width.toFixed(1)}×${visual.height.toFixed(1)})`);
|
|
710
|
-
this.visualInfo = sb.join('');
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
/**
|
|
714
|
-
* Handle the change of line heights by updating the form control.
|
|
715
|
-
*
|
|
716
|
-
* @param heights The line heights.
|
|
717
|
-
*/
|
|
718
|
-
onHeightsChange(heights) {
|
|
719
|
-
this.lnHeights.setValue(heights || null);
|
|
720
|
-
this.lnHeights.markAsDirty();
|
|
721
|
-
this.lnHeights.updateValueAndValidity();
|
|
722
|
-
}
|
|
723
|
-
/**
|
|
724
|
-
* Handle the change of timelines by updating the form control.
|
|
725
|
-
*
|
|
726
|
-
* @param timelines The timelines.
|
|
727
|
-
*/
|
|
728
|
-
onTimelinesChange(timelines) {
|
|
729
|
-
this.timelines.setValue(timelines);
|
|
730
|
-
this.timelines.markAsDirty();
|
|
731
|
-
this.timelines.updateValueAndValidity();
|
|
732
|
-
}
|
|
733
|
-
/**
|
|
734
|
-
* Emit the cancel event for this snapshot edit.
|
|
735
|
-
*/
|
|
736
|
-
close() {
|
|
737
|
-
this.snapshotCancel.emit();
|
|
738
|
-
}
|
|
739
|
-
/**
|
|
740
|
-
* Handle the render event from the snapshot view to get a reference
|
|
741
|
-
* to the renderer.
|
|
742
|
-
*
|
|
743
|
-
* @param event The rendition event.
|
|
744
|
-
*/
|
|
745
|
-
onSnapshotRender(event) {
|
|
746
|
-
this._renderer = event.detail.renderer;
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Toggle rulers in the snapshot view.
|
|
750
|
-
*/
|
|
751
|
-
toggleRulers() {
|
|
752
|
-
if (!this._renderer) {
|
|
753
|
-
return;
|
|
754
|
-
}
|
|
755
|
-
this.rulers = this._renderer.toggleRulers();
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Get a snapshot from the form data.
|
|
759
|
-
*
|
|
760
|
-
* @returns New snapshot object.
|
|
761
|
-
*/
|
|
762
|
-
getSnapshot() {
|
|
763
|
-
const snapshot = {
|
|
764
|
-
size: {
|
|
765
|
-
width: this.width.value,
|
|
766
|
-
height: this.height.value,
|
|
767
|
-
},
|
|
768
|
-
style: this.style.value || undefined,
|
|
769
|
-
defs: this.defs.value || undefined,
|
|
770
|
-
text: this.baseText.value,
|
|
771
|
-
textStyle: this.textStyle.value || undefined,
|
|
772
|
-
textOptions: {
|
|
773
|
-
lineHeightOffset: this.lineHeightOffset.value,
|
|
774
|
-
minLineHeights: this.lnHeights.value || undefined,
|
|
775
|
-
charSpacingOffset: this.charSpacingOffset.value,
|
|
776
|
-
spcWidthOffset: this.spcWidthOffset.value,
|
|
777
|
-
offset: {
|
|
778
|
-
x: this.offsetX.value,
|
|
779
|
-
y: this.offsetY.value,
|
|
780
|
-
},
|
|
781
|
-
},
|
|
782
|
-
operations: [...this.operations.value],
|
|
783
|
-
opStyle: this.opStyle.value || undefined,
|
|
784
|
-
};
|
|
785
|
-
// image
|
|
786
|
-
if (this.imageUrl.value) {
|
|
787
|
-
snapshot.image = {
|
|
788
|
-
url: this.imageUrl.value,
|
|
789
|
-
opacity: this.imageOpacity.value || undefined,
|
|
790
|
-
};
|
|
791
|
-
if (this.imageX.value ||
|
|
792
|
-
this.imageY.value ||
|
|
793
|
-
this.imageWidth.value ||
|
|
794
|
-
this.imageHeight.value) {
|
|
795
|
-
snapshot.image.canvas = {
|
|
796
|
-
x: this.imageX.value,
|
|
797
|
-
y: this.imageY.value,
|
|
798
|
-
width: this.imageWidth.value,
|
|
799
|
-
height: this.imageHeight.value,
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
// timelines
|
|
804
|
-
if (this.timelines.value.length) {
|
|
805
|
-
snapshot.timelines = {};
|
|
806
|
-
this.timelines.value.forEach((t) => {
|
|
807
|
-
snapshot.timelines[t.tag] = t;
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
else {
|
|
811
|
-
snapshot.timelines = undefined;
|
|
812
|
-
}
|
|
813
|
-
return snapshot;
|
|
814
|
-
}
|
|
815
|
-
/**
|
|
816
|
-
* Get a snapshot from the form data and emit it
|
|
817
|
-
* in the snapshot change event.
|
|
818
|
-
*/
|
|
819
|
-
save() {
|
|
820
|
-
if (this.form.invalid || this.noSave) {
|
|
821
|
-
return;
|
|
822
|
-
}
|
|
823
|
-
this._snapshot = this.getSnapshot();
|
|
824
|
-
this.snapshotChange.emit(this._snapshot);
|
|
825
|
-
}
|
|
826
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SnapshotEditorComponent, deps: [{ token: i1.FormBuilder }, { token: i2.GveApiService }, { token: i3.MatDialog }, { token: i4.DialogService }, { token: i5.MatSnackBar }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
827
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: SnapshotEditorComponent, isStandalone: true, selector: "gve-snapshot-editor", inputs: { snapshot: "snapshot", batchOps: "batchOps", noSave: "noSave", debug: "debug" }, outputs: { snapshotChange: "snapshotChange", snapshotCancel: "snapshotCancel" }, viewQueries: [{ propertyName: "snapshotView", first: true, predicate: ["snapshotView"], descendants: true }], ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-tab-group>\r\n <!-- text -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>article</mat-icon> <span class=\"label\">text</span>\r\n </ng-template>\r\n <mat-expansion-panel [expanded]=\"!baseText.value\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title> base text </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <gve-base-text-editor\r\n [text]=\"baseText.value\"\r\n (textChange)=\"onTextChange($event)\"\r\n />\r\n <fieldset>\r\n <div class=\"form-row\">\r\n <!-- offsetX -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetX\"\r\n placeholder=\"X offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- offsetY -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetY\"\r\n placeholder=\"Y offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- lineHeightOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>ln h-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"lineHeightOffset\"\r\n placeholder=\"ln h-offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- charSpacingOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>char spacing</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"charSpacingOffset\"\r\n placeholder=\"char spacing\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- spcWidthOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>spc w-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"spcWidthOffset\"\r\n placeholder=\"spc w-offset\"\r\n />\r\n </mat-form-field>\r\n <!-- minLineHeights -->\r\n <div class=\"boxed\">\r\n <gve-ln-heights-editor\r\n [lineCount]=\"lineCount\"\r\n [heights]=\"lnHeights.value\"\r\n (heightsChange)=\"onHeightsChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n <!-- textStyle -->\r\n <div>\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>text style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"textStyle\"\r\n placeholder=\"text style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </fieldset>\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- operations -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>edit</mat-icon> <span class=\"label\">operations</span>\r\n </ng-template>\r\n\r\n <div id=\"snapshot-container\">\r\n <div id=\"general\">\r\n <div class=\"form-row\">\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"width\"\r\n placeholder=\"width\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"height\"\r\n placeholder=\"height\"\r\n />\r\n </mat-form-field>\r\n\r\n <div class=\"form-row right\">\r\n <!-- remove ops -->\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Remove all the operations\"\r\n [disabled]=\"!operations.value.length || busy\"\r\n (click)=\"clearOperations()\"\r\n >\r\n <mat-icon>delete_forever</mat-icon> clear\r\n </button>\r\n\r\n <!-- batch add ops -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n matTooltip=\"Add a batch of operations\"\r\n class=\"mat-primary\"\r\n [disabled]=\"busy\"\r\n (click)=\"parseOperations()\"\r\n >\r\n <mat-icon>post_add</mat-icon> batch\r\n </button>\r\n\r\n <!-- add op -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n [disabled]=\"!baseText.value\"\r\n (click)=\"editNewOperation()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> operation\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ops -->\r\n <div id=\"ops\">\r\n <!-- operations list -->\r\n @if (operations.value.length) {\r\n <table id=\"list\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>ID</th>\r\n <th>type</th>\r\n <th>at</th>\r\n <th>run</th>\r\n <th>value</th>\r\n <th>itag</th>\r\n <th>otag</th>\r\n <th>gid</th>\r\n <th>feats</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (operation of operations.value; track operation.id; let\r\n index=$index) {\r\n <tr\r\n [ngClass]=\"{ selected: operation.id === resultOperationId }\"\r\n [ngClass]=\"{ edited: operation.id === editedOp?.id }\"\r\n >\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-primary\"\r\n (click)=\"editOperation(index)\"\r\n matTooltip=\"Edit operation\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-warn\"\r\n (click)=\"deleteOperation(index)\"\r\n matTooltip=\"Delete operation\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n <!-- run to -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-accent\"\r\n (click)=\"runTo(index)\"\r\n matTooltip=\"Run to this operation\"\r\n >\r\n <mat-icon class=\"mat-accent\">subscriptions</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ operation.id }}</td>\r\n <td>{{ operation.type | flatLookup : opTypeMap }}</td>\r\n <td>{{ operation.at }}</td>\r\n <td>{{ operation.run }}</td>\r\n <td>{{ operation.value }}</td>\r\n <td>{{ operation.inputTag }}</td>\r\n <td>{{ operation.outputTag }}</td>\r\n <td>{{ operation.groupId }}</td>\r\n <td>{{ operation.features?.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <!-- operation editor -->\r\n <mat-expansion-panel [expanded]=\"editedOp\" [disabled]=\"!editedOp\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>operation {{ editedOp?.id }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <fieldset>\r\n <gve-chain-operation-editor\r\n [hidePreview]=\"editedOpIndex === -1\"\r\n [operation]=\"editedOp\"\r\n (operationCancel)=\"onOperationCancel()\"\r\n (operationChange)=\"onOperationChange($event)\"\r\n (operationPreview)=\"onOperationPreview($event)\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- opStyle -->\r\n <div id=\"opStyle\">\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>operations style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"opStyle\"\r\n placeholder=\"operations style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- image -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>image</mat-icon> <span class=\"label\">image</span>\r\n </ng-template>\r\n\r\n <div id=\"image\">\r\n <div id=\"image-ctl\">\r\n <!-- url -->\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>URL</mat-label>\r\n <input matInput [formControl]=\"imageUrl\" />\r\n </mat-form-field>\r\n <div class=\"form-row\">\r\n <!-- x -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageX\"\r\n placeholder=\"X\"\r\n />\r\n </mat-form-field>\r\n <!-- y -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageY\"\r\n placeholder=\"Y\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageWidth\"\r\n />\r\n </mat-form-field>\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageHeight\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n <!-- defs -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>defs</mat-label>\r\n <textarea matInput [formControl]=\"defs\" rows=\"3\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n <div id=\"image-view\">\r\n @if (imageUrl.value) {\r\n <img alt=\"background\" [src]=\"imageUrl.value\" width=\"600\" />\r\n }\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- timelines -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>animation</mat-icon> <span class=\"label\">animation</span>\r\n </ng-template>\r\n\r\n <gve-animation-timeline-set\r\n [tags]=\"opTags\"\r\n [elementIds]=\"opElementIds\"\r\n [timelines]=\"timelines.value\"\r\n (timelinesChange)=\"onTimelinesChange($event)\"\r\n />\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- progress -->\r\n <div>\r\n <mat-progress-bar mode=\"indeterminate\" *ngIf=\"busy\" />\r\n </div>\r\n\r\n <!-- result -->\r\n @if (result) {\r\n <fieldset id=\"result\">\r\n <legend>result</legend>\r\n <gve-chain-result-view\r\n [result]=\"result\"\r\n [initialStepIndex]=\"initialStepIndex\"\r\n (stepPick)=\"onStepPick($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- snapshot view -->\r\n <fieldset id=\"preview\">\r\n <legend class=\"button-row\">\r\n <span>{{ viewTitle }}</span>\r\n </legend>\r\n <!-- snapshot view -->\r\n <gve-snapshot-view\r\n #snapshotView\r\n [debug]=\"debug\"\r\n [data]=\"viewData\"\r\n (snapshotRender)=\"onSnapshotRender($any($event))\"\r\n (visualEvent)=\"onVisualEvent($any($event))\"\r\n />\r\n <div class=\"button-row\">\r\n <!-- toggle ruler -->\r\n <mat-button-toggle\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Toggle rulers\"\r\n [checked]=\"rulers\"\r\n (change)=\"toggleRulers()\"\r\n >\r\n <mat-icon class=\"mat-primary\">straighten</mat-icon>\r\n </mat-button-toggle>\r\n <!-- run to last -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"primary\"\r\n matTooltip=\"Run all operations\"\r\n [disabled]=\"!operations.value.length\"\r\n (click)=\"runToLast()\"\r\n >\r\n <mat-icon>play_circle</mat-icon>\r\n </button>\r\n </div>\r\n @if (visualInfo) {\r\n <div id=\"visual-info\">{{ visualInfo }}</div>\r\n }\r\n </fieldset>\r\n\r\n <!--buttons -->\r\n <div class=\"form-row-center\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Discard changes\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n close\r\n </button>\r\n @if (!noSave) {\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save changes\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n }\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}.form-row .right{margin-left:auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}#text-range{margin:8px;border:1px solid silver;border-radius:6px;padding:6px}mat-expansion-panel{margin:8px 0}div#visual-info{font-size:95%;color:#909090;margin:8px}#list{margin:8px 0}#opStyle{margin-top:8px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr.selected{background-color:#c8d9eb}tr.edited{background-color:#f6f6e4}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:#909090}.error{color:red}.input-nr{width:6em}.full-width{width:100%}.code{font-family:Courier New,Courier,monospace}.boxed{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}span.label{margin-left:8px}gve-animation-timeline-set{margin:8px 0}div#image{display:grid;gap:8px;grid-template-rows:auto;grid-template-columns:1fr auto;grid-template-areas:\"image-ctl image-view\"}div#image-ctl{grid-area:image-ctl}div#image-view{grid-area:image-view}@media only screen and (max-width: 959px){div#image{grid-template-columns:1fr;grid-template-areas:\"image-ctl\" \"image-view\"}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i7.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i7.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "component", type: i8.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i9.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i9.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i9.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i10.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i10.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i11.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i13.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "directive", type: i14.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i14.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i14.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i15.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: NgToolsModule }, { kind: "pipe", type: i16.FlatLookupPipe, name: "flatLookup" }, { kind: "component", type: BaseTextEditorComponent, selector: "gve-base-text-editor", inputs: ["text"], outputs: ["textChange"] }, { kind: "component", type: ChainOperationEditorComponent, selector: "gve-chain-operation-editor", inputs: ["operation", "snapshot", "hidePreview"], outputs: ["operationChange", "operationPreview", "operationCancel"] }, { kind: "component", type: ChainResultViewComponent, selector: "gve-chain-result-view", inputs: ["result", "initialStepIndex"], outputs: ["stepPick"] }, { kind: "component", type: LnHeightsEditorComponent, selector: "gve-ln-heights-editor", inputs: ["lineCount", "heights"], outputs: ["heightsChange"] }, { kind: "component", type: AnimationTimelineSetComponent, selector: "gve-animation-timeline-set", inputs: ["timelines", "elementIds", "tags"], outputs: ["timelinesChange", "timelinesCancel"] }] }); }
|
|
828
|
-
}
|
|
829
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SnapshotEditorComponent, decorators: [{
|
|
830
|
-
type: Component,
|
|
831
|
-
args: [{ selector: 'gve-snapshot-editor', standalone: true, imports: [
|
|
832
|
-
CommonModule,
|
|
833
|
-
FormsModule,
|
|
834
|
-
ReactiveFormsModule,
|
|
835
|
-
MatButtonModule,
|
|
836
|
-
MatButtonToggleModule,
|
|
837
|
-
MatCheckboxModule,
|
|
838
|
-
MatExpansionModule,
|
|
839
|
-
MatFormFieldModule,
|
|
840
|
-
MatIconModule,
|
|
841
|
-
MatInputModule,
|
|
842
|
-
MatProgressBarModule,
|
|
843
|
-
MatSnackBarModule,
|
|
844
|
-
MatTabsModule,
|
|
845
|
-
MatTooltipModule,
|
|
846
|
-
NgToolsModule,
|
|
847
|
-
BaseTextEditorComponent,
|
|
848
|
-
BaseTextViewComponent,
|
|
849
|
-
ChainOperationEditorComponent,
|
|
850
|
-
ChainResultViewComponent,
|
|
851
|
-
LnHeightsEditorComponent,
|
|
852
|
-
AnimationTimelineSetComponent,
|
|
853
|
-
], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-tab-group>\r\n <!-- text -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>article</mat-icon> <span class=\"label\">text</span>\r\n </ng-template>\r\n <mat-expansion-panel [expanded]=\"!baseText.value\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title> base text </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <gve-base-text-editor\r\n [text]=\"baseText.value\"\r\n (textChange)=\"onTextChange($event)\"\r\n />\r\n <fieldset>\r\n <div class=\"form-row\">\r\n <!-- offsetX -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetX\"\r\n placeholder=\"X offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- offsetY -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetY\"\r\n placeholder=\"Y offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- lineHeightOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>ln h-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"lineHeightOffset\"\r\n placeholder=\"ln h-offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- charSpacingOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>char spacing</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"charSpacingOffset\"\r\n placeholder=\"char spacing\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- spcWidthOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>spc w-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"spcWidthOffset\"\r\n placeholder=\"spc w-offset\"\r\n />\r\n </mat-form-field>\r\n <!-- minLineHeights -->\r\n <div class=\"boxed\">\r\n <gve-ln-heights-editor\r\n [lineCount]=\"lineCount\"\r\n [heights]=\"lnHeights.value\"\r\n (heightsChange)=\"onHeightsChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n <!-- textStyle -->\r\n <div>\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>text style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"textStyle\"\r\n placeholder=\"text style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </fieldset>\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- operations -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>edit</mat-icon> <span class=\"label\">operations</span>\r\n </ng-template>\r\n\r\n <div id=\"snapshot-container\">\r\n <div id=\"general\">\r\n <div class=\"form-row\">\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"width\"\r\n placeholder=\"width\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"height\"\r\n placeholder=\"height\"\r\n />\r\n </mat-form-field>\r\n\r\n <div class=\"form-row right\">\r\n <!-- remove ops -->\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Remove all the operations\"\r\n [disabled]=\"!operations.value.length || busy\"\r\n (click)=\"clearOperations()\"\r\n >\r\n <mat-icon>delete_forever</mat-icon> clear\r\n </button>\r\n\r\n <!-- batch add ops -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n matTooltip=\"Add a batch of operations\"\r\n class=\"mat-primary\"\r\n [disabled]=\"busy\"\r\n (click)=\"parseOperations()\"\r\n >\r\n <mat-icon>post_add</mat-icon> batch\r\n </button>\r\n\r\n <!-- add op -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n [disabled]=\"!baseText.value\"\r\n (click)=\"editNewOperation()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> operation\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ops -->\r\n <div id=\"ops\">\r\n <!-- operations list -->\r\n @if (operations.value.length) {\r\n <table id=\"list\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>ID</th>\r\n <th>type</th>\r\n <th>at</th>\r\n <th>run</th>\r\n <th>value</th>\r\n <th>itag</th>\r\n <th>otag</th>\r\n <th>gid</th>\r\n <th>feats</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (operation of operations.value; track operation.id; let\r\n index=$index) {\r\n <tr\r\n [ngClass]=\"{ selected: operation.id === resultOperationId }\"\r\n [ngClass]=\"{ edited: operation.id === editedOp?.id }\"\r\n >\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-primary\"\r\n (click)=\"editOperation(index)\"\r\n matTooltip=\"Edit operation\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-warn\"\r\n (click)=\"deleteOperation(index)\"\r\n matTooltip=\"Delete operation\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n <!-- run to -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-accent\"\r\n (click)=\"runTo(index)\"\r\n matTooltip=\"Run to this operation\"\r\n >\r\n <mat-icon class=\"mat-accent\">subscriptions</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ operation.id }}</td>\r\n <td>{{ operation.type | flatLookup : opTypeMap }}</td>\r\n <td>{{ operation.at }}</td>\r\n <td>{{ operation.run }}</td>\r\n <td>{{ operation.value }}</td>\r\n <td>{{ operation.inputTag }}</td>\r\n <td>{{ operation.outputTag }}</td>\r\n <td>{{ operation.groupId }}</td>\r\n <td>{{ operation.features?.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <!-- operation editor -->\r\n <mat-expansion-panel [expanded]=\"editedOp\" [disabled]=\"!editedOp\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>operation {{ editedOp?.id }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <fieldset>\r\n <gve-chain-operation-editor\r\n [hidePreview]=\"editedOpIndex === -1\"\r\n [operation]=\"editedOp\"\r\n (operationCancel)=\"onOperationCancel()\"\r\n (operationChange)=\"onOperationChange($event)\"\r\n (operationPreview)=\"onOperationPreview($event)\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- opStyle -->\r\n <div id=\"opStyle\">\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>operations style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"opStyle\"\r\n placeholder=\"operations style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- image -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>image</mat-icon> <span class=\"label\">image</span>\r\n </ng-template>\r\n\r\n <div id=\"image\">\r\n <div id=\"image-ctl\">\r\n <!-- url -->\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>URL</mat-label>\r\n <input matInput [formControl]=\"imageUrl\" />\r\n </mat-form-field>\r\n <div class=\"form-row\">\r\n <!-- x -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageX\"\r\n placeholder=\"X\"\r\n />\r\n </mat-form-field>\r\n <!-- y -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageY\"\r\n placeholder=\"Y\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageWidth\"\r\n />\r\n </mat-form-field>\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageHeight\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n <!-- defs -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>defs</mat-label>\r\n <textarea matInput [formControl]=\"defs\" rows=\"3\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n <div id=\"image-view\">\r\n @if (imageUrl.value) {\r\n <img alt=\"background\" [src]=\"imageUrl.value\" width=\"600\" />\r\n }\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- timelines -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>animation</mat-icon> <span class=\"label\">animation</span>\r\n </ng-template>\r\n\r\n <gve-animation-timeline-set\r\n [tags]=\"opTags\"\r\n [elementIds]=\"opElementIds\"\r\n [timelines]=\"timelines.value\"\r\n (timelinesChange)=\"onTimelinesChange($event)\"\r\n />\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- progress -->\r\n <div>\r\n <mat-progress-bar mode=\"indeterminate\" *ngIf=\"busy\" />\r\n </div>\r\n\r\n <!-- result -->\r\n @if (result) {\r\n <fieldset id=\"result\">\r\n <legend>result</legend>\r\n <gve-chain-result-view\r\n [result]=\"result\"\r\n [initialStepIndex]=\"initialStepIndex\"\r\n (stepPick)=\"onStepPick($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- snapshot view -->\r\n <fieldset id=\"preview\">\r\n <legend class=\"button-row\">\r\n <span>{{ viewTitle }}</span>\r\n </legend>\r\n <!-- snapshot view -->\r\n <gve-snapshot-view\r\n #snapshotView\r\n [debug]=\"debug\"\r\n [data]=\"viewData\"\r\n (snapshotRender)=\"onSnapshotRender($any($event))\"\r\n (visualEvent)=\"onVisualEvent($any($event))\"\r\n />\r\n <div class=\"button-row\">\r\n <!-- toggle ruler -->\r\n <mat-button-toggle\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Toggle rulers\"\r\n [checked]=\"rulers\"\r\n (change)=\"toggleRulers()\"\r\n >\r\n <mat-icon class=\"mat-primary\">straighten</mat-icon>\r\n </mat-button-toggle>\r\n <!-- run to last -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"primary\"\r\n matTooltip=\"Run all operations\"\r\n [disabled]=\"!operations.value.length\"\r\n (click)=\"runToLast()\"\r\n >\r\n <mat-icon>play_circle</mat-icon>\r\n </button>\r\n </div>\r\n @if (visualInfo) {\r\n <div id=\"visual-info\">{{ visualInfo }}</div>\r\n }\r\n </fieldset>\r\n\r\n <!--buttons -->\r\n <div class=\"form-row-center\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Discard changes\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n close\r\n </button>\r\n @if (!noSave) {\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save changes\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n }\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}.form-row .right{margin-left:auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}#text-range{margin:8px;border:1px solid silver;border-radius:6px;padding:6px}mat-expansion-panel{margin:8px 0}div#visual-info{font-size:95%;color:#909090;margin:8px}#list{margin:8px 0}#opStyle{margin-top:8px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr.selected{background-color:#c8d9eb}tr.edited{background-color:#f6f6e4}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:#909090}.error{color:red}.input-nr{width:6em}.full-width{width:100%}.code{font-family:Courier New,Courier,monospace}.boxed{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}span.label{margin-left:8px}gve-animation-timeline-set{margin:8px 0}div#image{display:grid;gap:8px;grid-template-rows:auto;grid-template-columns:1fr auto;grid-template-areas:\"image-ctl image-view\"}div#image-ctl{grid-area:image-ctl}div#image-view{grid-area:image-view}@media only screen and (max-width: 959px){div#image{grid-template-columns:1fr;grid-template-areas:\"image-ctl\" \"image-view\"}}\n"] }]
|
|
854
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.GveApiService }, { type: i3.MatDialog }, { type: i4.DialogService }, { type: i5.MatSnackBar }], propDecorators: { snapshotView: [{
|
|
855
|
-
type: ViewChild,
|
|
856
|
-
args: ['snapshotView', { static: false }]
|
|
857
|
-
}], snapshot: [{
|
|
858
|
-
type: Input
|
|
859
|
-
}], batchOps: [{
|
|
860
|
-
type: Input
|
|
861
|
-
}], noSave: [{
|
|
862
|
-
type: Input
|
|
863
|
-
}], debug: [{
|
|
864
|
-
type: Input
|
|
865
|
-
}], snapshotChange: [{
|
|
866
|
-
type: Output
|
|
867
|
-
}], snapshotCancel: [{
|
|
868
|
-
type: Output
|
|
869
|
-
}] } });
|
|
870
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic25hcHNob3QtZWRpdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL215cm1pZG9uL2d2ZS1jb3JlL3NyYy9saWIvY29tcG9uZW50cy9zbmFwc2hvdC1lZGl0b3Ivc25hcHNob3QtZWRpdG9yLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL215cm1pZG9uL2d2ZS1jb3JlL3NyYy9saWIvY29tcG9uZW50cy9zbmFwc2hvdC1lZGl0b3Ivc25hcHNob3QtZWRpdG9yLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIsU0FBUyxFQUVULFlBQVksRUFDWixLQUFLLEVBQ0wsTUFBTSxFQUNOLFNBQVMsR0FDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBRUwsV0FBVyxFQUVYLFdBQVcsRUFDWCxtQkFBbUIsRUFDbkIsVUFBVSxHQUNYLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRS9DLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN4RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FB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SUFBSSxDQUFDLENBQUM7WUFDcEQsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDekQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3JELElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztZQUNyRCxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDN0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQy9ELElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLENBQUM7WUFDMUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3RDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztZQUM1RCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDNUQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLGdCQUFnQixDQUFDLENBQUM7WUFDdkUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFdBQVcs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aUJBQWlCLDhCQUNqQixrQkFBa0IseWRBQ2xCLGtCQUFrQiw0U0FDbEIsYUFBYSxvTEFDYixjQUFjLDJXQUNkLG9CQUFvQix5TkFDcEIsaUJBQWlCLDhCQUNqQixhQUFhLHd1QkFDYixnQkFBZ0IsNlRBQ2hCLGFBQWEsK0ZBQ2IsdUJBQXVCLDRHQUV2Qiw2QkFBNkIsOExBQzdCLHdCQUF3QixpSUFDeEIsd0JBQXdCLGdJQUN4Qiw2QkFBNkI7OzRGQU1wQix1QkFBdUI7a0JBOUJuQyxTQUFTOytCQUNFLHFCQUFxQixjQUNuQixJQUFJLFdBQ1A7d0JBQ1AsWUFBWTt3QkFDWixXQUFXO3dCQUNYLG1CQUFtQjt3QkFDbkIsZUFBZTt3QkFDZixxQkFBcUI7d0JBQ3JCLGlCQUFpQjt3QkFDakIsa0JBQWtCO3dCQUNsQixrQkFBa0I7d0JBQ2xCLGFBQWE7d0JBQ2IsY0FBYzt3QkFDZCxvQkFBb0I7d0JBQ3BCLGlCQUFpQjt3QkFDakIsYUFBYTt3QkFDYixnQkFBZ0I7d0JBQ2hCLGFBQWE7d0JBQ2IsdUJBQXVCO3dCQUN2QixxQkFBcUI7d0JBQ3JCLDZCQUE2Qjt3QkFDN0Isd0JBQXdCO3dCQUN4Qix3QkFBd0I7d0JBQ3hCLDZCQUE2QjtxQkFDOUIsV0FDUSxDQUFDLHNCQUFzQixDQUFDOzBMQWExQixZQUFZO3NCQURsQixTQUFTO3VCQUFDLGNBQWMsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUU7Z0JBT2pDLFFBQVE7c0JBRGxCLEtBQUs7Z0JBbUJDLFFBQVE7c0JBRGQsS0FBSztnQkFPQyxNQUFNO3NCQURaLEtBQUs7Z0JBT0MsS0FBSztzQkFEWCxLQUFLO2dCQU9VLGNBQWM7c0JBRDdCLE1BQU07Z0JBT1MsY0FBYztzQkFEN0IsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgQ1VTVE9NX0VMRU1FTlRTX1NDSEVNQSxcclxuICBDb21wb25lbnQsXHJcbiAgRWxlbWVudFJlZixcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgSW5wdXQsXHJcbiAgT3V0cHV0LFxyXG4gIFZpZXdDaGlsZCxcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtcclxuICBGb3JtQnVpbGRlcixcclxuICBGb3JtQ29udHJvbCxcclxuICBGb3JtR3JvdXAsXHJcbiAgRm9ybXNNb2R1bGUsXHJcbiAgUmVhY3RpdmVGb3Jtc01vZHVsZSxcclxuICBWYWxpZGF0b3JzLFxyXG59IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuXHJcbmltcG9ydCB7IE1hdEJ1dHRvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2J1dHRvbic7XHJcbmltcG9ydCB7IE1hdEJ1dHRvblRvZ2dsZU1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2J1dHRvbi10b2dnbGUnO1xyXG5pbXBvcnQgeyBNYXRDaGVja2JveE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NoZWNrYm94JztcclxuaW1wb3J0IHsgTWF0RXhwYW5zaW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZXhwYW5zaW9uJztcclxuaW1wb3J0IHsgTWF0Rm9ybUZpZWxkTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZm9ybS1maWVsZCc7XHJcbmltcG9ydCB7IE1hdEljb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pY29uJztcclxuaW1wb3J0IHsgTWF0SW5wdXRNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pbnB1dCc7XHJcbmltcG9ydCB7IE1hdFByb2dyZXNzQmFyTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvcHJvZ3Jlc3MtYmFyJztcclxuaW1wb3J0IHsgTWF0U25hY2tCYXIsIE1hdFNuYWNrQmFyTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvc25hY2stYmFyJztcclxuaW1wb3J0IHsgTWF0VGFic01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3RhYnMnO1xyXG5pbXBvcnQgeyBNYXRUb29sdGlwTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdG9vbHRpcCc7XHJcbmltcG9ydCB7IE1hdERpYWxvZyB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2RpYWxvZyc7XHJcblxyXG5pbXBvcnQgeyBjdXN0b21BbHBoYWJldCB9IGZyb20gJ25hbm9pZCc7XHJcblxyXG5pbXBvcnQgeyBOZ1Rvb2xzTW9kdWxlLCBkZWVwQ29weSB9IGZyb20gJ0BteXJtaWRvbi9uZy10b29scyc7XHJcbmltcG9ydCB7IERpYWxvZ1NlcnZpY2UgfSBmcm9tICdAbXlybWlkb24vbmctbWF0LXRvb2xzJztcclxuXHJcbmltcG9ydCB7XHJcbiAgQ2hhckNoYWluT3BlcmF0aW9uLFxyXG4gIENoYXJOb2RlLFxyXG4gIERFRkFVTFRfU1ZHX0JBU0VfVEVYVF9PUFRJT05TLFxyXG4gIEZlYXR1cmUsXHJcbiAgR3ZlQW5pbWF0aW9uVGltZWxpbmUsXHJcbiAgR3ZlVmlzdWFsRXZlbnQsXHJcbiAgU25hcHNob3QsXHJcbiAgU25hcHNob3RWaWV3Q29tcG9uZW50LFxyXG4gIFNuYXBzaG90Vmlld0RhdGEsXHJcbiAgU25hcHNob3RWaWV3UmVuZGVyRXZlbnQsXHJcbiAgU25hcHNob3RWaWV3U2VydmljZSxcclxufSBmcm9tICdAbXlybWlkb24vZ3ZlLXNuYXBzaG90LXZpZXcnO1xyXG5cclxuaW1wb3J0IHtcclxuICBCYXNlVGV4dFZpZXdDb21wb25lbnQsXHJcbiAgVmFyQmFzZVRleHRSYW5nZSxcclxufSBmcm9tICcuLi9iYXNlLXRleHQtdmlldy9iYXNlLXRleHQtdmlldy5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBDaGFpbk9wZXJhdGlvbkVkaXRvckNvbXBvbmVudCB9IGZyb20gJy4uL2NoYWluLW9wZXJhdGlvbi1lZGl0b3IvY2hhaW4tb3BlcmF0aW9uLWVkaXRvci5jb21wb25lbnQnO1xyXG5pbXBvcnQge1xyXG4gIENoYWluT3BlcmF0aW9uQ29udGV4dFN0ZXAsXHJcbiAgQ2hhckNoYWluUmVzdWx0LFxyXG4gIEd2ZUFwaVNlcnZpY2UsXHJcbn0gZnJvbSAnLi4vLi4vc2VydmljZXMvZ3ZlLWFwaS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgQ2hhaW5SZXN1bHRWaWV3Q29tcG9uZW50IH0gZnJvbSAnLi4vY2hhaW4tcmVzdWx0LXZpZXcvY2hhaW4tcmVzdWx0LXZpZXcuY29tcG9uZW50JztcclxuaW1wb3J0IHsgTG5IZWlnaHRzRWRpdG9yQ29tcG9uZW50IH0gZnJvbSAnLi4vbG4taGVpZ2h0cy1lZGl0b3IvbG4taGVpZ2h0cy1lZGl0b3IuY29tcG9uZW50JztcclxuaW1wb3J0IHsgQmFzZVRleHRFZGl0b3JDb21wb25lbnQgfSBmcm9tICcuLi9iYXNlLXRleHQtZWRpdG9yL2Jhc2UtdGV4dC1lZGl0b3IuY29tcG9uZW50JztcclxuaW1wb3J0IHsgQW5pbWF0aW9uVGltZWxpbmVTZXRDb21wb25lbnQgfSBmcm9tICcuLi9hbmltYXRpb24tdGltZWxpbmUtc2V0L2FuaW1hdGlvbi10aW1lbGluZS1zZXQuY29tcG9uZW50JztcclxuaW1wb3J0IHsgQmF0Y2hPcGVyYXRpb25FZGl0b3JDb21wb25lbnQgfSBmcm9tICcuLi9iYXRjaC1vcGVyYXRpb24tZWRpdG9yL2JhdGNoLW9wZXJhdGlvbi1lZGl0b3IuY29tcG9uZW50JztcclxuXHJcbi8vIGRlZmF1bHQgc25hcHNob3QgdmlldyB0aXRsZVxyXG5jb25zdCBWSUVXX1RJVExFID0gJ3ByZXZpZXcnO1xyXG5cclxuLy8gc3VmZml4IGZvciBJRHMgb2YgU1ZHIGVsZW1lbnRzIHRvIGJlIG1hZGUgdHJhbnNwYXJlbnQgYXQgZmlyc3QgcmVuZGl0aW9uXHJcbmNvbnN0IFNWR19UUkFOU1BfU1VGRklYID0gJ190JztcclxuXHJcbi8qKlxyXG4gKiDwn5SRIGBndmUtc25hcHNob3QtZWRpdG9yYFxyXG4gKlxyXG4gKiBBIGNvbXBvbmVudCB0byBlZGl0IGEgdGV4dCBzbmFwc2hvdC4gVGhpcyBpcyB0aGUgdG9wIGxldmVsIGNvbXBvbmVudCBpbiB0aGUgR1ZFIGNvcmVcclxuICogbGlicmFyeS5cclxuICpcclxuICogLSDilrbvuI8gYHNuYXBzaG90YCAoYFNuYXBzaG90YCk6IHRoZSBzbmFwc2hvdCB0byBlZGl0LlxyXG4gKiAtIOKWtu+4jyBgYmF0Y2hPcHNgIChgc3RyaW5nYCk6IHRoZSBiYXRjaCBvcGVyYXRpb25zIHRleHQgdG8gc2V0IGZvciB0aGUgZWRpdG9yLlxyXG4gKiAtIOKWtu+4jyBgbm9TYXZlYCAoYGJvb2xlYW5gKTogdHJ1ZSB0byBkaXNhYmxlIHNhdmluZy5cclxuICogLSDwn5SlIGBzbmFwc2hvdENoYW5nZWAgKGBTbmFwc2hvdGApOiBlbWl0dGVkIHdoZW4gdGhlIHVzZXIgc2F2ZXMgdGhlIGVkaXRlZCBzbmFwc2hvdC5cclxuICogLSDwn5SlIGBzbmFwc2hvdENhbmNlbGAgKGB2b2lkYCk6IGVtaXR0ZWQgd2hlbiB0aGUgdXNlciBjYW5jZWxzIHRoZSBzbmFwc2hvdCBlZGl0aW5nLlxyXG4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdndmUtc25hcHNob3QtZWRpdG9yJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtcclxuICAgIENvbW1vbk1vZHVsZSxcclxuICAgIEZvcm1zTW9kdWxlLFxyXG4gICAgUmVhY3RpdmVGb3Jtc01vZHVsZSxcclxuICAgIE1hdEJ1dHRvbk1vZHVsZSxcclxuICAgIE1hdEJ1dHRvblRvZ2dsZU1vZHVsZSxcclxuICAgIE1hdENoZWNrYm94TW9kdWxlLFxyXG4gICAgTWF0RXhwYW5zaW9uTW9kdWxlLFxyXG4gICAgTWF0Rm9ybUZpZWxkTW9kdWxlLFxyXG4gICAgTWF0SWNvbk1vZHVsZSxcclxuICAgIE1hdElucHV0TW9kdWxlLFxyXG4gICAgTWF0UHJvZ3Jlc3NCYXJNb2R1bGUsXHJcbiAgICBNYXRTbmFja0Jhck1vZHVsZSxcclxuICAgIE1hdFRhYnNNb2R1bGUsXHJcbiAgICBNYXRUb29sdGlwTW9kdWxlLFxyXG4gICAgTmdUb29sc01vZHVsZSxcclxuICAgIEJhc2VUZXh0RWRpdG9yQ29tcG9uZW50LFxyXG4gICAgQmFzZVRleHRWaWV3Q29tcG9uZW50LFxyXG4gICAgQ2hhaW5PcGVyYXRpb25FZGl0b3JDb21wb25lbnQsXHJcbiAgICBDaGFpblJlc3VsdFZpZXdDb21wb25lbnQsXHJcbiAgICBMbkhlaWdodHNFZGl0b3JDb21wb25lbnQsXHJcbiAgICBBbmltYXRpb25UaW1lbGluZVNldENvbXBvbmVudCxcclxuICBdLFxyXG4gIHNjaGVtYXM6IFtDVVNUT01fRUxFTUVOVFNfU0NIRU1BXSxcclxuICB0ZW1wbGF0ZVVybDogJy4vc25hcHNob3QtZWRpdG9yLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybDogJy4vc25hcHNob3QtZWRpdG9yLmNvbXBvbmVudC5jc3MnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgU25hcHNob3RFZGl0b3JDb21wb25lbnQge1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgX25hbm9pZCA9IGN1c3RvbUFscGhhYmV0KCcxMjM0NTY3ODkwYWJjZGVmJywgMTApO1xyXG4gIHByaXZhdGUgX3NuYXBzaG90PzogU25hcHNob3Q7XHJcbiAgcHJpdmF0ZSBfcmVuZGVyZXI/OiBTbmFwc2hvdFZpZXdTZXJ2aWNlO1xyXG4gIHByaXZhdGUgX3ByZXZpZXdpbmc/OiBib29sZWFuO1xyXG4gIHByaXZhdGUgX3RyYW5zcGFyZW50SWRzPzogc3RyaW5nW107XHJcbiAgcHJpdmF0ZSBfc3RlcFBpY2tGcm96ZW4/OiBib29sZWFuO1xyXG5cclxuICBAVmlld0NoaWxkKCdzbmFwc2hvdFZpZXcnLCB7IHN0YXRpYzogZmFsc2UgfSlcclxuICBwdWJsaWMgc25hcHNob3RWaWV3PzogRWxlbWVudFJlZjxTbmFwc2hvdFZpZXdDb21wb25lbnQ+O1xyXG5cclxuICAvKipcclxuICAgKiBUaGUgc25hcHNob3QgdG8gZWRpdC5cclxuICAgKi9cclxuICBASW5wdXQoKVxyXG4gIHB1YmxpYyBnZXQgc25hcHNob3QoKTogU25hcHNob3QgfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIHRoaXMuX3NuYXBzaG90O1xyXG4gIH1cclxuICBwdWJsaWMgc2V0IHNuYXBzaG90KHZhbHVlOiBTbmFwc2hvdCB8IHVuZGVmaW5lZCB8IG51bGwpIHtcclxuICAgIGlmICh0aGlzLl9zbmFwc2hvdCA9PT0gdmFsdWUpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdGhpcy5fc25hcHNob3QgPSB2YWx1ZSB8fCB1bmRlZmluZWQ7XHJcbiAgICB0aGlzLnVwZGF0ZUZvcm0odGhpcy5fc25hcHNob3QpO1xyXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIHRoaXMucnVuVG9MYXN0KCk7XHJcbiAgICB9LCAwKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBiYXRjaCBvcGVyYXRpb25zIHRleHQgdG8gc2V0IGZvciB0aGUgZWRpdG9yLlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGJhdGNoT3BzPzogc3RyaW5nO1xyXG5cclxuICAvKipcclxuICAgKiBUcnVlIHRvIGRpc2FibGUgc2F2aW5nLlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIG5vU2F2ZT86IGJvb2xlYW47XHJcblxyXG4gIC8qKlxyXG4gICAqIFRydWUgdG8gZW5hYmxlIGRlYnVnIG1vZGUgZm9yIHZpZXcgcmVuZGl0aW9uLlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGRlYnVnPzogYm9vbGVhbjtcclxuXHJcbiAgLyoqXHJcbiAgICogRW1pdHRlZCB3aGVuIHRoZSB1c2VyIHNhdmVzIHRoZSBlZGl0ZWQgc25hcHNob3QuXHJcbiAgICovXHJcbiAgQE91dHB1dCgpXHJcbiAgcHVibGljIHJlYWRvbmx5IHNuYXBzaG90Q2hhbmdlOiBFdmVudEVtaXR0ZXI8U25hcHNob3Q+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xyXG5cclxuICAvKipcclxuICAgKiBFbWl0dGVkIHdoZW4gdGhlIHVzZXIgY2FuY2VscyB0aGUgc25hcHNob3QgZWRpdGluZy5cclxuICAgKi9cclxuICBAT3V0cHV0KClcclxuICBwdWJsaWMgcmVhZG9ubHkgc25hcHNob3RDYW5jZWwgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcblxyXG4gIC8vIGdlbmVyYWxcclxuICBwdWJsaWMgd2lkdGg6IEZvcm1Db250cm9sPG51bWJlcj47XHJcbiAgcHVibGljIGhlaWdodDogRm9ybUNvbnRyb2w8bnVtYmVyPjtcclxuICBwdWJsaWMgc3R5bGU6IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+O1xyXG4gIC8vIGJhc2UgdGV4dFxyXG4gIHB1YmxpYyBiYXNlVGV4dDogRm9ybUNvbnRyb2w8Q2hhck5vZGVbXSB8IHN0cmluZz47XHJcbiAgcHVibGljIG9mZnNldFg6IEZvcm1Db250cm9sPG51bWJlcj47XHJcbiAgcHVibGljIG9mZnNldFk6IEZvcm1Db250cm9sPG51bWJlcj47XHJcbiAgcHVibGljIGxpbmVIZWlnaHRPZmZzZXQ6IEZvcm1Db250cm9sPG51bWJlcj47XHJcbiAgcHVibGljIGxuSGVpZ2h0czogRm9ybUNvbnRyb2w8UmVjb3JkPG51bWJlciwgbnVtYmVyPiB8IG51bGw+O1xyXG4gIHB1YmxpYyBjaGFyU3BhY2luZ09mZnNldDogRm9ybUNvbnRyb2w8bnVtYmVyPjtcclxuICBwdWJsaWMgc3BjV2lkdGhPZmZzZXQ6IEZvcm1Db250cm9sPG51bWJlcj47XHJcbiAgcHVibGljIHRleHRTdHlsZTogRm9ybUNvbnRyb2w8c3RyaW5nIHwgbnVsbD47XHJcbiAgLy8gb3BlcmF0aW9uc1xyXG4gIHB1YmxpYyBvcGVyYXRpb25zOiBGb3JtQ29udHJvbDxDaGFyQ2hhaW5PcGVyYXRpb25bXT47XHJcbiAgcHVibGljIG9wU3R5bGU6IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+O1xyXG4gIHB1YmxpYyBmb3JtOiBGb3JtR3JvdXA7XHJcbiAgLy8gaW1hZ2UgYW5kIGRlZnNcclxuICBwdWJsaWMgaW1hZ2VVcmw6IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+O1xyXG4gIHB1YmxpYyBpbWFnZU9wYWNpdHk6IEZvcm1Db250cm9sPG51bWJlcj47XHJcbiAgcHVibGljIGltYWdlWDogRm9ybUNvbnRyb2w8bnVtYmVyPjtcclxuICBwdWJsaWMgaW1hZ2VZOiBGb3JtQ29udHJvbDxudW1iZXI+O1xyXG4gIHB1YmxpYyBpbWFnZVdpZHRoOiBGb3JtQ29udHJvbDxudW1iZXI+O1xyXG4gIHB1YmxpYyBpbWFnZUhlaWdodDogRm9ybUNvbnRyb2w8bnVtYmVyPjtcclxuICBwdWJsaWMgZGVmczogRm9ybUNvbnRyb2w8c3RyaW5nIHwgbnVsbD47XHJcbiAgLy8gdGltZWxpbmVzXHJcbiAgcHVibGljIHRpbWVsaW5lczogRm9ybUNvbnRyb2w8R3ZlQW5pbWF0aW9uVGltZWxpbmVbXT47XHJcbiAgLy8gbGlzdCBvZiBvcGVyYXRpb25zIG91dHB1dCB0YWdzXHJcbiAgcHVibGljIG9wVGFnczogc3RyaW5nW10gPSBbXTtcclxuICAvLyBsaXN0IG9mIG9wZXJhdGlvbiBkaXBsb21hdGljLmcgZWxlbWVudCBJRHNcclxuICBwdWJsaWMgb3BFbGVtZW50SWRzOiBzdHJpbmdbXSA9IFtdO1xyXG5cclxuICAvLyB0aGUgY3VycmVudGx5IHBpY2tlZCBiYXNlIHRleHQgcmFuZ2VcclxuICBwdWJsaWMgdGV4dFJhbmdlPzogVmFyQmFzZVRleHRSYW5nZTtcclxuICAvLyB0aGUgbGluZXMgY291bnQgZm9yIHRoZSBjdXJyZW50IGJhc2UgdGV4dFxyXG4gIHB1YmxpYyBsaW5lQ291bnQgPSAwO1xyXG5cclxuICAvLyB0aGUgY3VycmVudGx5IGVkaXRlZCBvcGVyYXRpb25cclxuICBwdWJsaWMgZWRpdGVkT3A/OiBDaGFyQ2hhaW5PcGVyYXRpb247XHJcbiAgcHVibGljIGVkaXRlZE9wSW5kZXggPSAtMTtcclxuXHJcbiAgcHVibGljIGJ1c3k/OiBib29sZWFuO1xyXG4gIHB1YmxpYyBwYXJzZUVycm9yPzogc3RyaW5nO1xyXG4gIHB1YmxpYyBvcFR5cGVNYXAgPSB7XHJcbiAgICAwOiAncmVwbGFjZScsXHJcbiAgICAxOiAnZGVsZXRlJyxcclxuICAgIDI6ICdhZGQtYmVmb3JlJyxcclxuICAgIDM6ICdhZGQtYWZ0ZXInLFxyXG4gICAgNDogJ21vdmUtYmVmb3JlJyxcclxuICAgIDU6ICdtb3ZlLWFmdGVyJyxcclxuICAgIDY6ICdzd2FwJyxcclxuICAgIDc6ICdhbm5vdGF0ZScsXHJcbiAgfTtcclxuXHJcbiAgLy8gc25hcHNob3QgdmlldyBkYXRhXHJcbiAgcHVibGljIHZpZXdUaXRsZSA9IFZJRVdfVElUTEU7XHJcbiAgcHVibGljIHZpZXdEYXRhPzogU25hcHNob3RWaWV3RGF0YTtcclxuICBwdWJsaWMgdmlzdWFsSW5mbz86IHN0cmluZztcclxuICBwdWJsaWMgcnVsZXJzID0gdHJ1ZTtcclxuXHJcbiAgLy8gb3BlcmF0aW9ucyBleGVjdXRpb24gcmVzdWx0XHJcbiAgcHVibGljIHJlc3VsdD86IENoYXJDaGFpblJlc3VsdDtcclxuICBwdWJsaWMgcmVzdWx0T3BlcmF0aW9uSWQ/OiBzdHJpbmc7XHJcbiAgcHVibGljIGluaXRpYWxTdGVwSW5kZXggPSAtMTtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBmb3JtQnVpbGRlcjogRm9ybUJ1aWxkZXIsXHJcbiAgICBwcml2YXRlIF9hcGk6IEd2ZUFwaVNlcnZpY2UsXHJcbiAgICBwcml2YXRlIF9kaWFsb2c6IE1hdERpYWxvZyxcclxuICAgIHByaXZhdGUgX2RpYWxvZ1NlcnZpY2U6IERpYWxvZ1NlcnZpY2UsXHJcbiAgICBwcml2YXRlIF9zbmFja2JhcjogTWF0U25hY2tCYXJcclxuICApIHtcclxuICAgIC8vIGdlbmVyYWxcclxuICAgIHRoaXMud2lkdGggPSBuZXcgRm9ybUNvbnRyb2w8bnVtYmVyPig4MDAsIHsgbm9uTnVsbGFibGU6IHRydWUgfSk7XHJcbiAgICB0aGlzLmhlaWdodCA9IG5ldyBGb3JtQ29udHJvbDxudW1iZXI+KDYwMCwgeyBub25OdWxsYWJsZTogdHJ1ZSB9KTtcclxuICAgIHRoaXMuc3R5bGUgPSBuZXcgRm9ybUNvbnRyb2w8c3RyaW5nIHwgbnVsbD4obnVsbCk7XHJcbiAgICAvLyBiYXNlIHRleHRcclxuICAgIHRoaXMuYmFzZVRleHQgPSBuZXcgRm9ybUNvbnRyb2w8Q2hhck5vZGVbXSB8IHN0cmluZz4oW10sIHtcclxuICAgICAgbm9uTnVsbGFibGU6IHRydWUsXHJcbiAgICAgIHZhbGlkYXRvcnM6IFtWYWxpZGF0b3JzLnJlcXVpcmVkXSxcclxuICAgIH0pO1xyXG4gICAgdGhpcy5vZmZzZXRYID0gbmV3IEZvcm1Db250cm9sPG51bWJlcj4oMCwgeyBub25OdWxsYWJsZTogdHJ1ZSB9KTtcclxuICAgIHRoaXMub2Zmc2V0WSA9IG5ldyBGb3JtQ29udHJvbDxudW1iZXI+KDAsIHsgbm9uTnVsbGFibGU6IHRydWUgfSk7XHJcbiAgICB0aGlzLmxpbmVIZWlnaHRPZmZzZXQgPSBuZXcgRm9ybUNvbnRyb2w8bnVtYmVyPihcclxuICAgICAgREVGQVVMVF9TVkdfQkFTRV9URVhUX09QVElPTlMubGluZUhlaWdodE9mZnNldCxcclxuICAgICAgeyBub25OdWxsYWJsZTogdHJ1ZSB9XHJcbiAgICApO1xyXG4gICAgdGhpcy5sbkhlaWdodHMgPSBuZXcgRm9ybUNvbnRyb2w8UmVjb3JkPG51bWJlciwgbnVtYmVyPiB8IG51bGw+KG51bGwpO1xyXG4gICAgdGhpcy5jaGFyU3BhY2luZ09mZnNldCA9IG5ldyBGb3JtQ29udHJvbDxudW1iZXI+KDAsIHsgbm9uTnVsbGFibGU6IHRydWUgfSk7XHJcbiAgICB0aGlzLnNwY1dpZHRoT2Zmc2V0ID0gbmV3IEZvcm1Db250cm9sPG51bWJlcj4oMCwgeyBub25OdWxsYWJsZTogdHJ1ZSB9KTtcclxuICAgIHRoaXMudGV4dFN0eWxlID0gbmV3IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+KG51bGwpO1xyXG5cclxuICAgIC8vIG9wZXJhdGlvbnNcclxuICAgIHRoaXMub3BlcmF0aW9ucyA9IG5ldyBGb3JtQ29udHJvbDxDaGFyQ2hhaW5PcGVyYXRpb25bXT4oW10sIHtcclxuICAgICAgbm9uTnVsbGFibGU6IHRydWUsXHJcbiAgICB9KTtcclxuICAgIHRoaXMub3BTdHlsZSA9IG5ldyBGb3JtQ29udHJvbDxzdHJpbmcgfCBudWxsPihudWxsKTtcclxuICAgIC8vIGltYWdlXHJcbiAgICB0aGlzLmltYWdlVXJsID0gbmV3IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+KG51bGwpO1xyXG4gICAgdGhpcy5pbWFnZU9wYWNpdHkgPSBuZXcgRm9ybUNvbnRyb2w8bnVtYmVyPigxLCB7IG5vbk51bGxhYmxlOiB0cnVlIH0pO1xyXG4gICAgdGhpcy5pbWFnZVggPSBuZXcgRm9ybUNvbnRyb2w8bnVtYmVyPigwLCB7IG5vbk51bGxhYmxlOiB0cnVlIH0pO1xyXG4gICAgdGhpcy5pbWFnZVkgPSBuZXcgRm9ybUNvbnRyb2w8bnVtYmVyPigwLCB7IG5vbk51bGxhYmxlOiB0cnVlIH0pO1xyXG4gICAgdGhpcy5pbWFnZVdpZHRoID0gbmV3IEZvcm1Db250cm9sPG51bWJlcj4oMCwgeyBub25OdWxsYWJsZTogdHJ1ZSB9KTtcclxuICAgIHRoaXMuaW1hZ2VIZWlnaHQgPSBuZXcgRm9ybUNvbnRyb2w8bnVtYmVyPigwLCB7IG5vbk51bGxhYmxlOiB0cnVlIH0pO1xyXG4gICAgdGhpcy5kZWZzID0gbmV3IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+KG51bGwpO1xyXG5cclxuICAgIC8vIHRpbWVsaW5lc1xyXG4gICAgdGhpcy50aW1lbGluZXMgPSBuZXcgRm9ybUNvbnRyb2w8R3ZlQW5pbWF0aW9uVGltZWxpbmVbXT4oW10sIHtcclxuICAgICAgbm9uTnVsbGFibGU6IHRydWUsXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBmb3JtXHJcbiAgICB0aGlzLmZvcm0gPSBmb3JtQnVpbGRlci5ncm91cCh7XHJcbiAgICAgIHdpZHRoOiB0aGlzLndpZHRoLFxyXG4gICAgICBoZWlnaHQ6IHRoaXMuaGVpZ2h0LFxyXG4gICAgICBzdHlsZTogdGhpcy5zdHlsZSxcclxuICAgICAgYmFzZVRleHQ6IHRoaXMuYmFzZVRleHQsXHJcbiAgICAgIG9mZnNldFg6IHRoaXMub2Zmc2V0WCxcclxuICAgICAgb2Zmc2V0WTogdGhpcy5vZmZzZXRZLFxyXG4gICAgICBsaW5lSGVpZ2h0T2Zmc2V0OiB0aGlzLmxpbmVIZWlnaHRPZmZzZXQsXHJcbiAgICAgIGxuSGVpZ2h0czogdGhpcy5sbkhlaWdodHMsXHJcbiAgICAgIGNoYXJTcGFjaW5nT2Zmc2V0OiB0aGlzLmNoYXJTcGFjaW5nT2Zmc2V0LFxyXG4gICAgICBzcGNXaWR0aE9mZnNldDogdGhpcy5zcGNXaWR0aE9mZnNldCxcclxuICAgICAgdGV4dFN0eWxlOiB0aGlzLnRleHRTdHlsZSxcclxuICAgICAgb3BlcmF0aW9uczogdGhpcy5vcGVyYXRpb25zLFxyXG4gICAgICBvcFN0eWxlOiB0aGlzLm9wU3R5bGUsXHJcbiAgICAgIC8vIGltYWdlXHJcbiAgICAgIGltYWdlVXJsOiB0aGlzLmltYWdlVXJsLFxyXG4gICAgICBpbWFnZU9wYWNpdHk6IHRoaXMuaW1hZ2VPcGFjaXR5LFxyXG4gICAgICBpbWFnZVg6IHRoaXMuaW1hZ2VYLFxyXG4gICAgICBpbWFnZVk6IHRoaXMuaW1hZ2VZLFxyXG4gICAgICBpbWFnZVdpZHRoOiB0aGlzLmltYWdlV2lkdGgsXHJcbiAgICAgIGltYWdlSGVpZ2h0OiB0aGlzLmltYWdlSGVpZ2h0LFxyXG4gICAgICBkZWZzOiB0aGlzLmRlZnMsXHJcbiAgICAgIC8vIHRpbWVsaW5lc1xyXG4gICAgICB0aW1lbGluZXM6IHRoaXMudGltZWxpbmVzLFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXQgdGhlIHZpZXcgZGF0YSBmb3IgdGhlIHNuYXBzaG90IHZpZXcuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gc25hcHNob3QgVGhlIG9wdGlvbmFsIHNuYXBzaG90IGRhdGEgdG8gdXNlLiBJZiBub3QgcHJvdmlkZWQsXHJcbiAgICogYSBzbmFwc2hvdCB3aWxsIGJlIGNyZWF0ZWQgZnJvbSB0aGUgZm9ybSBkYXRhLlxyXG4gICAqIEBwYXJhbSB0aXRsZSBUaGUgb3B0aW9uYWwgdGl0bGUgdG8gc2V0IGZvciB0aGUgdmlldy5cclxuICAgKi9cclxuICBwcml2YXRlIHNldFZpZXdEYXRhKHNuYXBzaG90PzogU25hcHNob3QsIHRpdGxlID0gVklFV19USVRMRSk6IHZvaWQge1xyXG4gICAgY29uc29sZS5sb2coJ3NldCB2aWV3IGRhdGEnKTtcclxuXHJcbiAgICAvLyBnZXQgdGhlIHNuYXBzaG90IHRvIHVzZVxyXG4gICAgaWYgKCFzbmFwc2hvdCkge1xyXG4gICAgICBzbmFwc2hvdCA9IHRoaXMuZ2V0U25hcHNob3QoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyB1cGRhdGUgdmlldyBkYXRhXHJcbiAgICB0aGlzLnZpZXdUaXRsZSA9IHRpdGxlO1xyXG4gICAgdGhpcy52aXN1YWxJbmZvID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy52aWV3RGF0YSA9IHtcclxuICAgICAgc25hcHNob3Q6IHNuYXBzaG90LFxyXG4gICAgICBvcHRpb25zOiB7XHJcbiAgICAgICAgZGVidWc6IHRoaXMuZGVidWcsXHJcbiAgICAgICAgZGVsYXllZFJlbmRlcjogdHJ1ZSxcclxuICAgICAgICBzaG93UnVsZXJzOiB0cnVlLFxyXG4gICAgICAgIHNob3dHcmlkOiB0cnVlLFxyXG4gICAgICAgIHBhblpvb206IHRydWUsXHJcbiAgICAgICAgdHJhbnNwYXJlbnRJZHM6IHRoaXMuX3RyYW5zcGFyZW50SWRzLFxyXG4gICAgICB9LFxyXG4gICAgfTtcclxuXHJcbiAgICBjb25zb2xlLmxvZygndmlldyBkYXRhOiAnLCB0aGlzLnZpZXdEYXRhKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlRm9ybShzbmFwc2hvdDogU25hcHNob3QgfCB1bmRlZmluZWQpIHtcclxuICAgIHRoaXMuX3RyYW5zcGFyZW50SWRzID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy5pbml0aWFsU3RlcEluZGV4ID0gLTE7XHJcblxyXG4gICAgaWYgKCFzbmFwc2hvdCkge1xyXG4gICAgICB0aGlzLmZvcm0ucmVzZXQoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMud2lkdGguc2V0VmFsdWUoc25hcHNob3Quc2l6ZS53aWR0aCk7XHJcbiAgICAgIHRoaXMuaGVpZ2h0LnNldFZhbHVlKHNuYXBzaG90LnNpemUuaGVpZ2h0KTtcclxuICAgICAgdGhpcy5zdHlsZS5zZXRWYWx1ZShzbmFwc2hvdC5zdHlsZSB8fCBudWxsKTtcclxuICAgICAgdGhpcy5pbWFnZVVybC5zZXRWYWx1ZShzbmFwc2hvdC5pbWFnZT8udXJsIHx8IG51bGwpO1xyXG4gICAgICB0aGlzLmltYWdlT3BhY2l0eS5zZXRWYWx1ZShzbmFwc2hvdC5pbWFnZT8ub3BhY2l0eSB8fCAwKTtcclxuICAgICAgdGhpcy5pbWFnZVguc2V0VmFsdWUoc25hcHNob3QuaW1hZ2U/LmNhbnZhcz8ueCB8fCAwKTtcclxuICAgICAgdGhpcy5pbWFnZVkuc2V0VmFsdWUoc25hcHNob3QuaW1hZ2U/LmNhbnZhcz8ueSB8fCAwKTtcclxuICAgICAgdGhpcy5pbWFnZVdpZHRoLnNldFZhbHVlKHNuYXBzaG90LmltYWdlPy5jYW52YXM/LndpZHRoIHx8IDApO1xyXG4gICAgICB0aGlzLmltYWdlSGVpZ2h0LnNldFZhbHVlKHNuYXBzaG90LmltYWdlPy5jYW52YXM/LmhlaWdodCB8fCAwKTtcclxuICAgICAgdGhpcy5kZWZzLnNldFZhbHVlKHNuYXBzaG90LmRlZnMgfHwgbnVsbCk7XHJcbiAgICAgIHRoaXMuYmFzZVRleHQuc2V0VmFsdWUoc25hcHNob3QudGV4dCk7XHJcbiAgICAgIHRoaXMub2Zmc2V0WC5zZXRWYWx1ZShzbmFwc2hvdC50ZXh0T3B0aW9ucz8ub2Zmc2V0Py54IHx8IDApO1xyXG4gICAgICB0aGlzLm9mZnNldFkuc2V0VmFsdWUoc25hcHNob3QudGV4dE9wdGlvbnM/Lm9mZnNldD8ueSB8fCAwKTtcclxuICAgICAgdGhpcy5saW5lSGVpZ2h0T2Zmc2V0LnNldFZhbHVlKHNuYXBzaG90LnRleHRPcHRpb25zPy5saW5lSGVpZ2h0T2Zmc2V0KTtcclxuICAgICAgdGhpcy5sbkhlaWdodHMuc2V0VmFsdWUoc25hcHNob3QudGV4dE9wdGlvbnM/Lm1pbkxpbmVIZWlnaHRzIHx8IG51bGwpO1xyXG4gICAgICB0aGlzLmNoYXJTcGFjaW5nT2Zmc2V0LnNldFZhbHVlKHNuYXBzaG90LnRleHRPcHRpb25zPy5jaGFyU3BhY2luZ09mZnNldCk7XHJcbiAgICAgIHRoaXMuc3BjV2lkdGhPZmZzZXQuc2V0VmFsdWUoc25hcHNob3QudGV4dE9wdGlvbnM/LnNwY1dpZHRoT2Zmc2V0KTtcclxuICAgICAgdGhpcy50ZXh0U3R5bGUuc2V0VmFsdWUoc25hcHNob3QudGV4dFN0eWxlIHx8IG51bGwpO1xyXG4gICAgICB0aGlzLm9wZXJhdGlvbnMuc2V0VmFsdWUoc25hcHNob3Qub3BlcmF0aW9ucyk7XHJcbiAgICAgIHRoaXMub3BTdHlsZS5zZXRWYWx1ZShzbmFwc2hvdC5vcFN0eWxlIHx8IG51bGwpO1xyXG4gICAgICAvLyB0aW1lbGluZXNcclxuICAgICAgY29uc3QgdGltZWxpbmVzOiBHdmVBbmltYXRpb25UaW1lbGluZVtdID0gW107XHJcbiAgICAgIGlmIChzbmFwc2hvdC50aW1lbGluZXMpIHtcclxuICAgICAgICBmb3IgKGxldCB0YWcgaW4gc25hcHNob3QudGltZWxpbmVzKSB7XHJcbiAgICAgICAgICB0aW1lbGluZXMucHVzaChzbmFwc2hvdC50aW1lbGluZXNbdGFnXSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHRoaXMudGltZWxpbmVzLnNldFZhbHVlKHRpbWVsaW5lcyk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnVwZGF0ZUxpbmVDb3VudCh0aGlzLmJhc2VUZXh0LnZhbHVlIGFzIENoYXJOb2RlW10pO1xyXG4gICAgdGhpcy51cGRhdGVPcExpc3RzKCk7XHJcblxyXG4gICAgdGhpcy5mb3JtLm1hcmtBc1ByaXN0aW5lKCk7XHJcbiAgfVxyXG5cclxuICAvLyAjcmVnaW9uIGJhc2UgdGV4dFxyXG4gIC8qKlxyXG4gICAqIFVwZGF0ZSB0aGUgbGluZSBjb3VudCBiYXNlZCBvbiB0aGUgcmVjZWl2ZWQgdGV4dC5cclxuICAgKiBAcGFyYW0gdGV4dCBUaGUgdGV4dCB0byB1c2UgZm9yIGNvdW50aW5nIGxpbmVzLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgdXBkYXRlTGluZUNvdW50KHRleHQ6IENoYXJOb2RlW10pIHtcclxuICAgIGlmICghdGV4dC5sZW5ndGgpIHtcclxuICAgICAgdGhpcy5saW5lQ291bnQgPSAwO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5saW5lQ291bnQgPSB0ZXh0LmZpbHRlcigoYykgPT4gYy5kYXRhID09PSAnXFxuJykubGVuZ3RoICsgMTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZSB0aGUgZXZlbnQgZmlyZWQgYnkgdGhlIGJhc2UgdGV4dCBlZGl0b3IgdG8gcGljayBhIHRleHQgcmFuZ2UuXHJcbiAgICogQHBhcmFtIHJhbmdlIFRoZSBwaWNrZWQgcmFuZ2UuXHJcbiAgICovXHJcbiAgcHVibGljIG9uUmFuZ2VQaWNrKHJhbmdlOiBWYXJCYXNlVGV4dFJhbmdlKSB7XHJcbiAgICB0aGlzLnRleHRSYW5nZSA9IHJhbmdlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlIHRoZSBldmVudCBmaXJlZCBieSB0aGUgYmFzZSB0ZXh0IGVkaXRvciB0byBjaGFuZ2UgdGhlIGJhc2UgdGV4dC5cclxuICAgKiBAcGFyYW0gdGV4dCBUaGUgdGV4dCB0byBzZXQuXHJcbiAgICovXHJcbiAgcHVibGljIG9uVGV4dENoYW5nZSh0ZXh0OiBDaGFyTm9kZVtdKSB7XHJcbiAgICBjb25zb2xlLmxvZygndGV4dCBjaGFuZ2UnLCB0ZXh0KTtcclxuXHJcbiAgICAvLyB1cGRhdGUgdGhlIGZvcm0gY29udHJvbCBhbmQgcmVzZXQgdGhlIGN1cnJlbnQgdGV4dCByYW5nZVxyXG4gICAgdGhpcy5iYXNlVGV4dC5zZXRWYWx1ZSh0ZXh0KTtcclxuICAgIHRoaXMuYmFzZVRleHQudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xyXG4gICAgdGhpcy5iYXNlVGV4dC5tYXJrQXNEaXJ0eSgpO1xyXG4gICAgdGhpcy50ZXh0UmFuZ2UgPSB1bmRlZmluZWQ7XHJcblxyXG4gICAgLy8gdXBkYXRlIHRoZSBsaW5lIGNvdW50XHJcbiAgICB0aGlzLnVwZGF0ZUxpbmVDb3VudCh0ZXh0KTtcclxuXHJcbiAgICAvLyByZW1vdmUgYWxsIG9wZXJhdGlvbnMgYW5kIHVwZGF0ZSB0aGUgdmlldyBkYXRhXHJcbiAgICB0aGlzLnJlbW92ZUFsbE9wZXJhdGlvbnMoKTtcclxuXHJcbiAgICAvLyByZW1vdmUgYWxsIHRpbWVsaW5lc1xyXG4gICAgdGhpcy50aW1lbGluZXMucmVzZXQoKTtcclxuICB9XHJcbiAgLy8gI2VuZHJlZ2lvblxyXG5cclxuICAvLyAjcmVnaW9uIG9wZXJhdGlvbnNcclxuICAvKipcclxuICAgKiBVcGRhdGUgdGhlIGxpc3RzIG9mIG9wZXJhdGlvbiBvdXRwdXQgdGFncyBhbmQgZWxlbWVudCBJRHMgYnkgY29sbGVjdGluZ1xyXG4gICAqIGFsbCB0aGUgb3BlcmF0aW9uIHRhZ3MgYW5kIHRoZSBJRHMgb2YgdGhlIGVsZW1lbnRzIGluIHRoZWlyIGRpcGxvbWF0aWMuZ1xyXG4gICAqIFNWRyBjb2RlIGlmIGFueS5cclxuICAgKi9cclxuICBwcml2YXRlIHVwZGF0ZU9wTGlzdHMoKSB7XHJcbiAgICBjb25zdCB0YWdzID0gbmV3IFNldDxzdHJpbmc+KCk7XHJcbiAgICBjb25zdCBpZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcclxuXHJcbiAgICBsZXQgbiA9IDA7XHJcbiAgICBmb3IgKGNvbnN0IG9wIG9mIHRoaXMub3BlcmF0aW9ucy52YWx1ZSkge1xyXG4gICAgICAvLyBvdXRwdXQgdGFnXHJcbiAgICAgIG4rKztcclxuICAgICAgdGFncy5hZGQob3Aub3V0cHV0VGFnIHx8IGB2JHtufWApO1xyXG5cclxuICAgICAgLy8gZWxlbWVudCBJRHNcclxuICAgICAgaWYgKG9wLmRpcGxvbWF0aWNzPy5nKSB7XHJcbiAgICAgICAgdGhpcy5wYXJzZVN2Z0lkcyhvcC5kaXBsb21hdGljcy5nKT8uZm9yRWFjaCgoaWQpID0+IGlkcy5hZGQoaWQpKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMub3BUYWdzID0gWy4uLnRhZ3NdO1xyXG4gICAgdGhpcy5vcEVsZW1lbnRJZHMgPSBbLi4uaWRzXTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVkaXQgYSBuZXcgb3BlcmF0aW9uLlxyXG4gICAqL1xyXG4gIHB1YmxpYyBlZGl0TmV3T3BlcmF0aW9uKCkge1xyXG4gICAgLy8gY3JlYXRlIGEgbmV3IG9wZXJhdGlvbiBhbmQgZWRpdCBpdFxyXG4gICAgdGhpcy5lZGl0ZWRPcCA9IHtcclxuICAgICAgaWQ6IHRoaXMuX25hbm9pZCgpLFxyXG4gICAgICB0eXBlOiAwLFxyXG4gICAgICBhdDogdGhpcy50ZXh0UmFuZ2U/LmF0IHx8IDAsXHJcbiAgICAgIHJ1bjogdGhpcy50ZXh0UmFuZ2U/LnJ1biB8fCAxLFxyXG4gICAgfTtcclxuICAgIHRoaXMuZWRpdGVkT3BJbmRleCA9IC0xO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRWRpdCAoYSBjb3B5IG9mKSB0aGUgb3BlcmF0aW9uIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguXHJcbiAgICogQHBhcmFtIGluZGV4IFRoZSBvcGVyYXRpb24gaW5kZXguXHJcbiAgICovXHJcbiAgcHVibGljIGVkaXRPcGVyYXRpb24oaW5kZXg6IG51bWJlcikge1xyXG4gICAgdGhpcy5lZGl0ZWRPcEluZGV4ID0gaW5kZXg7XHJcbiAgICB0aGlzLmVkaXRlZE9wID0gZGVlcENvcHkodGhpcy5vcGVyYXRpb25zLnZhbHVlW2luZGV4XSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDbG9zZSB0aGUgY3VycmVudGx5IGVkaXRlZCBvcGVyYXRpb24uXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjbG9zZUVkaXRlZE9wZXJhdGlvbigpIHtcclxuICAgIHRoaXMuZWRpdGVkT3BJbmRleCA9IC0xO1xyXG4gICAgdGhpcy5lZGl0ZWRPcCA9IHVuZGVmaW5lZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZSB0aGUgZXZlbnQgZmlyZWQgYnkgdGhlIG9wZXJhdGlvbiBlZGl0b3IgdG8gY2FuY2VsXHJcbiAgICogdGhlIGN1cnJlbnQgb3BlcmF0aW9uIGVkaXRzLlxyXG4gICAqL1xyXG4gIHB1YmxpYyBvbk9wZXJhdGlvbkNhbmNlbCgpIHtcclxuICAgIHRoaXMuY2xvc2VFZGl0ZWRPcGVyYXRpb24oKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZSB0aGUgZXZlbnQgZmlyZWQgYnkgdGhlIG9wZXJhdGlvbiBlZGl0b3IgdG8gY2hhbmdlXHJcbiAgICogdGhlIGN1cnJlbnRseSBlZGl0ZWQgb3BlcmF0aW9uLCBvciBhZGQgYSBuZXcgb25lIGlmIHRoYXRcclxuICAgKiB3YXMgYSBuZXcgb3BlcmF0aW9uLlxyXG4gICAqIEBwYXJhbSBvcCBUaGUgY2hhbmdlZCBvcGVyYXRpb24uXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIG9uT3BlcmF0aW9uQ2hhbmdlKG9wOiBDaGFyQ2hhaW5PcGVyYXRpb24pIHtcclxuICAgIGNvbnNvbGUubG9nKCdvcGVyYXRpb24gY2hhbmdlJyk7XHJcbiAgICBjb25zdCBvcGVyYXRpb25zID0gWy4uLnRoaXMub3BlcmF0aW9ucy52YWx1ZV07XHJcblxyXG4gICAgLy8gcmVwbGFjZSBvciBhZGQgdGhlIG9wZXJhdGlvblxyXG4gICAgbGV0IGkgPSB0aGlzLmVkaXRlZE9wSW5kZXg7XHJcbiAgICBpZiAodGhpcy5lZGl0ZWRPcEluZGV4ID4gLTEpIHtcclxuICAgICAgb3BlcmF0aW9ucy5zcGxpY2UodGhpcy5lZGl0ZWRPcEluZGV4LCAxLCBvcCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBvcGVyYXRpb25zLnB1c2gob3ApO1xyXG4gICAgICBpID0gb3BlcmF0aW9ucy5sZW5ndGggLSAxO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHVwZGF0ZSB0aGUgb3BlcmF0aW9ucyBmb3JtIGNvbnRyb2xcclxuICAgIHRoaXMub3BlcmF0aW9ucy5zZXRWYWx1ZShvcGVyYXRpb25zKTtcclxuICAgIHRoaXMub3BlcmF0aW9ucy5tYXJrQXNEaXJ0eSgpO1xyXG4gICAgdGhpcy5vcGVyYXRpb25zLnVwZGF0ZVZhbHVlQW5kVmFsaWRpdHkoKTtcclxuXHJcbiAgICAvLyB1cGRhdGUgdGhlIG9wZXJhdGlvbiBsaXN0c1xyXG4gICAgdGhpcy51cGRhdGVPcExpc3RzKCk7XHJcblxyXG4gICAgLy8gdXBkYXRlIHRoZSB2aWV3IGRhdGFcclxuICAgIHRoaXMucmVzdWx0ID0gYXdhaXQgdGhpcy5ydW5UbyhpKTtcclxuXHJcbiAgICAvLyBjbG9zZSB0aGUgZWRpdGVkIG9wZXJhdGlvblxyXG4gICAgdGhpcy5jbG9zZUVkaXRlZE9wZXJhdGlvbigpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRGVsZXRlIHRoZSBvcGVyYXRpb24gYXQgdGhlIHNwZWNpZmllZCBpbmRleC5cclxuICAgKiBAcGFyYW0gaW5kZXggVGhlIGluZGV4IG9mIHRoZSBvcGVyYXRpb24gdG8gZGVsZXRlLlxyXG4gICAqL1xyXG4gIHB1YmxpYyBkZWxldGVPcGVyYXRpb24oaW5kZXg6IG51bWJlcikge1xyXG4gICAgdGhpcy5fZGlhbG9nU2VydmljZVxyXG4gICAgICAuY29uZmlybShcclxuICAgICAgICAnQ29uZmlybSBEZWxldGlvbicsXHJcbiAgICAgICAgYERlbGV0ZSBvcGVyYXRpb24gXCIke3RoaXMub3BlcmF0aW9ucy52YWx1ZVtpbmRleF0uaWR9XCI/YFxyXG4gICAgICApXHJcbiAgICAgIC5zdWJzY3JpYmUoKHllczogYm9vbGVhbikgPT4ge1xyXG4gICAgICAgIGlmICh5ZXMpIHtcclxuICAgICAgICAgIC8vIGNsb3NlIHRoZSBlZGl0ZWQgb3BlcmF0aW9uIGlmIGl0IGlzIHRoZSBvbmUgYmVpbmcgZGVsZXRlZFxyXG4gICAgICAgICAgaWYgKHRoaXMuZWRpdGVkT3BJbmRleCA9PT0gaW5kZXgpIHtcclxuICAgICAgICAgICAgdGhpcy5jbG9zZUVkaXRlZE9wZXJhdGlvbigpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgLy8gcmVzZXQgdGhlIHJlc3VsdCBvcGVyYXRpb24gSUQgaWYgaXQgaXMgdGhlIG9uZSBiZWluZyBkZWxldGVkXHJcbiAgICAgICAgICBpZiAodGhpcy5yZXN1bHRPcGVyYXRpb25JZCA9PT0gdGhpcy5vcGVyYXRpb25zLnZhbHVlW2luZGV4XS5pZCkge1xyXG4gICAgICAgICAgICB0aGlzLnJlc3VsdE9wZXJhdGlvbklkID0gdW5kZWZpbmVkO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgLy8gZGVsZXRlIHRoZSBvcGVyYXRpb24gYW5kIHVwZGF0ZSB0aGUgZm9ybSBjb250cm9sXHJcbiAgICAgICAgICBjb25zdCBvcGVyYXRpb25zID0gWy4uLnRoaXMub3BlcmF0aW9ucy52YWx1ZV07XHJcbiAgICAgICAgICBvcGVyYXRpb25zLnNwbGljZShpbmRleCwgMSk7XHJcbiAgICAgICAgICB0aGlzLm9wZXJhdGlvbnMuc2V0VmFsdWUob3BlcmF0aW9ucyk7XHJcbiAgICAgICAgICB0aGlzLm9wZXJhdGlvbnMubWFya0FzRGlydHkoKTtcclxuICAgICAgICAgIHRoaXMub3BlcmF0aW9ucy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KCk7XHJcblxyXG4gICAgICAgICAgLy8gdXBkYXRlIHRoZSBvcGVyYXRpb24gbGlzdHNcclxuICAgICAgICAgIHRoaXMudXBkYXRlT3BMaXN0cygpO1xyXG5cclxuICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgdmlldyBkYXRhXHJcbiAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5ydW5Ub0xhc3QoKTtcclxuICAgICAgICAgIH0sIDApO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBQYXJzZSB0aGUgb3BlcmF0aW9ucyBmcm9tIHRoZWlyIHRleHQgYW5kIGFwcGVuZCB0aGVtIHRvIHRoZSBjdXJyZW50XHJcbiAgICogc25hcHNob3Qgb3BlcmF0aW9ucy5cclxuICAgKi9cclxuICBwdWJsaWMgcGFyc2VPcGVyYXRpb25zKCkge1xyXG4gICAgaWYgKHRoaXMuYnVzeSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZGlhbG9nUmVmID0gdGhpcy5fZGlhbG9nLm9wZW4oQmF0Y2hPcGVyYXRpb25FZGl0b3JDb21wb25lbnQsIHtcclxuICAgICAgZGF0YTogeyBwcmVzZXQ6IHRoaXMuYmF0Y2hPcHMgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGRpYWxvZ1JlZi5hZnRlckNsb3NlZCgpLnN1YnNjcmliZSgoYmF0Y2hPcHM6IENoYXJDaGFpbk9wZXJhdGlvbltdKSA9PiB7XHJcbiAgICAgIGlmIChiYXRjaE9wcykge1xyXG4gICAgICAgIGNvbnN0IG9wZXJhdGlvbnMgPSBbLi4udGhpcy5vcGVyYXRpb25zLnZhbHVlXTtcclxuICAgICAgICBvcGVyYXRpb25zLnB1c2goLi4uYmF0Y2hPcHMpO1xyXG4gICAgICAgIHRoaXMub3BlcmF0aW9ucy5zZXRWYWx1ZShvcGVyYXRpb25zKTtcclxuICAgICAgICB0aGlzLm9wZXJhdGlvbnMubWFya0FzRGlydHkoKTtcclxuICAgICAgICB0aGlzLm9wZXJhdGlvbnMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xyXG4gICAgICAgIC8vIHVwZGF0ZSB0aGUgb3BlcmF0aW9uIGxpc3RzXHJcbiAgICAgICAgdGhpcy51cGRhdGVPcExpc3RzKCk7XHJcbiAgICAgICAgLy8gdXBkYXRlIHRoZSB2aWV3IGRhdGFcclxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgIHRoaXMucnVuVG9MYXN0KCk7XHJcbiAgICAgICAgfSwgMCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZW1vdmVBbGxPcGVyYXRpb25zKCk6IHZvaWQge1xyXG4gICAgdGhpcy5yZXN1bHRPcGVyYXRpb25JZCA9IHVuZGVmaW5lZDtcclxuICAgIHRoaXMuY2xvc2VFZGl0ZWRPcGVyYXRpb24oKTtcclxuICAgIHRoaXMub3BlcmF0aW9ucy5yZXNldCgpO1xyXG4gICAgdGhpcy5vcGVyYXRpb25zLm1hcmtBc0RpcnR5KCk7XHJcbiAgICB0aGlzLm9wZXJhdGlvbnMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xyXG4gICAgdGhpcy5vcFRhZ3MgPSBbXTtcclxuICAgIHRoaXMub3BFbGVtZW50SWRzID0gW107XHJcbiAgICB0aGlzLnNldFZpZXdEYXRhKCk7XHJcbiAgICB0aGlzLnJlc3VsdCA9IHVuZGVmaW5lZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlbW92ZSBhbGwgdGhlIG9wZXJhdGlvbnMuXHJcbiAgICovXHJcbiAgcHVibGljIGNsZWFyT3BlcmF0aW9ucygpOiB2b2lkIHtcclxuICAgIHRoaXMuX2RpYWxvZ1NlcnZpY2VcclxuICAgICAgLmNvbmZpcm0oJ0NvbmZpcm0nLCAnUmVtb3ZlIGFsbCBvcGVyYXRpb25zPycpXHJcbiAgICAgIC5zdWJzY3JpYmUoKHllczogYm9vbGVhbikgPT4ge1xyXG4gICAgICAgIGlmICh5ZXMpIHtcclxuICAgICAgICAgIHRoaXMucmVtb3ZlQWxsT3BlcmF0aW9ucygpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBQYXJzZSBhbGwgdGhlIGlkIGF0dHJpYnV0ZXMgZnJvbSB0aGUgcmVjZWl2ZWQgU1ZHIGNvZGUgYW5kXHJcbiAgICogcmV0dXJuIHRoZW0gYXMgYW4gYXJyYXkuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gc3ZnIFRoZSBTVkcgY29udGVudCB0byBwYXJzZSBvciB1bmRlZmluZWQuXHJcbiAgICogQHJldHVybnMgQXJyYXkgb2YgSURzIGZvdW5kIGluIHRoZSBTVkcgY29udGVudCBvciB1bmRlZmluZWQuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBwYXJzZVN2Z0lkcyhzdmc/OiBzdHJpbmcpOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCB7XHJcbiAgICBpZiAoIXN2Zykge1xyXG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHJlZ2V4ID0gLzxbXj5dK1xcYmlkPShbXCInXSkoLio/KVxcMS9nO1xyXG4gICAgY29uc3QgaWRzOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgbGV0IG1hdGNoOiBSZWdFeHBFeGVjQXJyYXkgfCBudWxsO1xyXG5cclxuICAgIHdoaWxlICgobWF0Y2ggPSByZWdleC5leGVjKHN2ZykpICE9PSBudWxsKSB7XHJcbiAgICAgIGlkcy5wdXNoKG1hdGNoWzJdKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gaWRzO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBnZXRUcmFuc3BhcmVudElkcyhnPzogc3RyaW5nKTogc3RyaW5nW10gfCB1bmRlZmluZWQge1xyXG4gICAgaWYgKCFnKSB7XHJcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcy5wYXJzZVN2Z0lkcyhnKT8uZmlsdGVyKChpZCkgPT4gaWQuZW5kc1dpdGgoU1ZHX1RSQU5TUF9TVUZGSVgpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJ1biB0aGUgb3BlcmF0aW9ucyB1cCB0byB0aGUgc3BlY2lmaWVkIGluZGV4IChpbmNsdWRlZCkuXHJcbiAgICogVGhpcyBpcyBjYWxsZWQgd2hlbjpcclxuICAgKiAtIGEgcHJldmlldyBpcyByZXF1ZXN0ZWQgYnkgdGhlIG9wZXJhdGlvbiBlZGl0b3IuXHJcbiAgICogLSB0aGUgY3VycmVudGx5IGVkaXRlZCBvcGVyYXRpb24gaXMgc2F2ZWQuXHJcbiAgICogLSB0aGUgdXNlciBwaWNrcyBhIHN0ZXAgaW4gdGhlIGNoYWluIHJlc3VsdCB2aWV3LlxyXG4gICAqIC0gcnVuVG9MYXN0IGlzIGNhbGxlZCwgd2hpY2ggaGFwcGVucyB3aGVuOlxyXG4gICAqICAgLSBzZXR0aW5nIHRoZSBzbmFwc2hvdC5cclxuICAgKiAgIC0gcGFyc2luZyBhIGJhdGNoIG9mIG9wZXJhdGlvbnMuXHJcbiAgICogICAtIGRlbGV0aW5nIGFuIG9wZXJhdGlvbi5cclxuICAgKlxyXG4gICAqIEBwYXJhbSBpbmRleCBUaGUgaW5kZXggb2YgdGhlIG9wZXJhdGlvbiB0byBydW4gdG8uXHJcbiAgICogQHBhcmFtIGxhc3RPcGVyYXRpb24gVGhlIG9wZXJhdGlvbiB0byB1c2UgaW4gcGxhY2Ugb2YgdGhlIGV4aXN0aW5nXHJcbiAgICogb3BlcmF0aW9uIGluIHRoZSBzbmFwc2hvdCBhdCBpbmRleC4gVGhpcyBpcyB1c2VkIHdoZW4gcHJldmlld2luZ1xyXG4gICAqIHRoZSBlZGl0ZWQgb3BlcmF0aW9uIGZyb20gd2l0aGluIHRoZSBvcGVyYXRpb24gZWRpdG9yLlxyXG4gICAqL1xyXG4gIHB1YmxpYyBydW5UbyhcclxuICAgIGluZGV4OiBudW1iZXIsXHJcbiAgICBsYXN0T3BlcmF0aW9uPzogQ2hhckNoYWluT3BlcmF0aW9uXHJcbiAgKTogUHJvbWlzZTxDaGFyQ2hhaW5SZXN1bHQ+IHtcclxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAgIGlmICh0aGlzLmJ1c3kpIHtcclxuICAgICAgICByZXR1cm4gcmVqZWN0KCdCdXN5Jyk7XHJcbiAgICAgIH1cclxuICAgICAgY29uc29sZS5sb2coJ3J1biB0bzogJyArIGluZGV4KTtcclxuXHJcbiAgICAgIC8vIGdldCB0aGUgc25hcHNob3QgKD10ZXh0IGFuZCBvcHMpIHRvIHJ1biBvcGVyYXRpb25zIG9uXHJcbiAgICAgIGNvbnN0IHNuYXBzaG90ID0gdGhpcy5nZXRTbmFwc2hvdCgpO1xyXG4gICAgICBpZiAoIXNuYXBzaG90LnRleHQpIHtcclxuICAgICAgICByZXR1cm4gcmVqZWN0KCdObyBzbmFwc2hvdCB0ZXh0Jyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIHJlbW92ZSBmcm9tIHRoZSBzbmFwc2hvdCB0aGUgb3BlcmF0aW9ucyBwYXN0IHRoZSBzcGVjaWZpZWQgaW5kZXgsXHJcbiAgICAgIC8vIGFsc28gcmVwbGFjaW5nIHRoZSBsYXN0IG9wZXJhdGlvbiB3aGVuIHRoaXMgd2FzIHJlY2VpdmVkIGFzIGEgcGFyYW1ldGVyXHJcbiAgICAgIHNuYXBzaG90Lm9wZXJhdGlvbnMgPSBbLi4udGhpcy5vcGVyYXRpb25zLnZhbHVlXTtcclxuXHJcbiAgICAgIGlmIChsYXN0T3BlcmF0aW9uKSB7XHJcbiAgICAgICAgc25hcHNob3Qub3BlcmF0aW9ucyA9IHNuYXBzaG90Lm9wZXJhdGlvbnMuc2xpY2UoMCwgaW5kZXgpO1xyXG4gICAgICAgIHNuYXBzaG90Lm9wZXJhdGlvbnMucHVzaChsYXN0T3BlcmF0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzbmFwc2hvdC5vcGVyYXRpb25zID0gc25hcHNob3Qub3BlcmF0aW9ucy5zbGljZSgwLCBpbmRleCArIDEpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBydW4gdGhlIG9wZXJhdGlvbnNcclxuICAgICAgdGhpcy5idXN5ID0gdHJ1ZTtcclxuICAgICAgdGhpcy5pbml0aWFsU3RlcEluZGV4ID0gaW5kZXg7XHJcbiAgICAgIHRoaXMuX2FwaVxyXG4gICAgICAgIC5ydW5PcGVyYXRpb25zKHNuYXBzaG90LnRleHQgYXMgQ2hhck5vZGVbXSwgc25hcHNob3Qub3BlcmF0aW9ucylcclxuICAgICAgICAuc3Vic2NyaWJlKHtcclxuICAgICAgICAgIG5leHQ6ICh3cmFwcGVyKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIGhhbmRsZSBvcGVyYXRpb24gKG5vbi1mYXRhbCkgZXJyb3Igb3IgcmVzdWx0XHJcbiAgICAgICAgICAgIGlmICh3cmFwcGVyLmVycm9yKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5fc25hY2tiYXIub3Blbih3cmFwcGVyLmVycm9yLCAnT0snKTtcclxuICAgICAgICAgICAgICByZWplY3Qod3JhcHBlci5lcnJvcik7XHJcbiAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBleHRyYWN0IHRoZSBJRHMgZnJvbSB0aGUgbGFzdCBvcGVyYXRpb24ncyBkaXBsb21hdGljcyBhbmQgZmlsdGVyXHJcbiAgICAgICAgICAgIC8vIHRoZW0gc28gdGhhdCBvbmx5IHRoZSBvbmVzIGVuZGluZyB3aXRoIF90IGFyZSBrZXB0LiBCeSBjb252ZW50aW9uLFxyXG4gICAgICAgICAgICAvLyBhbGwgdGhlIElEcyBlbmRpbmcgd2l0aCB0aGlzIHN1ZmZpeCBhcmUgdG8gYmUgbWFkZSBpbnZpc2libGUgYXRcclxuICAgICAgICAgICAgLy8gdGhlaXIgZmlyc3QgcmVuZGl0aW9uIChvcGFjaXR5PTApLiBBbiBhbmltYXRpb24gd2lsbCB0aGVuIG1ha2VcclxuICAgICAgICAgICAgLy8gdGhlbSB2aXNpYmxlLlxyXG4gICAgICAgICAgICBjb25zdCBsYXN0T3AgPSBzbmFwc2hvdC5vcGVyYXRpb25zW3NuYXBzaG90Lm9wZXJhdGlvbnMubGVuZ3RoIC0gMV07XHJcbiAgICAgICAgICAgIHRoaXMuX3RyYW5zcGFyZW50SWRzID0gdGhpcy5nZXRUcmFuc3BhcmVudElkcyhcclxuICAgICAgICAgICAgICBsYXN0T3AuZGlwbG9tYXRpY3M/LmdcclxuICAgICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgdmlldyBkYXRhXHJcbiAgICAgICAgICAgIHRoaXMuc2V0Vmlld0RhdGEoc25hcHNob3QsIGxhc3RPcC5vdXRwdXRUYWcpO1xyXG5cclxuICAgICAgICAgICAgLy8gcmV0dXJuIHRoZSByZXN1bHRcclxuICAgICAgICAgICAgcmVzb2x2ZSh3cmFwcGVyLnJlc3VsdCEpO1xyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIGVycm9yOiAoZXJyb3IpID0+IHtcclxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgIHRoaXMuX3RyYW5zcGFyZW50SWRzID0gdW5kZWZpbmVkO1xyXG4gICAgICAgICAgICB0aGlzLl9zbmFja2Jhci5vcGVuKCdFcnJvciBydW5uaW5nIG9wZXJhdGlvbnMnLCAnT0snKTtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBjb21wbGV0ZTogKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmJ1c3kgPSBmYWxzZTtcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgfSk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJ1biB0aGUgb3BlcmF0aW9ucyB1cCB0byB0aGUgbGFzdCBvcGVyYXRpb24gaWYgYW55LCB1cGRhdGluZyB0aGVcclxuICAgKiBleGVjdXRpb24gcmVzdWx0LiBUaGUgZXhlY3V0aW9uIHJlc3VsdCBpcyBhbHdheXMgdGhlIHJlc3VsdCBmcm9tXHJcbiAgICogYWxsIHRoZSBvcGVyYXRpb25zLCBhcyB1c2VycyBtdXN0IGJlIGFibGUgdG8gYnJvd3NlIGFjcm9zcyBpdHMgc3RlcHMuXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIHJ1blRvTGFzdCgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGlmICh0aGlzLm9wZXJhdGlvbnMudmFsdWUubGVuZ3RoKSB7XHJcbiAgICAgIHRoaXMucmVzdWx0ID0gYXdhaXQgdGhpcy5ydW5Ubyh0aGlzLm9wZXJhdGlvbnMudmFsdWUubGVuZ3RoIC0gMSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnNldFZpZXdEYXRhKCk7XHJcbiAgICAgIHRoaXMucmVzdWx0ID0gdW5kZWZpbmVkO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVXBkYXRlIHRoZSBzbmFwc2hvdCB2aWV3IGJ5IHJ1bm5pbmcgdGhlIG9wZXJhdGlvbnMgdXAgdG8gdGhlXHJcbiAgICogY3VycmVudGx5IGVkaXRlZCBvcGVyYXRpb24gaWYgYW55LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIG9wZXJhdGlvbiBUaGUgb3BlcmF0aW9uIGJlaW5nIHByZXZpZXdlZC5cclxuICAgKi9cclxuICBwdWJsaWMgb25PcGVyYXRpb25QcmV2aWV3KG9wZXJhdGlvbjogQ2hhckNoYWluT3BlcmF0aW9uKTogdm9pZCB7XHJcbiAgICAvLyBubyBtdWx0aXBsZSBwcmV2aWV3cyBvciBwcmV2aWV3aW5nIGEgbmV3IG9wZXJhdGlvblxyXG4gICAgaWYgKHRoaXMuX3ByZXZpZXdpbmcgfHwgdGhpcy5lZGl0ZWRPcEluZGV4IDwgMCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICB0aGlzLl9wcmV2aWV3aW5nID0gdHJ1ZTtcclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLnJ1blRvKHRoaXMuZWRpdGVkT3BJbmRleCwgb3BlcmF0aW9uKTtcclxuICAgICAgdGhpcy5fcHJldmlld2luZyA9IGZhbHNlO1xyXG4gICAgfSwgMCk7XHJcbiAgfVxyXG4gIC8vICNlbmRyZWdpb25cclxuXHJcbiAgLyoqXHJcbiAgICogQnVpbGQgdGhlIHNuYXBzaG90IGF0IHRoZSBzcGVjaWZpZWQgZXhlY3V0aW9uIHN0ZXAuIFRoaXMgaW1wbGllcyBhZGRpbmdcclxuICAgKiB0aGUgbm9kZXMgaW50cm9kdWNlZCBieSB0aGUgb3BlcmF0aW9ucyB1cCB0byB0aGUgc3BlY2lmaWVkIHN0ZXAsIGFuZFxyXG4gICAqIHVwZGF0aW5nIHRoZSBmZWF0dXJlcyBvZiB0aGUgbm9kZXMgaW50cm9kdWNlZCBieSB0aGUgc3BlY2lmaWVkIHN0ZXAuXHJcbiAgICogQWxzbywgdGhlIG9wZXJhdGlvbnMgYWZ0ZXIgdGhlIHNwZWNpZmllZCBzdGVwIGFyZSByZW1vdmVkIGZyb20gdGhlXHJcbiAgICogc25hcHNob3QuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gc3RlcCBUaGUgc3RlcCB0byBidWlsZCB0aGUgc25hcHNob3QgYXQuXHJcbiAgICogQHJldHVybnMgVGhlIHNuYXBzaG90IGF0IHRoZSBzcGVjaWZpZWQgc3RlcC5cclxuICAgKi9cclxuICBwcml2YXRlIGJ1aWxkU25hcHNob3RBdFN0ZXAoXHJcbiAgICBzdGVwOiBDaGFpbk9wZXJhdGlvbkNvbnRleHRTdGVwXHJcbiAgKTogU25hcHNob3QgfCBudWxsIHtcclxuICAgIC8vIG5vIHJlc3VsdCwgbm90aGluZyB0byBkb1xyXG4gICAgaWYgKCF0aGlzLnJlc3VsdCkge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBnZXQgdGhlIGN1cnJlbnRseSBlZGl0ZWQgc25hcHNob3RcclxuICAgIGNvbnN0IHNuYXBzaG90ID0gdGhpcy5nZXRTbmFwc2hvdCgpO1xyXG4gICAgLy8gZmluZCB0aGUgbWF4IElEIGluIHNuYXBzaG90LnRleHQgKD1vcmlnaW5hbCkgbm9kZXMsXHJcbiAgICAvLyBzbyB0aGF0IGFueSBJRCBncmVhdGVyIHRoYW4gaXQgYmVsb25ncyB0byBuZXcgbm9kZXNcclxuICAgIGNvbnN0IG1heE9yaWdpbmFsSWQgPSAoc25hcHNob3QudGV4dCBhcyBDaGFyTm9kZVtdKS5yZWR1Y2UoXHJcbiAgICAgIChtYXgsIG4pID0+IE1hdGgubWF4KG1heCwgbi5pZCksXHJcbiAgICAgIDBcclxuICAgICk7XHJcbiAgICAvLyBnZXQgYSBjb3B5IG9mIHRoZSBub2RlcyBvZiB0aGUgc25hcHNob3QgYmFzZSB0ZXh0XHJcbiAgICBjb25zdCBzbmFwTm9kZXM6IENoYXJOb2RlW10gPSBkZWVwQ29weShzbmFwc2hvdC50ZXh0IGFzIENoYXJOb2RlW10pO1xyXG5cclxuICAgIC8vIGdldCB0aGUgbm9kZXMgb2YgdGhlIHBpY2tlZCBzdGVwXHJcbiAgICBjb25zdCBzdGVwTm9kZXMgPSB0aGlzLnJlc3VsdC50YWdnZWROb2Rlc1tzdGVwLm91dHB1dFRhZ107XHJcblxyXG4gICAgLy8gdXBkYXRlIHRoZSBzbmFwc2hvdCB0ZXh0IG5vZGVzIGNvcGllcyB3aXRoIHRoZSBwaWNrZWQgc3RlcCBub2RlcyxcclxuICAgIC8vIGJ5IHVwZGF0aW5nIHRoZWlyIGZlYXR1cmVzIGlmIGV4aXN0aW5nLCBvciBhZGRpbmcgbmV3IG5vZGVzIGlmIG5vdC5cclxuICAgIGZvciAoY29uc3Qgc24gb2Ygc3RlcE5vZGVzKSB7XHJcbiAgICAgIC8vIGZpbmQgdGhlIG5vZGUgaW4gdGhlIG9yaWdpbmFsIHNuYXBzaG90IHRleHRcclxuICAgICAgY29uc3QgaSA9IHNuYXBOb2Rlcy5maW5kSW5kZXgoKG4pID0+IG4uaWQgPT09IHNuLmlkKTtcclxuICAgICAgLy8gaWYgZm91bmQsIHVwZGF0ZSBpdHMgZmVhdHVyZXMsIGVsc2UgYWRkIGl0XHJcbiAgICAgIGlmIChpID4gLTEpIHtcclxuICAgICAgICBzbmFwTm9kZXNbaV0uZmVhdHVyZXMgPSBzbi5mZWF0dXJlcztcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBuZXcgbm9kZTogd2UgYXNzdW1lIHRoYXQgaXQgaGFzIGEgbWFudWFsbHkgc2V0IHBvc2l0aW9uICh4LHkgZmVhdHVyZXMpXHJcbiAgICAgICAgc25hcE5vZGVzLnB1c2goc24pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gYXBwZW5kIG5vZGVzIGludHJvZHVjZWQgKmJlZm9yZSogdGhlIHBpY2tlZCBzdGVwLCBpZiBhbnlcclxuICAgIC8vICh0aG9zZSBpbnRyb2R1Y2VkIGJ5IHRoZSBwaWNrZWQgc3RlcCBoYXZlIGFscmVhZHkgYmVlbiBhZGRlZClcclxuICAgIGNvbnN0IHN0ZXBJbmRleCA9IHRoaXMucmVzdWx0LnN0ZXBzLmluZGV4T2Yoc3RlcCk7XHJcblxyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzdGVwSW5kZXg7IGkrKykge1xyXG4gICAgICBjb25zdCBzdGVwTm9kZXMgPSB0aGlzLnJlc3VsdC50YWdnZWROb2Rlc1t0aGlzLnJlc3VsdC5zdGVwc1tpXS5vdXRwdXRUYWddO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBuIG9mIHN0ZXBOb2Rlcykge1xyXG4gICAgICAgIGlmIChuLmlkID4gbWF4T3JpZ2luYWxJZCAmJiAhc25hcE5vZGVzLmZpbmQoKHgpID0+IHguaWQgPT09IG4uaWQpKSB7XHJcbiAgICAgICAgICBzbmFwTm9kZXMucHVzaChuKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyB1cGRhdGUgdGhlIHNuYXBzaG90IHRleHQgbm9kZXNcclxuICAgIHNuYXBzaG90LnRleHQgPSBzbmFwTm9kZXM7XHJcblxyXG4gICAgLy8gcmVtb3ZlIGZyb20gdGhlIHNuYXBzaG90IHRoZSBvcGVyYXRpb25zIGFmdGVyIHRoZSBwaWNrZWQgc3RlcFxyXG4gICAgY29uc3QgaSA9IHNuYXBzaG90Lm9wZXJhdGlvbnMuZmluZEluZGV4KChvKSA9PiBvLmlkID09PSBzdGVwLm9wZXJhdGlvbi5pZCk7XHJcbiAgICBpZiAoaSA+IC0xKSB7XHJcbiAgICAgIHNuYXBzaG90Lm9wZXJhdGlvbnMgPSBzbmFwc2hvdC5vcGVyYXRpb25zLnNsaWNlKDAsIGkgKyAxKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gc25hcHNob3Q7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHBsYXlUaW1lbGluZSh0bDogR3ZlQW5pbWF0aW9uVGltZWxpbmUpOiB2b2lkIHtcclxuICAgIGNvbnN0IHNoYWRvd1Jvb3QgPSB0aGlzLnNuYXBzaG90Vmlldz8ubmF0aXZlRWxlbWVudD8uc2hhZG93Um9vdDtcclxuICAgIGlmICh0bCAmJiBzaGFkb3dSb290KSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKCdwbGF5IHRpbWVsaW5lJywgdGwpO1xyXG4gICAgICB0aGlzLl9yZW5kZXJlcj8ucGxheVRpbWVsaW5lKHRsLCB1bmRlZmluZWQsIHNoYWRvd1Jvb3QpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKCF0aGlzLnNuYXBzaG90Vmlldykge1xyXG4gICAgICAgIGNvbnNvbGUud2Fybignbm8gc25hcHNob3RWaWV3IGZvciB0aW1lbGluZScpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnNvbGUud2Fybignbm8gc2hhZG93Um9vdCBmb3IgdGltZWxpbmUnKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlIHRoZSBldmVudCBmaXJlZCBieSB0aGUgY2hhaW4gcmVzdWx0IHZpZXcgdG8gcGljayBhIHN0ZXAuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gc3RlcCBUaGUgc3RlcCB0byBwaWNrLlxyXG4gICAqL1xyXG4gIHB1YmxpYyBhc3luYyBvblN0ZXBQaWNrKHN0ZXA6IENoYWluT3BlcmF0aW9uQ29udGV4dFN0ZXApOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGlmICghdGhpcy5yZXN1bHQgfHwgdGhpcy5fc3RlcFBpY2tGcm96ZW4pIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGdldCB0aGUgY3VycmVudGx5IGVkaXRlZCBzbmFwc2hvdFxyXG4gICAgY29uc3Qgc25hcHNob3QgPSB0aGlzLmJ1aWxkU25hcHNob3RBdFN0ZXAoc3RlcCkhO1xyXG4gICAgLy8gdXBkYXRlIHJlc3VsdCBvcGVyYXRpb24gSURcclxuICAgIHRoaXMucmVzdWx0T3BlcmF0aW9uSWQgPSBzdGVwLm9wZXJhdGlvbi5pZDtcclxuICAgIC8vIHVwZGF0ZSB0cmFuc3BhcmVudCBJRHNcclxuICAgIHRoaXMuX3RyYW5zcGFyZW50SWRzID0gdGhpcy5nZXRUcmFuc3BhcmVudElkcyhcclxuICAgICAgc3RlcC5vcGVyYXRpb24uZGlwbG9tYXRpY3M/LmdcclxuICAgICk7XHJcbiAgICAvLyB1cGRhdGUgdmlldyBkYXRhXHJcbiAgICB0aGlzLnNldFZpZXdEYXRhKHNuYXBzaG90LCBzdGVwLm91dHB1dFRhZyk7XHJcblxyXG4gICAgLy8gcGxheSBhbmltYXRpb24gaWYgYW55XHJcbiAgICBjb25zdCB0bCA9IHRoaXMudGltZWxpbmVzLnZhbHVlLmZpbmQoKHQpID0+IHQudGFnID09PSBzdGVwLm91dHB1dFRhZyk7XHJcbiAgICBpZiAodGwpIHtcclxuICAgICAgdGhpcy5fc3RlcFBpY2tGcm96ZW4gPSB0cnVlO1xyXG5cclxuICAgICAgLy8gZmluZCB0aGUgaW5kZXggb2YgdGhlIHBpY2tlZCBzdGVwIGluIHRoZSBzbmFwc2hvdCBvcGVyYXRpb25zXHJcbiAgICAgIGNvbnN0IGkgPSBzbmFwc2hvdC5vcGVyYXRpb25zLmZpbmRJbmRleChcclxuICAgICAgICAobykgPT4gby5pZCA9PT0gc3RlcC5vcGVyYXRpb24uaWRcclxuICAgICAgKTtcclxuICAgICAgLy8gcnVuIHRoZSBvcGVyYXRpb25zIHVwIHRvIHRoZSBwaWNrZWQgc3RlcCBhcyB3ZSBuZWVkIHRvIGhpZGVcclxuICAgICAgLy8gdGhvc2UgdmlzdWFscyB0byBiZSByZXZlYWxlZCBieSB0aGUgYW5pbWF0aW9uXHJcbiAgICAgIGF3YWl0IHRoaXMucnVuVG8oaSk7XHJcbiAgICAgIHRoaXMuX3N0ZXBQaWNrRnJvemVuID0gZmFsc2U7XHJcblxyXG4gICAgICAvLyBwbGF5IHRoZSB0aW1lbGluZVxyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICB0aGlzLnBsYXlUaW1lbGluZSh0bCk7XHJcbiAgICAgIH0sIDApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlIHRoZSBldmVudCBmaXJlZCBieSBhIHZpc3VhbCBpbiB0aGUgc25hcHNob3Qgdmlldy5cclxuICAgKlxyXG4gICAqIEBwYXJhbSBldmVudCBUaGUgZXZlbnQuXHJcbiAgICovXHJcbiAgcHVibGljIG9uVmlzdWFsRXZlbnQoZXZlbnQ6IEN1c3RvbUV2ZW50PEd2ZVZpc3VhbEV2ZW50Pik6IHZvaWQge1xyXG4gICAgY29uc3QgZCA9IGV2ZW50LmRldGFpbDtcclxuXHJcbiAgICBpZiAoZC5ldmVudC50eXBlID09PSAnbW91c2VvdmVyJykge1xyXG4gICAgICBjb25zdCB2aXN1YWwgPSBkLnNvdXJjZTtcclxuICAgICAgY29uc3Qgc2I6IHN0cmluZ1tdID0gW107XHJcbiAgICAgIC8vIGlkICh0eXBlKVxyXG4gICAgICBzYi5wdXNoKCcjJyArIHZpc3VhbC5pZCk7XHJcbiAgICAgIHNiLnB1c2goYCAoJHt2aXN1YWwudHlwZX0pYCk7XHJcbiAgICAgIC8vIDogbGFiZWwgYW5kIGZlYXR1cmVzXHJcbiAgICAgIGlmICh2aXN1YWwuZGF0YT8ubGFiZWwpIHtcclxuICAgICAgICBzYi5wdXNoKCc6ICcpO1xyXG4gICAgICAgIHNiLnB1c2godmlzdWFsLmRhdGEubGFiZWwpO1xyXG4gICAgICB9XHJcbiAgICAgIGlmICh2aXN1YWwuZGF0YT8uZmVhdHVyZXM/Lmxlbmd0aCkge1xyXG4gICAgICAgIHNiLnB1c2goJyAnKTtcclxuICAgICAgICBzYi5wdXNoKFxyXG4gICAgICAgICAgdmlzdWFsLmRhdGEuZmVhdHVyZXNcclxuICAgICAgICAgICAgLm1hcCgoZjogRmVhdHVyZSkgPT4gYCR7Zi5uYW1lfT0ke2YudmFsdWV9YClcclxuICAgICAgICAgICAgLmpvaW4oJ1xcbicpXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgICAvLyAoQHgseSB3aWR0aMOXaGVpZ2h0KVxyXG4gICAgICBzYi5wdXNoKFxyXG4gICAgICAgIGAgKEAke3Zpc3VhbC54LnRvRml4ZWQoMSl9LCR7dmlzdWFsLnkudG9GaXhlZCgxKX0gYCArXHJcbiAgICAgICAgYOKXuyR7dmlzdWFsLndpZHRoLnRvRml4ZWQoMSl9w5cke3Zpc3VhbC5oZWlnaHQudG9GaXhlZCgxKX0pYFxyXG4gICAgICApO1xyXG4gICAgICB0aGlzLnZpc3VhbEluZm8gPSBzYi5qb2luKCcnKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZSB0aGUgY2hhbmdlIG9mIGxpbmUgaGVpZ2h0cyBieSB1cGRhdGluZyB0aGUgZm9ybSBjb250cm9sLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIGhlaWdodHMgVGhlIGxpbmUgaGVpZ2h0cy5cclxuICAgKi9cclxuICBwdWJsaWMgb25IZWlnaHRzQ2hhbmdlKGhlaWdodHM6IFJlY29yZDxudW1iZXIsIG51bWJlcj4gfCB1bmRlZmluZWQpOiB2b2lkIHtcclxuICAgIHRoaXMubG5IZWlnaHRzLnNldFZhbHVlKGhlaWdodHMgfHwgbnVsbCk7XHJcbiAgICB0aGlzLmxuSGVpZ2h0cy5tYXJrQXNEaXJ0eSgpO1xyXG4gICAgdGhpcy5sbkhlaWdodHMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlIHRoZSBjaGFuZ2Ugb2YgdGltZWxpbmVzIGJ5IHVwZGF0aW5nIHRoZSBmb3JtIGNvbnRyb2wuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gdGltZWxpbmVzIFRoZSB0aW1lbGluZXMuXHJcbiAgICovXHJcbiAgcHVibGljIG9uVGltZWxpbmVzQ2hhbmdlKHRpbWVsaW5lczogR3ZlQW5pbWF0aW9uVGltZWxpbmVbXSk6IHZvaWQge1xyXG4gICAgdGhpcy50aW1lbGluZXMuc2V0VmFsdWUodGltZWxpbmVzKTtcclxuICAgIHRoaXMudGltZWxpbmVzLm1hcmtBc0RpcnR5KCk7XHJcbiAgICB0aGlzLnRpbWVsaW5lcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBFbWl0IHRoZSBjYW5jZWwgZXZlbnQgZm9yIHRoaXMgc25hcHNob3QgZWRpdC5cclxuICAgKi9cclxuICBwdWJsaWMgY2xvc2UoKTogdm9pZCB7XHJcbiAgICB0aGlzLnNuYXBzaG90Q2FuY2VsLmVtaXQoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZSB0aGUgcmVuZGVyIGV2ZW50IGZyb20gdGhlIHNuYXBzaG90IHZpZXcgdG8gZ2V0IGEgcmVmZXJlbmNlXHJcbiAgICogdG8gdGhlIHJlbmRlcmVyLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIGV2ZW50IFRoZSByZW5kaXRpb24gZXZlbnQuXHJcbiAgICovXHJcbiAgcHVibGljIG9uU25hcHNob3RSZW5kZXIoZXZlbnQ6IEN1c3RvbUV2ZW50PFNuYXBzaG90Vmlld1JlbmRlckV2ZW50Pik6IHZvaWQge1xyXG4gICAgdGhpcy5fcmVuZGVyZXIgPSAoZXZlbnQuZGV0YWlsIGFzIFNuYXBzaG90Vmlld1JlbmRlckV2ZW50KS5yZW5kZXJlcjtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRvZ2dsZSBydWxlcnMgaW4gdGhlIHNuYXBzaG90IHZpZXcuXHJcbiAgICovXHJcbiAgcHVibGljIHRvZ2dsZVJ1bGVycygpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5fcmVuZGVyZXIpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdGhpcy5ydWxlcnMgPSB0aGlzLl9yZW5kZXJlci50b2dnbGVSdWxlcnMoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldCBhIHNuYXBzaG90IGZyb20gdGhlIGZvcm0gZGF0YS5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIE5ldyBzbmFwc2hvdCBvYmplY3QuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRTbmFwc2hvdCgpOiBTbmFwc2hvdCB7XHJcbiAgICBjb25zdCBzbmFwc2hvdDogU25hcHNob3QgPSB7XHJcbiAgICAgIHNpemU6IHtcclxuICAgICAgICB3aWR0aDogdGhpcy53aWR0aC52YWx1ZSxcclxuICAgICAgICBoZWlnaHQ6IHRoaXMuaGVpZ2h0LnZhbHVlLFxyXG4gICAgICB9LFxyXG4gICAgICBzdHlsZTogdGhpcy5zdHlsZS52YWx1ZSB8fCB1bmRlZmluZWQsXHJcbiAgICAgIGRlZnM6IHRoaXMuZGVmcy52YWx1ZSB8fCB1bmRlZmluZWQsXHJcbiAgICAgIHRleHQ6IHRoaXMuYmFzZVRleHQudmFsdWUhLFxyXG4gICAgICB0ZXh0U3R5bGU6IHRoaXMudGV4dFN0eWxlLnZhbHVlIHx8IHVuZGVmaW5lZCxcclxuICAgICAgdGV4dE9wdGlvbnM6IHtcclxuICAgICAgICBsaW5lSGVpZ2h0T2Zmc2V0OiB0aGlzLmxpbmVIZWlnaHRPZmZzZXQudmFsdWUsXHJcbiAgICAgICAgbWluTGluZUhlaWdodHM6IHRoaXMubG5IZWlnaHRzLnZhbHVlIHx8IHVuZGVmaW5lZCxcclxuICAgICAgICBjaGFyU3BhY2luZ09mZnNldDogdGhpcy5jaGFyU3BhY2luZ09mZnNldC52YWx1ZSxcclxuICAgICAgICBzcGNXaWR0aE9mZnNldDogdGhpcy5zcGNXaWR0aE9mZnNldC52YWx1ZSxcclxuICAgICAgICBvZmZzZXQ6IHtcclxuICAgICAgICAgIHg6IHRoaXMub2Zmc2V0WC52YWx1ZSxcclxuICAgICAgICAgIHk6IHRoaXMub2Zmc2V0WS52YWx1ZSxcclxuICAgICAgICB9LFxyXG4gICAgICB9LFxyXG4gICAgICBvcGVyYXRpb25zOiBbLi4udGhpcy5vcGVyYXRpb25zLnZhbHVlXSxcclxuICAgICAgb3BTdHlsZTogdGhpcy5vcFN0eWxlLnZhbHVlIHx8IHVuZGVmaW5lZCxcclxuICAgIH07XHJcblxyXG4gICAgLy8gaW1hZ2VcclxuICAgIGlmICh0aGlzLmltYWdlVXJsLnZhbHVlKSB7XHJcbiAgICAgIHNuYXBzaG90LmltYWdlID0ge1xyXG4gICAgICAgIHVybDogdGhpcy5pbWFnZVVybC52YWx1ZSxcclxuICAgICAgICBvcGFjaXR5OiB0aGlzLmltYWdlT3BhY2l0eS52YWx1ZSB8fCB1bmRlZmluZWQsXHJcbiAgICAgIH07XHJcbiAgICAgIGlmIChcclxuICAgICAgICB0aGlzLmltYWdlWC52YWx1ZSB8fFxyXG4gICAgICAgIHRoaXMuaW1hZ2VZLnZhbHVlIHx8XHJcbiAgICAgICAgdGhpcy5pbWFnZVdpZHRoLnZhbHVlIHx8XHJcbiAgICAgICAgdGhpcy5pbWFnZUhlaWdodC52YWx1ZVxyXG4gICAgICApIHtcclxuICAgICAgICBzbmFwc2hvdC5pbWFnZS5jYW52YXMgPSB7XHJcbiAgICAgICAgICB4OiB0aGlzLmltYWdlWC52YWx1ZSxcclxuICAgICAgICAgIHk6IHRoaXMuaW1hZ2VZLnZhbHVlLFxyXG4gICAgICAgICAgd2lkdGg6IHRoaXMuaW1hZ2VXaWR0aC52YWx1ZSxcclxuICAgICAgICAgIGhlaWdodDogdGhpcy5pbWFnZUhlaWdodC52YWx1ZSxcclxuICAgICAgICB9O1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gdGltZWxpbmVzXHJcbiAgICBpZiAodGhpcy50aW1lbGluZXMudmFsdWUubGVuZ3RoKSB7XHJcbiAgICAgIHNuYXBzaG90LnRpbWVsaW5lcyA9IHt9O1xyXG4gICAgICB0aGlzLnRpbWVsaW5lcy52YWx1ZS5mb3JFYWNoKCh0KSA9PiB7XHJcbiAgICAgICAgc25hcHNob3QudGltZWxpbmVzIVt0LnRhZ10gPSB0O1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHNuYXBzaG90LnRpbWVsaW5lcyA9IHVuZGVmaW5lZDtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gc25hcHNob3Q7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXQgYSBzbmFwc2hvdCBmcm9tIHRoZSBmb3JtIGRhdGEgYW5kIGVtaXQgaXRcclxuICAgKiBpbiB0aGUgc25hcHNob3QgY2hhbmdlIGV2ZW50LlxyXG4gICAqL1xyXG4gIHB1YmxpYyBzYXZlKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuZm9ybS5pbnZhbGlkIHx8IHRoaXMubm9TYXZlKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHRoaXMuX3NuYXBzaG90ID0gdGhpcy5nZXRTbmFwc2hvdCgpO1xyXG4gICAgdGhpcy5zbmFwc2hvdENoYW5nZS5lbWl0KHRoaXMuX3NuYXBzaG90KTtcclxuICB9XHJcbn1cclxuIiwiPGZvcm0gW2Zvcm1Hcm91cF09XCJmb3JtXCIgKHN1Ym1pdCk9XCJzYXZlKClcIj5cclxuICA8bWF0LXRhYi1ncm91cD5cclxuICAgIDwhLS0gdGV4dCAtLT5cclxuICAgIDxtYXQtdGFiPlxyXG4gICAgICA8bmctdGVtcGxhdGUgbWF0LXRhYi1sYWJlbD5cclxuICAgICAgICA8bWF0LWljb24+YXJ0aWNsZTwvbWF0LWljb24+IDxzcGFuIGNsYXNzPVwibGFiZWxcIj50ZXh0PC9zcGFuPlxyXG4gICAgICA8L25nLXRlbXBsYXRlPlxyXG4gICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbCBbZXhwYW5kZWRdPVwiIWJhc2VUZXh0LnZhbHVlXCI+XHJcbiAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxyXG4gICAgICAgICAgPG1hdC1wYW5lbC10aXRsZT4gYmFzZSB0ZXh0IDwvbWF0LXBhbmVsLXRpdGxlPlxyXG4gICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XHJcbiAgICAgICAgPGd2ZS1iYXNlLXRleHQtZWRpdG9yXHJcbiAgICAgICAgICBbdGV4dF09XCJiYXNlVGV4dC52YWx1ZVwiXHJcbiAgICAgICAgICAodGV4dENoYW5nZSk9XCJvblRleHRDaGFuZ2UoJGV2ZW50KVwiXHJcbiAgICAgICAgLz5cclxuICAgICAgICA8ZmllbGRzZXQ+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cclxuICAgICAgICAgICAgPCEtLSBvZmZzZXRYIC0tPlxyXG4gICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJpbnB1dC1uclwiPlxyXG4gICAgICAgICAgICAgIDxtYXQtbGFiZWw+WCBvZmZzZXQ8L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgICA8aW5wdXRcclxuICAgICAgICAgICAgICAgIG1hdElucHV0XHJcbiAgICAgICAgICAgICAgICB0eXBlPVwibnVtYmVyXCJcclxuICAgICAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJvZmZzZXRYXCJcclxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiWCBvZmZzZXRcIlxyXG4gICAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcblxyXG4gICAgICAgICAgICA8IS0tIG9mZnNldFkgLS0+XHJcbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LW5yXCI+XHJcbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD5ZIG9mZnNldDwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgICAgbWF0SW5wdXRcclxuICAgICAgICAgICAgICAgIHR5cGU9XCJudW1iZXJcIlxyXG4gICAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cIm9mZnNldFlcIlxyXG4gICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJZIG9mZnNldFwiXHJcbiAgICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuXHJcbiAgICAgICAgICAgIDwhLS0gbGluZUhlaWdodE9mZnNldCAtLT5cclxuICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiaW5wdXQtbnJcIj5cclxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPmxuIGgtb2Zmc2V0PC9tYXQtbGFiZWw+XHJcbiAgICAgICAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICAgICAgICBtYXRJbnB1dFxyXG4gICAgICAgICAgICAgICAgdHlwZT1cIm51bWJlclwiXHJcbiAgICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwibGluZUhlaWdodE9mZnNldFwiXHJcbiAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cImxuIGgtb2Zmc2V0XCJcclxuICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG5cclxuICAgICAgICAgICAgPCEtLSBjaGFyU3BhY2luZ09mZnNldCAtLT5cclxuICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiaW5wdXQtbnJcIj5cclxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPmNoYXIgc3BhY2luZzwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgICAgbWF0SW5wdXRcclxuICAgICAgICAgICAgICAgIHR5cGU9XCJudW1iZXJcIlxyXG4gICAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImNoYXJTcGFjaW5nT2Zmc2V0XCJcclxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiY2hhciBzcGFjaW5nXCJcclxuICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG5cclxuICAgICAgICAgICAgPCEtLSBzcGNXaWR0aE9mZnNldCAtLT5cclxuICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiaW5wdXQtbnJcIj5cclxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPnNwYyB3LW9mZnNldDwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgICAgbWF0SW5wdXRcclxuICAgICAgICAgICAgICAgIHR5cGU9XCJudW1iZXJcIlxyXG4gICAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cInNwY1dpZHRoT2Zmc2V0XCJcclxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwic3BjIHctb2Zmc2V0XCJcclxuICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgICA8IS0tIG1pbkxpbmVIZWlnaHRzIC0tPlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiYm94ZWRcIj5cclxuICAgICAgICAgICAgICA8Z3ZlLWxuLWhlaWdodHMtZWRpdG9yXHJcbiAgICAgICAgICAgICAgICBbbGluZUNvdW50XT1cImxpbmVDb3VudFwiXHJcbiAgICAgICAgICAgICAgICBbaGVpZ2h0c109XCJsbkhlaWdodHMudmFsdWVcIlxyXG4gICAgICAgICAgICAgICAgKGhlaWdodHNDaGFuZ2UpPVwib25IZWlnaHRzQ2hhbmdlKCRldmVudClcIlxyXG4gICAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICA8IS0tIHRleHRTdHlsZSAtLT5cclxuICAgICAgICAgIDxkaXY+XHJcbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImxvbmctdGV4dFwiIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCI+XHJcbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD50ZXh0IHN0eWxlPC9tYXQtbGFiZWw+XHJcbiAgICAgICAgICAgICAgPHRleHRhcmVhXHJcbiAgICAgICAgICAgICAgICBtYXRJbnB1dFxyXG4gICAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cInRleHRTdHlsZVwiXHJcbiAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cInRleHQgc3R5bGVcIlxyXG4gICAgICAgICAgICAgID48L3RleHRhcmVhPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9maWVsZHNldD5cclxuICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxyXG4gICAgPC9tYXQtdGFiPlxyXG5cclxuICAgIDwhLS0gb3BlcmF0aW9ucyAtLT5cclxuICAgIDxtYXQtdGFiPlxyXG4gICAgICA8bmctdGVtcGxhdGUgbWF0LXRhYi1sYWJlbD5cclxuICAgICAgICA8bWF0LWljb24+ZWRpdDwvbWF0LWljb24+IDxzcGFuIGNsYXNzPVwibGFiZWxcIj5vcGVyYXRpb25zPC9zcGFuPlxyXG4gICAgICA8L25nLXRlbXBsYXRlPlxyXG5cclxuICAgICAgPGRpdiBpZD1cInNuYXBzaG90LWNvbnRhaW5lclwiPlxyXG4gICAgICAgIDxkaXYgaWQ9XCJnZW5lcmFsXCI+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cclxuICAgICAgICAgICAgPCEtLSB3aWR0aCAtLT5cclxuICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiaW5wdXQtbnJcIj5cclxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPndpZHRoPC9tYXQtbGFiZWw+XHJcbiAgICAgICAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICAgICAgICBtYXRJbnB1dFxyXG4gICAgICAgICAgICAgICAgdHlwZT1cIm51bWJlclwiXHJcbiAgICAgICAgICAgICAgICBtaW49XCIwXCJcclxuICAgICAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJ3aWR0aFwiXHJcbiAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cIndpZHRoXCJcclxuICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG5cclxuICAgICAgICAgICAgPCEtLSBoZWlnaHQgLS0+XHJcbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LW5yXCI+XHJcbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD5oZWlnaHQ8L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgICA8aW5wdXRcclxuICAgICAgICAgICAgICAgIG1hdElucHV0XHJcbiAgICAgICAgICAgICAgICB0eXBlPVwibnVtYmVyXCJcclxuICAgICAgICAgICAgICAgIG1pbj1cIjBcIlxyXG4gICAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImhlaWdodFwiXHJcbiAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cImhlaWdodFwiXHJcbiAgICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuXHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLXJvdyByaWdodFwiPlxyXG4gICAgICAgICAgICAgIDwhLS0gcmVtb3ZlIG9wcyAtLT5cclxuICAgICAgICAgICAgICA8YnV0dG9uXHJcbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgICAgICAgICAgIGNsYXNzPVwibWF0LXdhcm5cIlxyXG4gICAgICAgICAgICAgICAgbWF0LWZsYXQtYnV0dG9uXHJcbiAgICAgICAgICAgICAgICBtYXRUb29sdGlwPVwiUmVtb3ZlIGFsbCB0aGUgb3BlcmF0aW9uc1wiXHJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIW9wZXJhdGlvbnMudmFsdWUubGVuZ3RoIHx8IGJ1c3lcIlxyXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImNsZWFyT3BlcmF0aW9ucygpXCJcclxuICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICA8bWF0LWljb24+ZGVsZXRlX2ZvcmV2ZXI8L21hdC1pY29uPiBjbGVhclxyXG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG5cclxuICAgICAgICAgICAgICA8IS0tIGJhdGNoIGFkZCBvcHMgLS0+XHJcbiAgICAgICAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXHJcbiAgICAgICAgICAgICAgICBtYXQtZmxhdC1idXR0b25cclxuICAgICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJBZGQgYSBiYXRjaCBvZiBvcGVyYXRpb25zXCJcclxuICAgICAgICAgICAgICAgIGNsYXNzPVwibWF0LXByaW1hcnlcIlxyXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImJ1c3lcIlxyXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cInBhcnNlT3BlcmF0aW9ucygpXCJcclxuICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICA8bWF0LWljb24+cG9zdF9hZGQ8L21hdC1pY29uPiBiYXRjaFxyXG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG5cclxuICAgICAgICAgICAgICA8IS0tIGFkZCBvcCAtLT5cclxuICAgICAgICAgICAgICA8YnV0dG9uXHJcbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgICAgICAgICAgIG1hdC1mbGF0LWJ1dHRvblxyXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJtYXQtcHJpbWFyeVwiXHJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWJhc2VUZXh0LnZhbHVlXCJcclxuICAgICAgICAgICAgICAgIChjbGljayk9XCJlZGl0TmV3T3BlcmF0aW9uKClcIlxyXG4gICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgIDxtYXQtaWNvbj5hZGRfY2lyY2xlPC9tYXQtaWNvbj4gb3BlcmF0aW9uXHJcbiAgICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgIDwhLS0gb3BzIC0tPlxyXG4gICAgICAgIDxkaXYgaWQ9XCJvcHNcIj5cclxuICAgICAgICAgIDwhLS0gb3BlcmF0aW9ucyBsaXN0IC0tPlxyXG4gICAgICAgICAgQGlmIChvcGVyYXRpb25zLnZhbHVlLmxlbmd0aCkge1xyXG4gICAgICAgICAgPHRhYmxlIGlkPVwibGlzdFwiPlxyXG4gICAgICAgICAgICA8dGhlYWQ+XHJcbiAgICAgICAgICAgICAgPHRyPlxyXG4gICAgICAgICAgICAgICAgPHRoPjwvdGg+XHJcbiAgICAgICAgICAgICAgICA8dGg+SUQ8L3RoPlxyXG4gICAgICAgICAgICAgICAgPHRoPnR5cGU8L3RoPlxyXG4gICAgICAgICAgICAgICAgPHRoPmF0PC90aD5cclxuICAgICAgICAgICAgICAgIDx0aD5ydW48L3RoPlxyXG4gICAgICAgICAgICAgICAgPHRoPnZhbHVlPC90aD5cclxuICAgICAgICAgICAgICAgIDx0aD5pdGFnPC90aD5cclxuICAgICAgICAgICAgICAgIDx0aD5vdGFnPC90aD5cclxuICAgICAgICAgICAgICAgIDx0aD5naWQ8L3RoPlxyXG4gICAgICAgICAgICAgICAgPHRoPmZlYXRzPC90aD5cclxuICAgICAgICAgICAgICA8L3RyPlxyXG4gICAgICAgICAgICA8L3RoZWFkPlxyXG4gICAgICAgICAgICA8dGJvZHk+XHJcbiAgICAgICAgICAgICAgQGZvciAob3BlcmF0aW9uIG9mIG9wZXJhdGlvbnMudmFsdWU7IHRyYWNrIG9wZXJhdGlvbi5pZDsgbGV0XHJcbiAgICAgICAgICAgICAgaW5kZXg9JGluZGV4KSB7XHJcbiAgICAgICAgICAgICAgPHRyXHJcbiAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7IHNlbGVjdGVkOiBvcGVyYXRpb24uaWQgPT09IHJlc3VsdE9wZXJhdGlvbklkIH1cIlxyXG4gICAgICAgICAgICAgICAgW25nQ2xhc3NdPVwieyBlZGl0ZWQ6IG9wZXJhdGlvbi5pZCA9PT0gZWRpdGVkT3A/LmlkIH1cIlxyXG4gICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZpdC13aWR0aFwiPlxyXG4gICAgICAgICAgICAgICAgICA8IS0tIGVkaXQgLS0+XHJcbiAgICAgICAgICAgICAgICAgIDxidXR0b25cclxuICAgICAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgICAgICAgICAgICAgICBtYXQtaWNvbi1idXR0b25cclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cIm1hdC1wcmltYXJ5XCJcclxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiZWRpdE9wZXJhdGlvbihpbmRleClcIlxyXG4gICAgICAgICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJFZGl0IG9wZXJhdGlvblwiXHJcbiAgICAgICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgICAgICA8bWF0LWljb24+ZWRpdDwvbWF0LWljb24+XHJcbiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgICA8IS0tIGRlbGV0ZSAtLT5cclxuICAgICAgICAgICAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgICAgICAgICAgICAgIG1hdC1pY29uLWJ1dHRvblxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwibWF0LXdhcm5cIlxyXG4gICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJkZWxldGVPcGVyYXRpb24oaW5kZXgpXCJcclxuICAgICAgICAgICAgICAgICAgICBtYXRUb29sdGlwPVwiRGVsZXRlIG9wZXJhdGlvblwiXHJcbiAgICAgICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJtYXQtd2FyblwiPmRlbGV0ZTwvbWF0LWljb24+XHJcbiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgICA8IS0tIHJ1biB0byAtLT5cclxuICAgICAgICAgICAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgICAgICAgICAgICAgIG1hdC1pY29uLWJ1dHRvblxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwibWF0LWFjY2VudFwiXHJcbiAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cInJ1blRvKGluZGV4KVwiXHJcbiAgICAgICAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cIlJ1biB0byB0aGlzIG9wZXJhdGlvblwiXHJcbiAgICAgICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJtYXQtYWNjZW50XCI+c3Vic2NyaXB0aW9uczwvbWF0LWljb24+XHJcbiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgPC90ZD5cclxuICAgICAgICAgICAgICAgIDx0ZD57eyBvcGVyYXRpb24uaWQgfX08L3RkPlxyXG4gICAgICAgICAgICAgICAgPHRkPnt7IG9wZXJhdGlvbi50eXBlIHwgZmxhdExvb2t1cCA6IG9wVHlwZU1hcCB9fTwvdGQ+XHJcbiAgICAgICAgICAgICAgICA8dGQ+e3sgb3BlcmF0aW9uLmF0IH19PC90ZD5cclxuICAgICAgICAgICAgICAgIDx0ZD57eyBvcGVyYXRpb24ucnVuIH19PC90ZD5cclxuICAgICAgICAgICAgICAgIDx0ZD57eyBvcGVyYXRpb24udmFsdWUgfX08L3RkPlxyXG4gICAgICAgICAgICAgICAgPHRkPnt7IG9wZXJhdGlvbi5pbnB1dFRhZyB9fTwvdGQ+XHJcbiAgICAgICAgICAgICAgICA8dGQ+e3sgb3BlcmF0aW9uLm91dHB1dFRhZyB9fTwvdGQ+XHJcbiAgICAgICAgICAgICAgICA8dGQ+e3sgb3BlcmF0aW9uLmdyb3VwSWQgfX08L3RkPlxyXG4gICAgICAgICAgICAgICAgPHRkPnt7IG9wZXJhdGlvbi5mZWF0dXJlcz8ubGVuZ3RoIH19PC90ZD5cclxuICAgICAgICAgICAgICA8L3RyPlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgPC90Ym9keT5cclxuICAgICAgICAgIDwvdGFibGU+XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgPCEtLSBvcGVyYXRpb24gZWRpdG9yIC0tPlxyXG4gICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWwgW2V4cGFuZGVkXT1cImVkaXRlZE9wXCIgW2Rpc2FibGVkXT1cIiFlZGl0ZWRPcFwiPlxyXG4gICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XHJcbiAgICAgICAgICAgICAgPG1hdC1wYW5lbC10aXRsZT5vcGVyYXRpb24ge3sgZWRpdGVkT3A/LmlkIH19PC9tYXQtcGFuZWwtdGl0bGU+XHJcbiAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XHJcbiAgICAgICAgICAgIDxmaWVsZHNldD5cclxuICAgICAgICAgICAgICA8Z3ZlLWNoYWluLW9wZXJhdGlvbi1lZGl0b3JcclxuICAgICAgICAgICAgICAgIFtoaWRlUHJldmlld109XCJlZGl0ZWRPcEluZGV4ID09PSAtMVwiXHJcbiAgICAgICAgICAgICAgICBbb3BlcmF0aW9uXT1cImVkaXRlZE9wXCJcclxuICAgICAgICAgICAgICAgIChvcGVyYXRpb25DYW5jZWwpPVwib25PcGVyYXRpb25DYW5jZWwoKVwiXHJcbiAgICAgICAgICAgICAgICAob3BlcmF0aW9uQ2hhbmdlKT1cIm9uT3BlcmF0aW9uQ2hhbmdlKCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgKG9wZXJhdGlvblByZXZpZXcpPVwib25PcGVyYXRpb25QcmV2aWV3KCRldmVudClcIlxyXG4gICAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICAgIDwvZmllbGRzZXQ+XHJcbiAgICAgICAgICA8L21hdC1leHBhbnNpb24tcGFuZWw+XHJcblxyXG4gICAgICAgICAgPCEtLSBvcFN0eWxlIC0tPlxyXG4gICAgICAgICAgPGRpdiBpZD1cIm9wU3R5bGVcIj5cclxuICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwibG9uZy10ZXh0XCIgYXBwZWFyYW5jZT1cIm91dGxpbmVcIj5cclxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPm9wZXJhdGlvbnMgc3R5bGU8L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgICA8dGV4dGFyZWFcclxuICAgICAgICAgICAgICAgIG1hdElucHV0XHJcbiAgICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwib3BTdHlsZVwiXHJcbiAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cIm9wZXJhdGlvbnMgc3R5bGVcIlxyXG4gICAgICAgICAgICAgID48L3RleHRhcmVhPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgPC9tYXQtdGFiPlxyXG5cclxuICAgIDwhLS0gaW1hZ2UgLS0+XHJcbiAgICA8bWF0LXRhYj5cclxuICAgICAgPG5nLXRlbXBsYXRlIG1hdC10YWItbGFiZWw+XHJcbiAgICAgICAgPG1hdC1pY29uPmltYWdlPC9tYXQtaWNvbj4gPHNwYW4gY2xhc3M9XCJsYWJlbFwiPmltYWdlPC9zcGFuPlxyXG4gICAgICA8L25nLXRlbXBsYXRlPlxyXG5cclxuICAgICAgPGRpdiBpZD1cImltYWdlXCI+XHJcbiAgICAgICAgPGRpdiBpZD1cImltYWdlLWN0bFwiPlxyXG4gICAgICAgICAgPCEtLSB1cmwgLS0+XHJcbiAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJsb25nLXRleHRcIj5cclxuICAgICAgICAgICAgPG1hdC1sYWJlbD5VUkw8L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgPGlucHV0IG1hdElucHV0IFtmb3JtQ29udHJvbF09XCJpbWFnZVVybFwiIC8+XHJcbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XHJcbiAgICAgICAgICAgIDwhLS0geCAtLT5cclxuICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiaW5wdXQtbnJcIj5cclxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPlg8L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgICA8aW5wdXRcclxuICAgICAgICAgICAgICAgIG1hdElucHV0XHJcbiAgICAgICAgICAgICAgICB0eXBlPVwibnVtYmVyXCJcclxuICAgICAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJpbWFnZVhcIlxyXG4gICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJYXCJcclxuICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgICA8IS0tIHkgLS0+XHJcbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LW5yXCI+XHJcbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD5ZPC9tYXQtbGFiZWw+XHJcbiAgICAgICAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICAgICAgICBtYXRJbnB1dFxyXG4gICAgICAgICAgICAgICAgdHlwZT1cIm51bWJlclwiXHJcbiAgICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwiaW1hZ2VZXCJcclxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiWVwiXHJcbiAgICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XHJcbiAgICAgICAgICAgIDwhLS0gd2lkdGggLS0+XHJcbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LW5yXCI+XHJcbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD53aWR0aDwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgICAgbWF0SW5wdXRcclxuICAgICAgICAgICAgICAgIHR5cGU9XCJudW1iZXJcIlxyXG4gICAgICAgICAgICAgICAgbWluPVwiMFwiXHJcbiAgICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwiaW1hZ2VXaWR0aFwiXHJcbiAgICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuICAgICAgICAgICAgPCEtLSBoZWlnaHQgLS0+XHJcbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LW5yXCI+XHJcbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD5oZWlnaHQ8L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgICA8aW5wdXRcclxuICAgICAgICAgICAgICAgIG1hdElucHV0XHJcbiAgICAgICAgICAgICAgICB0eXBlPVwibnVtYmVyXCJcclxuICAgICAgICAgICAgICAgIG1pbj1cIjBcIlxyXG4gICAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImltYWdlSGVpZ2h0XCJcclxuICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICA8IS0tIGRlZnMgLS0+XHJcbiAgICAgICAgICA8ZGl2PlxyXG4gICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJsb25nLXRleHRcIj5cclxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPmRlZnM8L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgICA8dGV4dGFyZWEgbWF0SW5wdXQgW2Zvcm1Db250cm9sXT1cImRlZnNcIiByb3dzPVwiM1wiPjwvdGV4dGFyZWE+XHJcbiAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8ZGl2IGlkPVwiaW1hZ2Utdmlld1wiPlxyXG4gICAgICAgICAgQGlmIChpbWFnZVVybC52YWx1ZSkge1xyXG4gICAgICAgICAgPGltZyBhbHQ9XCJiYWNrZ3JvdW5kXCIgW3NyY109XCJpbWFnZVVybC52YWx1ZVwiIHdpZHRoPVwiNjAwXCIgLz5cclxuICAgICAgICAgIH1cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9kaXY+XHJcbiAgICA8L21hdC10YWI+XHJcblxyXG4gICAgPCEtLSB0aW1lbGluZXMgLS0+XHJcbiAgICA8bWF0LXRhYj5cclxuICAgICAgPG5nLXRlbXBsYXRlIG1hdC10YWItbGFiZWw+XHJcbiAgICAgICAgPG1hdC1pY29uPmFuaW1hdGlvbjwvbWF0LWljb24+IDxzcGFuIGNsYXNzPVwibGFiZWxcIj5hbmltYXRpb248L3NwYW4+XHJcbiAgICAgIDwvbmctdGVtcGxhdGU+XHJcblxyXG4gICAgICA8Z3ZlLWFuaW1hdGlvbi10aW1lbGluZS1zZXRcclxuICAgICAgICBbdGFnc109XCJvcFRhZ3NcIlxyXG4gICAgICAgIFtlbGVtZW50SWRzXT1cIm9wRWxlbWVudElkc1wiXHJcbiAgICAgICAgW3RpbWVsaW5lc109XCJ0aW1lbGluZXMudmFsdWVcIlxyXG4gICAgICAgICh0aW1lbGluZXNDaGFuZ2UpPVwib25UaW1lbGluZXNDaGFuZ2UoJGV2ZW50KVwiXHJcbiAgICAgIC8+XHJcbiAgICA8L21hdC10YWI+XHJcbiAgPC9tYXQtdGFiLWdyb3VwPlxyXG5cclxuICA8IS0tIHByb2dyZXNzIC0tPlxyXG4gIDxkaXY+XHJcbiAgICA8bWF0LXByb2dyZXNzLWJhciBtb2RlPVwiaW5kZXRlcm1pbmF0ZVwiICpuZ0lmPVwiYnVzeVwiIC8+XHJcbiAgPC9kaXY+XHJcblxyXG4gIDwhLS0gcmVzdWx0IC0tPlxyXG4gIEBpZiAocmVzdWx0KSB7XHJcbiAgPGZpZWxkc2V0IGlkPVwicmVzdWx0XCI+XHJcbiAgICA8bGVnZW5kPnJlc3VsdDwvbGVnZW5kPlxyXG4gICAgPGd2ZS1jaGFpbi1yZXN1bHQtdmlld1xyXG4gICAgICBbcmVzdWx0XT1cInJlc3VsdFwiXHJcbiAgICAgIFtpbml0aWFsU3RlcEluZGV4XT1cImluaXRpYWxTdGVwSW5kZXhcIlxyXG4gICAgICAoc3RlcFBpY2spPVwib25TdGVwUGljaygkZXZlbnQpXCJcclxuICAgIC8+XHJcbiAgPC9maWVsZHNldD5cclxuICB9XHJcblxyXG4gIDwhLS0gc25hcHNob3QgdmlldyAtLT5cclxuICA8ZmllbGRzZXQgaWQ9XCJwcmV2aWV3XCI+XHJcbiAgICA8bGVnZW5kIGNsYXNzPVwiYnV0dG9uLXJvd1wiPlxyXG4gICAgICA8c3Bhbj57eyB2aWV3VGl0bGUgfX08L3NwYW4+XHJcbiAgICA8L2xlZ2VuZD5cclxuICAgIDwhLS0gc25hcHNob3QgdmlldyAtLT5cclxuICAgIDxndmUtc25hcHNob3Qtdmlld1xyXG4gICAgICAjc25hcHNob3RWaWV3XHJcbiAgICAgIFtkZWJ1Z109XCJkZWJ1Z1wiXHJcbiAgICAgIFtkYXRhXT1cInZpZXdEYXRhXCJcclxuICAgICAgKHNuYXBzaG90UmVuZGVyKT1cIm9uU25hcHNob3RSZW5kZXIoJGFueSgkZXZlbnQpKVwiXHJcbiAgICAgICh2aXN1YWxFdmVudCk9XCJvblZpc3VhbEV2ZW50KCRhbnkoJGV2ZW50KSlcIlxyXG4gICAgLz5cclxuICAgIDxkaXYgY2xhc3M9XCJidXR0b24tcm93XCI+XHJcbiAgICAgIDwhLS0gdG9nZ2xlIHJ1bGVyIC0tPlxyXG4gICAgICA8bWF0LWJ1dHRvbi10b2dnbGVcclxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgICBtYXQtaWNvbi1idXR0b25cclxuICAgICAgICBjb2xvcj1cInByaW1hcnlcIlxyXG4gICAgICAgIG1hdFRvb2x0aXA9XCJUb2dnbGUgcnVsZXJzXCJcclxuICAgICAgICBbY2hlY2tlZF09XCJydWxlcnNcIlxyXG4gICAgICAgIChjaGFuZ2UpPVwidG9nZ2xlUnVsZXJzKClcIlxyXG4gICAgICA+XHJcbiAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwibWF0LXByaW1hcnlcIj5zdHJhaWdodGVuPC9tYXQtaWNvbj5cclxuICAgICAgPC9tYXQtYnV0dG9uLXRvZ2dsZT5cclxuICAgICAgPCEtLSBydW4gdG8gbGFzdCAtLT5cclxuICAgICAgPGJ1dHRvblxyXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgIG1hdC1pY29uLWJ1dHRvblxyXG4gICAgICAgIGNsYXNzPVwicHJpbWFyeVwiXHJcbiAgICAgICAgbWF0VG9vbHRpcD1cIlJ1biBhbGwgb3BlcmF0aW9uc1wiXHJcbiAgICAgICAgW2Rpc2FibGVkXT1cIiFvcGVyYXRpb25zLnZhbHVlLmxlbmd0aFwiXHJcbiAgICAgICAgKGNsaWNrKT1cInJ1blRvTGFzdCgpXCJcclxuICAgICAgPlxyXG4gICAgICAgIDxtYXQtaWNvbj5wbGF5X2NpcmNsZTwvbWF0LWljb24+XHJcbiAgICAgIDwvYnV0dG9uPlxyXG4gICAgPC9kaXY+XHJcbiAgICBAaWYgKHZpc3VhbEluZm8pIHtcclxuICAgIDxkaXYgaWQ9XCJ2aXN1YWwtaW5mb1wiPnt7IHZpc3VhbEluZm8gfX08L2Rpdj5cclxuICAgIH1cclxuICA8L2ZpZWxkc2V0PlxyXG5cclxuICA8IS0tYnV0dG9ucyAtLT5cclxuICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3ctY2VudGVyXCI+XHJcbiAgICA8YnV0dG9uXHJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICBjbGFzcz1cIm1hdC13YXJuXCJcclxuICAgICAgbWF0LWZsYXQtYnV0dG9uXHJcbiAgICAgIG1hdFRvb2x0aXA9XCJEaXNjYXJkIGNoYW5nZXNcIlxyXG4gICAgICAoY2xpY2spPVwiY2xvc2UoKVwiXHJcbiAgICA+XHJcbiAgICAgIDxtYXQtaWNvbj5jbGVhcjwvbWF0LWljb24+XHJcbiAgICAgIGNsb3NlXHJcbiAgICA8L2J1dHRvbj5cclxuICAgIEBpZiAoIW5vU2F2ZSkge1xyXG4gICAgPGJ1dHRvblxyXG4gICAgICB0eXBlPVwic3VibWl0XCJcclxuICAgICAgY2xhc3M9XCJtYXQtcHJpbWFyeVwiXHJcbiAgICAgIG1hdC1mbGF0LWJ1dHRvblxyXG4gICAgICBtYXRUb29sdGlwPVwiU2F2ZSBjaGFuZ2VzXCJcclxuICAgICAgW2Rpc2FibGVkXT1cImZvcm0uaW52YWxpZFwiXHJcbiAgICA+XHJcbiAgICAgIDxtYXQtaWNvbj5jaGVja19jaXJjbGU8L21hdC1pY29uPlxyXG4gICAgICBzYXZlXHJcbiAgICA8L2J1dHRvbj5cclxuICAgIH1cclxuICA8L2Rpdj5cclxuPC9mb3JtPlxyXG4iXX0=
|