@smarterplan/ngx-smarterplan-locations 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/esm2020/lib/components/carousel/carousel.component.mjs +28 -0
- package/esm2020/lib/components/chevron/chevron.component.mjs +18 -0
- package/esm2020/lib/components/detail-location/detail-location.component.mjs +154 -0
- package/esm2020/lib/components/form-location/form-location.component.mjs +215 -0
- package/esm2020/lib/components/images/images.component.mjs +91 -0
- package/esm2020/lib/components/locations/locations.component.mjs +138 -0
- package/esm2020/lib/components/locations/map/map-popup/map-popup.component.mjs +66 -0
- package/esm2020/lib/components/locations/map/map.component.mjs +91 -0
- package/esm2020/lib/components/plans/calibration/calibration.component.mjs +484 -0
- package/esm2020/lib/components/plans/edit-plan/edit-plan.component.mjs +314 -0
- package/esm2020/lib/components/plans/plans.component.mjs +211 -0
- package/esm2020/lib/components/tab-navigation/tab-navigation.component.mjs +40 -0
- package/esm2020/lib/components/visits/visits.component.mjs +227 -0
- package/esm2020/lib/components/zones/add-zone/add-zone.component.mjs +592 -0
- package/esm2020/lib/components/zones/add-zone/selection/selection.component.mjs +77 -0
- package/esm2020/lib/components/zones/zones.component.mjs +214 -0
- package/esm2020/lib/helper.service.mjs +2 -0
- package/esm2020/lib/ngx-smarterplan-location-routing.module.mjs +49 -0
- package/esm2020/lib/ngx-smarterplan-locations.module.mjs +107 -0
- package/esm2020/lib/ngx-smarterplan-locations.service.mjs +14 -0
- package/esm2020/public-api.mjs +6 -0
- package/esm2020/smarterplan-ngx-smarterplan-locations.mjs +5 -0
- package/fesm2015/smarterplan-ngx-smarterplan-locations.mjs +3126 -0
- package/fesm2015/smarterplan-ngx-smarterplan-locations.mjs.map +1 -0
- package/fesm2020/smarterplan-ngx-smarterplan-locations.mjs +2987 -0
- package/fesm2020/smarterplan-ngx-smarterplan-locations.mjs.map +1 -0
- package/lib/components/carousel/carousel.component.d.ts +12 -0
- package/lib/components/chevron/chevron.component.d.ts +9 -0
- package/lib/components/detail-location/detail-location.component.d.ts +51 -0
- package/lib/components/form-location/form-location.component.d.ts +40 -0
- package/lib/components/images/images.component.d.ts +28 -0
- package/lib/components/locations/locations.component.d.ts +49 -0
- package/lib/components/locations/map/map-popup/map-popup.component.d.ts +22 -0
- package/lib/components/locations/map/map.component.d.ts +22 -0
- package/lib/components/plans/calibration/calibration.component.d.ts +140 -0
- package/lib/components/plans/edit-plan/edit-plan.component.d.ts +54 -0
- package/lib/components/plans/plans.component.d.ts +59 -0
- package/lib/components/tab-navigation/tab-navigation.component.d.ts +13 -0
- package/lib/components/visits/visits.component.d.ts +51 -0
- package/lib/components/zones/add-zone/add-zone.component.d.ts +154 -0
- package/lib/components/zones/add-zone/selection/selection.component.d.ts +44 -0
- package/lib/components/zones/zones.component.d.ts +66 -0
- package/lib/helper.service.d.ts +6 -0
- package/lib/ngx-smarterplan-location-routing.module.d.ts +7 -0
- package/lib/ngx-smarterplan-locations.module.d.ts +31 -0
- package/lib/ngx-smarterplan-locations.service.d.ts +6 -0
- package/package.json +39 -0
- package/public-api.d.ts +2 -0
- package/smarterplan-ngx-smarterplan-locations.d.ts +5 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { Component, ViewChild } from '@angular/core';
|
|
2
|
+
import { getDocument } from "pdfjs-dist";
|
|
3
|
+
import { getMetaForImage } from 'ngx-smarterplan-core';
|
|
4
|
+
import panzoom from 'panzoom';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "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([
|
|
89
|
+
"/dashboard/localisation",
|
|
90
|
+
this.spaceID,
|
|
91
|
+
"plans",
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** **********************************************************************************************
|
|
96
|
+
* MENU NAV BAR
|
|
97
|
+
*********************************************************************************************** */
|
|
98
|
+
setupMenuItems() {
|
|
99
|
+
this.menuItems = [
|
|
100
|
+
{ label: "Locations", url: "/localisation" },
|
|
101
|
+
{
|
|
102
|
+
label: this.currentSpace.name,
|
|
103
|
+
url: `/localisation/${this.spaceID}`,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
label: "Plans",
|
|
107
|
+
url: `/localisation/${this.currentSpace.id}/plans`,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
label: "Calibration",
|
|
111
|
+
url: `/localisation/${this.currentSpace.id}/plan-calibration?spaceID=${this.currentSpace.id}`,
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
/** **********************************************************************************************
|
|
116
|
+
* CANVAS
|
|
117
|
+
*********************************************************************************************** */
|
|
118
|
+
/** Display the plan */
|
|
119
|
+
async configureCanvas() {
|
|
120
|
+
/** Get canvas */
|
|
121
|
+
if (!this.canvas) {
|
|
122
|
+
const canvas = document.querySelector("#canvas");
|
|
123
|
+
this.canvas = canvas;
|
|
124
|
+
}
|
|
125
|
+
if (!this.chosenPlanIsPdf) {
|
|
126
|
+
const image = await getMetaForImage(this.chosenPlan.filepath);
|
|
127
|
+
/** Compute the new size for the canvas/matterport, base on the dimension of the plan, keeping the ratio */
|
|
128
|
+
const size = this.getSizeForCanvas(image.width, image.height);
|
|
129
|
+
/** Compute the plan zoom ratio (use for the calibration later) */
|
|
130
|
+
this.canvasZoom = size.w / image.width;
|
|
131
|
+
this.resizeView(size);
|
|
132
|
+
/** Draw Plan on the canvas */
|
|
133
|
+
this.drawImage(this.chosenPlan.filepath);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// TODO
|
|
137
|
+
this.pdfToCanvas();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** Update size of the canvas/matterport */
|
|
141
|
+
resizeView(size) {
|
|
142
|
+
this.canvasDiv.nativeElement.style.width = `${size.w}px`;
|
|
143
|
+
this.canvasDiv.nativeElement.style.height = `${size.h}px`;
|
|
144
|
+
this.canvas.style.width = `${size.w}px`;
|
|
145
|
+
this.canvas.style.height = `${size.h}px`;
|
|
146
|
+
this.canvas.width = size.w;
|
|
147
|
+
this.canvas.height = size.h;
|
|
148
|
+
this.canvasSize = size;
|
|
149
|
+
}
|
|
150
|
+
/** Draw something on the canvas */
|
|
151
|
+
drawImage(url, x = 0, y = 0, icone = false) {
|
|
152
|
+
const image = new Image();
|
|
153
|
+
const size = this.canvasSize;
|
|
154
|
+
const context = this.canvas.getContext("2d");
|
|
155
|
+
/** Flip the context, for symmetry */
|
|
156
|
+
// if (this.reflectV) {
|
|
157
|
+
// context.translate(size.w, 0);
|
|
158
|
+
// context.scale(-1, 1);
|
|
159
|
+
// }
|
|
160
|
+
// if (this.reflectH) {
|
|
161
|
+
// context.translate(0, size.h);
|
|
162
|
+
// context.scale(1, -1);
|
|
163
|
+
// }
|
|
164
|
+
let imageWidth = size.w;
|
|
165
|
+
let imageHeight = size.h;
|
|
166
|
+
image.addEventListener("load", () => {
|
|
167
|
+
if (icone) {
|
|
168
|
+
imageWidth = image.width;
|
|
169
|
+
imageHeight = image.height;
|
|
170
|
+
}
|
|
171
|
+
context.drawImage(image, 0, 0, image.width, image.height, x, y, imageWidth, imageHeight);
|
|
172
|
+
});
|
|
173
|
+
image.src = url;
|
|
174
|
+
}
|
|
175
|
+
/** Get the size for the canvas, based on the plan size, keeping the ratio */
|
|
176
|
+
getSizeForCanvas(w, h) {
|
|
177
|
+
let canvasW = this.canvasDiv.nativeElement.offsetWidth;
|
|
178
|
+
let canvasH = this.canvasDiv.nativeElement.offsetHeight;
|
|
179
|
+
const imageRatio = w / h;
|
|
180
|
+
const canvasRatio = canvasW / canvasH;
|
|
181
|
+
if (imageRatio > canvasRatio) {
|
|
182
|
+
canvasH = canvasW / imageRatio;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
canvasW = canvasH * imageRatio;
|
|
186
|
+
}
|
|
187
|
+
return { w: canvasW, h: canvasH };
|
|
188
|
+
}
|
|
189
|
+
/** [TODO] Convert a PDF to a Canvas */
|
|
190
|
+
async pdfToCanvas() {
|
|
191
|
+
const pdfjs = await import("pdfjs-dist/build/pdf");
|
|
192
|
+
const pdfjsWorker = await import("pdfjs-dist/build/pdf.worker.entry");
|
|
193
|
+
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
|
194
|
+
const pdf = await getDocument(this.chosenPlan.filepath).promise;
|
|
195
|
+
const page = await pdf.getPage(1);
|
|
196
|
+
const viewPortParameters = { scale: 1 };
|
|
197
|
+
const viewport = page.getViewport(viewPortParameters);
|
|
198
|
+
this.canvas.height = viewport.height;
|
|
199
|
+
this.canvas.width = viewport.width;
|
|
200
|
+
const size = this.getSizeForCanvas(viewport.width, viewport.height);
|
|
201
|
+
console.log(size);
|
|
202
|
+
this.canvasSize = size;
|
|
203
|
+
this.canvasZoom = size.w / viewport.width;
|
|
204
|
+
const context = this.canvas.getContext("2d");
|
|
205
|
+
const renderContext = {
|
|
206
|
+
canvasContext: context,
|
|
207
|
+
viewport,
|
|
208
|
+
};
|
|
209
|
+
const renderTask = page.render(renderContext).promise;
|
|
210
|
+
renderTask.then(() => console.log("Page rendered"));
|
|
211
|
+
// const res = canvas.toDataURL();
|
|
212
|
+
// if (pdf != null) pdf.destroy();
|
|
213
|
+
// return res;
|
|
214
|
+
}
|
|
215
|
+
/** User click to user Symmetry Vertical */
|
|
216
|
+
onReflectV() {
|
|
217
|
+
this.reflectV = !this.reflectV;
|
|
218
|
+
this.configureCanvas();
|
|
219
|
+
}
|
|
220
|
+
/** User click to user Symmetry Horizontal */
|
|
221
|
+
onReflectH() {
|
|
222
|
+
this.reflectH = !this.reflectH;
|
|
223
|
+
this.configureCanvas();
|
|
224
|
+
}
|
|
225
|
+
/** **********************************************************************************************
|
|
226
|
+
* MATTERPORT
|
|
227
|
+
*********************************************************************************************** */
|
|
228
|
+
/** Launch matterport */
|
|
229
|
+
async launchViewer() {
|
|
230
|
+
await this.matterportImportService.initSdkForModel(this.chosenPlan.model3d);
|
|
231
|
+
const { sdk } = this.matterportImportService;
|
|
232
|
+
this.floors = Object.values(this.matterportImportService.floors);
|
|
233
|
+
// console.log(this.floors);
|
|
234
|
+
setTimeout(async () => {
|
|
235
|
+
/** Move Floor mode */
|
|
236
|
+
await sdk.Mode.moveTo(sdk.Mode.Mode.FLOORPLAN);
|
|
237
|
+
/** Display the correct floor for the plan */
|
|
238
|
+
try {
|
|
239
|
+
await this.matterportImportService.moveToFloor(this.chosenPlan.name);
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
console.log("couldnot move to floor");
|
|
243
|
+
}
|
|
244
|
+
/** We can display the matterport view now */
|
|
245
|
+
this.loading = false;
|
|
246
|
+
}, 300);
|
|
247
|
+
/** When the user try to change the view mode we set it back to floorpan */
|
|
248
|
+
sdk.on(sdk.Mode.Event.CHANGE_END, (oldMode, newMode) => {
|
|
249
|
+
if (newMode !== sdk.Mode.Mode.FLOORPLAN) {
|
|
250
|
+
sdk.Mode.moveTo(sdk.Mode.Mode.FLOORPLAN, {
|
|
251
|
+
transition: "transition.instant",
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
});
|
|
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"
|
|
370
|
+
? testPosition.x
|
|
371
|
+
: testPosition.z;
|
|
372
|
+
const positionY = this.calibrage.nameYAxis === "x"
|
|
373
|
+
? testPosition.x
|
|
374
|
+
: testPosition.z;
|
|
375
|
+
const testX = positionX * this.calibrage.scaleX +
|
|
376
|
+
this.calibrage.offsetX;
|
|
377
|
+
const testY = positionY * this.calibrage.scaleY +
|
|
378
|
+
this.calibrage.offsetY;
|
|
379
|
+
// console.log("test position GREEN", testX, testY);
|
|
380
|
+
const transformedX = (testX - this.calibrage.offsetXPlan) /
|
|
381
|
+
this.calibrage.scalePlan; // we are undoing the pan and zoom
|
|
382
|
+
const transformedY = (testY - this.calibrage.offsetYPlan) /
|
|
383
|
+
this.calibrage.scalePlan;
|
|
384
|
+
this.positions.push({
|
|
385
|
+
navID: navigation.id,
|
|
386
|
+
planID: this.chosenPlan.id,
|
|
387
|
+
x: transformedX,
|
|
388
|
+
y: transformedY,
|
|
389
|
+
});
|
|
390
|
+
const iconSize = 30 * this.calibrage.scalePlan;
|
|
391
|
+
const shift = iconSize / 2;
|
|
392
|
+
this.drawImage("https://api.iconify.design/mdi:adjust.svg?color=green&height=30&width=30", transformedX - shift, transformedY - shift, true);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/** Save calibration */
|
|
398
|
+
async onSave() {
|
|
399
|
+
if (this.currentZone) {
|
|
400
|
+
/** Normalize with the zoom */
|
|
401
|
+
// this.calibrage.offsetX /= this.canvasZoom;
|
|
402
|
+
// this.calibrage.offsetY /= this.canvasZoom;
|
|
403
|
+
// this.calibrage.x /= this.canvasZoom;
|
|
404
|
+
// this.calibrage.y /= this.canvasZoom;
|
|
405
|
+
this.calibrage.new = true;
|
|
406
|
+
this.calibrage.imgWidth = this.canvasSize.w;
|
|
407
|
+
this.calibrage.imgHeight = this.canvasSize.h;
|
|
408
|
+
await this.planService.updatePlan({
|
|
409
|
+
id: this.chosenPlan.id,
|
|
410
|
+
calibration: JSON.stringify(this.calibrage),
|
|
411
|
+
});
|
|
412
|
+
await Promise.all(this.positions.map(async (position) => {
|
|
413
|
+
const { navID } = position;
|
|
414
|
+
delete position.navID;
|
|
415
|
+
const nav = this.currentNavigations.find((_nav) => _nav.id === navID);
|
|
416
|
+
let positionsDataToUpdate;
|
|
417
|
+
if (nav.positionOnPlan) {
|
|
418
|
+
const positionOnPlan = nav.positionOnPlan.map((entry) => JSON.parse(entry));
|
|
419
|
+
const positionForCurrentPlan = positionOnPlan.find((entry) => entry.planID === this.chosenPlan.id);
|
|
420
|
+
if (positionForCurrentPlan) {
|
|
421
|
+
positionOnPlan.splice(positionOnPlan.indexOf(positionForCurrentPlan), 1, position);
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
positionOnPlan.push(position);
|
|
425
|
+
}
|
|
426
|
+
positionsDataToUpdate = [...positionOnPlan];
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
positionsDataToUpdate = [position];
|
|
430
|
+
}
|
|
431
|
+
// console.log(positionsDataToUpdate);
|
|
432
|
+
await this.navigationService.updateNavigation({
|
|
433
|
+
id: navID,
|
|
434
|
+
positionOnPlan: positionsDataToUpdate.map((entry) => JSON.stringify(entry)),
|
|
435
|
+
});
|
|
436
|
+
}));
|
|
437
|
+
}
|
|
438
|
+
this.matterportImportService.removeFrame();
|
|
439
|
+
this.router.navigate([
|
|
440
|
+
"/dashboard/localisation",
|
|
441
|
+
this.spaceID,
|
|
442
|
+
"plans",
|
|
443
|
+
]);
|
|
444
|
+
alert(this.translate.instant("calibration.success"));
|
|
445
|
+
}
|
|
446
|
+
/** Reset the canvas */
|
|
447
|
+
onReset() {
|
|
448
|
+
this.reflectH = false;
|
|
449
|
+
this.reflectV = false;
|
|
450
|
+
this.preview = false;
|
|
451
|
+
this.configureCanvas();
|
|
452
|
+
}
|
|
453
|
+
/** Cancel, leave */
|
|
454
|
+
onCancel() {
|
|
455
|
+
this.matterportImportService.removeFrame();
|
|
456
|
+
this.router.navigate([
|
|
457
|
+
"/dashboard/localisation",
|
|
458
|
+
this.spaceID,
|
|
459
|
+
"plans",
|
|
460
|
+
]);
|
|
461
|
+
alert(this.translate.instant("calibration.canceled"));
|
|
462
|
+
}
|
|
463
|
+
async onFloorClick(floor) {
|
|
464
|
+
this.currentFloor = floor;
|
|
465
|
+
await this.matterportImportService.moveToFloor(floor.id);
|
|
466
|
+
}
|
|
467
|
+
onActivateZoomChange() {
|
|
468
|
+
this.zoomCanBeChanged = !this.zoomCanBeChanged;
|
|
469
|
+
const iframe = document.querySelector("#viewer-frame");
|
|
470
|
+
if (iframe) {
|
|
471
|
+
iframe.style.zIndex = this.zoomCanBeChanged ? "1" : "0";
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
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 });
|
|
476
|
+
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 [ngStyle]=\"{'opacity': 'calc(' + (-(opacity-100)+10) + '/ 100)'}\">{{'Less' | translate}}</div>\n <div class=\"legend-title\">{{'Plan Opacity' | translate }}</div>\n <div [ngStyle]=\"{'opacity': 'calc(' + (opacity+10) + '/ 100)'}\">{{'More' | 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=\"label-legend me-3\">{{'Pan/Zoom Visit' | translate}} {{zoomCanBeChanged ? \"ON\" : \"OFF\"}}\n </div>\n <input type=\"checkbox\" (change)=\"onActivateZoomChange()\" style=\"margin-top: 5px;\">\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\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);position:absolute;margin:auto;width:100%;text-align:center;font-weight:700}.tool .label-legend{color:var(--smarterplan-primary);font-size:1.1rem}.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 } });
|
|
477
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: CalibrationComponent, decorators: [{
|
|
478
|
+
type: Component,
|
|
479
|
+
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 [ngStyle]=\"{'opacity': 'calc(' + (-(opacity-100)+10) + '/ 100)'}\">{{'Less' | translate}}</div>\n <div class=\"legend-title\">{{'Plan Opacity' | translate }}</div>\n <div [ngStyle]=\"{'opacity': 'calc(' + (opacity+10) + '/ 100)'}\">{{'More' | 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=\"label-legend me-3\">{{'Pan/Zoom Visit' | translate}} {{zoomCanBeChanged ? \"ON\" : \"OFF\"}}\n </div>\n <input type=\"checkbox\" (change)=\"onActivateZoomChange()\" style=\"margin-top: 5px;\">\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\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);position:absolute;margin:auto;width:100%;text-align:center;font-weight:700}.tool .label-legend{color:var(--smarterplan-primary);font-size:1.1rem}.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"] }]
|
|
480
|
+
}], 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: [{
|
|
481
|
+
type: ViewChild,
|
|
482
|
+
args: ["canvasDiv"]
|
|
483
|
+
}] } });
|
|
484
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsaWJyYXRpb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvcGxhbnMvY2FsaWJyYXRpb24vY2FsaWJyYXRpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvcGxhbnMvY2FsaWJyYXRpb24vY2FsaWJyYXRpb24uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBc0IsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBR3pFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFekMsT0FBTyxFQUFzRyxlQUFlLEVBQTJCLE1BQU0sc0JBQXNCLENBQUM7QUFDcEwsT0FBTyxPQUFPLE1BQU0sU0FBUyxDQUFDOzs7Ozs7Ozs7QUFPOUIsTUFBTSxPQUFPLG9CQUFvQjtJQXFGN0IsWUFDWSx1QkFBZ0QsRUFDaEQsV0FBd0IsRUFDeEIsS0FBcUIsRUFDckIsTUFBYyxFQUNkLFdBQXdCLEVBQ3hCLFlBQTBCLEVBQzFCLGlCQUFvQyxFQUNwQyxTQUEyQjtRQVAzQiw0QkFBdUIsR0FBdkIsdUJBQXVCLENBQXlCO1FBQ2hELGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ3hCLFVBQUssR0FBTCxLQUFLLENBQWdCO1FBQ3JCLFdBQU0sR0FBTixNQUFNLENBQVE7UUFDZCxnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQUN4QixpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUMxQixzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQ3BDLGNBQVMsR0FBVCxTQUFTLENBQWtCO1FBM0Z2QyxxQ0FBcUM7UUFDckMsY0FBUyxHQUFlLEVBQUUsQ0FBQztRQVczQixxQ0FBcUM7UUFDckMsZUFBVSxHQUFHLENBQUMsQ0FBQztRQUVmLG9DQUFvQztRQUNwQyxZQUFPLEdBQVcsRUFBRSxDQUFDO1FBRXJCLDRGQUE0RjtRQUM1RixhQUFRLEdBQVcsR0FBRyxDQUFDO1FBRXZCLHlIQUF5SDtRQUN6SCxpQkFBWSxHQUFXLEdBQUcsQ0FBQztRQUszQixvSEFBb0g7UUFDcEgsb0JBQWUsR0FBWSxLQUFLLENBQUM7UUFFakMsaURBQWlEO1FBQ2pELHVCQUFrQixHQUFhLEVBQUUsQ0FBQztRQUVsQyw2Q0FBNkM7UUFDN0MsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUVqQiwrQ0FBK0M7UUFDL0MsYUFBUSxHQUFHLEtBQUssQ0FBQztRQVVqQixvQkFBZSxHQUFHLEtBQUssQ0FBQztRQUV4QiwrREFBK0Q7UUFDL0QsbUJBQWMsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO1FBRWhDLGdFQUFnRTtRQUNoRSxvQkFBZSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUM7UUFFckMsZ0RBQWdEO1FBQ2hELGtCQUFhLEdBQTZCLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFFekQsaURBQWlEO1FBQ2pELG1CQUFjLEdBQTZCLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFFMUQsbURBQW1EO1FBQ25ELGNBQVMsR0FBUSxFQUFFLENBQUM7UUFFcEIsMkNBQTJDO1FBQzNDLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFFaEIsNEJBQTRCO1FBQzVCLFlBQU8sR0FBRyxJQUFJLENBQUM7UUFPZixjQUFTLEdBQThELEVBQUUsQ0FBQztRQUUxRSxXQUFNLEdBQVUsRUFBRSxDQUFDO1FBSW5CLHFCQUFnQixHQUFZLEtBQUssQ0FBQztJQVcvQixDQUFDO0lBRUosV0FBVztRQUNQLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFO1lBQ2YsSUFBSSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsRUFBRSxDQUFDO1NBQzlDO0lBQ0wsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRO1FBQ1YsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDO1FBQ3ZELElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFbkUsbUJBQW1CO1FBQ25CLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUV0QixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxFQUFFLENBQUM7UUFFbkQsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ2pCLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzlELElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNwQixVQUFVLENBQUMsR0FBRyxFQUFFO2dCQUNaLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO29CQUM3QixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFO3dCQUNoQyxNQUFNLEVBQUUsSUFBSTt3QkFDWixhQUFhLEVBQUUsQ0FBQzt3QkFDaEIsT0FBTyxFQUFFLEdBQUc7d0JBQ1osT0FBTyxFQUFFLEdBQUc7d0JBQ1osV0FBVyxFQUFFLENBQUM7d0JBQ2QsU0FBUyxFQUFFLElBQUk7cUJBQ2xCLENBQUMsQ0FBQztnQkFDUCxDQUFDLENBQUMsQ0FBQztZQUNQLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUNYO2FBQU07WUFDSCxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQztnQkFDakIseUJBQXlCO2dCQUN6QixJQUFJLENBQUMsT0FBTztnQkFDWixPQUFPO2FBQ1YsQ0FBQyxDQUFDO1NBQ047SUFDTCxDQUFDO0lBRUQ7O3VHQUVtRztJQUNuRyxjQUFjO1FBQ1YsSUFBSSxDQUFDLFNBQVMsR0FBRztZQUNiLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxHQUFHLEVBQUUsZUFBZSxFQUFFO1lBQzVDO2dCQUNJLEtBQUssRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUk7Z0JBQzdCLEdBQUcsRUFBRSxpQkFBaUIsSUFBSSxDQUFDLE9BQU8sRUFBRTthQUN2QztZQUNEO2dCQUNJLEtBQUssRUFBRSxPQUFPO2dCQUNkLEdBQUcsRUFBRSxpQkFBaUIsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLFFBQVE7YUFDckQ7WUFDRDtnQkFDSSxLQUFLLEVBQUUsYUFBYTtnQkFDcEIsR0FBRyxFQUFFLGlCQUFpQixJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsNkJBQTZCLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxFQUFFO2FBQ2hHO1NBQ0osQ0FBQztJQUNOLENBQUM7SUFFRDs7dUdBRW1HO0lBRW5HLHVCQUF1QjtJQUN2QixLQUFLLENBQUMsZUFBZTtRQUNqQixpQkFBaUI7UUFDakIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDZCxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsYUFBYSxDQUNqQyxTQUFTLENBQ1MsQ0FBQztZQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztTQUN4QjtRQUVELElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQ3ZCLE1BQU0sS0FBSyxHQUFHLE1BQU0sZUFBZSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDOUQsMkdBQTJHO1lBQzNHLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUU5RCxrRUFBa0U7WUFDbEUsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7WUFFdkMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUV0Qiw4QkFBOEI7WUFDOUIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1NBQzVDO2FBQU07WUFDSCxPQUFPO1lBQ1AsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1NBQ3RCO0lBQ0wsQ0FBQztJQUVELDJDQUEyQztJQUMzQyxVQUFVLENBQUMsSUFBSTtRQUNYLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsR0FBRyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDekQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQztRQUMxRCxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsR0FBRyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDeEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ3pDLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDM0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUM1QixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztJQUMzQixDQUFDO0lBRUQsbUNBQW1DO0lBQ25DLFNBQVMsQ0FBQyxHQUFXLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxLQUFLO1FBQzlDLE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxFQUFFLENBQUM7UUFDMUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQztRQUM3QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUU3QyxxQ0FBcUM7UUFDckMsdUJBQXVCO1FBQ3ZCLG9DQUFvQztRQUNwQyw0QkFBNEI7UUFDNUIsSUFBSTtRQUNKLHVCQUF1QjtRQUN2QixvQ0FBb0M7UUFDcEMsNEJBQTRCO1FBQzVCLElBQUk7UUFFSixJQUFJLFVBQVUsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3hCLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDekIsS0FBSyxDQUFDLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUU7WUFDaEMsSUFBSSxLQUFLLEVBQUU7Z0JBQ1AsVUFBVSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7Z0JBQ3pCLFdBQVcsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO2FBQzlCO1lBQ0QsT0FBTyxDQUFDLFNBQVMsQ0FDYixLQUFLLEVBQ0wsQ0FBQyxFQUNELENBQUMsRUFDRCxLQUFLLENBQUMsS0FBSyxFQUNYLEtBQUssQ0FBQyxNQUFNLEVBQ1osQ0FBQyxFQUNELENBQUMsRUFDRCxVQUFVLEVBQ1YsV0FBVyxDQUNkLENBQUM7UUFDTixDQUFDLENBQUMsQ0FBQztRQUNILEtBQUssQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQ3BCLENBQUM7SUFFRCw2RUFBNkU7SUFDN0UsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDakIsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDO1FBQ3ZELElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQztRQUV4RCxNQUFNLFVBQVUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pCLE1BQU0sV0FBVyxHQUFHLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFFdEMsSUFBSSxVQUFVLEdBQUcsV0FBVyxFQUFFO1lBQzFCLE9BQU8sR0FBRyxPQUFPLEdBQUcsVUFBVSxDQUFDO1NBQ2xDO2FBQU07WUFDSCxPQUFPLEdBQUcsT0FBTyxHQUFHLFVBQVUsQ0FBQztTQUNsQztRQUNELE9BQU8sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUN0QyxDQUFDO0lBRUQsdUNBQXVDO0lBQ3ZDLEtBQUssQ0FBQyxXQUFXO1FBQ2IsTUFBTSxLQUFLLEdBQUcsTUFBTSxNQUFNLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUNuRCxNQUFNLFdBQVcsR0FBRyxNQUFNLE1BQU0sQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO1FBRXRFLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxTQUFTLEdBQUcsV0FBVyxDQUFDO1FBRWxELE1BQU0sR0FBRyxHQUFxQixNQUFNLFdBQVcsQ0FDM0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQzNCLENBQUMsT0FBTyxDQUFDO1FBQ1YsTUFBTSxJQUFJLEdBQUcsTUFBTSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRWxDLE1BQU0sa0JBQWtCLEdBQUcsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDeEMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBRXRELElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUM7UUFDckMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQztRQUVuQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDcEUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztRQUV2QixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQztRQUUxQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FDbEMsSUFBSSxDQUNxQixDQUFDO1FBQzlCLE1BQU0sYUFBYSxHQUFHO1lBQ2xCLGFBQWEsRUFBRSxPQUFPO1lBQ3RCLFFBQVE7U0FDWCxDQUFDO1FBQ0YsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxPQUFPLENBQUM7UUFFdEQsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUM7UUFFcEQsa0NBQWtDO1FBQ2xDLGtDQUFrQztRQUNsQyxjQUFjO0lBQ2xCLENBQUM7SUFFRCwyQ0FBMkM7SUFDM0MsVUFBVTtRQUNOLElBQUksQ0FBQyxRQUFRLEdBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQy9CLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQsNkNBQTZDO0lBQzdDLFVBQVU7UUFDTixJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUMvQixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOzt1R0FFbUc7SUFFbkcsd0JBQXdCO0lBQ3hCLEtBQUssQ0FBQyxZQUFZO1FBQ2QsTUFBTSxJQUFJLENBQUMsdUJBQXVCLENBQUMsZUFBZSxDQUM5QyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FDMUIsQ0FBQztRQUVGLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsdUJBQXVCLENBQUM7UUFDN0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNqRSw0QkFBNEI7UUFDNUIsVUFBVSxDQUFDLEtBQUssSUFBSSxFQUFFO1lBQ2xCLHNCQUFzQjtZQUN0QixNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQy9DLDZDQUE2QztZQUM3QyxJQUFJO2dCQUNBLE1BQU0sSUFBSSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsQ0FDMUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQ3ZCLENBQUM7YUFDTDtZQUFDLE1BQU07Z0JBQ0osT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO2FBQ3pDO1lBRUQsNkNBQTZDO1lBQzdDLElBQUksQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUVSLDJFQUEyRTtRQUUzRSxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsRUFBRSxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRTtZQUNuRCxJQUFJLE9BQU8sS0FBSyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUU7Z0JBQ3JDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRTtvQkFDckMsVUFBVSxFQUFFLG9CQUFvQjtpQkFDbkMsQ0FBQyxDQUFDO2FBQ047UUFDTCxDQUFDLENBQUMsQ0FBQztRQUVILDhDQUE4QztRQUM5QyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNoQyx3SEFBd0g7WUFDeEgsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUU7Z0JBQ3ZCLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDO2dCQUN2QyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7Z0JBQ2xDLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDO2FBQzNCO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsbURBQW1EO0lBQ25ELEtBQUssQ0FBQyxnQkFBZ0I7UUFDbEIsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQ3hELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUVsQyxpRkFBaUY7UUFDakYsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUU1QywwREFBMEQ7UUFDMUQsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUU7WUFDdkIsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7WUFDNUIsSUFBSSxDQUFDLHlCQUF5QixFQUFFLENBQUM7U0FDcEM7SUFDTCxDQUFDO0lBRUQsNkVBQTZFO0lBQzdFLEtBQUssQ0FBQyx5QkFBeUI7UUFDM0IsTUFBTSxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQztRQUU3QyxtQ0FBbUM7UUFDbkMsT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUN2QyxxRUFBcUU7WUFDckUsTUFBTSxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxFQUFFO2dCQUN4RCxLQUFLLEVBQUUsR0FBRzthQUNiLENBQUMsQ0FBQztTQUNOO1FBRUQsNEZBQTRGO1FBQzVGLElBQUksQ0FBQyxlQUFlLEdBQUcsS0FBSyxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7dUdBRW1HO0lBRW5HLDBCQUEwQjtJQUMxQixLQUFLLENBQUMsU0FBUztRQUNYLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLG1CQUFtQjtRQUNuQixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDekIsQ0FBQztJQUVELEtBQUssQ0FBQyxTQUFTO1FBQ1gsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztRQUM3QyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsYUFBYTtZQUNkLE1BQU0sSUFBSSxDQUFDLHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUM7Z0JBQzlELENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztnQkFDYixDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUM7Z0JBQ2IsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2FBQ2hCLENBQUMsQ0FBQztRQUNQLElBQUksQ0FBQyxjQUFjO1lBQ2YsTUFBTSxJQUFJLENBQUMsdUJBQXVCLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDOUQsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUNiLENBQUMsRUFBRSxDQUFDO2dCQUNKLENBQUMsRUFBRSxDQUFDO2FBQ1AsQ0FBQyxDQUFDO1FBQ1AsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUM7UUFDbkMsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7UUFDOUQsSUFBSSxVQUFVLEtBQUssQ0FBQyxFQUFFO1lBQ2xCLGdEQUFnRDtZQUNoRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztZQUNoRSxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsR0FBRyxHQUFHLENBQUM7WUFDL0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEdBQUcsR0FBRyxDQUFDO1lBQy9CLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDO1lBQy9DLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxHQUFHLFVBQVUsR0FBRyxXQUFXLENBQUM7U0FDcEQ7YUFBTTtZQUNILGlEQUFpRDtZQUNqRCxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsR0FBRyxHQUFHLENBQUM7WUFDL0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEdBQUcsR0FBRyxDQUFDO1lBQy9CLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDO1lBQy9DLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxHQUFHLFVBQVUsR0FBRyxXQUFXLENBQUM7U0FDcEQ7UUFDRCxNQUFNLGFBQWEsR0FDZixNQUFNLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLGlCQUFpQixDQUFDO1lBQzlELENBQUMsRUFBRSxDQUFDO1lBQ0osQ0FBQyxFQUFFLENBQUM7WUFDSixDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUM7U0FDaEIsQ0FBQyxDQUFDO1FBQ1AsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUM7UUFDbkMsSUFBSSxVQUFVLEtBQUssQ0FBQyxFQUFFO1lBQ2xCLGlEQUFpRDtZQUNqRCxVQUFVLEdBQUcsYUFBYSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztZQUNwRCxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sR0FBRyxhQUFhLENBQUMsQ0FBQyxDQUFDO1lBQ3pDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxHQUFHLFVBQVUsR0FBRyxXQUFXLENBQUM7U0FDcEQ7YUFBTTtZQUNILE1BQU0sVUFBVSxHQUFHLGFBQWEsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7WUFDMUQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEdBQUcsYUFBYSxDQUFDLENBQUMsQ0FBQztZQUN6QyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxVQUFVLEdBQUcsV0FBVyxDQUFDO1NBQ3BEO1FBRUQsMkRBQTJEO1FBQzNELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDbEQsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUcsYUFBYSxDQUFDO1FBQ3RDLDhCQUE4QjtRQUM5QixJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7UUFDL0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO1FBQy9CLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztRQUNqQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQsbUJBQW1CO0lBQ25CLEtBQUssQ0FBQyxhQUFhO1FBQ2YsdUJBQXVCO1FBQ3ZCLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUVwRSxJQUFJLElBQUksRUFBRTtZQUNOLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1lBQ3hCLE1BQU0sV0FBVyxHQUNiLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLHFCQUFxQixDQUM5QyxJQUFJLENBQUMsV0FBVyxDQUNuQixDQUFDO1lBQ04sSUFBSSxDQUFDLGtCQUFrQixHQUFHLFdBQVcsQ0FBQztZQUN0QyxNQUFNLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN2QixJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUN4QixLQUFLLE1BQU0sVUFBVSxJQUFJLFdBQVcsRUFBRTtvQkFDbEMsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQ3JELE1BQU0sU0FBUyxHQUNYLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxLQUFLLEdBQUc7d0JBQzVCLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQzt3QkFDaEIsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7b0JBQ3pCLE1BQU0sU0FBUyxHQUNYLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxLQUFLLEdBQUc7d0JBQzVCLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQzt3QkFDaEIsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7b0JBQ3pCLE1BQU0sS0FBSyxHQUNQLFNBQVMsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU07d0JBQ2pDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDO29CQUMzQixNQUFNLEtBQUssR0FDUCxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNO3dCQUNqQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQztvQkFDM0Isb0RBQW9EO29CQUNwRCxNQUFNLFlBQVksR0FDZCxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQzt3QkFDcEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxrQ0FBa0M7b0JBQ2hFLE1BQU0sWUFBWSxHQUNkLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDO3dCQUNwQyxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQztvQkFDN0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUM7d0JBQ2hCLEtBQUssRUFBRSxVQUFVLENBQUMsRUFBRTt3QkFDcEIsTUFBTSxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRTt3QkFDMUIsQ0FBQyxFQUFFLFlBQVk7d0JBQ2YsQ0FBQyxFQUFFLFlBQVk7cUJBQ2xCLENBQUMsQ0FBQztvQkFDSCxNQUFNLFFBQVEsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUM7b0JBQy9DLE1BQU0sS0FBSyxHQUFHLFFBQVEsR0FBRyxDQUFDLENBQUM7b0JBQzNCLElBQUksQ0FBQyxTQUFTLENBQ1YsMEVBQTBFLEVBQzFFLFlBQVksR0FBRyxLQUFLLEVBQ3BCLFlBQVksR0FBRyxLQUFLLEVBQ3BCLElBQUksQ0FDUCxDQUFDO2lCQUNMO2FBQ0o7U0FDSjtJQUNMLENBQUM7SUFFRCx1QkFBdUI7SUFDdkIsS0FBSyxDQUFDLE1BQU07UUFDUixJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDbEIsOEJBQThCO1lBQzlCLDZDQUE2QztZQUM3Qyw2Q0FBNkM7WUFDN0MsdUNBQXVDO1lBQ3ZDLHVDQUF1QztZQUN2QyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUM7WUFDMUIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFDNUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFFN0MsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQztnQkFDOUIsRUFBRSxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRTtnQkFDdEIsV0FBVyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQzthQUM5QyxDQUFDLENBQUM7WUFDSCxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQ2IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxFQUFFO2dCQUNsQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEdBQUcsUUFBUSxDQUFDO2dCQUMzQixPQUFPLFFBQVEsQ0FBQyxLQUFLLENBQUM7Z0JBQ3RCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQ3BDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEtBQUssQ0FDOUIsQ0FBQztnQkFDRixJQUFJLHFCQUFxQixDQUFDO2dCQUMxQixJQUFJLEdBQUcsQ0FBQyxjQUFjLEVBQUU7b0JBQ3BCLE1BQU0sY0FBYyxHQUFHLEdBQUcsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDcEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FDcEIsQ0FBQztvQkFDRixNQUFNLHNCQUFzQixHQUFHLGNBQWMsQ0FBQyxJQUFJLENBQzlDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFLLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUNqRCxDQUFDO29CQUNGLElBQUksc0JBQXNCLEVBQUU7d0JBQ3hCLGNBQWMsQ0FBQyxNQUFNLENBQ2pCLGNBQWMsQ0FBQyxPQUFPLENBQUMsc0JBQXNCLENBQUMsRUFDOUMsQ0FBQyxFQUNELFFBQVEsQ0FDWCxDQUFDO3FCQUNMO3lCQUFNO3dCQUNILGNBQWMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7cUJBQ2pDO29CQUNELHFCQUFxQixHQUFHLENBQUMsR0FBRyxjQUFjLENBQUMsQ0FBQztpQkFDL0M7cUJBQU07b0JBQ0gscUJBQXFCLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztpQkFDdEM7Z0JBQ0Qsc0NBQXNDO2dCQUN0QyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxnQkFBZ0IsQ0FBQztvQkFDMUMsRUFBRSxFQUFFLEtBQUs7b0JBQ1QsY0FBYyxFQUFFLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQ2hELElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQ3hCO2lCQUNKLENBQUMsQ0FBQztZQUNQLENBQUMsQ0FBQyxDQUNMLENBQUM7U0FDTDtRQUNELElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUUzQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQztZQUNqQix5QkFBeUI7WUFDekIsSUFBSSxDQUFDLE9BQU87WUFDWixPQUFPO1NBQ1YsQ0FBQyxDQUFDO1FBQ0gsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQsdUJBQXVCO0lBQ3ZCLE9BQU87UUFDSCxJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztRQUN0QixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztRQUN0QixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztRQUVyQixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVELG9CQUFvQjtJQUNwQixRQUFRO1FBQ0osSUFBSSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzNDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDO1lBQ2pCLHlCQUF5QjtZQUN6QixJQUFJLENBQUMsT0FBTztZQUNaLE9BQU87U0FDVixDQUFDLENBQUM7UUFDSCxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFRCxLQUFLLENBQUMsWUFBWSxDQUFDLEtBQUs7UUFDcEIsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUM7UUFDMUIsTUFBTSxJQUFJLENBQUMsdUJBQXVCLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQsb0JBQW9CO1FBQ2hCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztRQUMvQyxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBZ0IsQ0FBQztRQUN0RSxJQUFJLE1BQU0sRUFBRTtZQUNSLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7U0FDM0Q7SUFDTCxDQUFDOztpSEEvbEJRLG9CQUFvQjtxR0FBcEIsb0JBQW9CLCtKQ2JqQyxneElBMEZNOzJGRDdFTyxvQkFBb0I7a0JBTGhDLFNBQVM7K0JBQ0UsaUJBQWlCOzhTQWFELFNBQVM7c0JBQWhDLFNBQVM7dUJBQUMsV0FBVyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRWxlbWVudFJlZiwgT25Jbml0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgZ2V0RG9jdW1lbnQgfSBmcm9tIFwicGRmanMtZGlzdFwiO1xuaW1wb3J0IHsgUERGRG9jdW1lbnRQcm94eSB9IGZyb20gXCJuZzItcGRmLXZpZXdlclwiO1xuaW1wb3J0IHsgWm9uZSwgTWVudUl0ZW0sIFBsYW4sIFNwYWNlLCBOYXZpZ2F0aW9uLCBQbGFuU2VydmljZSwgWm9uZVNlcnZpY2UsIFNwYWNlU2VydmljZSwgTmF2aWdhdGlvblNlcnZpY2UsIGdldE1ldGFGb3JJbWFnZSwgTWF0dGVycG9ydEltcG9ydFNlcnZpY2UgfSBmcm9tICduZ3gtc21hcnRlcnBsYW4tY29yZSc7XG5pbXBvcnQgcGFuem9vbSBmcm9tICdwYW56b29tJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbGliLWNhbGlicmF0aW9uJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NhbGlicmF0aW9uLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vY2FsaWJyYXRpb24uY29tcG9uZW50LnNjc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBDYWxpYnJhdGlvbkNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG5cbiAgICAvKiogSXRlbSB0byBkaXNwbGF5IGZvciB0aGUgbmF2YmFyICovXG4gICAgbWVudUl0ZW1zOiBNZW51SXRlbVtdID0gW107XG5cbiAgICAvKiogQ2FudmFzIChQbGFuKSAqL1xuICAgIGNhbnZhcztcblxuICAgIC8qKiBDYW52YXNEaXYgKERpdiB0aGF0IGNvbnRhaW4gdGhlIGNhbnZhcyArIG1hdHRlcnBvcnQgaWZyYW1lKSAqL1xuICAgIEBWaWV3Q2hpbGQoXCJjYW52YXNEaXZcIikgY2FudmFzRGl2OiBFbGVtZW50UmVmO1xuXG4gICAgLyoqIFNpemUgb2YgdGhlIGNhbnZhcyAmIG1hdHRlcnBvcnQgaWZyYW1lICovXG4gICAgY2FudmFzU2l6ZTogeyB3OiBudW1iZXI7IGg6IG51bWJlciB9O1xuXG4gICAgLyoqIFpvb20gcmF0aW8gb2YgdGhlIGNhbnZhcy9wbGFuICAqL1xuICAgIGNhbnZhc1pvb20gPSAwO1xuXG4gICAgLyoqIE9wYWNpdHkgZm9yIG1hdHRlcnBvcnQgaWZyYW1lICovXG4gICAgb3BhY2l0eTogbnVtYmVyID0gNTA7XG5cbiAgICAvKiogQ3VycmVudCByb3RhdGlvbiBmb3IgbWF0dGVycG9ydCwgWzAtMzYwXSwgIG1hdHRlcnBvcnQgcm90YXRpb24gaXMgYmluZCB0byBpbnB1dCByYW5nZSAqL1xuICAgIHJvdGF0aW9uOiBudW1iZXIgPSAxODA7XG5cbiAgICAvKiogUHJldmlvdXMgcm90YXRpb24sIHVzZSB0byBjYWxjdWxhdGUgdGhlIGRlbHRhUm90YXRpb24gdG8gcm90YXRlLCB3aGVuIHVzZXIgY2hhbmdlIHJvdGF0aW9uIHZhbHVlIHVzaW5nIHJhbmdlIGlucHV0ICovXG4gICAgcHJldlJvdGF0aW9uOiBudW1iZXIgPSAxODA7XG5cbiAgICAvKiogQ3VycmVudCBDYW1lcmEgUG9zZSAqL1xuICAgIGNhbWVyYVBvc2U6IGFueTtcblxuICAgIC8qKiBUcnVlIHdoZW4gdGhlIHVzZXIgaXMgY3VycmVudGx5IHJvdGF0aW5nIHdpdGggdGhlIGlucHV0IHJhbmdlLCB0aGUgbWF0dGVycG9ydCByb3RhdGlvbiBldmVudHMgd2lsbCBiZSBpZ25vcmVkICovXG4gICAgaXNSb3RhdGluZ1JhbmdlOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKiogUm90YXRpbmcgcXVldWUgZXZlbnQgdG8gc2VuZCB0byBtYXR0ZXJwb3J0ICovXG4gICAgcm90YXRpbmdRdWV1ZUV2ZW50OiBudW1iZXJbXSA9IFtdO1xuXG4gICAgLyoqIFRydWUgd2hlbiBWZXJ0aWNhbCBzeW1tZXRyeSBpcyBlbmFibGVkICovXG4gICAgcmVmbGVjdFYgPSBmYWxzZTtcblxuICAgIC8qKiBUcnVlIHdoZW4gSG9yaXpvbnRhbCBzeW1tZXRyeSBpcyBlbmFibGVkICovXG4gICAgcmVmbGVjdEggPSBmYWxzZTtcblxuICAgIGNob3NlblBsYW46IFBsYW47XG5cbiAgICBzcGFjZUlEOiBzdHJpbmc7XG5cbiAgICBjdXJyZW50U3BhY2U6IFNwYWNlO1xuXG4gICAgY3VycmVudFpvbmU6IFpvbmU7XG5cbiAgICBjaG9zZW5QbGFuSXNQZGYgPSBmYWxzZTtcblxuICAgIC8qKiBGaXJzdCBQb2ludCBpbiB2aXNpdCwgdXNlZCB0byBkZXRlcm1pbmUgdGhlIGNhbGlicmF0aW9uICAqL1xuICAgIGZpcnN0TWFya1Zpc2l0ID0geyB4OiAwLCB5OiAwIH07XG5cbiAgICAvKiogU2Vjb25kIFBvaW50IGluIHZpc2l0LCB1c2VkIHRvIGRldGVybWluZSB0aGUgY2FsaWJyYXRpb24gICovXG4gICAgc2Vjb25kTWFya1Zpc2l0ID0geyB4OiAwLjUsIHk6IDAuNSB9O1xuXG4gICAgLyoqIEVxdWl2YWxlbnQgb2YgJ2ZpcnN0TWFya1Zpc2l0JyBpbiBjYW52YXMgICovXG4gICAgZmlyc3RNYXJrUGxhbjogeyB4OiBudW1iZXI7IHk6IG51bWJlciB9ID0geyB4OiAwLCB5OiAwIH07XG5cbiAgICAvKiogRXF1aXZhbGVudCBvZiAnc2Vjb25kTWFya1Zpc2l0JyBpbiBjYW52YXMgICovXG4gICAgc2Vjb25kTWFya1BsYW46IHsgeDogbnVtYmVyOyB5OiBudW1iZXIgfSA9IHsgeDogMCwgeTogMCB9O1xuXG4gICAgLyoqIENhbGlicmF0aW9uIHJlc3VsdCwgKG9mZnNldFgsIG9mZnNldFksIHgsIHkpICovXG4gICAgY2FsaWJyYWdlOiBhbnkgPSB7fTtcblxuICAgIC8qKiBJcyBpbiBwcmV2aWV3IG1vZGUgKHNlZSBzY2FuIHJlc3VsdCkgKi9cbiAgICBwcmV2aWV3ID0gZmFsc2U7XG5cbiAgICAvKiogTWF0dGVycG9ydCBpcyBsb2FkaW5nICovXG4gICAgbG9hZGluZyA9IHRydWU7XG5cbiAgICAvKiBmb3IgcGFuIGFuZCB6b29tIG9mIGNhbnZhcyAqL1xuICAgIHBhbnpvb206IGFueTtcblxuICAgIGN1cnJlbnROYXZpZ2F0aW9uczogTmF2aWdhdGlvbltdO1xuXG4gICAgcG9zaXRpb25zOiB7IG5hdklEOiBzdHJpbmc7IHBsYW5JRDogc3RyaW5nOyB4OiBudW1iZXI7IHk6IG51bWJlciB9W10gPSBbXTtcblxuICAgIGZsb29yczogYW55W10gPSBbXTtcblxuICAgIGN1cnJlbnRGbG9vcjtcblxuICAgIHpvb21DYW5CZUNoYW5nZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIG1hdHRlcnBvcnRJbXBvcnRTZXJ2aWNlOiBNYXR0ZXJwb3J0SW1wb3J0U2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBwbGFuU2VydmljZTogUGxhblNlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgcm91dGU6IEFjdGl2YXRlZFJvdXRlLFxuICAgICAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxuICAgICAgICBwcml2YXRlIHpvbmVTZXJ2aWNlOiBab25lU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBzcGFjZVNlcnZpY2U6IFNwYWNlU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBuYXZpZ2F0aW9uU2VydmljZTogTmF2aWdhdGlvblNlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgdHJhbnNsYXRlOiBUcmFuc2xhdGVTZXJ2aWNlLFxuICAgICkge31cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMubG9hZGluZykge1xuICAgICAgICAgICAgdGhpcy5tYXR0ZXJwb3J0SW1wb3J0U2VydmljZS5yZW1vdmVGcmFtZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgbmdPbkluaXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc3BhY2VJRCA9IHRoaXMucm91dGUuc25hcHNob3QucXVlcnlQYXJhbXMuc3BhY2VJRDtcbiAgICAgICAgdGhpcy5jdXJyZW50U3BhY2UgPSBhd2FpdCB0aGlzLnNwYWNlU2VydmljZS5nZXRTcGFjZSh0aGlzLnNwYWNlSUQpO1xuXG4gICAgICAgIC8qKiBNZW51IG5hdiBiYXIgKi9cbiAgICAgICAgdGhpcy5zZXR1cE1lbnVJdGVtcygpO1xuXG4gICAgICAgIHRoaXMuY2hvc2VuUGxhbiA9IHRoaXMucGxhblNlcnZpY2UuZ2V0Q2hvc2VuUGxhbigpO1xuXG4gICAgICAgIGlmICh0aGlzLmNob3NlblBsYW4pIHtcbiAgICAgICAgICAgIHRoaXMuY2hvc2VuUGxhbklzUGRmID0gdGhpcy5jaG9zZW5QbGFuLmFubmV4ZS5pbmNsdWRlcyhcInBkZlwiKTtcbiAgICAgICAgICAgIHRoaXMubGF1bmNoVmlld2VyKCk7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZ3VyZUNhbnZhcygpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnBhbnpvb20gPSBwYW56b29tKHRoaXMuY2FudmFzLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBib3VuZHM6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBib3VuZHNQYWRkaW5nOiAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgbWF4Wm9vbTogMi41LFxuICAgICAgICAgICAgICAgICAgICAgICAgbWluWm9vbTogMC4xLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdGlhbFpvb206IDEsXG4gICAgICAgICAgICAgICAgICAgICAgICB6b29tU3BlZWQ6IDAuMDIsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSwgNTAwKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFtcbiAgICAgICAgICAgICAgICBcIi9kYXNoYm9hcmQvbG9jYWxpc2F0aW9uXCIsXG4gICAgICAgICAgICAgICAgdGhpcy5zcGFjZUlELFxuICAgICAgICAgICAgICAgIFwicGxhbnNcIixcbiAgICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTUVOVSBOQVYgQkFSXG4gICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXG4gICAgc2V0dXBNZW51SXRlbXMoKSB7XG4gICAgICAgIHRoaXMubWVudUl0ZW1zID0gW1xuICAgICAgICAgICAgeyBsYWJlbDogXCJMb2NhdGlvbnNcIiwgdXJsOiBcIi9sb2NhbGlzYXRpb25cIiB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGxhYmVsOiB0aGlzLmN1cnJlbnRTcGFjZS5uYW1lLFxuICAgICAgICAgICAgICAgIHVybDogYC9sb2NhbGlzYXRpb24vJHt0aGlzLnNwYWNlSUR9YCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbGFiZWw6IFwiUGxhbnNcIixcbiAgICAgICAgICAgICAgICB1cmw6IGAvbG9jYWxpc2F0aW9uLyR7dGhpcy5jdXJyZW50U3BhY2UuaWR9L3BsYW5zYCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbGFiZWw6IFwiQ2FsaWJyYXRpb25cIixcbiAgICAgICAgICAgICAgICB1cmw6IGAvbG9jYWxpc2F0aW9uLyR7dGhpcy5jdXJyZW50U3BhY2UuaWR9L3BsYW4tY2FsaWJyYXRpb24/c3BhY2VJRD0ke3RoaXMuY3VycmVudFNwYWNlLmlkfWAsXG4gICAgICAgICAgICB9LFxuICAgICAgICBdO1xuICAgIH1cblxuICAgIC8qKiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0FOVkFTXG4gICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXG5cbiAgICAvKiogRGlzcGxheSB0aGUgcGxhbiAqL1xuICAgIGFzeW5jIGNvbmZpZ3VyZUNhbnZhcygpIHtcbiAgICAgICAgLyoqIEdldCBjYW52YXMgKi9cbiAgICAgICAgaWYgKCF0aGlzLmNhbnZhcykge1xuICAgICAgICAgICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcbiAgICAgICAgICAgICAgICBcIiNjYW52YXNcIixcbiAgICAgICAgICAgICkgYXMgSFRNTENhbnZhc0VsZW1lbnQ7XG4gICAgICAgICAgICB0aGlzLmNhbnZhcyA9IGNhbnZhcztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5jaG9zZW5QbGFuSXNQZGYpIHtcbiAgICAgICAgICAgIGNvbnN0IGltYWdlID0gYXdhaXQgZ2V0TWV0YUZvckltYWdlKHRoaXMuY2hvc2VuUGxhbi5maWxlcGF0aCk7XG4gICAgICAgICAgICAvKiogQ29tcHV0ZSB0aGUgbmV3IHNpemUgZm9yIHRoZSBjYW52YXMvbWF0dGVycG9ydCwgYmFzZSBvbiB0aGUgZGltZW5zaW9uIG9mIHRoZSBwbGFuLCBrZWVwaW5nIHRoZSByYXRpbyAqL1xuICAgICAgICAgICAgY29uc3Qgc2l6ZSA9IHRoaXMuZ2V0U2l6ZUZvckNhbnZhcyhpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0KTtcblxuICAgICAgICAgICAgLyoqIENvbXB1dGUgdGhlIHBsYW4gem9vbSByYXRpbyAodXNlIGZvciB0aGUgY2FsaWJyYXRpb24gbGF0ZXIpICovXG4gICAgICAgICAgICB0aGlzLmNhbnZhc1pvb20gPSBzaXplLncgLyBpbWFnZS53aWR0aDtcblxuICAgICAgICAgICAgdGhpcy5yZXNpemVWaWV3KHNpemUpO1xuXG4gICAgICAgICAgICAvKiogRHJhdyBQbGFuIG9uIHRoZSBjYW52YXMgKi9cbiAgICAgICAgICAgIHRoaXMuZHJhd0ltYWdlKHRoaXMuY2hvc2VuUGxhbi5maWxlcGF0aCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBUT0RPXG4gICAgICAgICAgICB0aGlzLnBkZlRvQ2FudmFzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogVXBkYXRlIHNpemUgb2YgdGhlIGNhbnZhcy9tYXR0ZXJwb3J0ICovXG4gICAgcmVzaXplVmlldyhzaXplKSB7XG4gICAgICAgIHRoaXMuY2FudmFzRGl2Lm5hdGl2ZUVsZW1lbnQuc3R5bGUud2lkdGggPSBgJHtzaXplLnd9cHhgO1xuICAgICAgICB0aGlzLmNhbnZhc0Rpdi5uYXRpdmVFbGVtZW50LnN0eWxlLmhlaWdodCA9IGAke3NpemUuaH1weGA7XG4gICAgICAgIHRoaXMuY2FudmFzLnN0eWxlLndpZHRoID0gYCR7c2l6ZS53fXB4YDtcbiAgICAgICAgdGhpcy5jYW52YXMuc3R5bGUuaGVpZ2h0ID0gYCR7c2l6ZS5ofXB4YDtcbiAgICAgICAgdGhpcy5jYW52YXMud2lkdGggPSBzaXplLnc7XG4gICAgICAgIHRoaXMuY2FudmFzLmhlaWdodCA9IHNpemUuaDtcbiAgICAgICAgdGhpcy5jYW52YXNTaXplID0gc2l6ZTtcbiAgICB9XG5cbiAgICAvKiogRHJhdyBzb21ldGhpbmcgb24gdGhlIGNhbnZhcyAqL1xuICAgIGRyYXdJbWFnZSh1cmw6IHN0cmluZywgeCA9IDAsIHkgPSAwLCBpY29uZSA9IGZhbHNlKSB7XG4gICAgICAgIGNvbnN0IGltYWdlID0gbmV3IEltYWdlKCk7XG4gICAgICAgIGNvbnN0IHNpemUgPSB0aGlzLmNhbnZhc1NpemU7XG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLmNhbnZhcy5nZXRDb250ZXh0KFwiMmRcIik7XG5cbiAgICAgICAgLyoqIEZsaXAgdGhlIGNvbnRleHQsIGZvciBzeW1tZXRyeSAqL1xuICAgICAgICAvLyBpZiAodGhpcy5yZWZsZWN0Vikge1xuICAgICAgICAvLyAgICAgY29udGV4dC50cmFuc2xhdGUoc2l6ZS53LCAwKTtcbiAgICAgICAgLy8gICAgIGNvbnRleHQuc2NhbGUoLTEsIDEpO1xuICAgICAgICAvLyB9XG4gICAgICAgIC8vIGlmICh0aGlzLnJlZmxlY3RIKSB7XG4gICAgICAgIC8vICAgICBjb250ZXh0LnRyYW5zbGF0ZSgwLCBzaXplLmgpO1xuICAgICAgICAvLyAgICAgY29udGV4dC5zY2FsZSgxLCAtMSk7XG4gICAgICAgIC8vIH1cblxuICAgICAgICBsZXQgaW1hZ2VXaWR0aCA9IHNpemUudztcbiAgICAgICAgbGV0IGltYWdlSGVpZ2h0ID0gc2l6ZS5oO1xuICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKFwibG9hZFwiLCAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoaWNvbmUpIHtcbiAgICAgICAgICAgICAgICBpbWFnZVdpZHRoID0gaW1hZ2Uud2lkdGg7XG4gICAgICAgICAgICAgICAgaW1hZ2VIZWlnaHQgPSBpbWFnZS5oZWlnaHQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgICAgICAgICBpbWFnZSxcbiAgICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICAgIDAsXG4gICAgICAgICAgICAgICAgaW1hZ2Uud2lkdGgsXG4gICAgICAgICAgICAgICAgaW1hZ2UuaGVpZ2h0LFxuICAgICAgICAgICAgICAgIHgsXG4gICAgICAgICAgICAgICAgeSxcbiAgICAgICAgICAgICAgICBpbWFnZVdpZHRoLFxuICAgICAgICAgICAgICAgIGltYWdlSGVpZ2h0LFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGltYWdlLnNyYyA9IHVybDtcbiAgICB9XG5cbiAgICAvKiogR2V0IHRoZSBzaXplIGZvciB0aGUgY2FudmFzLCBiYXNlZCBvbiB0aGUgcGxhbiBzaXplLCBrZWVwaW5nIHRoZSByYXRpbyAqL1xuICAgIGdldFNpemVGb3JDYW52YXModywgaCkge1xuICAgICAgICBsZXQgY2FudmFzVyA9IHRoaXMuY2FudmFzRGl2Lm5hdGl2ZUVsZW1lbnQub2Zmc2V0V2lkdGg7XG4gICAgICAgIGxldCBjYW52YXNIID0gdGhpcy5jYW52YXNEaXYubmF0aXZlRWxlbWVudC5vZmZzZXRIZWlnaHQ7XG5cbiAgICAgICAgY29uc3QgaW1hZ2VSYXRpbyA9IHcgLyBoO1xuICAgICAgICBjb25zdCBjYW52YXNSYXRpbyA9IGNhbnZhc1cgLyBjYW52YXNIO1xuXG4gICAgICAgIGlmIChpbWFnZVJhdGlvID4gY2FudmFzUmF0aW8pIHtcbiAgICAgICAgICAgIGNhbnZhc0ggPSBjYW52YXNXIC8gaW1hZ2VSYXRpbztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhbnZhc1cgPSBjYW52YXNIICogaW1hZ2VSYXRpbztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyB3OiBjYW52YXNXLCBoOiBjYW52YXNIIH07XG4gICAgfVxuXG4gICAgLyoqIFtUT0RPXSBDb252ZXJ0IGEgUERGIHRvIGEgQ2FudmFzICovXG4gICAgYXN5bmMgcGRmVG9DYW52YXMoKSB7XG4gICAgICAgIGNvbnN0IHBkZmpzID0gYXdhaXQgaW1wb3J0KFwicGRmanMtZGlzdC9idWlsZC9wZGZcIik7XG4gICAgICAgIGNvbnN0IHBkZmpzV29ya2VyID0gYXdhaXQgaW1wb3J0KFwicGRmanMtZGlzdC9idWlsZC9wZGYud29ya2VyLmVudHJ5XCIpO1xuXG4gICAgICAgIHBkZmpzLkdsb2JhbFdvcmtlck9wdGlvbnMud29ya2VyU3JjID0gcGRmanNXb3JrZXI7XG5cbiAgICAgICAgY29uc3QgcGRmOiBQREZEb2N1bWVudFByb3h5ID0gYXdhaXQgZ2V0RG9jdW1lbnQoXG4gICAgICAgICAgICB0aGlzLmNob3NlblBsYW4uZmlsZXBhdGgsXG4gICAgICAgICkucHJvbWlzZTtcbiAgICAgICAgY29uc3QgcGFnZSA9IGF3YWl0IHBkZi5nZXRQYWdlKDEpO1xuXG4gICAgICAgIGNvbnN0IHZpZXdQb3J0UGFyYW1ldGVycyA9IHsgc2NhbGU6IDEgfTtcbiAgICAgICAgY29uc3Qgdmlld3BvcnQgPSBwYWdlLmdldFZpZXdwb3J0KHZpZXdQb3J0UGFyYW1ldGVycyk7XG5cbiAgICAgICAgdGhpcy5jYW52YXMuaGVpZ2h0ID0gdmlld3BvcnQuaGVpZ2h0O1xuICAgICAgICB0aGlzLmNhbnZhcy53aWR0aCA9IHZpZXdwb3J0LndpZHRoO1xuXG4gICAgICAgIGNvbnN0IHNpemUgPSB0aGlzLmdldFNpemVGb3JDYW52YXModmlld3BvcnQud2lkdGgsIHZpZXdwb3J0LmhlaWdodCk7XG4gICAgICAgIGNvbnNvbGUubG9nKHNpemUpO1xuICAgICAgICB0aGlzLmNhbnZhc1NpemUgPSBzaXplO1xuXG4gICAgICAgIHRoaXMuY2FudmFzWm9vbSA9IHNpemUudyAvIHZpZXdwb3J0LndpZHRoO1xuXG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLmNhbnZhcy5nZXRDb250ZXh0KFxuICAgICAgICAgICAgXCIyZFwiLFxuICAgICAgICApIGFzIENhbnZhc1JlbmRlcmluZ0NvbnRleHQyRDtcbiAgICAgICAgY29uc3QgcmVuZGVyQ29udGV4dCA9IHtcbiAgICAgICAgICAgIGNhbnZhc0NvbnRleHQ6IGNvbnRleHQsXG4gICAgICAgICAgICB2aWV3cG9ydCxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgcmVuZGVyVGFzayA9IHBhZ2UucmVuZGVyKHJlbmRlckNvbnRleHQpLnByb21pc2U7XG5cbiAgICAgICAgcmVuZGVyVGFzay50aGVuKCgpID0+IGNvbnNvbGUubG9nKFwiUGFnZSByZW5kZXJlZFwiKSk7XG5cbiAgICAgICAgLy8gY29uc3QgcmVzID0gY2FudmFzLnRvRGF0YVVSTCgpO1xuICAgICAgICAvLyBpZiAocGRmICE9IG51bGwpIHBkZi5kZXN0cm95KCk7XG4gICAgICAgIC8vIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgLyoqIFVzZXIgY2xpY2sgdG8gdXNlciBTeW1tZXRyeSBWZXJ0aWNhbCAqL1xuICAgIG9uUmVmbGVjdFYoKSB7XG4gICAgICAgIHRoaXMucmVmbGVjdFYgPSAhdGhpcy5yZWZsZWN0VjtcbiAgICAgICAgdGhpcy5jb25maWd1cmVDYW52YXMoKTtcbiAgICB9XG5cbiAgICAvKiogVXNlciBjbGljayB0byB1c2VyIFN5bW1ldHJ5IEhvcml6b250YWwgKi9cbiAgICBvblJlZmxlY3RIKCkge1xuICAgICAgICB0aGlzLnJlZmxlY3RIID0gIXRoaXMucmVmbGVjdEg7XG4gICAgICAgIHRoaXMuY29uZmlndXJlQ2FudmFzKCk7XG4gICAgfVxuXG4gICAgLyoqICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNQVRURVJQT1JUXG4gICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXG5cbiAgICAvKiogTGF1bmNoIG1hdHRlcnBvcnQgKi9cbiAgICBhc3luYyBsYXVuY2hWaWV3ZXIoKSB7XG4gICAgICAgIGF3YWl0IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2UuaW5pdFNka0Zvck1vZGVsKFxuICAgICAgICAgICAgdGhpcy5jaG9zZW5QbGFuLm1vZGVsM2QsXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgeyBzZGsgfSA9IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2U7XG4gICAgICAgIHRoaXMuZmxvb3JzID0gT2JqZWN0LnZhbHVlcyh0aGlzLm1hdHRlcnBvcnRJbXBvcnRTZXJ2aWNlLmZsb29ycyk7XG4gICAgICAgIC8vIGNvbnNvbGUubG9nKHRoaXMuZmxvb3JzKTtcbiAgICAgICAgc2V0VGltZW91dChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAvKiogTW92ZSBGbG9vciBtb2RlICovXG4gICAgICAgICAgICBhd2FpdCBzZGsuTW9kZS5tb3ZlVG8oc2RrLk1vZGUuTW9kZS5GTE9PUlBMQU4pO1xuICAgICAgICAgICAgLyoqIERpc3BsYXkgdGhlIGNvcnJlY3QgZmxvb3IgZm9yIHRoZSBwbGFuICovXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2UubW92ZVRvRmxvb3IoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2hvc2VuUGxhbi5uYW1lLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcImNvdWxkbm90IG1vdmUgdG8gZmxvb3JcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8qKiBXZSBjYW4gZGlzcGxheSB0aGUgbWF0dGVycG9ydCB2aWV3IG5vdyAqL1xuICAgICAgICAgICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XG4gICAgICAgIH0sIDMwMCk7XG5cbiAgICAgICAgLyoqIFdoZW4gdGhlIHVzZXIgdHJ5IHRvIGNoYW5nZSB0aGUgdmlldyBtb2RlIHdlIHNldCBpdCBiYWNrIHRvIGZsb29ycGFuICovXG5cbiAgICAgICAgc2RrLm9uKHNkay5Nb2RlLkV2ZW50LkNIQU5HRV9FTkQsIChvbGRNb2RlLCBuZXdNb2RlKSA9PiB7XG4gICAgICAgICAgICBpZiAobmV3TW9kZSAhPT0gc2RrLk1vZGUuTW9kZS5GTE9PUlBMQU4pIHtcbiAgICAgICAgICAgICAgICBzZGsuTW9kZS5tb3ZlVG8oc2RrLk1vZGUuTW9kZS5GTE9PUlBMQU4sIHtcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNpdGlvbjogXCJ0cmFuc2l0aW9uLmluc3RhbnRcIixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLyoqIFVwZGF0ZSBjdXJyZW50IGNhbWVyYSBwb3NlIGFuZCByb3RhdGlvbiAqL1xuICAgICAgICBzZGsuQ2FtZXJhLnBvc2Uuc3Vic2NyaWJlKChldmVudCkgPT4ge1xuICAgICAgICAgICAgLyoqIFdlIHVwZGF0ZSBvbmx5IGlmIHRoZSB1c2VyIGlzIG5vdCBjaGFuZ2luZyB0aGUgcm90YXRpb24gd2l0aCB0aGUgPGlucHV0PiByYW5nZSwgdG8gbm90IG92ZXJyaWRlIHRoZSA8aW5wdXQ+IHZhbHVlICovXG4gICAgICAgICAgICBpZiAoIXRoaXMuaXNSb3RhdGluZ1JhbmdlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5yb3RhdGlvbiA9IGV2ZW50LnJvdGF0aW9uLnkgKyAxODA7XG4gICAgICAgICAgICAgICAgdGhpcy5wcmV2Um90YXRpb24gPSB0aGlzLnJvdGF0aW9uO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FtZXJhUG9zZSA9IGV2ZW50O1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogV2hlbiB0aGUgPGlucHV0PiByYW5nZSwgZm9yIHJvdGF0aW9uLCBjaGFuZ2UgKi9cbiAgICBhc3luYyBvblJvdGF0aW9uQ2hhbmdlKCkge1xuICAgICAgICBjb25zdCByb3RhdGlvbkRlbHRhID0gdGhpcy5yb3RhdGlvbiAtIHRoaXMucHJldlJvdGF0aW9uO1xuICAgICAgICB0aGlzLnByZXZSb3RhdGlvbiA9IHRoaXMucm90YXRpb247XG5cbiAgICAgICAgLyoqIFNlbmQgdGhlIHJvdGF0aW9uRGVsdGEgdG8gdGggcXVldWUgZXZlbnQgaW4gb3JkZXIgdG8gYmUgc2VuZCB0byBtYXR0ZXJwb3J0ICovXG4gICAgICAgIHRoaXMucm90YXRpbmdRdWV1ZUV2ZW50LnB1c2gocm90YXRpb25EZWx0YSk7XG5cbiAgICAgICAgLyoqIFN0YXJ0IHRvIHByb2Nlc3MgdGhlIHF1ZXVlLCBpZiBpdCdzIHRoZSBmaXJzdCBldmVudCAqL1xuICAgICAgICBpZiAoIXRoaXMuaXNSb3RhdGluZ1JhbmdlKSB7XG4gICAgICAgICAgICB0aGlzLmlzUm90YXRpbmdSYW5nZSA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLnByb2Nlc3NSb3RhdGluZ1F1ZXVlRXZlbnQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBQcm9jZXNzIHRoZSByb3RhdGluZyBldmVudCBxdWV1ZSwgc2VuZCBldmVudCBvbmUgYnkgb25lIHRvIG1hdHRlcnBvcnQgICovXG4gICAgYXN5bmMgcHJvY2Vzc1JvdGF0aW5nUXVldWVFdmVudCgpIHtcbiAgICAgICAgY29uc3QgeyBzZGsgfSA9IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2U7XG5cbiAgICAgICAgLyoqIFdoaWxlIHRoZSBxdWV1ZSBpcyBub3QgZW1wdHkgKi9cbiAgICAgICAgd2hpbGUgKHRoaXMucm90YXRpbmdRdWV1ZUV2ZW50Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIC8qKiBSb3RhdGUgbWF0dGVycG9ydCBieSBkZWx0YVJvdGF0aW9uIGFuZCByZW1vdmUgZXZlbnQgZnJvbSBxdWV1ZSAqL1xuICAgICAgICAgICAgYXdhaXQgc2RrLkNhbWVyYS5yb3RhdGUodGhpcy5yb3RhdGluZ1F1ZXVlRXZlbnQuc2hpZnQoKSwgMCwge1xuICAgICAgICAgICAgICAgIHNwZWVkOiAzNjAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKiBXaGVuIHRoZSBxdWV1ZSBpcyBlbXB0eSwgdGhlbiB0aGUgdXNlciBpcyBub3Qgcm90YXRpbmcgd2l0aCB0aGUgPGlucHV0PiByYW5nZSBhbnltb3JlICovXG4gICAgICAgIHRoaXMuaXNSb3RhdGluZ1JhbmdlID0gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBVU0VSIEFDVElPTlNcbiAgICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogKi9cblxuICAgIC8qKiBQcmV2aWV3IGNhbGlicmF0aW9uICovXG4gICAgYXN5bmMgb25QcmV2aWV3KCkge1xuICAgICAgICB0aGlzLnByZXZpZXcgPSB0cnVlO1xuICAgICAgICAvKiogUGxhY2Ugc3dlZXBzICovXG4gICAgICAgIHRoaXMub25QbGFjZVN3ZWVwcygpO1xuICAgIH1cblxuICAgIGFzeW5jIGNhbGlicmF0ZSgpIHtcbiAgICAgICAgY29uc3QgW25hdmlnYXRpb25dID0gdGhpcy5jdXJyZW50TmF2aWdhdGlvbnM7XG4gICAgICAgIGNvbnN0IHBvc2l0aW9uID0gSlNPTi5wYXJzZShuYXZpZ2F0aW9uLnBvc2l0aW9uKTtcbiAgICAgICAgdGhpcy5maXJzdE1hcmtQbGFuID1cbiAgICAgICAgICAgIGF3YWl0IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2Uuc2RrLlJlbmRlcmVyLmdldFNjcmVlblBvc2l0aW9uKHtcbiAgICAgICAgICAgICAgICB4OiBwb3NpdGlvbi54LFxuICAgICAgICAgICAgICAgIHk6IHBvc2l0aW9uLnksXG4gICAgICAgICAgICAgICAgejogcG9zaXRpb24ueixcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNlY29uZE1hcmtQbGFuID1cbiAgICAgICAgICAgIGF3YWl0IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2Uuc2RrLlJlbmRlcmVyLmdldFNjcmVlblBvc2l0aW9uKHtcbiAgICAgICAgICAgICAgICB4OiBwb3NpdGlvbi54LFxuICAgICAgICAgICAgICAgIHk6IDAsXG4gICAgICAgICAgICAgICAgejogMCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICBjb25zdCBkZWx0YVpWaXNpdCA9IDAgLSBwb3NpdGlvbi56O1xuICAgICAgICBsZXQgZGVsdGFYUGxhbiA9IHRoaXMuc2Vjb25kTWFya1BsYW4ueCAtIHRoaXMuZmlyc3RNYXJrUGxhbi54O1xuICAgICAgICBpZiAoZGVsdGFYUGxhbiA9PT0gMCkge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCJ3ZSBtb3ZlZCBhbG9uZyBZIGF4aXMgb24gUGxhblwiKTtcbiAgICAgICAgICAgIGNvbnN0IGRlbHRhWVBsYW4gPSB0aGlzLnNlY29uZE1hcmtQbGFuLnkgLSB0aGlzLmZpcnN0TWFya1BsYW4ueTtcbiAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLm5hbWVZQXhpcyA9IFwielwiO1xuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2UubmFtZVhBeGlzID0gXCJ4XCI7XG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5vZmZzZXRZID0gdGhpcy5zZWNvbmRNYXJrUGxhbi55O1xuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uuc2NhbGVZID0gZGVsdGFZUGxhbiAvIGRlbHRhWlZpc2l0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCIgd2UgbW92ZWQgYWxvbmcgWCBheGlzIG9uIFBsYW5cIik7XG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5uYW1lWUF4aXMgPSBcInhcIjtcbiAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLm5hbWVYQXhpcyA9IFwielwiO1xuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WCA9IHRoaXMuc2Vjb25kTWFya1BsYW4ueDtcbiAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLnNjYWxlWCA9IGRlbHRhWFBsYW4gLyBkZWx0YVpWaXNpdDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0aGlyZE1hcmtQbGFuID1cbiAgICAgICAgICAgIGF3YWl0IHRoaXMubWF0dGVycG9ydEltcG9ydFNlcnZpY2Uuc2RrLlJlbmRlcmVyLmdldFNjcmVlblBvc2l0aW9uKHtcbiAgICAgICAgICAgICAgICB4OiAwLFxuICAgICAgICAgICAgICAgIHk6IDAsXG4gICAgICAgICAgICAgICAgejogcG9zaXRpb24ueixcbiAgICAgICAgICAgIH0pO1xuICAgICAgICBjb25zdCBkZWx0YVhWaXNpdCA9IDAgLSBwb3NpdGlvbi54O1xuICAgICAgICBpZiAoZGVsdGFYUGxhbiA9PT0gMCkge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCIgd2UgbW92ZWQgYWxvbmcgWCBheGlzIG9uIFBsYW5cIik7XG4gICAgICAgICAgICBkZWx0YVhQbGFuID0gdGhpcmRNYXJrUGxhbi54IC0gdGhpcy5maXJzdE1hcmtQbGFuLng7XG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5vZmZzZXRYID0gdGhpcmRNYXJrUGxhbi54O1xuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uuc2NhbGVYID0gZGVsdGFYUGxhbiAvIGRlbHRhWFZpc2l0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgZGVsdGFZUGxhbiA9IHRoaXJkTWFya1BsYW4ueSAtIHRoaXMuZmlyc3RNYXJrUGxhbi55O1xuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WSA9IHRoaXJkTWFya1BsYW4ueTtcbiAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLnNjYWxlWSA9IGRlbHRhWVBsYW4gLyBkZWx0YVhWaXNpdDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKiBUYWtlIGNvbnNpZGlyYXRpb24gb2YgcGFuIGFuZCB6b29tIG9mIHBsYW4gb24gY2FudmFzICovXG4gICAgICAgIGNvbnN0IHRyYW5zZm9ybUluZm8gPSB0aGlzLnBhbnpvb20uZ2V0VHJhbnNmb3JtKCk7XG4gICAgICAgIGNvbnN0IHsgc2NhbGUsIHgsIHkgfSA9IHRyYW5zZm9ybUluZm87XG4gICAgICAgIC8vIGNvbnNvbGUubG9nKHRyYW5zZm9ybUluZm8pO1xuICAgICAgICB0aGlzLmNhbGlicmFnZS5vZmZzZXRYUGxhbiA9IHg7XG4gICAgICAgIHRoaXMuY2FsaWJyYWdlLm9mZnNldFlQbGFuID0geTtcbiAgICAgICAgdGhpcy5jYWxpYnJhZ2Uuc2NhbGVQbGFuID0gc2NhbGU7XG4gICAgICAgIGNvbnNvbGUubG9nKHRoaXMuY2FsaWJyYWdlKTtcbiAgICB9XG5cbiAgICAvKiogUGxhY2Ugc3dlZXBzICovXG4gICAgYXN5bmMgb25QbGFjZVN3ZWVwcygpIHtcbiAgICAgICAgLyoqIERpc3BsYXkgYWxsIHNjYW4gKi9cbiAgICAgICAgY29uc3Qgem9uZSA9IGF3YWl0IHRoaXMuem9uZVNlcnZpY2UuZ2V0Wm9uZSh0aGlzLmNob3NlblBsYW4uem9uZUlEKTtcblxuICAgICAgICBpZiAoem9uZSkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50Wm9uZSA9IHpvbmU7XG4gICAgICAgICAgICBjb25zdCBuYXZpZ2F0aW9ucyA9XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5uYXZpZ2F0aW9uU2VydmljZS5nZXROYXZpZ2F0aW9uc0ZvclpvbmUoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFpvbmUsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudE5hdmlnYXRpb25zID0gbmF2aWdhdGlvbnM7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmNhbGlicmF0ZSgpO1xuICAgICAgICAgICAgaWYgKG5hdmlnYXRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IG5hdmlnYXRpb24gb2YgbmF2aWdhdGlvbnMpIHsgICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICBjb25zdCB0ZXN0UG9zaXRpb24gPSBKU09OLnBhcnNlKG5hdmlnYXRpb24ucG9zaXRpb24pO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwb3NpdGlvblggPVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2UubmFtZVhBeGlzID09PSBcInhcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gdGVzdFBvc2l0aW9uLnhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHRlc3RQb3NpdGlvbi56O1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwb3NpdGlvblkgPVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2UubmFtZVlBeGlzID09PSBcInhcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gdGVzdFBvc2l0aW9uLnhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHRlc3RQb3NpdGlvbi56O1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0ZXN0WCA9XG4gICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvblggKiB0aGlzLmNhbGlicmFnZS5zY2FsZVggK1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WDtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGVzdFkgPVxuICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb25ZICogdGhpcy5jYWxpYnJhZ2Uuc2NhbGVZICtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLm9mZnNldFk7XG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKFwidGVzdCBwb3NpdGlvbiBHUkVFTlwiLCB0ZXN0WCwgdGVzdFkpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0cmFuc2Zvcm1lZFggPVxuICAgICAgICAgICAgICAgICAgICAgICAgKHRlc3RYIC0gdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WFBsYW4pIC9cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLnNjYWxlUGxhbjsgLy8gd2UgYXJlIHVuZG9pbmcgdGhlIHBhbiBhbmQgem9vbVxuICAgICAgICAgICAgICAgICAgICBjb25zdCB0cmFuc2Zvcm1lZFkgPVxuICAgICAgICAgICAgICAgICAgICAgICAgKHRlc3RZIC0gdGhpcy5jYWxpYnJhZ2Uub2Zmc2V0WVBsYW4pIC9cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLnNjYWxlUGxhbjtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wb3NpdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICBuYXZJRDogbmF2aWdhdGlvbi5pZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHBsYW5JRDogdGhpcy5jaG9zZW5QbGFuLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgeDogdHJhbnNmb3JtZWRYLFxuICAgICAgICAgICAgICAgICAgICAgICAgeTogdHJhbnNmb3JtZWRZLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaWNvblNpemUgPSAzMCAqIHRoaXMuY2FsaWJyYWdlLnNjYWxlUGxhbjtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2hpZnQgPSBpY29uU2l6ZSAvIDI7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZHJhd0ltYWdlKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJodHRwczovL2FwaS5pY29uaWZ5LmRlc2lnbi9tZGk6YWRqdXN0LnN2Zz9jb2xvcj1ncmVlbiZoZWlnaHQ9MzAmd2lkdGg9MzBcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybWVkWCAtIHNoaWZ0LFxuICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtZWRZIC0gc2hpZnQsXG4gICAgICAgICAgICAgICAgICAgICAgICB0cnVlLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBTYXZlIGNhbGlicmF0aW9uICovXG4gICAgYXN5bmMgb25TYXZlKCkge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50Wm9uZSkge1xuICAgICAgICAgICAgLyoqIE5vcm1hbGl6ZSB3aXRoIHRoZSB6b29tICovXG4gICAgICAgICAgICAvLyB0aGlzLmNhbGlicmFnZS5vZmZzZXRYIC89IHRoaXMuY2FudmFzWm9vbTtcbiAgICAgICAgICAgIC8vIHRoaXMuY2FsaWJyYWdlLm9mZnNldFkgLz0gdGhpcy5jYW52YXNab29tO1xuICAgICAgICAgICAgLy8gdGhpcy5jYWxpYnJhZ2UueCAvPSB0aGlzLmNhbnZhc1pvb207XG4gICAgICAgICAgICAvLyB0aGlzLmNhbGlicmFnZS55IC89IHRoaXMuY2FudmFzWm9vbTtcbiAgICAgICAgICAgIHRoaXMuY2FsaWJyYWdlLm5ldyA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmNhbGlicmFnZS5pbWdXaWR0aCA9IHRoaXMuY2FudmFzU2l6ZS53O1xuICAgICAgICAgICAgdGhpcy5jYWxpYnJhZ2UuaW1nSGVpZ2h0ID0gdGhpcy5jYW52YXNTaXplLmg7XG5cbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGxhblNlcnZpY2UudXBkYXRlUGxhbih7XG4gICAgICAgICAgICAgICAgaWQ6IHRoaXMuY2hvc2VuUGxhbi5pZCxcbiAgICAgICAgICAgICAgICBjYWxpYnJhdGlvbjogSlNPTi5zdHJpbmdpZnkodGhpcy5jYWxpYnJhZ2UpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgICAgICB0aGlzLnBvc2l0aW9ucy5tYXAoYXN5bmMgKHBvc2l0aW9uKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHsgbmF2SUQgfSA9IHBvc2l0aW9uO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgcG9zaXRpb24ubmF2SUQ7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5hdiA9IHRoaXMuY3VycmVudE5hdmlnYXRpb25zLmZpbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAoX25hdikgPT4gX25hdi5pZCA9PT0gbmF2SUQsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGxldCBwb3NpdGlvbnNEYXRhVG9VcGRhdGU7XG4gICAgICAgICAgICAgICAgICAgIGlmIChuYXYucG9zaXRpb25PblBsYW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uT25QbGFuID0gbmF2LnBvc2l0aW9uT25QbGFuLm1hcCgoZW50cnkpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgSlNPTi5wYXJzZShlbnRyeSksXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcG9zaXRpb25Gb3JDdXJyZW50UGxhbiA9IHBvc2l0aW9uT25QbGFuLmZpbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGVudHJ5KSA9PiBlbnRyeS5wbGFuSUQgPT09IHRoaXMuY2hvc2VuUGxhbi5pZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocG9zaXRpb25Gb3JDdXJyZW50UGxhbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uT25QbGFuLnNwbGljZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb25PblBsYW4uaW5kZXhPZihwb3NpdGlvbkZvckN1cnJlbnRQbGFuKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb25PblBsYW4ucHVzaChwb3NpdGlvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbnNEYXRhVG9VcGRhdGUgPSBbLi4ucG9zaXRpb25PblBsYW5dO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb25zRGF0YVRvVXBkYXRlID0gW3Bvc2l0aW9uXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhwb3NpdGlvbnNEYXRhVG9VcGRhdGUpO1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLm5hdmlnYXRpb25TZXJ2aWNlLnVwZGF0ZU5hdmlnYXRpb24oe1xuICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IG5hdklELFxuICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb25PblBsYW46IHBvc2l0aW9uc0RhdGFUb1VwZGF0ZS5tYXAoKGVudHJ5KSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGVudHJ5KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1hdHRlcnBvcnRJbXBvcnRTZXJ2aWNlLnJlbW92ZUZyYW1lKCk7XG5cbiAgICAgICAgdGhpcy5yb3V0ZXIubmF2aWdhdGUoW1xuICAgICAgICAgICAgXCIvZGFzaGJvYXJkL2xvY2FsaXNhdGlvblwiLFxuICAgICAgICAgICAgdGhpcy5zcGFjZUlELFxuICAgICAgICAgICAgXCJwbGFuc1wiLFxuICAgICAgICBdKTtcbiAgICAgICAgYWxlcnQodGhpcy50cmFuc2xhdGUuaW5zdGFudChcImNhbGlicmF0aW9uLnN1Y2Nlc3NcIikpO1xuICAgIH1cblxuICAgIC8qKiBSZXNldCB0aGUgY2FudmFzICovXG4gICAgb25SZXNldCgpIHtcbiAgICAgICAgdGhpcy5yZWZsZWN0SCA9IGZhbHNlO1xuICAgICAgICB0aGlzLnJlZmxlY3RWID0gZmFsc2U7XG4gICAgICAgIHRoaXMucHJldmlldyA9IGZhbHNlO1xuXG4gICAgICAgIHRoaXMuY29uZmlndXJlQ2FudmFzKCk7XG4gICAgfVxuXG4gICAgLyoqIENhbmNlbCwgbGVhdmUgKi9cbiAgICBvbkNhbmNlbCgpIHtcbiAgICAgICAgdGhpcy5tYXR0ZXJwb3J0SW1wb3J0U2VydmljZS5yZW1vdmVGcmFtZSgpO1xuICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbXG4gICAgICAgICAgICBcIi9kYXNoYm9hcmQvbG9jYWxpc2F0aW9uXCIsXG4gICAgICAgICAgICB0aGlzLnNwYWNlSUQsXG4gICAgICAgICAgICBcInBsYW5zXCIsXG4gICAgICAgIF0pO1xuICAgICAgICBhbGVydCh0aGlzLnRyYW5zbGF0ZS5pbnN0YW50KFwiY2FsaWJyYXRpb24uY2FuY2VsZWRcIikpO1xuICAgIH1cblxuICAgIGFzeW5jIG9uRmxvb3JDbGljayhmbG9vcikge1xuICAgICAgICB0aGlzLmN1cnJlbnRGbG9vciA9IGZsb29yO1xuICAgICAgICBhd2FpdCB0aGlzLm1hdHRlcnBvcnRJbXBvcnRTZXJ2aWNlLm1vdmVUb0Zsb29yKGZsb29yLmlkKTtcbiAgICB9XG5cbiAgICBvbkFjdGl2YXRlWm9vbUNoYW5nZSgpIHtcbiAgICAgICAgdGhpcy56b29tQ2FuQmVDaGFuZ2VkID0gIXRoaXMuem9vbUNhbkJlQ2hhbmdlZDtcbiAgICAgICAgY29uc3QgaWZyYW1lID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcIiN2aWV3ZXItZnJhbWVcIikgYXMgSFRNTEVsZW1lbnQ7XG4gICAgICAgIGlmIChpZnJhbWUpIHtcbiAgICAgICAgICAgIGlmcmFtZS5zdHlsZS56SW5kZXggPSB0aGlzLnpvb21DYW5CZUNoYW5nZWQgPyBcIjFcIiA6IFwiMFwiO1xuICAgICAgICB9XG4gICAgfVxuXG59XG4iLCI8ZGl2IGNsYXNzPVwicm93IG10LTNcIj5cbiAgICA8ZGl2IGNsYXNzPVwiY29sXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJtLTNcIj5cbiAgICAgICAgICAgIDxsaWItdGFiLW5hdmlnYXRpb24gW21lbnVJdGVtc109J21lbnVJdGVtcyc+PC9saWItdGFiLW5hdmlnYXRpb24+XG4gICAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuPC9kaXY+XG5cbjxkaXYgaWQ9XCJyb3dDYW52YXNcIj5cbiAgICA8ZGl2ICNjYW52YXNEaXYgaWQ9XCJjYW52YXNEaXZcIj5cblxuICAgICAgICA8ZGl2IGlkPVwidmlld2VyLWZyYW1lXCIgW3N0eWxlLnBvaW50ZXItZXZlbnRzXT1cInpvb21DYW5CZUNoYW5nZWQ/J2F1dG8nOidub25lJ1wiPlxuICAgICAgICAgICAgPCEtLSA8ZGl2IGNsYXNzPVwiYmx1clwiPjwvZGl2PiAtLT5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxjYW52YXMgaWQ9XCJjYW52YXNcIiBbbmdTdHlsZV09XCJ7J29wYWNpdHknOiAocHJldmlld3x8bG9hZGluZykgPyAnMScgOiAnY2FsYygnICsgb3BhY2l0eSArICcvIDEwMCknfVwiPjwvY2FudmFzPlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiBjbGFzcz1cImNhbGlicmF0aW9uLXRvb2xzIGNvbnRhaW5lci1mbHVpZFwiICpuZ0lmPVwiIShwcmV2aWV3IHx8IGxvYWRpbmcpXCI+XG4gICAgICAgIDxoMT57eydDYWxpYnJhdGlvbiB0b29sJyB8IHRyYW5zbGF0ZX19PC9oMT5cbiAgICAgICAgPGRpdiBjbGFzcz1cInRvb2xcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJyb3cgbXMtMCBtZS0wIGxlZ2VuZFwiPlxuICAgICAgICAgICAgICAgIDxkaXYgW25nU3R5bGVdPVwieydvcGFjaXR5JzogJ2NhbGMoJyArICgtKG9wYWNpdHktMTAwKSsxMCkgKyAnLyAxMDApJ31cIj57eydMZXNzJyB8IHRyYW5zbGF0ZX19PC9kaXY+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImxlZ2VuZC10aXRsZVwiPnt7J1BsYW4gT3BhY2l0eScgfCB0cmFuc2xhdGUgfX08L2Rpdj5cbiAgICAgICAgICAgICAgICA8ZGl2IFtuZ1N0eWxlXT1cInsnb3BhY2l0eSc6ICdjYWxjKCcgKyAob3BhY2l0eSsxMCkgKyAnLyAxMDApJ31cIj57eydNb3JlJyB8IHRyYW5zbGF0ZX19PC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJyb3cgbXMtMCBtZS0wIFwiPlxuICAgICAgICAgICAgICAgIDxpbnB1dCBbZGlzYWJsZWRdPVwiZmFsc2VcIiBbbmdNb2RlbE9wdGlvbnNdPVwie3N0YW5kYWxvbmU6IHRydWV9XCIgWyhuZ01vZGVsKV09XCJvcGFjaXR5XCIgdHlwZT1cInJhbmdlXCJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJmb3JtLXJhbmdlXCIgbWluPVwiMFwiIG1heD1cIjEwMFwiIHZhbHVlPVwiNTBcIiBpZD1cIm9wYWNpdHlcIj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInRvb2xcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJyb3cgbXMtMCBtZS0wIFwiPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJsYWJlbC1sZWdlbmRcIj57eydDaGFuZ2UgVmlzaXQgRmxvb3InIHwgdHJhbnNsYXRlfX08L2Rpdj5cbiAgICAgICAgICAgICAgICA8ZGl2IG5nYkRyb3Bkb3duIGNsYXNzPVwiZC1pbmxpbmUtYmxvY2sgbXMtM1wiPlxuICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1sYWJlbC1maWxlIHJvdW5kZWQtcGlsbFwiIGlkPVwiZHJvcGRvd25CYXNpYzFcIiBuZ2JEcm9wZG93blRvZ2dsZT5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7Y3VycmVudEZsb29yID8gY3VycmVudEZsb29yLmlkIDogKCdGbG9vcicgfCB0cmFuc2xhdGUpIH19PC9idXR0b24+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgbmdiRHJvcGRvd25NZW51IGFyaWEtbGFiZWxsZWRieT1cImRyb3Bkb3duQmFzaWMxXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIG5nYkRyb3Bkb3duSXRlbSAqbmdGb3I9XCJsZXQgZmxvb3Igb2YgZmxvb3JzXCIgKGNsaWNrKT1cIm9uRmxvb3JDbGljayhmbG9vcilcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7eyBmbG9vci5uYW1lLmxlbmd0aCA+IDAgPyBmbG9vci5uYW1lIDogKCdGbG9vciAnICsgZmxvb3IuaWQpIH19XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInRvb2xcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJyb3cgbXMtMCBtZS0wIFwiPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJsYWJlbC1sZWdlbmQgbWUtM1wiPnt7J1Bhbi9ab29tIFZpc2l0JyB8IHRyYW5zbGF0ZX19IHt7em9vbUNhbkJlQ2hhbmdlZCA/IFwiT05cIiA6IFwiT0ZGXCJ9fVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiAoY2hhbmdlKT1cIm9uQWN0aXZhdGVab29tQ2hhbmdlKClcIiBzdHlsZT1cIm1hcmdpbi10b3A6IDVweDtcIj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZCBib3JkZXItd2FybmluZyBtYi0zIG10LTNcIiAqbmdJZj1cInpvb21DYW5CZUNoYW5nZWRcIj5cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQtYm9keSB0ZXh0LXdhcm5pbmdcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxoNSBjbGFzcz1cImNhcmQtdGl0bGVcIj57e1wiY2FsaWJyYXRpb24ud2FpdC1tZXNzYWdlXCIgfCB0cmFuc2xhdGV9fTwvaDU+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJhY3Rpb25cIj5cbiAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1vdXRsaW5lLXByaW1hcnkgcm91bmRlZC1waWxsXCIgKGNsaWNrKT1cIm9uUHJldmlldygpXCJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiem9vbUNhbkJlQ2hhbmdlZFwiPnt7J1ByZXZpZXcnIHwgdHJhbnNsYXRlfX08L2J1dHRvbj5cbiAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1vdXRsaW5lLXByaW1hcnkgcm91bmRlZC1waWxsXCIgKGNsaWNrKT1cIm9uQ2FuY2VsKClcIj57eydDYW5jZWwnIHxcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxuXG4gICAgICAgIDwvZGl2PlxuXG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImNhbGlicmF0aW9uLXRvb2xzIGNvbnRhaW5lci1mbHVpZFwiICpuZ0lmPVwicHJldmlld1wiPlxuICAgICAgICA8aDE+e3snVmFsaWRhdGlvbicgfCB0cmFuc2xhdGV9fTwvaDE+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJhY3Rpb25cIj5cbiAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1vdXRsaW5lLXByaW1hcnkgcm91bmRlZC1waWxsXCIgKGNsaWNrKT1cIm9uU2F2ZSgpXCI+e3snVmFsaWRhdGUnIHxcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxuICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLW91dGxpbmUtcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25SZXNldCgpXCI+e3snUmVzZXQnIHxcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxuICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLW91dGxpbmUtcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25DYW5jZWwoKVwiPnt7J0NhbmNlbCcgfFxuICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19PC9idXR0b24+XG5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cblxuICAgIDxkaXYgY2xhc3M9XCJjYWxpYnJhdGlvbi10b29scyBjb250YWluZXItZmx1aWRcIiAqbmdJZj1cImxvYWRpbmdcIj5cbiAgICAgICAgPGgzPnt7XCJXYWl0aW5nIGZvciBNYXR0ZXJwb3J0XCIgfCB0cmFuc2xhdGV9fS4uLjwvaDM+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXgganVzdGlmeS1jb250ZW50LWNlbnRlclwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNwaW5uZXItYm9yZGVyXCIgcm9sZT1cInN0YXR1c1wiPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidmlzdWFsbHktaGlkZGVuXCI+TG9hZGluZy4uLjwvc3Bhbj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgIDwvZGl2PlxuPC9kaXY+Il19
|