@smarterplan/ngx-smarterplan-locations 0.2.44 → 0.2.45

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