@smarterplan/ngx-smarterplan-locations 0.3.4 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/esm2022/lib/components/carousel/carousel.component.mjs +30 -0
  2. package/esm2022/lib/components/chevron/chevron.component.mjs +18 -0
  3. package/esm2022/lib/components/detail-location/detail-location.component.mjs +183 -0
  4. package/{esm2020 → esm2022}/lib/components/form-location/form-location.component.mjs +254 -237
  5. package/esm2022/lib/components/images/images.component.mjs +120 -0
  6. package/esm2022/lib/components/locations/locations.component.mjs +157 -0
  7. package/esm2022/lib/components/locations/map/map-popup/map-popup.component.mjs +72 -0
  8. package/esm2022/lib/components/locations/map/map.component.mjs +92 -0
  9. package/esm2022/lib/components/plan-legend/plan-legend.component.mjs +49 -0
  10. package/esm2022/lib/components/plans/calibration/calibration.component.mjs +494 -0
  11. package/esm2022/lib/components/plans/edit-plan/edit-plan.component.mjs +350 -0
  12. package/{esm2020 → esm2022}/lib/components/plans/plans.component.mjs +243 -225
  13. package/esm2022/lib/components/tab-navigation/tab-navigation.component.mjs +43 -0
  14. package/esm2022/lib/components/visits/visits.component.mjs +294 -0
  15. package/esm2022/lib/components/zones/add-audio-zone/add-audio-zone.component.mjs +250 -0
  16. package/esm2022/lib/components/zones/add-zone/add-zone.component.mjs +333 -0
  17. package/esm2022/lib/components/zones/add-zone/selection/selection.component.mjs +81 -0
  18. package/esm2022/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.mjs +518 -0
  19. package/esm2022/lib/components/zones/zones.component.mjs +291 -0
  20. package/{esm2020 → esm2022}/lib/helper.service.mjs +133 -133
  21. package/esm2022/lib/ngx-smarterplan-location-routing.module.mjs +50 -0
  22. package/esm2022/lib/ngx-smarterplan-locations.module.mjs +124 -0
  23. package/esm2022/lib/ngx-smarterplan-locations.service.mjs +15 -0
  24. package/esm2022/lib/pipes/count-audio-sweeps.pipe.mjs +29 -0
  25. package/esm2022/lib/radio-button/radio-button.component.mjs +28 -0
  26. package/{esm2020 → esm2022}/public-api.mjs +8 -8
  27. package/{esm2020 → esm2022}/smarterplan-ngx-smarterplan-locations.mjs +4 -4
  28. package/{fesm2020 → fesm2022}/smarterplan-ngx-smarterplan-locations.mjs +3959 -3738
  29. package/fesm2022/smarterplan-ngx-smarterplan-locations.mjs.map +1 -0
  30. package/index.d.ts +5 -5
  31. package/lib/components/carousel/carousel.component.d.ts +12 -12
  32. package/lib/components/chevron/chevron.component.d.ts +9 -9
  33. package/lib/components/detail-location/detail-location.component.d.ts +55 -55
  34. package/lib/components/form-location/form-location.component.d.ts +45 -45
  35. package/lib/components/images/images.component.d.ts +33 -33
  36. package/lib/components/locations/locations.component.d.ts +51 -51
  37. package/lib/components/locations/map/map-popup/map-popup.component.d.ts +22 -22
  38. package/lib/components/locations/map/map.component.d.ts +21 -22
  39. package/lib/components/plan-legend/plan-legend.component.d.ts +14 -14
  40. package/lib/components/plans/calibration/calibration.component.d.ts +140 -140
  41. package/lib/components/plans/edit-plan/edit-plan.component.d.ts +55 -55
  42. package/lib/components/plans/plans.component.d.ts +63 -63
  43. package/lib/components/tab-navigation/tab-navigation.component.d.ts +13 -13
  44. package/lib/components/visits/visits.component.d.ts +63 -63
  45. package/lib/components/zones/add-audio-zone/add-audio-zone.component.d.ts +63 -63
  46. package/lib/components/zones/add-zone/add-zone.component.d.ts +69 -69
  47. package/lib/components/zones/add-zone/selection/selection.component.d.ts +44 -44
  48. package/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.d.ts +107 -107
  49. package/lib/components/zones/zones.component.d.ts +73 -73
  50. package/lib/helper.service.d.ts +53 -53
  51. package/lib/ngx-smarterplan-location-routing.module.d.ts +7 -7
  52. package/lib/ngx-smarterplan-locations.module.d.ts +36 -36
  53. package/lib/ngx-smarterplan-locations.service.d.ts +6 -6
  54. package/lib/pipes/count-audio-sweeps.pipe.d.ts +10 -10
  55. package/lib/radio-button/radio-button.component.d.ts +12 -12
  56. package/package.json +13 -19
  57. package/public-api.d.ts +4 -4
  58. package/esm2020/lib/components/carousel/carousel.component.mjs +0 -28
  59. package/esm2020/lib/components/chevron/chevron.component.mjs +0 -18
  60. package/esm2020/lib/components/detail-location/detail-location.component.mjs +0 -168
  61. package/esm2020/lib/components/images/images.component.mjs +0 -107
  62. package/esm2020/lib/components/locations/locations.component.mjs +0 -145
  63. package/esm2020/lib/components/locations/map/map-popup/map-popup.component.mjs +0 -66
  64. package/esm2020/lib/components/locations/map/map.component.mjs +0 -91
  65. package/esm2020/lib/components/plan-legend/plan-legend.component.mjs +0 -47
  66. package/esm2020/lib/components/plans/calibration/calibration.component.mjs +0 -468
  67. package/esm2020/lib/components/plans/edit-plan/edit-plan.component.mjs +0 -324
  68. package/esm2020/lib/components/tab-navigation/tab-navigation.component.mjs +0 -41
  69. package/esm2020/lib/components/visits/visits.component.mjs +0 -275
  70. package/esm2020/lib/components/zones/add-audio-zone/add-audio-zone.component.mjs +0 -230
  71. package/esm2020/lib/components/zones/add-zone/add-zone.component.mjs +0 -315
  72. package/esm2020/lib/components/zones/add-zone/selection/selection.component.mjs +0 -77
  73. package/esm2020/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.mjs +0 -502
  74. package/esm2020/lib/components/zones/zones.component.mjs +0 -268
  75. package/esm2020/lib/ngx-smarterplan-location-routing.module.mjs +0 -49
  76. package/esm2020/lib/ngx-smarterplan-locations.module.mjs +0 -123
  77. package/esm2020/lib/ngx-smarterplan-locations.service.mjs +0 -14
  78. package/esm2020/lib/pipes/count-audio-sweeps.pipe.mjs +0 -27
  79. package/esm2020/lib/radio-button/radio-button.component.mjs +0 -26
  80. package/fesm2015/smarterplan-ngx-smarterplan-locations.mjs +0 -3983
  81. package/fesm2015/smarterplan-ngx-smarterplan-locations.mjs.map +0 -1
  82. package/fesm2020/smarterplan-ngx-smarterplan-locations.mjs.map +0 -1
@@ -0,0 +1,494 @@
1
+ import { Component, ViewChild } from '@angular/core';
2
+ import { getDocument } from 'pdfjs-dist';
3
+ // import { PDFDocumentProxy } from 'ng2-pdf-viewer';
4
+ import { getMetaForImage, } from '@smarterplan/ngx-smarterplan-core';
5
+ import panzoom from 'panzoom';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@smarterplan/ngx-smarterplan-core";
8
+ import * as i2 from "@angular/router";
9
+ import * as i3 from "@ngx-translate/core";
10
+ import * as i4 from "@ng-bootstrap/ng-bootstrap";
11
+ import * as i5 from "@angular/common";
12
+ import * as i6 from "@angular/forms";
13
+ import * as i7 from "../../tab-navigation/tab-navigation.component";
14
+ class CalibrationComponent {
15
+ matterportImportService;
16
+ planService;
17
+ route;
18
+ router;
19
+ zoneService;
20
+ spaceService;
21
+ navigationService;
22
+ translate;
23
+ /** Item to display for the navbar */
24
+ menuItems = [];
25
+ /** Canvas (Plan) */
26
+ canvas;
27
+ /** CanvasDiv (Div that contain the canvas + matterport iframe) */
28
+ canvasDiv;
29
+ /** Size of the canvas & matterport iframe */
30
+ canvasSize;
31
+ /** Zoom ratio of the canvas/plan */
32
+ canvasZoom = 0;
33
+ /** Opacity for matterport iframe */
34
+ opacity = 50;
35
+ /** Current rotation for matterport, [0-360], matterport rotation is bind to input range */
36
+ rotation = 180;
37
+ /** Previous rotation, use to calculate the deltaRotation to rotate, when user change rotation value using range input */
38
+ prevRotation = 180;
39
+ /** Current Camera Pose */
40
+ cameraPose;
41
+ /** True when the user is currently rotating with the input range, the matterport rotation events will be ignored */
42
+ isRotatingRange = false;
43
+ /** Rotating queue event to send to matterport */
44
+ rotatingQueueEvent = [];
45
+ /** True when Vertical symmetry is enabled */
46
+ reflectV = false;
47
+ /** True when Horizontal symmetry is enabled */
48
+ reflectH = false;
49
+ chosenPlan;
50
+ spaceID;
51
+ currentSpace;
52
+ currentZone;
53
+ chosenPlanIsPdf = false;
54
+ /** First Point in visit, used to determine the calibration */
55
+ firstMarkVisit = { x: 0, y: 0 };
56
+ /** Second Point in visit, used to determine the calibration */
57
+ secondMarkVisit = { x: 0.5, y: 0.5 };
58
+ /** Equivalent of 'firstMarkVisit' in canvas */
59
+ firstMarkPlan = { x: 0, y: 0 };
60
+ /** Equivalent of 'secondMarkVisit' in canvas */
61
+ secondMarkPlan = { x: 0, y: 0 };
62
+ /** Calibration result, (offsetX, offsetY, x, y) */
63
+ calibrage = {};
64
+ /** Is in preview mode (see scan result) */
65
+ preview = false;
66
+ /** Matterport is loading */
67
+ loading = true;
68
+ /* for pan and zoom of canvas */
69
+ panzoom;
70
+ currentNavigations;
71
+ positions = [];
72
+ floors = [];
73
+ currentFloor;
74
+ zoomCanBeChanged = false;
75
+ constructor(matterportImportService, planService, route, router, zoneService, spaceService, navigationService, translate) {
76
+ this.matterportImportService = matterportImportService;
77
+ this.planService = planService;
78
+ this.route = route;
79
+ this.router = router;
80
+ this.zoneService = zoneService;
81
+ this.spaceService = spaceService;
82
+ this.navigationService = navigationService;
83
+ this.translate = translate;
84
+ }
85
+ ngOnDestroy() {
86
+ if (!this.loading) {
87
+ this.matterportImportService.removeFrame();
88
+ }
89
+ }
90
+ async ngOnInit() {
91
+ this.spaceID = this.route.snapshot.queryParams.spaceID;
92
+ this.currentSpace = await this.spaceService.getSpace(this.spaceID);
93
+ /** Menu nav bar */
94
+ this.setupMenuItems();
95
+ this.chosenPlan = this.planService.getChosenPlan();
96
+ if (this.chosenPlan) {
97
+ this.chosenPlanIsPdf = this.chosenPlan.annexe.includes('pdf');
98
+ this.launchViewer();
99
+ setTimeout(() => {
100
+ this.configureCanvas().then(() => {
101
+ this.panzoom = panzoom(this.canvas, {
102
+ bounds: true,
103
+ boundsPadding: 0,
104
+ maxZoom: 2.5,
105
+ minZoom: 0.1,
106
+ initialZoom: 1,
107
+ zoomSpeed: 0.02,
108
+ });
109
+ });
110
+ }, 500);
111
+ }
112
+ else {
113
+ this.router.navigate(['/dashboard/localisation', this.spaceID, 'plans']);
114
+ }
115
+ }
116
+ /** **********************************************************************************************
117
+ * MENU NAV BAR
118
+ *********************************************************************************************** */
119
+ setupMenuItems() {
120
+ this.menuItems = [
121
+ { label: 'Locations', url: '/localisation' },
122
+ {
123
+ label: this.currentSpace.name,
124
+ url: `/localisation/${this.spaceID}`,
125
+ },
126
+ {
127
+ label: 'Plans',
128
+ url: `/localisation/${this.currentSpace.id}/plans`,
129
+ },
130
+ {
131
+ label: 'Calibration',
132
+ url: `/localisation/${this.currentSpace.id}/plan-calibration?spaceID=${this.currentSpace.id}`,
133
+ },
134
+ ];
135
+ }
136
+ /** **********************************************************************************************
137
+ * CANVAS
138
+ *********************************************************************************************** */
139
+ /** Display the plan */
140
+ async configureCanvas() {
141
+ /** Get canvas */
142
+ if (!this.canvas) {
143
+ const canvas = document.querySelector('#canvas');
144
+ this.canvas = canvas;
145
+ }
146
+ if (!this.chosenPlanIsPdf) {
147
+ const image = await getMetaForImage(this.chosenPlan.filepath);
148
+ /** Compute the new size for the canvas/matterport, base on the dimension of the plan, keeping the ratio */
149
+ const size = this.getSizeForCanvas(image.width, image.height);
150
+ /** Compute the plan zoom ratio (use for the calibration later) */
151
+ this.canvasZoom = size.w / image.width;
152
+ this.resizeView(size);
153
+ /** Draw Plan on the canvas */
154
+ this.drawImage(this.chosenPlan.filepath);
155
+ }
156
+ else {
157
+ // TODO
158
+ this.pdfToCanvas();
159
+ }
160
+ }
161
+ /** Update size of the canvas/matterport */
162
+ resizeView(size) {
163
+ this.canvasDiv.nativeElement.style.width = `${size.w}px`;
164
+ this.canvasDiv.nativeElement.style.height = `${size.h}px`;
165
+ this.canvas.style.width = `${size.w}px`;
166
+ this.canvas.style.height = `${size.h}px`;
167
+ this.canvas.width = size.w;
168
+ this.canvas.height = size.h;
169
+ this.canvasSize = size;
170
+ }
171
+ /** Draw something on the canvas */
172
+ drawImage(url, x = 0, y = 0, icone = false) {
173
+ const image = new Image();
174
+ const size = this.canvasSize;
175
+ const context = this.canvas.getContext('2d');
176
+ /** Flip the context, for symmetry */
177
+ // if (this.reflectV) {
178
+ // context.translate(size.w, 0);
179
+ // context.scale(-1, 1);
180
+ // }
181
+ // if (this.reflectH) {
182
+ // context.translate(0, size.h);
183
+ // context.scale(1, -1);
184
+ // }
185
+ let imageWidth = size.w;
186
+ let imageHeight = size.h;
187
+ image.addEventListener('load', () => {
188
+ if (icone) {
189
+ imageWidth = image.width;
190
+ imageHeight = image.height;
191
+ }
192
+ context.drawImage(image, 0, 0, image.width, image.height, x, y, imageWidth, imageHeight);
193
+ });
194
+ image.src = url;
195
+ }
196
+ /** Get the size for the canvas, based on the plan size, keeping the ratio */
197
+ getSizeForCanvas(w, h) {
198
+ let canvasW = this.canvasDiv.nativeElement.offsetWidth;
199
+ let canvasH = this.canvasDiv.nativeElement.offsetHeight;
200
+ const imageRatio = w / h;
201
+ const canvasRatio = canvasW / canvasH;
202
+ if (imageRatio > canvasRatio) {
203
+ canvasH = canvasW / imageRatio;
204
+ }
205
+ else {
206
+ canvasW = canvasH * imageRatio;
207
+ }
208
+ return { w: canvasW, h: canvasH };
209
+ }
210
+ /** [TODO] Convert a PDF to a Canvas */
211
+ async pdfToCanvas() {
212
+ const pdfjs = await import('pdfjs-dist/build/pdf');
213
+ const pdfjsWorker = await import('pdfjs-dist/build/pdf.worker.entry');
214
+ pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
215
+ const pdf = await getDocument(this.chosenPlan.filepath)
216
+ .promise;
217
+ const page = await pdf.getPage(1);
218
+ const viewPortParameters = { scale: 1 };
219
+ const viewport = page.getViewport(viewPortParameters);
220
+ this.canvas.height = viewport.height;
221
+ this.canvas.width = viewport.width;
222
+ const size = this.getSizeForCanvas(viewport.width, viewport.height);
223
+ console.log(size);
224
+ this.canvasSize = size;
225
+ this.canvasZoom = size.w / viewport.width;
226
+ const context = this.canvas.getContext('2d');
227
+ const renderContext = {
228
+ canvasContext: context,
229
+ viewport,
230
+ };
231
+ const renderTask = page.render(renderContext).promise;
232
+ renderTask.then(() => console.log('Page rendered'));
233
+ // const res = canvas.toDataURL();
234
+ // if (pdf != null) pdf.destroy();
235
+ // return res;
236
+ }
237
+ /** User click to user Symmetry Vertical */
238
+ onReflectV() {
239
+ this.reflectV = !this.reflectV;
240
+ this.configureCanvas();
241
+ }
242
+ /** User click to user Symmetry Horizontal */
243
+ onReflectH() {
244
+ this.reflectH = !this.reflectH;
245
+ this.configureCanvas();
246
+ }
247
+ /** **********************************************************************************************
248
+ * MATTERPORT
249
+ *********************************************************************************************** */
250
+ /** Launch matterport */
251
+ async launchViewer() {
252
+ await this.matterportImportService.initSdkForModel(this.chosenPlan.model3d);
253
+ const { sdk } = this.matterportImportService;
254
+ this.floors = Object.values(this.matterportImportService.floors);
255
+ // console.log(this.floors);
256
+ setTimeout(async () => {
257
+ /** Move Floor mode */
258
+ sdk.Mode.moveTo(sdk.Mode.Mode.FLOORPLAN).then(async (nextMode) => {
259
+ /** Display the correct floor for the plan */
260
+ try {
261
+ const matterportFloor = this.chosenPlan.zone.metadata ?
262
+ JSON.parse(this.chosenPlan.zone.metadata).matterportFloorSequence : null;
263
+ await this.matterportImportService.moveToFloor(this.chosenPlan.zone.name, matterportFloor);
264
+ /** When the user try to change the view mode we set it back to floorpan */
265
+ sdk.on(sdk.Mode.Event.CHANGE_END, (oldMode, newMode) => {
266
+ if (newMode !== sdk.Mode.Mode.FLOORPLAN) {
267
+ sdk.Mode.moveTo(sdk.Mode.Mode.FLOORPLAN, {
268
+ transition: 'transition.instant',
269
+ });
270
+ }
271
+ });
272
+ }
273
+ catch {
274
+ console.log('couldnot move to floor');
275
+ }
276
+ });
277
+ /** We can display the matterport view now */
278
+ this.loading = false;
279
+ }, 1000);
280
+ /** Update current camera pose and rotation */
281
+ sdk.Camera.pose.subscribe((event) => {
282
+ /** We update only if the user is not changing the rotation with the <input> range, to not override the <input> value */
283
+ if (!this.isRotatingRange) {
284
+ this.rotation = event.rotation.y + 180;
285
+ this.prevRotation = this.rotation;
286
+ this.cameraPose = event;
287
+ }
288
+ });
289
+ }
290
+ /** When the <input> range, for rotation, change */
291
+ async onRotationChange() {
292
+ const rotationDelta = this.rotation - this.prevRotation;
293
+ this.prevRotation = this.rotation;
294
+ /** Send the rotationDelta to th queue event in order to be send to matterport */
295
+ this.rotatingQueueEvent.push(rotationDelta);
296
+ /** Start to process the queue, if it's the first event */
297
+ if (!this.isRotatingRange) {
298
+ this.isRotatingRange = true;
299
+ this.processRotatingQueueEvent();
300
+ }
301
+ }
302
+ /** Process the rotating event queue, send event one by one to matterport */
303
+ async processRotatingQueueEvent() {
304
+ const { sdk } = this.matterportImportService;
305
+ /** While the queue is not empty */
306
+ while (this.rotatingQueueEvent.length > 0) {
307
+ /** Rotate matterport by deltaRotation and remove event from queue */
308
+ await sdk.Camera.rotate(this.rotatingQueueEvent.shift(), 0, {
309
+ speed: 360,
310
+ });
311
+ }
312
+ /** When the queue is empty, then the user is not rotating with the <input> range anymore */
313
+ this.isRotatingRange = false;
314
+ }
315
+ /** **********************************************************************************************
316
+ * USER ACTIONS
317
+ *********************************************************************************************** */
318
+ /** Preview calibration */
319
+ async onPreview() {
320
+ this.preview = true;
321
+ /** Place sweeps */
322
+ this.onPlaceSweeps();
323
+ }
324
+ async calibrate() {
325
+ const [navigation] = this.currentNavigations;
326
+ const position = JSON.parse(navigation.position);
327
+ this.firstMarkPlan =
328
+ await this.matterportImportService.sdk.Renderer.getScreenPosition({
329
+ x: position.x,
330
+ y: position.y,
331
+ z: position.z,
332
+ });
333
+ this.secondMarkPlan =
334
+ await this.matterportImportService.sdk.Renderer.getScreenPosition({
335
+ x: position.x,
336
+ y: 0,
337
+ z: 0,
338
+ });
339
+ const deltaZVisit = 0 - position.z;
340
+ let deltaXPlan = this.secondMarkPlan.x - this.firstMarkPlan.x;
341
+ if (deltaXPlan === 0) {
342
+ // console.log("we moved along Y axis on Plan");
343
+ const deltaYPlan = this.secondMarkPlan.y - this.firstMarkPlan.y;
344
+ this.calibrage.nameYAxis = 'z';
345
+ this.calibrage.nameXAxis = 'x';
346
+ this.calibrage.offsetY = this.secondMarkPlan.y;
347
+ this.calibrage.scaleY = deltaYPlan / deltaZVisit;
348
+ }
349
+ else {
350
+ // console.log(" we moved along X axis on Plan");
351
+ this.calibrage.nameYAxis = 'x';
352
+ this.calibrage.nameXAxis = 'z';
353
+ this.calibrage.offsetX = this.secondMarkPlan.x;
354
+ this.calibrage.scaleX = deltaXPlan / deltaZVisit;
355
+ }
356
+ const thirdMarkPlan = await this.matterportImportService.sdk.Renderer.getScreenPosition({
357
+ x: 0,
358
+ y: 0,
359
+ z: position.z,
360
+ });
361
+ const deltaXVisit = 0 - position.x;
362
+ if (deltaXPlan === 0) {
363
+ // console.log(" we moved along X axis on Plan");
364
+ deltaXPlan = thirdMarkPlan.x - this.firstMarkPlan.x;
365
+ this.calibrage.offsetX = thirdMarkPlan.x;
366
+ this.calibrage.scaleX = deltaXPlan / deltaXVisit;
367
+ }
368
+ else {
369
+ const deltaYPlan = thirdMarkPlan.y - this.firstMarkPlan.y;
370
+ this.calibrage.offsetY = thirdMarkPlan.y;
371
+ this.calibrage.scaleY = deltaYPlan / deltaXVisit;
372
+ }
373
+ /** Take considiration of pan and zoom of plan on canvas */
374
+ const transformInfo = this.panzoom.getTransform();
375
+ const { scale, x, y } = transformInfo;
376
+ // console.log(transformInfo);
377
+ this.calibrage.offsetXPlan = x;
378
+ this.calibrage.offsetYPlan = y;
379
+ this.calibrage.scalePlan = scale;
380
+ console.log(this.calibrage);
381
+ }
382
+ /** Place sweeps */
383
+ async onPlaceSweeps() {
384
+ /** Display all scan */
385
+ const zone = await this.zoneService.getZone(this.chosenPlan.zoneID);
386
+ if (zone) {
387
+ this.currentZone = zone;
388
+ const navigations = await this.navigationService.getNavigationsForZone(this.currentZone);
389
+ this.currentNavigations = navigations;
390
+ await this.calibrate();
391
+ if (navigations.length > 0) {
392
+ for (const navigation of navigations) {
393
+ const testPosition = JSON.parse(navigation.position);
394
+ const positionX = this.calibrage.nameXAxis === 'x' ? testPosition.x : testPosition.z;
395
+ const positionY = this.calibrage.nameYAxis === 'x' ? testPosition.x : testPosition.z;
396
+ const testX = positionX * this.calibrage.scaleX + this.calibrage.offsetX;
397
+ const testY = positionY * this.calibrage.scaleY + this.calibrage.offsetY;
398
+ // console.log("test position GREEN", testX, testY);
399
+ const transformedX = (testX - this.calibrage.offsetXPlan) / this.calibrage.scalePlan; // we are undoing the pan and zoom
400
+ const transformedY = (testY - this.calibrage.offsetYPlan) / this.calibrage.scalePlan;
401
+ this.positions.push({
402
+ navID: navigation.id,
403
+ planID: this.chosenPlan.id,
404
+ x: transformedX,
405
+ y: transformedY,
406
+ });
407
+ const iconSize = 30 * this.calibrage.scalePlan;
408
+ const shift = iconSize / 2;
409
+ this.drawImage('https://api.iconify.design/mdi:adjust.svg?color=green&height=30&width=30', transformedX - shift, transformedY - shift, true);
410
+ }
411
+ }
412
+ }
413
+ }
414
+ /** Save calibration */
415
+ async onSave() {
416
+ if (this.currentZone) {
417
+ /** Normalize with the zoom */
418
+ // this.calibrage.offsetX /= this.canvasZoom;
419
+ // this.calibrage.offsetY /= this.canvasZoom;
420
+ // this.calibrage.x /= this.canvasZoom;
421
+ // this.calibrage.y /= this.canvasZoom;
422
+ this.calibrage.new = true;
423
+ this.calibrage.imgWidth = this.canvasSize.w;
424
+ this.calibrage.imgHeight = this.canvasSize.h;
425
+ await this.planService.updatePlan({
426
+ id: this.chosenPlan.id,
427
+ calibration: JSON.stringify(this.calibrage),
428
+ });
429
+ await Promise.all(this.positions.map(async (position) => {
430
+ const { navID } = position;
431
+ delete position.navID;
432
+ const nav = this.currentNavigations.find((_nav) => _nav.id === navID);
433
+ let positionsDataToUpdate;
434
+ if (nav.positionOnPlan) {
435
+ const positionOnPlan = nav.positionOnPlan.map((entry) => JSON.parse(entry));
436
+ const positionForCurrentPlan = positionOnPlan.find((entry) => entry.planID === this.chosenPlan.id);
437
+ if (positionForCurrentPlan) {
438
+ positionOnPlan.splice(positionOnPlan.indexOf(positionForCurrentPlan), 1, position);
439
+ }
440
+ else {
441
+ positionOnPlan.push(position);
442
+ }
443
+ positionsDataToUpdate = [...positionOnPlan];
444
+ }
445
+ else {
446
+ positionsDataToUpdate = [position];
447
+ }
448
+ // console.log(positionsDataToUpdate);
449
+ await this.navigationService.updateNavigation({
450
+ id: navID,
451
+ positionOnPlan: positionsDataToUpdate.map((entry) => JSON.stringify(entry)),
452
+ });
453
+ }));
454
+ }
455
+ this.matterportImportService.removeFrame();
456
+ this.router.navigate(['/dashboard/localisation', this.spaceID, 'plans']);
457
+ alert(this.translate.instant('calibration.success'));
458
+ }
459
+ /** Reset the canvas */
460
+ onReset() {
461
+ this.reflectH = false;
462
+ this.reflectV = false;
463
+ this.preview = false;
464
+ this.configureCanvas();
465
+ }
466
+ /** Cancel, leave */
467
+ onCancel() {
468
+ this.matterportImportService.removeFrame();
469
+ this.router.navigate(['/dashboard/localisation', this.spaceID, 'plans']);
470
+ alert(this.translate.instant('calibration.canceled'));
471
+ }
472
+ async onFloorClick(floor) {
473
+ this.currentFloor = floor;
474
+ await this.matterportImportService.moveToFloor(floor.id);
475
+ }
476
+ onActivateZoomChange() {
477
+ this.zoomCanBeChanged = !this.zoomCanBeChanged;
478
+ const iframe = document.querySelector('#viewer-frame');
479
+ if (iframe) {
480
+ iframe.style.zIndex = this.zoomCanBeChanged ? '1' : '0';
481
+ }
482
+ }
483
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CalibrationComponent, deps: [{ token: i1.MatterportImportService }, { token: i1.PlanService }, { token: i2.ActivatedRoute }, { token: i2.Router }, { token: i1.ZoneService }, { token: i1.SpaceService }, { token: i1.NavigationService }, { token: i3.TranslateService }], target: i0.ɵɵFactoryTarget.Component });
484
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: CalibrationComponent, selector: "lib-calibration", viewQueries: [{ propertyName: "canvasDiv", first: true, predicate: ["canvasDiv"], descendants: true }], ngImport: i0, template: "<div class=\"row mt-3\">\r\n <div class=\"col\">\r\n <div class=\"m-3\">\r\n <lib-tab-navigation [menuItems]='menuItems'></lib-tab-navigation>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div id=\"rowCanvas\">\r\n <div #canvasDiv id=\"canvasDiv\">\r\n\r\n <div id=\"viewer-frame\" [style.pointer-events]=\"zoomCanBeChanged?'auto':'none'\">\r\n <!-- <div class=\"blur\"></div> -->\r\n </div>\r\n <canvas id=\"canvas\" [ngStyle]=\"{'opacity': (preview||loading) ? '1' : 'calc(' + opacity + '/ 100)'}\"></canvas>\r\n </div>\r\n\r\n <div class=\"calibration-tools container-fluid\" *ngIf=\"!(preview || loading)\">\r\n <h1>{{'Calibration tool' | translate}}</h1>\r\n <div class=\"tool\">\r\n <div class=\"row ms-0 me-0 legend\">\r\n <div class=\"legend-bar-indicator\" [ngStyle]=\"{'opacity': 'calc(' + (-(opacity-100)+10) + '/ 100)'}\">\r\n {{'Less' | translate}}</div>\r\n <div class=\"legend-title\">{{'Plan Opacity' | translate }}</div>\r\n <div class=\"legend-bar-indicator\" [ngStyle]=\"{'opacity': 'calc(' + (opacity+10) + '/ 100)'}\">{{'More' |\r\n translate}}</div>\r\n </div>\r\n <div class=\"row ms-0 me-0 \">\r\n <input [disabled]=\"false\" [ngModelOptions]=\"{standalone: true}\" [(ngModel)]=\"opacity\" type=\"range\"\r\n class=\"form-range\" min=\"0\" max=\"100\" value=\"50\" id=\"opacity\">\r\n </div>\r\n </div>\r\n <div class=\"tool\">\r\n <div class=\"row ms-0 me-0 \">\r\n <div class=\"label-legend\">{{'Change Visit Floor' | translate}}</div>\r\n <div ngbDropdown class=\"d-inline-block ms-3\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownBasic1\" ngbDropdownToggle>\r\n {{currentFloor ? currentFloor.id : ('Floor' | translate) }}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownBasic1\">\r\n <button ngbDropdownItem *ngFor=\"let floor of floors\" (click)=\"onFloorClick(floor)\">\r\n {{ floor.name.length > 0 ? floor.name : ('Floor ' + floor.id) }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n <div class=\"tool\">\r\n <div class=\"row ms-0 me-0 \">\r\n <div class=\"tool-checkbox-container\">\r\n <div class=\"tool-checkbox-subcontainer\">\r\n <div class=\"label-legend me-3\">{{'Pan/Zoom Visit' | translate}} {{zoomCanBeChanged ? \"ON\" :\r\n \"OFF\"}}\r\n </div>\r\n <input type=\"checkbox\" (change)=\"onActivateZoomChange()\" style=\"margin-top: 5px;\">\r\n </div>\r\n <div class=\"card border-warning mb-3 mt-3\" *ngIf=\"zoomCanBeChanged\">\r\n <div class=\"card-body text-warning\">\r\n <h5 class=\"card-title\">{{\"calibration.wait-message\" | translate}}</h5>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"action\">\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onPreview()\"\r\n [disabled]=\"zoomCanBeChanged\">{{'Preview' | translate}}</button>\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onCancel()\">{{'Cancel' |\r\n translate}}</button>\r\n\r\n </div>\r\n\r\n </div>\r\n <div class=\"calibration-tools container-fluid\" *ngIf=\"preview\">\r\n <h1>{{'Validation' | translate}}</h1>\r\n <div class=\"action\">\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onSave()\">{{'Validate' |\r\n translate}}</button>\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onReset()\">{{'Reset' |\r\n translate}}</button>\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onCancel()\">{{'Cancel' |\r\n translate}}</button>\r\n\r\n </div>\r\n </div>\r\n\r\n\r\n <div class=\"calibration-tools container-fluid\" *ngIf=\"loading\">\r\n <h3>{{\"Waiting for Matterport\" | translate}}...</h3>\r\n <div class=\"d-flex justify-content-center\">\r\n <div class=\"spinner-border\" role=\"status\">\r\n <span class=\"visually-hidden\">Loading...</span>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n</div>", styles: [".button-visit{display:none;height:30px;width:30px;position:absolute;background:url(https://api.iconify.design/mdi:map-marker-check.svg?color=red&height=30) no-repeat scroll 0 0 transparent;border:none}#button-visit-left{left:350px;top:550px}#button-visit-right{left:500px;top:600px}#rowCanvas{display:flex}#canvasDiv{height:100%;width:100%;position:relative}#canvas{width:100%;height:100%;opacity:.5}#viewer-frame{top:0;position:absolute;width:100%;height:100%}.calibration-tools{margin-left:20px;width:400px;background-color:#fff;z-index:11;border:1px solid var(--smarterplan-primary);padding:7px}.form-range{width:100%}.tool{margin-top:20px}.tool .legend{justify-content:space-between;position:relative;margin-bottom:5px}.tool .legend-title{font-size:1.2rem;color:var(--smarterplan-primary);margin:auto;width:100%;font-weight:700;display:flex;justify-content:center}.tool .legend-bar-indicator{width:15%!important}.tool .label-legend{color:var(--smarterplan-primary);font-size:1.1rem;max-width:55%}.tool .tool-checkbox-container{display:flex;flex-direction:column}.tool .tool-checkbox-container .tool-checkbox-subcontainer{display:flex}.blur{width:150px;height:52px;position:absolute;background-color:#1e2023;bottom:0}.symmetry{padding:5px;border:solid 2px;border-radius:10px;color:var(--smarterplan-primary);margin:25px 10px;cursor:pointer}.symmetry:hover{color:var(--smarterplan-primary)}.symmetry-row{justify-content:center}.action{margin-top:30px;display:flex;justify-content:space-evenly}h1{color:var(--smarterplan-primary);text-align:center;margin-bottom:20px}h3{color:var(--smarterplan-primary);text-align:center;margin-bottom:10px}.btn-outline-primary.disabled{background-color:var(--smarterplan-orange)!important}\n"], dependencies: [{ kind: "directive", type: i4.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "popperOptions", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { kind: "directive", type: i4.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { kind: "directive", type: i4.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { kind: "directive", type: i4.NgbDropdownItem, selector: "[ngbDropdownItem]", inputs: ["disabled"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i6.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: i6.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i7.TabNavigationComponent, selector: "lib-tab-navigation", inputs: ["menuItems"], outputs: ["onGoBack"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
485
+ }
486
+ export { CalibrationComponent };
487
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CalibrationComponent, decorators: [{
488
+ type: Component,
489
+ args: [{ selector: 'lib-calibration', template: "<div class=\"row mt-3\">\r\n <div class=\"col\">\r\n <div class=\"m-3\">\r\n <lib-tab-navigation [menuItems]='menuItems'></lib-tab-navigation>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div id=\"rowCanvas\">\r\n <div #canvasDiv id=\"canvasDiv\">\r\n\r\n <div id=\"viewer-frame\" [style.pointer-events]=\"zoomCanBeChanged?'auto':'none'\">\r\n <!-- <div class=\"blur\"></div> -->\r\n </div>\r\n <canvas id=\"canvas\" [ngStyle]=\"{'opacity': (preview||loading) ? '1' : 'calc(' + opacity + '/ 100)'}\"></canvas>\r\n </div>\r\n\r\n <div class=\"calibration-tools container-fluid\" *ngIf=\"!(preview || loading)\">\r\n <h1>{{'Calibration tool' | translate}}</h1>\r\n <div class=\"tool\">\r\n <div class=\"row ms-0 me-0 legend\">\r\n <div class=\"legend-bar-indicator\" [ngStyle]=\"{'opacity': 'calc(' + (-(opacity-100)+10) + '/ 100)'}\">\r\n {{'Less' | translate}}</div>\r\n <div class=\"legend-title\">{{'Plan Opacity' | translate }}</div>\r\n <div class=\"legend-bar-indicator\" [ngStyle]=\"{'opacity': 'calc(' + (opacity+10) + '/ 100)'}\">{{'More' |\r\n translate}}</div>\r\n </div>\r\n <div class=\"row ms-0 me-0 \">\r\n <input [disabled]=\"false\" [ngModelOptions]=\"{standalone: true}\" [(ngModel)]=\"opacity\" type=\"range\"\r\n class=\"form-range\" min=\"0\" max=\"100\" value=\"50\" id=\"opacity\">\r\n </div>\r\n </div>\r\n <div class=\"tool\">\r\n <div class=\"row ms-0 me-0 \">\r\n <div class=\"label-legend\">{{'Change Visit Floor' | translate}}</div>\r\n <div ngbDropdown class=\"d-inline-block ms-3\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownBasic1\" ngbDropdownToggle>\r\n {{currentFloor ? currentFloor.id : ('Floor' | translate) }}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownBasic1\">\r\n <button ngbDropdownItem *ngFor=\"let floor of floors\" (click)=\"onFloorClick(floor)\">\r\n {{ floor.name.length > 0 ? floor.name : ('Floor ' + floor.id) }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n <div class=\"tool\">\r\n <div class=\"row ms-0 me-0 \">\r\n <div class=\"tool-checkbox-container\">\r\n <div class=\"tool-checkbox-subcontainer\">\r\n <div class=\"label-legend me-3\">{{'Pan/Zoom Visit' | translate}} {{zoomCanBeChanged ? \"ON\" :\r\n \"OFF\"}}\r\n </div>\r\n <input type=\"checkbox\" (change)=\"onActivateZoomChange()\" style=\"margin-top: 5px;\">\r\n </div>\r\n <div class=\"card border-warning mb-3 mt-3\" *ngIf=\"zoomCanBeChanged\">\r\n <div class=\"card-body text-warning\">\r\n <h5 class=\"card-title\">{{\"calibration.wait-message\" | translate}}</h5>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"action\">\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onPreview()\"\r\n [disabled]=\"zoomCanBeChanged\">{{'Preview' | translate}}</button>\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onCancel()\">{{'Cancel' |\r\n translate}}</button>\r\n\r\n </div>\r\n\r\n </div>\r\n <div class=\"calibration-tools container-fluid\" *ngIf=\"preview\">\r\n <h1>{{'Validation' | translate}}</h1>\r\n <div class=\"action\">\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onSave()\">{{'Validate' |\r\n translate}}</button>\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onReset()\">{{'Reset' |\r\n translate}}</button>\r\n <button type=\"button\" class=\"btn btn-outline-primary rounded-pill\" (click)=\"onCancel()\">{{'Cancel' |\r\n translate}}</button>\r\n\r\n </div>\r\n </div>\r\n\r\n\r\n <div class=\"calibration-tools container-fluid\" *ngIf=\"loading\">\r\n <h3>{{\"Waiting for Matterport\" | translate}}...</h3>\r\n <div class=\"d-flex justify-content-center\">\r\n <div class=\"spinner-border\" role=\"status\">\r\n <span class=\"visually-hidden\">Loading...</span>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n</div>", styles: [".button-visit{display:none;height:30px;width:30px;position:absolute;background:url(https://api.iconify.design/mdi:map-marker-check.svg?color=red&height=30) no-repeat scroll 0 0 transparent;border:none}#button-visit-left{left:350px;top:550px}#button-visit-right{left:500px;top:600px}#rowCanvas{display:flex}#canvasDiv{height:100%;width:100%;position:relative}#canvas{width:100%;height:100%;opacity:.5}#viewer-frame{top:0;position:absolute;width:100%;height:100%}.calibration-tools{margin-left:20px;width:400px;background-color:#fff;z-index:11;border:1px solid var(--smarterplan-primary);padding:7px}.form-range{width:100%}.tool{margin-top:20px}.tool .legend{justify-content:space-between;position:relative;margin-bottom:5px}.tool .legend-title{font-size:1.2rem;color:var(--smarterplan-primary);margin:auto;width:100%;font-weight:700;display:flex;justify-content:center}.tool .legend-bar-indicator{width:15%!important}.tool .label-legend{color:var(--smarterplan-primary);font-size:1.1rem;max-width:55%}.tool .tool-checkbox-container{display:flex;flex-direction:column}.tool .tool-checkbox-container .tool-checkbox-subcontainer{display:flex}.blur{width:150px;height:52px;position:absolute;background-color:#1e2023;bottom:0}.symmetry{padding:5px;border:solid 2px;border-radius:10px;color:var(--smarterplan-primary);margin:25px 10px;cursor:pointer}.symmetry:hover{color:var(--smarterplan-primary)}.symmetry-row{justify-content:center}.action{margin-top:30px;display:flex;justify-content:space-evenly}h1{color:var(--smarterplan-primary);text-align:center;margin-bottom:20px}h3{color:var(--smarterplan-primary);text-align:center;margin-bottom:10px}.btn-outline-primary.disabled{background-color:var(--smarterplan-orange)!important}\n"] }]
490
+ }], ctorParameters: function () { return [{ type: i1.MatterportImportService }, { type: i1.PlanService }, { type: i2.ActivatedRoute }, { type: i2.Router }, { type: i1.ZoneService }, { type: i1.SpaceService }, { type: i1.NavigationService }, { type: i3.TranslateService }]; }, propDecorators: { canvasDiv: [{
491
+ type: ViewChild,
492
+ args: ['canvasDiv']
493
+ }] } });
494
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsaWJyYXRpb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvcGxhbnMvY2FsaWJyYXRpb24vY2FsaWJyYXRpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvcGxhbnMvY2FsaWJyYXRpb24vY2FsaWJyYXRpb24uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBc0IsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBR3pFLE9BQU8sRUFBRSxXQUFXLEVBQW9CLE1BQU0sWUFBWSxDQUFDO0FBQzNELHFEQUFxRDtBQUNyRCxPQUFPLEVBVUgsZUFBZSxHQUVsQixNQUFNLG1DQUFtQyxDQUFDO0FBQzNDLE9BQU8sT0FBTyxNQUFNLFNBQVMsQ0FBQzs7Ozs7Ozs7O0FBRTlCLE1BS2Esb0JBQW9CO0lBcUZqQjtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBM0ZaLHFDQUFxQztJQUNyQyxTQUFTLEdBQWUsRUFBRSxDQUFDO0lBRTNCLG9CQUFvQjtJQUNwQixNQUFNLENBQUM7SUFFUCxrRUFBa0U7SUFDMUMsU0FBUyxDQUFhO0lBRTlDLDZDQUE2QztJQUM3QyxVQUFVLENBQTRCO0lBRXRDLHFDQUFxQztJQUNyQyxVQUFVLEdBQUcsQ0FBQyxDQUFDO0lBRWYsb0NBQW9DO0lBQ3BDLE9BQU8sR0FBVyxFQUFFLENBQUM7SUFFckIsNEZBQTRGO0lBQzVGLFFBQVEsR0FBVyxHQUFHLENBQUM7SUFFdkIseUhBQXlIO0lBQ3pILFlBQVksR0FBVyxHQUFHLENBQUM7SUFFM0IsMEJBQTBCO0lBQzFCLFVBQVUsQ0FBTTtJ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QzNDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMseUJBQXlCLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3pFLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVELEtBQUssQ0FBQyxZQUFZLENBQUMsS0FBSztRQUNwQixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQztRQUMxQixNQUFNLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRCxvQkFBb0I7UUFDaEIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDO1FBQy9DLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsZUFBZSxDQUFnQixDQUFDO1FBQ3RFLElBQUksTUFBTSxFQUFFO1lBQ1IsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztTQUMzRDtJQUNMLENBQUM7d0dBaGtCUSxvQkFBb0I7NEZBQXBCLG9CQUFvQiwrSkN6QmpDLGl6SkFpR007O1NEeEVPLG9CQUFvQjs0RkFBcEIsb0JBQW9CO2tCQUxoQyxTQUFTOytCQUNJLGlCQUFpQjs4U0FZSCxTQUFTO3NCQUFoQyxTQUFTO3VCQUFDLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEVsZW1lbnRSZWYsIE9uSW5pdCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xyXG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XHJcbmltcG9ydCB7IGdldERvY3VtZW50LCBQREZEb2N1bWVudFByb3h5IH0gZnJvbSAncGRmanMtZGlzdCc7XHJcbi8vIGltcG9ydCB7IFBERkRvY3VtZW50UHJveHkgfSBmcm9tICduZzItcGRmLXZpZXdlcic7XHJcbmltcG9ydCB7XHJcbiAgICBab25lLFxyXG4gICAgTWVudUl0ZW0sXHJcbiAgICBQbGFuLFxyXG4gICAgU3BhY2UsXHJcbiAgICBOYXZpZ2F0aW9uLFxyXG4gICAgUGxhblNlcnZpY2UsXHJcbiAgICBab25lU2VydmljZSxcclxuICAgIFNwYWNlU2VydmljZSxcclxuICAgIE5hdmlnYXRpb25TZXJ2aWNlLFxyXG4gICAgZ2V0TWV0YUZvckltYWdlLFxyXG4gICAgTWF0dGVycG9ydEltcG9ydFNlcnZpY2UsXHJcbn0gZnJvbSAnQHNtYXJ0ZXJwbGFuL25neC1zbWFydGVycGxhbi1jb3JlJztcclxuaW1wb3J0IHBhbnpvb20gZnJvbSAncGFuem9vbSc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICAgIHNlbGVjdG9yOiAnbGliLWNhbGlicmF0aW9uJyxcclxuICAgIHRlbXBsYXRlVXJsOiAnLi9jYWxpYnJhdGlvbi5jb21wb25lbnQuaHRtbCcsXHJcbiAgICBzdHlsZVVybHM6IFsnLi9jYWxpYnJhdGlvbi5jb21wb25lbnQuc2NzcyddLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQ2FsaWJyYXRpb25Db21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xyXG4gICAgLyoqIEl0ZW0gdG8gZGlzcGxheSBmb3IgdGhlIG5hdmJhciAqL1xyXG4gICAgbWVudUl0ZW1zOiBNZW51SXRlbVtdID0gW107XHJcblxyXG4gICAgLyoqIENhbnZhcyAoUGxhbikgKi9cclxuICAgIGNhbnZhcztcclxuXHJcbiAgICAvKiogQ2FudmFzRGl2IChEaXYgdGhhdCBjb250YWluIHRoZSBjYW52YXMgKyBtYXR0ZXJwb3J0IGlmcmFtZSkgKi9cclxuICAgIEBWaWV3Q2hpbGQoJ2NhbnZhc0RpdicpIGNhbnZhc0RpdjogRWxlbWVudFJlZjtcclxuXHJcbiAgICAvKiogU2l6ZSBvZiB0aGUgY2FudmFzICYgbWF0dGVycG9ydCBpZnJhbWUgKi9cclxuICAgIGNhbnZhc1NpemU6IHsgdzogbnVtYmVyOyBoOiBudW1iZXI7IH07XHJcblxyXG4gICAgLyoqIFpvb20gcmF0aW8gb2YgdGhlIGNhbnZhcy9wbGFuICAqL1xyXG4gICAgY2FudmFzWm9vbSA9IDA7XHJcblxyXG4gICAgLyoqIE9wYWNpdHkgZm9yIG1hdHRlcnBvcnQgaWZyYW1lICovXHJcbiAgICBvcGFjaXR5OiBudW1iZXIgPSA1MDtcclxuXHJcbiAgICAvKiogQ3VycmVudCByb3RhdGlvbiBmb3IgbWF0dGVycG9ydCwgWzAtMzYwXSwgIG1hdHRlcnBvcnQgcm90YXRpb24gaXMgYmluZCB0byBpbnB1dCByYW5nZSAqL1xyXG4gICAgcm90YXRpb246IG51bWJlciA9IDE4MDtcclxuXHJcbiAgICAvKiogUHJldmlvdXMgcm90YXRpb24sIHVzZSB0byBjYWxjdWxhdGUgdGhlIGRlbHRhUm90YXRpb24gdG8gcm90YXRlLCB3aGVuIHVzZXIgY2hhbmdlIHJvdGF0aW9uIHZhbHVlIHVzaW5nIHJhbmdlIGlucHV0ICovXHJcbiAgICBwcmV2Um90YXRpb246IG51bWJlciA9IDE4MDtcclxuXHJcbiAgICAvKiogQ3VycmVudCBDYW1lcmEgUG9zZSAqL1xyXG4gICAgY2FtZXJhUG9zZTogYW55O1xyXG5cclxuICAgIC8qKiBUcnVlIHdoZW4gdGhlIHVzZXIgaXMgY3VycmVudGx5IHJvdGF0aW5nIHdpdGggdGhlIGlucHV0IHJhbmdlLCB0aGUgbWF0dGVycG9ydCByb3RhdGlvbiBldmVudHMgd2lsbCBiZSBpZ25vcmVkICovXHJcbiAgICBpc1JvdGF0aW5nUmFuZ2U6IGJvb2xlYW4gPSBmYWxzZTtcclxuXHJcbiAgICAvKiogUm90YXRpbmcgcXVldWUgZXZlbnQgdG8gc2VuZCB0byBtYXR0ZXJwb3J0ICovXHJcbiAgICByb3RhdGluZ1F1ZXVlRXZlbnQ6IG51bWJlcltdID0gW107XHJcblxyXG4gICAgLyoqIFRydWUgd2hlbiBWZXJ0aWNhbCBzeW1tZXRyeSBpcyBlbmFibGVkICovXHJcbiAgICByZWZsZWN0ViA9IGZhbHNlO1xyXG5cclxuICAgIC8qKiBUcnVlIHdoZW4gSG9yaXpvbnRhbCBzeW1tZXRyeSBpcyBlbmFibGVkICovXHJcbiAgICByZWZsZWN0SCA9IGZhbHNlO1xyXG5cclxuICAgIGNob3NlblBsYW46IFBsYW47XHJcblxyXG4gICAgc3BhY2VJRDogc3RyaW5nO1xyXG5cclxuICAgIGN1cnJlbnRTcGFjZTogU3BhY2U7XHJcblxyXG4gICAgY3VycmVudFpvbmU6IFpvbmU7XHJcblxyXG4gICAgY2hvc2VuUGxhbklzUGRmID0gZmFsc2U7XHJcblxyXG4gICAgLyoqIEZpcnN0IFBvaW50IGluIHZpc2l0LCB1c2VkIHRvIGRldGVybWluZSB0aGUgY2FsaWJyYXRpb24gICovXHJcbiAgICBmaXJzdE1hcmtWaXNpdCA9IHsgeDogMCwgeTogMCB9O1xyXG5cclxuICAgIC8qKiBTZWNvbmQgUG9pbnQgaW4gdmlzaXQsIHVzZWQgdG8gZGV0ZXJtaW5lIHRoZSBjYWxpYnJhdGlvbiAgKi9cclxuICAgIHNlY29uZE1hcmtWaXNpdCA9IHsgeDogMC41LCB5OiAwLjUgfTtcclxuXHJcbiAgICAvKiogRXF1aXZhbGVudCBvZiAnZmlyc3RNYXJrVmlzaXQnIGluIGNhbnZhcyAgKi9cclxuICAgIGZpcnN0TWFya1BsYW46IHsgeDogbnVtYmVyOyB5OiBudW1iZXI7IH0gPSB7IHg6IDAsIHk6IDAgfTtcclxuXHJcbiAgICAvKiogRXF1aXZhbGVudCBvZiAnc2Vjb25kTWFya1Zpc2l0JyBpbiBjYW52YXMgICovXHJcbiAgICBzZWNvbmRNYXJrUGxhbjogeyB4OiBudW1iZXI7IHk6IG51bWJlcjsgfSA9IHsgeDogMCwgeTogMCB9O1xyXG5cclxuICAgIC8qKiBDYWxpYnJhdGlvbiByZXN1bHQsIChvZmZzZXRYLCBvZmZzZXRZLCB4LCB5KSAqL1xyXG4gICAgY2FsaWJyYWdlOiBhbnkgPSB7fTtcclxuXHJcbiAgICAvKiogSXMgaW4gcHJldmlldyBtb2RlIChzZWUgc2NhbiByZXN1bHQpICovXHJcbiAgICBwcmV2aWV3ID0gZmFsc2U7XHJcblxyXG4gICAgLyoqIE1hdHRlcnBvcnQgaXMgbG9hZGluZyAqL1xyXG4gICAgbG9hZGluZyA9IHRydWU7XHJcblxyXG4gICAgLyogZm9yIHBhbiBhbmQgem9vbSBvZiBjYW52YXMgKi9cclxuICAgIHBhbnpvb206IGFueTtcclxuXHJcbiAgICBjdXJyZW50TmF2aWdhdGlvbnM6IE5hdmlnYXRpb25bXTtcclxuXHJcbiAgICBwb3NpdGlvbnM6IHsgbmF2SUQ6IHN0cmluZzsgcGxhbklEOiBzdHJpbmc7IHg6IG51bWJlcjsgeTogbnVtYmVyOyB9W10gPSBbXTtcclxuXHJcbiAgICBmbG9vcnM6IGFueVtdID0gW107XHJcblxyXG4gICAgY3VycmVudEZsb29yO1xyXG5cclxuICAgIHpvb21DYW5CZUNoYW5nZWQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwcml2YXRlIG1hdHRlcnBvcnRJbXBvcnRTZXJ2aWNlOiBNYXR0ZXJwb3J0SW1wb3J0U2VydmljZSxcclxuICAgICAgICBwcml2YXRlIHBsYW5TZXJ2aWNlOiBQbGFuU2VydmljZSxcclxuICAgICAgICBwcml2YXRlIHJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSxcclxuICAgICAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxyXG4gICAgICAgIHByaXZhdGUgem9uZVNlcnZpY2U6IFpvbmVTZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgc3BhY2VTZXJ2aWNlOiBTcGFjZVNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSBuYXZpZ2F0aW9uU2VydmljZTogTmF2aWdhdGlvblNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSB0cmFuc2xhdGU6IFRyYW5zbGF0ZVNlcnZpY2VcclxuICAgICkgeyB9XHJcblxyXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKCF0aGlzLmxvYWRpbmcpIHtcclxuICAgICAgICAgICAgdGhpcy5tYXR0ZXJwb3J0SW1wb3J0U2VydmljZS5yZW1vdmVGcmFtZSgpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBuZ09uSW5pdCgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICB0aGlzLnNwYWNlSUQgPSB0aGlzLnJvdXRlLnNuYXBzaG90LnF1ZXJ5UGFyYW1zLnNwYWNlSUQ7XHJcbiAgICAgICAgdGhpcy5jdXJyZW50U3BhY2UgPSBhd2FpdCB0aGlzLnNwYWNlU2VydmljZS5nZXRTcGFjZSh0aGlzLnNwYWNlSUQpO1xyXG5cclxuICAgICAgICAvKiogTWVudSBuYXYgYmFyICovXHJcbiAgICAgICAgdGhpcy5zZXR1cE1lbnVJdGVtcygpO1xyXG5cclxuICAgICAgICB0aGlzLmNob3NlblBsYW4gPSB0aGlzLnBsYW5TZXJ2aWNlLmdldENob3NlblBsYW4oKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuY2hvc2VuUGxhbikge1xyXG4gICAgICAgICAgICB0aGlzLmNob3NlblBsYW5Jc1BkZiA9IHRoaXMuY2hvc2VuUGxhbi5hbm5leGUuaW5jbHVkZXMoJ3BkZicpO1xyXG4gICAgICAgICAgICB0aGlzLmxhdW5jaFZpZXdlcigpO1xyXG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlndXJlQ2FudmFzKCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wYW56b29tID0gcGFuem9vbSh0aGlzLmNhbnZhcywge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBib3VuZHM6IHRydWUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kc1BhZGRpbmc6IDAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heFpvb206IDIuNSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWluWm9vbTogMC4xLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsWm9vbTogMSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgem9vbVNwZWVkOiAwLjAyLFxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0sIDUwMCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5yb3V0ZXIubmF2aWdhdGUoWycvZGFzaGJvYXJkL2xvY2FsaXNhdGlvbicsIHRoaXMuc3BhY2VJRCwgJ3BsYW5zJ10pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKiogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1FTlUgTkFWIEJBUlxyXG4gICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbiAgICBzZXR1cE1lbnVJdGVtcygpIHtcclxuICAgICAgICB0aGlzLm1lbnVJdGVtcyA9IFtcclxuICAgICAgICAgICAgeyBsYWJlbDogJ0xvY2F0aW9ucycsIHVybDogJy9sb2NhbGlzYXRpb24nIH0sXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIGxhYmVsOiB0aGlzLmN1cnJlbnRTcGFjZS5uYW1lLFxyXG4gICAgICAgICAgICAgICAgdXJsOiBgL2xvY2FsaXNhdGlvbi8ke3RoaXMuc3BhY2VJRH1gLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICBsYWJlbDogJ1BsYW5zJyxcclxuICAgICAgICAgICAgICAgIHVybDogYC9sb2NhbGlzYXRpb24vJHt0aGlzLmN1cnJlbnRTcGFjZS5pZH0vcGxhbnNgLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICBsYWJlbDogJ0NhbGlicmF0aW9uJyxcclxuICAgICAgICAgICAgICAgIHVybDogYC9sb2NhbGlzYXRpb24vJHt0aGlzLmN1cnJlbnRTcGFjZS5pZH0vcGxhbi1jYWxpYnJhdGlvbj9zcGFjZUlEPSR7dGhpcy5jdXJyZW50U3BhY2UuaWR9YCxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDQU5WQVNcclxuICAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAqL1xyXG5cclxuICAgIC8qKiBEaXNwbGF5IHRoZSBwbGFuICovXHJcbiAgICBhc3luYyBjb25maWd1cmVDYW52YXMoKSB7XHJcbiAgICAgICAgLyoqIEdldCBjYW52YXMgKi9cclxuICAgICAgICBpZiAoIXRoaXMuY2FudmFzKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNjYW52YXMnKSBhcyBIVE1MQ2FudmFzRWxlbWVudDtcclxuICAgICAgICAgICAgdGhpcy5jYW52YXMgPSBjYW52YXM7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIXRoaXMuY2hvc2VuUGxhbklzUGRmKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGltYWdlID0gYXdhaXQgZ2V0TWV0YUZvckltYWdlKHRoaXMuY2hvc2VuUGxhbi5maWxlcGF0aCk7XHJcbiAgICAgICAgICAgIC8qKiBDb21wdXRlIHRoZSBuZXcgc2l6ZSBmb3IgdGhlIGNhbnZhcy9tYXR0ZXJwb3J0LCBiYXNlIG9uIHRoZSBkaW1lbnNpb24gb2YgdGhlIHBsYW4sIGtlZXBpbmcgdGhlIHJhdGlvICovXHJcbiAgICAgICAgICAgIGNvbnN0IHNpemUgPSB0aGlzLmdldFNpemVGb3JDYW52YXMoaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCk7XHJcblxyXG4gICAgICAgICAgICAvKiogQ29tcHV0ZSB0aGUgcGxhbiB6b29tIHJhdGlvICh1c2UgZm9yIHRoZSBjYWxpYnJhdGlvbiBsYXRlcikgKi9cclxuICAgICAgICAgICAgdGhpcy5jYW52YXNab29tID0gc2l6ZS53IC8gaW1hZ2Uud2lkdGg7XHJcblxyXG4gICAgICAgICAgICB0aGlzLnJlc2l6ZVZpZXcoc2l6ZSk7XHJcblxyXG4gICAgICAgICAgICAvKiogRHJhdyBQbGFuIG9uIHRoZSBjYW52YXMgKi9cclxuICAgICAgICAgICAgdGhpcy5kcmF3SW1hZ2UodGhpcy5jaG9zZW5QbGFuLmZpbGVwYXRoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBUT0RPXHJcbiAgICAgICAgICAgIHRoaXMucGRmVG9DYW52YXMoKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIFVwZGF0ZSBzaXplIG9mIHRoZSBjYW52YXMvbWF0dGVycG9ydCAqL1xyXG4gICAgcmVzaXplVmlldyhzaXplKSB7XHJcbiAgICAgICAgdGhpcy5jYW52YXNEaXYubmF0aXZlRWxlbWVudC5zdHlsZS53aWR0aCA9IGAke3NpemUud31weGA7XHJcbiAgICAgICAgdGhpcy5jYW52YXNEaXYubmF0aXZlRWxlbWVudC5zdHlsZS5oZWlnaHQgPSBgJHtzaXplLmh9cHhgO1xyXG4gICAgICAgIHRoaXMuY2FudmFzLnN0eWxlLndpZHRoID0gYCR7c2l6ZS53fXB4YDtcclxuICAgICAgICB0aGlzLmNhbnZhcy5zdHlsZS5oZWlnaHQgPSBgJHtzaXplLmh9cHhgO1xyXG4gICAgICAgIHRoaXMuY2FudmFzLndpZHRoID0gc2l6ZS53O1xyXG4gICAgICAgIHRoaXMuY2FudmFzLmhlaWdodCA9IHNpemUuaDtcclxuICAgICAgICB0aGlzLmNhbnZhc1NpemUgPSBzaXplO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKiBEcmF3IHNvbWV0aGluZyBvbiB0aGUgY2FudmFzICovXHJcbiAgICBkcmF3SW1hZ2UodXJsOiBzdHJpbmcsIHggPSAwLCB5ID0gMCwgaWNvbmUgPSBmYWxzZSkge1xyXG4gICAgICAgIGNvbnN0IGltYWdlID0gbmV3IEltYWdlKCk7XHJcbiAgICAgICAgY29uc3Qgc2l6ZSA9IHRoaXMuY2FudmFzU2l6ZTtcclxuICAgICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcclxuXHJcbiAgICAgICAgLyoqIEZsaXAgdGhlIGNvbnRleHQsIGZvciBzeW1tZXRyeSAqL1xyXG4gICAgICAgIC8vIGlmICh0aGlzLnJlZmxlY3RWKSB7XHJcbiAgICAgICAgLy8gICAgIGNvbnRleHQudHJhbnNsYXRlKHNpemUudywgMCk7XHJcbiAgICAgICAgLy8gICAgIGNvbnRleHQuc2NhbGUoLTEsIDEpO1xyXG4gICAgICAgIC8vIH1cclxuICAgICAgICAvLyBpZiAodGhpcy5yZWZsZWN0SCkge1xyXG4gICAgICAgIC8vICAgICBjb250ZXh0LnRyYW5zbGF0ZSgwLCBzaXplLmgpO1xyXG4gICAgICAgIC8vICAgICBjb250ZXh0LnNjYWxlKDEsIC0xKTtcclxuICAgICAgICAvLyB9XHJcblxyXG4gICAgICAgIGxldCBpbWFnZVdpZHRoID0gc2l6ZS53O1xyXG4gICAgICAgIGxldCBpbWFnZUhlaWdodCA9IHNpemUuaDtcclxuICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgKCkgPT4ge1xyXG4gICAgICAgICAgICBpZiAoaWNvbmUpIHtcclxuICAgICAgICAgICAgICAgIGltYWdlV2lkdGggPSBpbWFnZS53aWR0aDtcclxuICAgICAgICAgICAgICAgIGltYWdlSGVpZ2h0ID0gaW1hZ2UuaGVpZ2h0O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGNvbnRleHQuZHJhd0ltYWdlKFxyXG4gICAgICAgICAgICAgICAgaW1hZ2UsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIGltYWdlLndpZHRoLFxyXG4gICAgICAgICAgICAgICAgaW1hZ2UuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgICAgeCxcclxuICAgICAgICAgICAgICAgIHksXHJcbiAgICAgICAgICAgICAgICBpbWFnZVdpZHRoLFxyXG4gICAgICAgICAgICAgICAgaW1hZ2VIZWlnaHRcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICB9KTtcclxuICAgICAgICBpbWFnZS5zcmMgPSB1cmw7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIEdldCB0aGUgc2l6ZSBmb3IgdGhlIGNhbnZhcywgYmFzZWQgb24gdGhlIHBsYW4gc2l6ZSwga2VlcGluZyB0aGUgcmF0aW8gKi9cclxuICAgIGdldFNpemVGb3JDYW52YXModywgaCkge1xyXG4gICAgICAgIGxldCBjYW52YXNXID0gdGhpcy5jYW52YXNEaXYubmF0aXZlRWxlbWVudC5vZmZzZXRXaWR0aDtcclxuICAgICAgICBsZXQgY2FudmFzSCA9IHRoaXMuY2FudmFzRGl2Lm5hdGl2ZUVsZW1lbnQub2Zmc2V0SGVpZ2h0O1xyXG5cclxuICAgICAgICBjb25zdCBpbWFnZVJhdGlvID0gdyAvIGg7XHJcbiAgICAgICAgY29uc3QgY2FudmFzUmF0aW8gPSBjYW52YXNXIC8gY2FudmFzSDtcclxuXHJcbiAgICAgICAgaWYgKGltYWdlUmF0aW8gPiBjYW52YXNSYXRpbykge1xyXG4gICAgICAgICAgICBjYW52YXNIID0gY2FudmFzVyAvIGltYWdlUmF0aW87XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgY2FudmFzVyA9IGNhbnZhc0ggKiBpbWFnZVJhdGlvO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4geyB3OiBjYW52YXNXLCBoOiBjYW52YXNIIH07XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIFtUT0RPXSBDb252ZXJ0IGEgUERGIHRvIGEgQ2FudmFzICovXHJcbiAgICBhc3luYyBwZGZUb0NhbnZhcygpIHtcclxuICAgICAgICBjb25zdCBwZGZqcyA9IGF3YWl0IGltcG9ydCgncGRmanMtZGlzdC9idWlsZC9wZGYnKTtcclxuICAgICAgICBjb25zdCBwZGZqc1dvcmtlciA9IGF3YWl0IGltcG9ydCgncGRmanMtZGlzdC9idWlsZC9wZGYud29ya2VyLmVudHJ5Jyk7XHJcblxyXG4gICAgICAgIHBkZmpzLkdsb2JhbFdvcmtlck9wdGlvbnMud29ya2VyU3JjID0gcGRmanNXb3JrZXI7XHJcblxyXG4gICAgICAgIGNvbnN0IHBkZjogUERGRG9jdW1lbnRQcm94eSA9IGF3YWl0IGdldERvY3VtZW50KHRoaXMuY2hvc2VuUGxhbi5maWxlcGF0aClcclxuICAgICAgICAgICAgLnByb21pc2U7XHJcbiAgICAgICAgY29uc3QgcGFnZSA9IGF3YWl0IHBkZi5nZXRQYWdlKDEpO1xyXG5cclxuICAgICAgICBjb25zdCB2aWV3UG9ydFBhcmFtZXRlcnMgPSB7IHNjYWxlOiAxIH07XHJcbiAgICAgICAgY29uc3Qgdmlld3BvcnQgPSBwYWdlLmdldFZpZXdwb3J0KHZpZXdQb3J0UGFyYW1ldGVycyk7XHJcblxyXG4gICAgICAgIHRoaXMuY2FudmFzLmhlaWdodCA9IHZpZXdwb3J0LmhlaWdodDtcclxuICAgICAgICB0aGlzLmNhbnZhcy53aWR0aCA9IHZpZXdwb3J0LndpZHRoO1xyXG5cclxuICAgICAgICBjb25zdCBzaXplID0gdGhpcy5nZXRTaXplRm9yQ2FudmFzKHZpZXdwb3J0LndpZHRoLCB2aWV3cG9ydC5oZWlnaHQpO1xyXG4gICAgICAgIGNvbnNvbGUubG9nKHNpemUpO1xyXG4gICAgICAgIHRoaXMuY2FudmFzU2l6ZSA9IHNpemU7XHJcblxyXG4gICAgICAgIHRoaXMuY2FudmFzWm9vbSA9IHNpemUudyAvIHZpZXdwb3J0LndpZHRoO1xyXG5cclxuICAgICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKSBhcyBDYW52YXNSZW5kZXJpbmdDb250ZXh0MkQ7XHJcbiAgICAgICAgY29uc3QgcmVuZGVyQ29udGV4dCA9IHtcclxuICAgICAgICAgICAgY2FudmFzQ29udGV4dDogY29udGV4dCxcclxuICAgICAgICAgICAgdmlld3BvcnQsXHJcbiAgICAgICAgfTtcclxuICAgICAgICBjb25zdCByZW5kZXJUYXNrID0gcGFnZS5yZW5kZXIocmVuZGVyQ29udGV4dCkucHJvbWlzZTtcclxuXHJcbiAgICAgICAgcmVuZGVyVGFzay50aGVuKCgpID0+IGNvbnNvbGUubG9nKCdQYWdlIHJlbmRlcmVkJykpO1xyXG5cclxuICAgICAgICAvLyBjb25zdCByZXMgPSBjYW52YXMudG9EYXRhVVJMKCk7XHJcbiAgICAgICAgLy8gaWYgKHBkZiAhPSBudWxsKSBwZGYuZGVzdHJveSgpO1xyXG4gICAgICAgIC8vIHJldHVybiByZXM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIFVzZXIgY2xpY2sgdG8gdXNlciBTeW1tZXRyeSBWZXJ0aWNhbCAqL1xyXG4gICAgb25SZWZsZWN0VigpIHtcclxuICAgICAgICB0aGlzLnJlZmxlY3RWID0gIXRoaXMucmVmbGVjdFY7XHJcbiAgICAgICAgdGhpcy5jb25maWd1cmVDYW52YXMoKTtcclxuICAgIH1cclxuXHJcbiAgICAvKiogVXNlciBjbGljayB0byB1c2VyIFN5bW1ldHJ5IEhvcml6b250YWwgKi9cclxuICAgIG9uUmVmbGVjdEgoKSB7XHJcbiAgICAgICAgdGhpcy5yZWZsZWN0SCA9ICF0aGlzLnJlZmxlY3RIO1xyXG4gICAgICAgIHRoaXMuY29uZmlndXJlQ2FudmFzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1BVFRFUlBPUlRcclxuICAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAqL1xyXG5cclxuICAgIC8qKiBMYXVuY2ggbWF0dGVycG9ydCAqL1xyXG4gICAgYXN5bmMgbGF1bmNoVmlld2VyKCkge1xyXG4gICAgICAgIGF3YWl0IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2UuaW5pdFNka0Zvck1vZGVsKHRoaXMuY2hvc2VuUGxhbi5tb2RlbDNkKTtcclxuXHJcbiAgICAgICAgY29uc3QgeyBzZGsgfSA9IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2U7XHJcbiAgICAgICAgdGhpcy5mbG9vcnMgPSBPYmplY3QudmFsdWVzKHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2UuZmxvb3JzKTtcclxuICAgICAgICAvLyBjb25zb2xlLmxvZyh0aGlzLmZsb29ycyk7XHJcbiAgICAgICAgc2V0VGltZW91dChhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgIC8qKiBNb3ZlIEZsb29yIG1vZGUgKi9cclxuICAgICAgICAgICAgc2RrLk1vZGUubW92ZVRvKHNkay5Nb2RlLk1vZGUuRkxPT1JQTEFOKS50aGVuKGFzeW5jIChuZXh0TW9kZSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLyoqIERpc3BsYXkgdGhlIGNvcnJlY3QgZmxvb3IgZm9yIHRoZSBwbGFuICovXHJcbiAgICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1hdHRlcnBvcnRGbG9vciA9IHRoaXMuY2hvc2VuUGxhbi56b25lLm1ldGFkYXRhID9cclxuICAgICAgICAgICAgICAgICAgICAgICAgSlNPTi5wYXJzZSh0aGlzLmNob3NlblBsYW4uem9uZS5tZXRhZGF0YSkubWF0dGVycG9ydEZsb29yU2VxdWVuY2UgOiBudWxsO1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2UubW92ZVRvRmxvb3IodGhpcy5jaG9zZW5QbGFuLnpvbmUubmFtZSwgbWF0dGVycG9ydEZsb29yKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLyoqIFdoZW4gdGhlIHVzZXIgdHJ5IHRvIGNoYW5nZSB0aGUgdmlldyBtb2RlIHdlIHNldCBpdCBiYWNrIHRvIGZsb29ycGFuICovXHJcbiAgICAgICAgICAgICAgICAgICAgc2RrLm9uKHNkay5Nb2RlLkV2ZW50LkNIQU5HRV9FTkQsIChvbGRNb2RlLCBuZXdNb2RlKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuZXdNb2RlICE9PSBzZGsuTW9kZS5Nb2RlLkZMT09SUExBTikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2RrLk1vZGUubW92ZVRvKHNkay5Nb2RlLk1vZGUuRkxPT1JQTEFOLCB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNpdGlvbjogJ3RyYW5zaXRpb24uaW5zdGFudCcsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfSBjYXRjaCB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ2NvdWxkbm90IG1vdmUgdG8gZmxvb3InKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAvKiogV2UgY2FuIGRpc3BsYXkgdGhlIG1hdHRlcnBvcnQgdmlldyBub3cgKi9cclxuICAgICAgICAgICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XHJcbiAgICAgICAgfSwgMTAwMCk7XHJcblxyXG4gICAgICAgIC8qKiBVcGRhdGUgY3VycmVudCBjYW1lcmEgcG9zZSBhbmQgcm90YXRpb24gKi9cclxuICAgICAgICBzZGsuQ2FtZXJhLnBvc2Uuc3Vic2NyaWJlKChldmVudCkgPT4ge1xyXG4gICAgICAgICAgICAvKiogV2UgdXBkYXRlIG9ubHkgaWYgdGhlIHVzZXIgaXMgbm90IGNoYW5naW5nIHRoZSByb3RhdGlvbiB3aXRoIHRoZSA8aW5wdXQ+IHJhbmdlLCB0byBub3Qgb3ZlcnJpZGUgdGhlIDxpbnB1dD4gdmFsdWUgKi9cclxuICAgICAgICAgICAgaWYgKCF0aGlzLmlzUm90YXRpbmdSYW5nZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5yb3RhdGlvbiA9IGV2ZW50LnJvdGF0aW9uLnkgKyAxODA7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnByZXZSb3RhdGlvbiA9IHRoaXMucm90YXRpb247XHJcbiAgICAgICAgICAgICAgICB0aGlzLmNhbWVyYVBvc2UgPSBldmVudDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKiBXaGVuIHRoZSA8aW5wdXQ+IHJhbmdlLCBmb3Igcm90YXRpb24sIGNoYW5nZSAqL1xyXG4gICAgYXN5bmMgb25Sb3RhdGlvbkNoYW5nZSgpIHtcclxuICAgICAgICBjb25zdCByb3RhdGlvbkRlbHRhID0gdGhpcy5yb3RhdGlvbiAtIHRoaXMucHJldlJvdGF0aW9uO1xyXG4gICAgICAgIHRoaXMucHJldlJvdGF0aW9uID0gdGhpcy5yb3RhdGlvbjtcclxuXHJcbiAgICAgICAgLyoqIFNlbmQgdGhlIHJvdGF0aW9uRGVsdGEgdG8gdGggcXVldWUgZXZlbnQgaW4gb3JkZXIgdG8gYmUgc2VuZCB0byBtYXR0ZXJwb3J0ICovXHJcbiAgICAgICAgdGhpcy5yb3RhdGluZ1F1ZXVlRXZlbnQucHVzaChyb3RhdGlvbkRlbHRhKTtcclxuXHJcbiAgICAgICAgLyoqIFN0YXJ0IHRvIHByb2Nlc3MgdGhlIHF1ZXVlLCBpZiBpdCdzIHRoZSBmaXJzdCBldmVudCAqL1xyXG4gICAgICAgIGlmICghdGhpcy5pc1JvdGF0aW5nUmFuZ2UpIHtcclxuICAgICAgICAgICAgdGhpcy5pc1JvdGF0aW5nUmFuZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGlzLnByb2Nlc3NSb3RhdGluZ1F1ZXVlRXZlbnQoKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIFByb2Nlc3MgdGhlIHJvdGF0aW5nIGV2ZW50IHF1ZXVlLCBzZW5kIGV2ZW50IG9uZSBieSBvbmUgdG8gbWF0dGVycG9ydCAgKi9cclxuICAgIGFzeW5jIHByb2Nlc3NSb3RhdGluZ1F1ZXVlRXZlbnQoKSB7XHJcbiAgICAgICAgY29uc3QgeyBzZGsgfSA9IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2U7XHJcblxyXG4gICAgICAgIC8qKiBXaGlsZSB0aGUgcXVldWUgaXMgbm90IGVtcHR5ICovXHJcbiAgICAgICAgd2hpbGUgKHRoaXMucm90YXRpbmdRdWV1ZUV2ZW50Lmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgLyoqIFJvdGF0ZSBtYXR0ZXJwb3J0IGJ5IGRlbHRhUm90YXRpb24gYW5kIHJlbW92ZSBldmVudCBmcm9tIHF1ZXVlICovXHJcbiAgICAgICAgICAgIGF3YWl0IHNkay5DYW1lcmEucm90YXRlKHRoaXMucm90YXRpbmdRdWV1ZUV2ZW50LnNoaWZ0KCksIDAsIHtcclxuICAgICAgICAgICAgICAgIHNwZWVkOiAzNjAsXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLyoqIFdoZW4gdGhlIHF1ZXVlIGlzIGVtcHR5LCB0aGVuIHRoZSB1c2VyIGlzIG5vdCByb3RhdGluZyB3aXRoIHRoZSA8aW5wdXQ+IHJhbmdlIGFueW1vcmUgKi9cclxuICAgICAgICB0aGlzLmlzUm90YXRpbmdSYW5nZSA9IGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBVU0VSIEFDVElPTlNcclxuICAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAqL1xyXG5cclxuICAgIC8qKiBQcmV2aWV3IGNhbGlicmF0aW9uICovXHJcbiAgICBhc3luYyBvblByZXZpZXcoKSB7XHJcbiAgICAgICAgdGhpcy5wcmV2aWV3ID0gdHJ1ZTtcclxuICAgICAgICAvKiogUGxhY2Ugc3dlZXBzICovXHJcbiAgICAgICAgdGhpcy5vblBsYWNlU3dlZXBzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgY2FsaWJyYXRlKCkge1xyXG4gICAgICAgIGNvbnN0IFtuYXZpZ2F0aW9uXSA9IHRoaXMuY3VycmVudE5hdmlnYXRpb25zO1xyXG4gICAgICAgIGNvbnN0IHBvc2l0aW9uID0gSlNPTi5wYXJzZShuYXZpZ2F0aW9uLnBvc2l0aW9uKTtcclxuICAgICAgICB0aGlzLmZpcnN0TWFya1BsYW4gPVxyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLm1hdHRlcnBvcnRJbXBvcnRTZXJ2aWNlLnNkay5SZW5kZXJlci5nZXRTY3JlZW5Qb3NpdGlvbih7XHJcbiAgICAgICAgICAgICAgICB4OiBwb3NpdGlvbi54LFxyXG4gICAgICAgICAgICAgICAgeTogcG9zaXRpb24ueSxcclxuICAgICAgICAgICAgICAgIHo6IHBvc2l0aW9uLnosXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMuc2Vjb25kTWFya1BsYW4gPVxyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLm1hdHRlcnBvcnRJbXBvcnRTZXJ2aWNlLnNkay5SZW5kZXJlci5nZXRTY3JlZW5Qb3NpdGlvbih7XHJcbiAgICAgICAgICAgICAgICB4OiBwb3NpdGlvbi54LFxyXG4gICAgICAgICAgICAgICAgeTogMCxcclxuICAgICAgICAgICAgICAgIHo6IDAsXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIGNvbnN0IGRlbHRhWlZpc2l0ID0gMCAtIHBvc2l0aW9uLno7XHJcbiAgICAgICAgbGV0IGRlbHRhWFBsYW4gPSB0aGlzLnNlY29uZE1hcmtQbGFuLnggLSB0aGlzLmZpcnN0TWFya1BsYW4ueDtcclxuICAgICAgICBpZiAoZGVsdGFYUGxhbiA9PT0gMCkge1xyXG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhcIndlIG1vdmVkIGFsb25nIFkgYXhpcyBvbiBQbGFuXCIpO1xyXG4gICAgICAgICAgICBjb25zdCBkZWx0YVlQbGFuID0gdGhpcy5zZWNvbmRNYXJrUGxhbi55IC0gdGhpcy5maXJzdE1hcmtQbGFuLnk7XHJcbiAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLm5hbWVZQXhpcyA9ICd6JztcclxuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2UubmFtZVhBeGlzID0gJ3gnO1xyXG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5vZmZzZXRZID0gdGhpcy5zZWNvbmRNYXJrUGxhbi55O1xyXG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5zY2FsZVkgPSBkZWx0YVlQbGFuIC8gZGVsdGFaVmlzaXQ7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCIgd2UgbW92ZWQgYWxvbmcgWCBheGlzIG9uIFBsYW5cIik7XHJcbiAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLm5hbWVZQXhpcyA9ICd4JztcclxuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2UubmFtZVhBeGlzID0gJ3onO1xyXG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5vZmZzZXRYID0gdGhpcy5zZWNvbmRNYXJrUGxhbi54O1xyXG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5zY2FsZVggPSBkZWx0YVhQbGFuIC8gZGVsdGFaVmlzaXQ7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHRoaXJkTWFya1BsYW4gPVxyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLm1hdHRlcnBvcnRJbXBvcnRTZXJ2aWNlLnNkay5SZW5kZXJlci5nZXRTY3JlZW5Qb3NpdGlvbih7XHJcbiAgICAgICAgICAgICAgICB4OiAwLFxyXG4gICAgICAgICAgICAgICAgeTogMCxcclxuICAgICAgICAgICAgICAgIHo6IHBvc2l0aW9uLnosXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIGNvbnN0IGRlbHRhWFZpc2l0ID0gMCAtIHBvc2l0aW9uLng7XHJcbiAgICAgICAgaWYgKGRlbHRhWFBsYW4gPT09IDApIHtcclxuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCIgd2UgbW92ZWQgYWxvbmcgWCBheGlzIG9uIFBsYW5cIik7XHJcbiAgICAgICAgICAgIGRlbHRhWFBsYW4gPSB0aGlyZE1hcmtQbGFuLnggLSB0aGlzLmZpcnN0TWFya1BsYW4ueDtcclxuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WCA9IHRoaXJkTWFya1BsYW4ueDtcclxuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uuc2NhbGVYID0gZGVsdGFYUGxhbiAvIGRlbHRhWFZpc2l0O1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGRlbHRhWVBsYW4gPSB0aGlyZE1hcmtQbGFuLnkgLSB0aGlzLmZpcnN0TWFya1BsYW4ueTtcclxuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WSA9IHRoaXJkTWFya1BsYW4ueTtcclxuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uuc2NhbGVZID0gZGVsdGFZUGxhbiAvIGRlbHRhWFZpc2l0O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLyoqIFRha2UgY29uc2lkaXJhdGlvbiBvZiBwYW4gYW5kIHpvb20gb2YgcGxhbiBvbiBjYW52YXMgKi9cclxuICAgICAgICBjb25zdCB0cmFuc2Zvcm1JbmZvID0gdGhpcy5wYW56b29tLmdldFRyYW5zZm9ybSgpO1xyXG4gICAgICAgIGNvbnN0IHsgc2NhbGUsIHgsIHkgfSA9IHRyYW5zZm9ybUluZm87XHJcbiAgICAgICAgLy8gY29uc29sZS5sb2codHJhbnNmb3JtSW5mbyk7XHJcbiAgICAgICAgdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WFBsYW4gPSB4O1xyXG4gICAgICAgIHRoaXMuY2FsaWJyYWdlLm9mZnNldFlQbGFuID0geTtcclxuICAgICAgICB0aGlzLmNhbGlicmFnZS5zY2FsZVBsYW4gPSBzY2FsZTtcclxuICAgICAgICBjb25zb2xlLmxvZyh0aGlzLmNhbGlicmFnZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIFBsYWNlIHN3ZWVwcyAqL1xyXG4gICAgYXN5bmMgb25QbGFjZVN3ZWVwcygpIHtcclxuICAgICAgICAvKiogRGlzcGxheSBhbGwgc2NhbiAqL1xyXG4gICAgICAgIGNvbnN0IHpvbmUgPSBhd2FpdCB0aGlzLnpvbmVTZXJ2aWNlLmdldFpvbmUodGhpcy5jaG9zZW5QbGFuLnpvbmVJRCk7XHJcblxyXG4gICAgICAgIGlmICh6b25lKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFpvbmUgPSB6b25lO1xyXG4gICAgICAgICAgICBjb25zdCBuYXZpZ2F0aW9ucyA9IGF3YWl0IHRoaXMubmF2aWdhdGlvblNlcnZpY2UuZ2V0TmF2aWdhdGlvbnNGb3Jab25lKFxyXG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50Wm9uZVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnROYXZpZ2F0aW9ucyA9IG5hdmlnYXRpb25zO1xyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLmNhbGlicmF0ZSgpO1xyXG4gICAgICAgICAgICBpZiAobmF2aWdhdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBuYXZpZ2F0aW9uIG9mIG5hdmlnYXRpb25zKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGVzdFBvc2l0aW9uID0gSlNPTi5wYXJzZShuYXZpZ2F0aW9uLnBvc2l0aW9uKTtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBwb3NpdGlvblggPVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5uYW1lWEF4aXMgPT09ICd4JyA/IHRlc3RQb3NpdGlvbi54IDogdGVzdFBvc2l0aW9uLno7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcG9zaXRpb25ZID1cclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2UubmFtZVlBeGlzID09PSAneCcgPyB0ZXN0UG9zaXRpb24ueCA6IHRlc3RQb3NpdGlvbi56O1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRlc3RYID1cclxuICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb25YICogdGhpcy5jYWxpYnJhZ2Uuc2NhbGVYICsgdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WDtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCB0ZXN0WSA9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uWSAqIHRoaXMuY2FsaWJyYWdlLnNjYWxlWSArIHRoaXMuY2FsaWJyYWdlLm9mZnNldFk7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCJ0ZXN0IHBvc2l0aW9uIEdSRUVOXCIsIHRlc3RYLCB0ZXN0WSk7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdHJhbnNmb3JtZWRYID1cclxuICAgICAgICAgICAgICAgICAgICAgICAgKHRlc3RYIC0gdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WFBsYW4pIC8gdGhpcy5jYWxpYnJhZ2Uuc2NhbGVQbGFuOyAvLyB3ZSBhcmUgdW5kb2luZyB0aGUgcGFuIGFuZCB6b29tXHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdHJhbnNmb3JtZWRZID1cclxuICAgICAgICAgICAgICAgICAgICAgICAgKHRlc3RZIC0gdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WVBsYW4pIC8gdGhpcy5jYWxpYnJhZ2Uuc2NhbGVQbGFuO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucG9zaXRpb25zLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBuYXZJRDogbmF2aWdhdGlvbi5pZCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgcGxhbklEOiB0aGlzLmNob3NlblBsYW4uaWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHg6IHRyYW5zZm9ybWVkWCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgeTogdHJhbnNmb3JtZWRZLFxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGljb25TaXplID0gMzAgKiB0aGlzLmNhbGlicmFnZS5zY2FsZVBsYW47XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2hpZnQgPSBpY29uU2l6ZSAvIDI7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kcmF3SW1hZ2UoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICdodHRwczovL2FwaS5pY29uaWZ5LmRlc2lnbi9tZGk6YWRqdXN0LnN2Zz9jb2xvcj1ncmVlbiZoZWlnaHQ9MzAmd2lkdGg9MzAnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm1lZFggLSBzaGlmdCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtZWRZIC0gc2hpZnQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKiBTYXZlIGNhbGlicmF0aW9uICovXHJcbiAgICBhc3luYyBvblNhdmUoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFpvbmUpIHtcclxuICAgICAgICAgICAgLyoqIE5vcm1hbGl6ZSB3aXRoIHRoZSB6b29tICovXHJcbiAgICAgICAgICAgIC8vIHRoaXMuY2FsaWJyYWdlLm9mZnNldFggLz0gdGhpcy5jYW52YXNab29tO1xyXG4gICAgICAgICAgICAvLyB0aGlzLmNhbGlicmFnZS5vZmZzZXRZIC89IHRoaXMuY2FudmFzWm9vbTtcclxuICAgICAgICAgICAgLy8gdGhpcy5jYWxpYnJhZ2UueCAvPSB0aGlzLmNhbnZhc1pvb207XHJcbiAgICAgICAgICAgIC8vIHRoaXMuY2FsaWJyYWdlLnkgLz0gdGhpcy5jYW52YXNab29tO1xyXG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5uZXcgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5pbWdXaWR0aCA9IHRoaXMuY2FudmFzU2l6ZS53O1xyXG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5pbWdIZWlnaHQgPSB0aGlzLmNhbnZhc1NpemUuaDtcclxuXHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGxhblNlcnZpY2UudXBkYXRlUGxhbih7XHJcbiAgICAgICAgICAgICAgICBpZDogdGhpcy5jaG9zZW5QbGFuLmlkLFxyXG4gICAgICAgICAgICAgICAgY2FsaWJyYXRpb246IEpTT04uc3RyaW5naWZ5KHRoaXMuY2FsaWJyYWdlKSxcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxyXG4gICAgICAgICAgICAgICAgdGhpcy5wb3NpdGlvbnMubWFwKGFzeW5jIChwb3NpdGlvbikgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHsgbmF2SUQgfSA9IHBvc2l0aW9uO1xyXG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBwb3NpdGlvbi5uYXZJRDtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBuYXYgPSB0aGlzLmN1cnJlbnROYXZpZ2F0aW9ucy5maW5kKChfbmF2KSA9PiBfbmF2LmlkID09PSBuYXZJRCk7XHJcbiAgICAgICAgICAgICAgICAgICAgbGV0IHBvc2l0aW9uc0RhdGFUb1VwZGF0ZTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAobmF2LnBvc2l0aW9uT25QbGFuKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uT25QbGFuID0gbmF2LnBvc2l0aW9uT25QbGFuLm1hcCgoZW50cnkpID0+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBKU09OLnBhcnNlKGVudHJ5KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwb3NpdGlvbkZvckN1cnJlbnRQbGFuID0gcG9zaXRpb25PblBsYW4uZmluZChcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChlbnRyeSkgPT4gZW50cnkucGxhbklEID09PSB0aGlzLmNob3NlblBsYW4uaWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBvc2l0aW9uRm9yQ3VycmVudFBsYW4pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uT25QbGFuLnNwbGljZShcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbk9uUGxhbi5pbmRleE9mKHBvc2l0aW9uRm9yQ3VycmVudFBsYW4pLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb25cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbk9uUGxhbi5wdXNoKHBvc2l0aW9uKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbnNEYXRhVG9VcGRhdGUgPSBbLi4ucG9zaXRpb25PblBsYW5dO1xyXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uc0RhdGFUb1VwZGF0ZSA9IFtwb3NpdGlvbl07XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKHBvc2l0aW9uc0RhdGFUb1VwZGF0ZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5uYXZpZ2F0aW9uU2VydmljZS51cGRhdGVOYXZpZ2F0aW9uKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IG5hdklELFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbk9uUGxhbjogcG9zaXRpb25zRGF0YVRvVXBkYXRlLm1hcCgoZW50cnkpID0+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShlbnRyeSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2UucmVtb3ZlRnJhbWUoKTtcclxuXHJcbiAgICAgICAgdGhpcy5yb3V0ZXIubmF2aWdhdGUoWycvZGFzaGJvYXJkL2xvY2FsaXNhdGlvbicsIHRoaXMuc3BhY2VJRCwgJ3BsYW5zJ10pO1xyXG4gICAgICAgIGFsZXJ0KHRoaXMudHJhbnNsYXRlLmluc3RhbnQoJ2NhbGlicmF0aW9uLnN1Y2Nlc3MnKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIFJlc2V0IHRoZSBjYW52YXMgKi9cclxuICAgIG9uUmVzZXQoKSB7XHJcbiAgICAgICAgdGhpcy5yZWZsZWN0SCA9IGZhbHNlO1xyXG4gICAgICAgIHRoaXMucmVmbGVjdFYgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLnByZXZpZXcgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgdGhpcy5jb25maWd1cmVDYW52YXMoKTtcclxuICAgIH1cclxuXHJcbiAgICAvKiogQ2FuY2VsLCBsZWF2ZSAqL1xyXG4gICAgb25DYW5jZWwoKSB7XHJcbiAgICAgICAgdGhpcy5tYXR0ZXJwb3J0SW1wb3J0U2VydmljZS5yZW1vdmVGcmFtZSgpO1xyXG4gICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFsnL2Rhc2hib2FyZC9sb2NhbGlzYXRpb24nLCB0aGlzLnNwYWNlSUQsICdwbGFucyddKTtcclxuICAgICAgICBhbGVydCh0aGlzLnRyYW5zbGF0ZS5pbnN0YW50KCdjYWxpYnJhdGlvbi5jYW5jZWxlZCcpKTtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvbkZsb29yQ2xpY2soZmxvb3IpIHtcclxuICAgICAgICB0aGlzLmN1cnJlbnRGbG9vciA9IGZsb29yO1xyXG4gICAgICAgIGF3YWl0IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2UubW92ZVRvRmxvb3IoZmxvb3IuaWQpO1xyXG4gICAgfVxyXG5cclxuICAgIG9uQWN0aXZhdGVab29tQ2hhbmdlKCkge1xyXG4gICAgICAgIHRoaXMuem9vbUNhbkJlQ2hhbmdlZCA9ICF0aGlzLnpvb21DYW5CZUNoYW5nZWQ7XHJcbiAgICAgICAgY29uc3QgaWZyYW1lID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3ZpZXdlci1mcmFtZScpIGFzIEhUTUxFbGVtZW50O1xyXG4gICAgICAgIGlmIChpZnJhbWUpIHtcclxuICAgICAgICAgICAgaWZyYW1lLnN0eWxlLnpJbmRleCA9IHRoaXMuem9vbUNhbkJlQ2hhbmdlZCA/ICcxJyA6ICcwJztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxuIiwiPGRpdiBjbGFzcz1cInJvdyBtdC0zXCI+XHJcbiAgICA8ZGl2IGNsYXNzPVwiY29sXCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cIm0tM1wiPlxyXG4gICAgICAgICAgICA8bGliLXRhYi1uYXZpZ2F0aW9uIFttZW51SXRlbXNdPSdtZW51SXRlbXMnPjwvbGliLXRhYi1uYXZpZ2F0aW9uPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbjwvZGl2PlxyXG5cclxuPGRpdiBpZD1cInJvd0NhbnZhc1wiPlxyXG4gICAgPGRpdiAjY2FudmFzRGl2IGlkPVwiY2FudmFzRGl2XCI+XHJcblxyXG4gICAgICAgIDxkaXYgaWQ9XCJ2aWV3ZXItZnJhbWVcIiBbc3R5bGUucG9pbnRlci1ldmVudHNdPVwiem9vbUNhbkJlQ2hhbmdlZD8nYXV0byc6J25vbmUnXCI+XHJcbiAgICAgICAgICAgIDwhLS0gPGRpdiBjbGFzcz1cImJsdXJcIj48L2Rpdj4gLS0+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPGNhbnZhcyBpZD1cImNhbnZhc1wiIFtuZ1N0eWxlXT1cInsnb3BhY2l0eSc6IChwcmV2aWV3fHxsb2FkaW5nKSA/ICcxJyA6ICdjYWxjKCcgKyBvcGFjaXR5ICsgJy8gMTAwKSd9XCI+PC9jYW52YXM+XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgICA8ZGl2IGNsYXNzPVwiY2FsaWJyYXRpb24tdG9vbHMgY29udGFpbmVyLWZsdWlkXCIgKm5nSWY9XCIhKHByZXZpZXcgfHwgbG9hZGluZylcIj5cclxuICAgICAgICA8aDE+e3snQ2FsaWJyYXRpb24gdG9vbCcgfCB0cmFuc2xhdGV9fTwvaDE+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInRvb2xcIj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInJvdyBtcy0wIG1lLTAgbGVnZW5kXCI+XHJcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibGVnZW5kLWJhci1pbmRpY2F0b3JcIiBbbmdTdHlsZV09XCJ7J29wYWNpdHknOiAnY2FsYygnICsgKC0ob3BhY2l0eS0xMDApKzEwKSArICcvIDEwMCknfVwiPlxyXG4gICAgICAgICAgICAgICAgICAgIHt7J0xlc3MnIHwgdHJhbnNsYXRlfX08L2Rpdj5cclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJsZWdlbmQtdGl0bGVcIj57eydQbGFuIE9wYWNpdHknIHwgdHJhbnNsYXRlIH19PC9kaXY+XHJcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibGVnZW5kLWJhci1pbmRpY2F0b3JcIiBbbmdTdHlsZV09XCJ7J29wYWNpdHknOiAnY2FsYygnICsgKG9wYWNpdHkrMTApICsgJy8gMTAwKSd9XCI+e3snTW9yZScgfFxyXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19PC9kaXY+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwicm93IG1zLTAgbWUtMCBcIj5cclxuICAgICAgICAgICAgICAgIDxpbnB1dCBbZGlzYWJsZWRdPVwiZmFsc2VcIiBbbmdNb2RlbE9wdGlvbnNdPVwie3N0YW5kYWxvbmU6IHRydWV9XCIgWyhuZ01vZGVsKV09XCJvcGFjaXR5XCIgdHlwZT1cInJhbmdlXCJcclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tcmFuZ2VcIiBtaW49XCIwXCIgbWF4PVwiMTAwXCIgdmFsdWU9XCI1MFwiIGlkPVwib3BhY2l0eVwiPlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwidG9vbFwiPlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwicm93IG1zLTAgbWUtMCBcIj5cclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJsYWJlbC1sZWdlbmRcIj57eydDaGFuZ2UgVmlzaXQgRmxvb3InIHwgdHJhbnNsYXRlfX08L2Rpdj5cclxuICAgICAgICAgICAgICAgIDxkaXYgbmdiRHJvcGRvd24gY2xhc3M9XCJkLWlubGluZS1ibG9jayBtcy0zXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tbGFiZWwtZmlsZSByb3VuZGVkLXBpbGxcIiBpZD1cImRyb3Bkb3duQmFzaWMxXCIgbmdiRHJvcGRvd25Ub2dnbGU+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHt7Y3VycmVudEZsb29yID8gY3VycmVudEZsb29yLmlkIDogKCdGbG9vcicgfCB0cmFuc2xhdGUpIH19PC9idXR0b24+XHJcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBuZ2JEcm9wZG93bk1lbnUgYXJpYS1sYWJlbGxlZGJ5PVwiZHJvcGRvd25CYXNpYzFcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPGJ1dHRvbiBuZ2JEcm9wZG93bkl0ZW0gKm5nRm9yPVwibGV0IGZsb29yIG9mIGZsb29yc1wiIChjbGljayk9XCJvbkZsb29yQ2xpY2soZmxvb3IpXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7eyBmbG9vci5uYW1lLmxlbmd0aCA+IDAgPyBmbG9vci5uYW1lIDogKCdGbG9vciAnICsgZmxvb3IuaWQpIH19XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwidG9vbFwiPlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwicm93IG1zLTAgbWUtMCBcIj5cclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0b29sLWNoZWNrYm94LWNvbnRhaW5lclwiPlxyXG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0b29sLWNoZWNrYm94LXN1YmNvbnRhaW5lclwiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibGFiZWwtbGVnZW5kIG1lLTNcIj57eydQYW4vWm9vbSBWaXNpdCcgfCB0cmFuc2xhdGV9fSB7e3pvb21DYW5CZUNoYW5nZWQgPyBcIk9OXCIgOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJPRkZcIn19XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgKGNoYW5nZSk9XCJvbkFjdGl2YXRlWm9vbUNoYW5nZSgpXCIgc3R5bGU9XCJtYXJnaW4tdG9wOiA1cHg7XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQgYm9yZGVyLXdhcm5pbmcgbWItMyBtdC0zXCIgKm5nSWY9XCJ6b29tQ2FuQmVDaGFuZ2VkXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWJvZHkgdGV4dC13YXJuaW5nXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8aDUgY2xhc3M9XCJjYXJkLXRpdGxlXCI+e3tcImNhbGlicmF0aW9uLndhaXQtbWVzc2FnZVwiIHwgdHJhbnNsYXRlfX08L2g1PlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImFjdGlvblwiPlxyXG4gICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0biBidG4tb3V0bGluZS1wcmltYXJ5IHJvdW5kZWQtcGlsbFwiIChjbGljayk9XCJvblByZXZpZXcoKVwiXHJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiem9vbUNhbkJlQ2hhbmdlZFwiPnt7J1ByZXZpZXcnIHwgdHJhbnNsYXRlfX08L2J1dHRvbj5cclxuICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLW91dGxpbmUtcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25DYW5jZWwoKVwiPnt7J0NhbmNlbCcgfFxyXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlfX08L2J1dHRvbj5cclxuXHJcbiAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgPC9kaXY+XHJcbiAgICA8ZGl2IGNsYXNzPVwiY2FsaWJyYXRpb24tdG9vbHMgY29udGFpbmVyLWZsdWlkXCIgKm5nSWY9XCJwcmV2aWV3XCI+XHJcbiAgICAgICAgPGgxPnt7J1ZhbGlkYXRpb24nIHwgdHJhbnNsYXRlfX08L2gxPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJhY3Rpb25cIj5cclxuICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLW91dGxpbmUtcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25TYXZlKClcIj57eydWYWxpZGF0ZScgfFxyXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlfX08L2J1dHRvbj5cclxuICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLW91dGxpbmUtcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25SZXNldCgpXCI+e3snUmVzZXQnIHxcclxuICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19PC9idXR0b24+XHJcbiAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1vdXRsaW5lLXByaW1hcnkgcm91bmRlZC1waWxsXCIgKGNsaWNrKT1cIm9uQ2FuY2VsKClcIj57eydDYW5jZWwnIHxcclxuICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19PC9idXR0b24+XHJcblxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcblxyXG5cclxuICAgIDxkaXYgY2xhc3M9XCJjYWxpYnJhdGlvbi10b29scyBjb250YWluZXItZmx1aWRcIiAqbmdJZj1cImxvYWRpbmdcIj5cclxuICAgICAgICA8aDM+e3tcIldhaXRpbmcgZm9yIE1hdHRlcnBvcnRcIiB8IHRyYW5zbGF0ZX19Li4uPC9oMz5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGp1c3RpZnktY29udGVudC1jZW50ZXJcIj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNwaW5uZXItYm9yZGVyXCIgcm9sZT1cInN0YXR1c1wiPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ2aXN1YWxseS1oaWRkZW5cIj5Mb2FkaW5nLi4uPC9zcGFuPlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICA8L2Rpdj5cclxuPC9kaXY+Il19