@smarterplan/ngx-smarterplan-locations 0.2.44 → 0.2.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/esm2020/lib/components/carousel/carousel.component.mjs +28 -0
  2. package/esm2020/lib/components/chevron/chevron.component.mjs +18 -0
  3. package/esm2020/lib/components/detail-location/detail-location.component.mjs +168 -0
  4. package/esm2020/lib/components/form-location/form-location.component.mjs +237 -0
  5. package/esm2020/lib/components/images/images.component.mjs +107 -0
  6. package/esm2020/lib/components/locations/locations.component.mjs +145 -0
  7. package/esm2020/lib/components/locations/map/map-popup/map-popup.component.mjs +66 -0
  8. package/esm2020/lib/components/locations/map/map.component.mjs +91 -0
  9. package/esm2020/lib/components/plan-legend/plan-legend.component.mjs +47 -0
  10. package/esm2020/lib/components/plans/calibration/calibration.component.mjs +468 -0
  11. package/esm2020/lib/components/plans/edit-plan/edit-plan.component.mjs +324 -0
  12. package/esm2020/lib/components/plans/plans.component.mjs +225 -0
  13. package/esm2020/lib/components/tab-navigation/tab-navigation.component.mjs +41 -0
  14. package/esm2020/lib/components/visits/visits.component.mjs +283 -0
  15. package/esm2020/lib/components/zones/add-audio-zone/add-audio-zone.component.mjs +230 -0
  16. package/esm2020/lib/components/zones/add-zone/add-zone.component.mjs +315 -0
  17. package/esm2020/lib/components/zones/add-zone/selection/selection.component.mjs +77 -0
  18. package/esm2020/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.mjs +502 -0
  19. package/esm2020/lib/components/zones/zones.component.mjs +268 -0
  20. package/esm2020/lib/helper.service.mjs +134 -0
  21. package/esm2020/lib/ngx-smarterplan-location-routing.module.mjs +49 -0
  22. package/esm2020/lib/ngx-smarterplan-locations.module.mjs +125 -0
  23. package/esm2020/lib/ngx-smarterplan-locations.service.mjs +14 -0
  24. package/esm2020/lib/pipes/count-audio-sweeps.pipe.mjs +27 -0
  25. package/esm2020/lib/radio-button/radio-button.component.mjs +26 -0
  26. package/esm2020/public-api.mjs +9 -0
  27. package/esm2020/smarterplan-ngx-smarterplan-locations.mjs +5 -0
  28. package/fesm2015/smarterplan-ngx-smarterplan-locations.mjs +3991 -0
  29. package/fesm2015/smarterplan-ngx-smarterplan-locations.mjs.map +1 -0
  30. package/fesm2020/smarterplan-ngx-smarterplan-locations.mjs +3828 -0
  31. package/fesm2020/smarterplan-ngx-smarterplan-locations.mjs.map +1 -0
  32. package/lib/components/carousel/carousel.component.d.ts +12 -0
  33. package/lib/components/chevron/chevron.component.d.ts +9 -0
  34. package/lib/components/detail-location/detail-location.component.d.ts +55 -0
  35. package/lib/components/form-location/form-location.component.d.ts +45 -0
  36. package/lib/components/images/images.component.d.ts +33 -0
  37. package/lib/components/locations/locations.component.d.ts +51 -0
  38. package/lib/components/locations/map/map-popup/map-popup.component.d.ts +22 -0
  39. package/lib/components/locations/map/map.component.d.ts +22 -0
  40. package/lib/components/plan-legend/plan-legend.component.d.ts +14 -0
  41. package/lib/components/plans/calibration/calibration.component.d.ts +140 -0
  42. package/lib/components/plans/edit-plan/edit-plan.component.d.ts +55 -0
  43. package/lib/components/plans/plans.component.d.ts +63 -0
  44. package/lib/components/tab-navigation/tab-navigation.component.d.ts +13 -0
  45. package/lib/components/visits/visits.component.d.ts +62 -0
  46. package/lib/components/zones/add-audio-zone/add-audio-zone.component.d.ts +63 -0
  47. package/lib/components/zones/add-zone/add-zone.component.d.ts +69 -0
  48. package/lib/components/zones/add-zone/selection/selection.component.d.ts +44 -0
  49. package/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.d.ts +107 -0
  50. package/lib/components/zones/zones.component.d.ts +73 -0
  51. package/lib/helper.service.d.ts +53 -0
  52. package/lib/ngx-smarterplan-location-routing.module.d.ts +7 -0
  53. package/lib/ngx-smarterplan-locations.module.d.ts +36 -0
  54. package/lib/ngx-smarterplan-locations.service.d.ts +6 -0
  55. package/lib/pipes/count-audio-sweeps.pipe.d.ts +10 -0
  56. package/lib/radio-button/radio-button.component.d.ts +12 -0
  57. package/package.json +22 -5
  58. package/{src/public-api.ts → public-api.d.ts} +4 -11
  59. package/smarterplan-ngx-smarterplan-locations.d.ts +5 -0
  60. package/.browserslistrc +0 -16
  61. package/karma.conf.js +0 -44
  62. package/ng-package.json +0 -7
  63. package/src/lib/components/carousel/carousel.component.html +0 -13
  64. package/src/lib/components/carousel/carousel.component.scss +0 -0
  65. package/src/lib/components/carousel/carousel.component.spec.ts +0 -25
  66. package/src/lib/components/carousel/carousel.component.ts +0 -31
  67. package/src/lib/components/chevron/chevron.component.html +0 -5
  68. package/src/lib/components/chevron/chevron.component.scss +0 -16
  69. package/src/lib/components/chevron/chevron.component.spec.ts +0 -25
  70. package/src/lib/components/chevron/chevron.component.ts +0 -17
  71. package/src/lib/components/detail-location/detail-location.component.html +0 -108
  72. package/src/lib/components/detail-location/detail-location.component.scss +0 -0
  73. package/src/lib/components/detail-location/detail-location.component.spec.ts +0 -25
  74. package/src/lib/components/detail-location/detail-location.component.ts +0 -215
  75. package/src/lib/components/form-location/form-location.component.html +0 -160
  76. package/src/lib/components/form-location/form-location.component.scss +0 -62
  77. package/src/lib/components/form-location/form-location.component.spec.ts +0 -25
  78. package/src/lib/components/form-location/form-location.component.ts +0 -274
  79. package/src/lib/components/images/images.component.html +0 -27
  80. package/src/lib/components/images/images.component.scss +0 -0
  81. package/src/lib/components/images/images.component.spec.ts +0 -25
  82. package/src/lib/components/images/images.component.ts +0 -133
  83. package/src/lib/components/locations/locations.component.html +0 -63
  84. package/src/lib/components/locations/locations.component.scss +0 -121
  85. package/src/lib/components/locations/locations.component.spec.ts +0 -25
  86. package/src/lib/components/locations/locations.component.ts +0 -186
  87. package/src/lib/components/locations/map/map-popup/map-popup.component.html +0 -11
  88. package/src/lib/components/locations/map/map-popup/map-popup.component.scss +0 -51
  89. package/src/lib/components/locations/map/map-popup/map-popup.component.spec.ts +0 -25
  90. package/src/lib/components/locations/map/map-popup/map-popup.component.ts +0 -79
  91. package/src/lib/components/locations/map/map.component.html +0 -2
  92. package/src/lib/components/locations/map/map.component.scss +0 -0
  93. package/src/lib/components/locations/map/map.component.spec.ts +0 -25
  94. package/src/lib/components/locations/map/map.component.ts +0 -111
  95. package/src/lib/components/plan-legend/plan-legend.component.html +0 -9
  96. package/src/lib/components/plan-legend/plan-legend.component.scss +0 -38
  97. package/src/lib/components/plan-legend/plan-legend.component.spec.ts +0 -25
  98. package/src/lib/components/plan-legend/plan-legend.component.ts +0 -50
  99. package/src/lib/components/plans/calibration/calibration.component.html +0 -98
  100. package/src/lib/components/plans/calibration/calibration.component.scss +0 -136
  101. package/src/lib/components/plans/calibration/calibration.component.spec.ts +0 -25
  102. package/src/lib/components/plans/calibration/calibration.component.ts +0 -603
  103. package/src/lib/components/plans/edit-plan/edit-plan.component.html +0 -77
  104. package/src/lib/components/plans/edit-plan/edit-plan.component.scss +0 -9
  105. package/src/lib/components/plans/edit-plan/edit-plan.component.spec.ts +0 -25
  106. package/src/lib/components/plans/edit-plan/edit-plan.component.ts +0 -421
  107. package/src/lib/components/plans/plans.component.html +0 -102
  108. package/src/lib/components/plans/plans.component.scss +0 -24
  109. package/src/lib/components/plans/plans.component.spec.ts +0 -25
  110. package/src/lib/components/plans/plans.component.ts +0 -305
  111. package/src/lib/components/tab-navigation/tab-navigation.component.html +0 -7
  112. package/src/lib/components/tab-navigation/tab-navigation.component.scss +0 -27
  113. package/src/lib/components/tab-navigation/tab-navigation.component.spec.ts +0 -25
  114. package/src/lib/components/tab-navigation/tab-navigation.component.ts +0 -35
  115. package/src/lib/components/visits/visits.component.html +0 -134
  116. package/src/lib/components/visits/visits.component.scss +0 -24
  117. package/src/lib/components/visits/visits.component.spec.ts +0 -25
  118. package/src/lib/components/visits/visits.component.ts +0 -357
  119. package/src/lib/components/zones/add-audio-zone/add-audio-zone.component.html +0 -73
  120. package/src/lib/components/zones/add-audio-zone/add-audio-zone.component.scss +0 -14
  121. package/src/lib/components/zones/add-audio-zone/add-audio-zone.component.spec.ts +0 -25
  122. package/src/lib/components/zones/add-audio-zone/add-audio-zone.component.ts +0 -269
  123. package/src/lib/components/zones/add-zone/add-zone.component.html +0 -153
  124. package/src/lib/components/zones/add-zone/add-zone.component.scss +0 -44
  125. package/src/lib/components/zones/add-zone/add-zone.component.spec.ts +0 -25
  126. package/src/lib/components/zones/add-zone/add-zone.component.ts +0 -377
  127. package/src/lib/components/zones/add-zone/selection/selection.component.html +0 -3
  128. package/src/lib/components/zones/add-zone/selection/selection.component.scss +0 -16
  129. package/src/lib/components/zones/add-zone/selection/selection.component.spec.ts +0 -25
  130. package/src/lib/components/zones/add-zone/selection/selection.component.ts +0 -95
  131. package/src/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.html +0 -73
  132. package/src/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.scss +0 -23
  133. package/src/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.spec.ts +0 -25
  134. package/src/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.ts +0 -595
  135. package/src/lib/components/zones/zones.component.html +0 -181
  136. package/src/lib/components/zones/zones.component.scss +0 -36
  137. package/src/lib/components/zones/zones.component.spec.ts +0 -25
  138. package/src/lib/components/zones/zones.component.ts +0 -339
  139. package/src/lib/helper.service.ts +0 -161
  140. package/src/lib/ngx-smarterplan-location-routing.module.ts +0 -41
  141. package/src/lib/ngx-smarterplan-locations.module.ts +0 -74
  142. package/src/lib/ngx-smarterplan-locations.service.spec.ts +0 -16
  143. package/src/lib/ngx-smarterplan-locations.service.ts +0 -9
  144. package/src/lib/pipes/count-audio-sweeps.pipe.ts +0 -21
  145. package/src/lib/radio-button/radio-button.component.html +0 -9
  146. package/src/lib/radio-button/radio-button.component.scss +0 -152
  147. package/src/lib/radio-button/radio-button.component.spec.ts +0 -25
  148. package/src/lib/radio-button/radio-button.component.ts +0 -26
  149. package/src/test.ts +0 -27
  150. package/tsconfig.lib.json +0 -15
  151. package/tsconfig.lib.prod.json +0 -10
  152. package/tsconfig.spec.json +0 -17
@@ -0,0 +1,502 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { getCoefficientsForImage, getMetaForImage, showScanPointsOnPlanInDiv } from '@smarterplan/ngx-smarterplan-core';
3
+ import panzoom from 'panzoom';
4
+ import { buttonIsInSelection, isInPolygon, rotate, setVisuallySelected, styleButton, SweepState } from '../../../../helper.service';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "@smarterplan/ngx-smarterplan-core";
7
+ import * as i2 from "@ngx-translate/core";
8
+ import * as i3 from "../selection/selection.component";
9
+ import * as i4 from "../../../plan-legend/plan-legend.component";
10
+ import * as i5 from "../../../../radio-button/radio-button.component";
11
+ import * as i6 from "@ng-bootstrap/ng-bootstrap";
12
+ import * as i7 from "@angular/common";
13
+ export class SweepPlanSelectionComponent {
14
+ constructor(zoneService, navigationService, planService, translate) {
15
+ this.zoneService = zoneService;
16
+ this.navigationService = navigationService;
17
+ this.planService = planService;
18
+ this.translate = translate;
19
+ this.chosenScansOnPlan = [];
20
+ this.navIDsZoneEdit = [];
21
+ // sweeps belonging to any audio zone
22
+ this.occupiedSweeps = [];
23
+ // sweeps unavailable (cannot be chosen)
24
+ this.unavailableSweeps = [];
25
+ // if choosing sweeps for audio zone
26
+ this.editingAudioZone = false;
27
+ this.multipleFloors = false;
28
+ /** all scan buttons Element */
29
+ this.buttonElements = [];
30
+ /** Scan buttons that are in the current selection */
31
+ this.buttonsInSelection = [];
32
+ this.sweepsSelected = new EventEmitter();
33
+ this.isSettingStartSweep = false;
34
+ this.chosenSweepsPerFloor = new Map(); // map matching floorID to sweeps selected
35
+ this.inputSweepsPerFloor = new Map(); // map matching floorID to sweeps selected for zone in edition
36
+ this.selectionChanged = false;
37
+ }
38
+ async ngOnInit() {
39
+ await this.getPlans();
40
+ this.setSweepsOfInputZone();
41
+ }
42
+ ngOnChanges() {
43
+ if (this.chosenPlan) {
44
+ this.setSweepsOfInputZone();
45
+ this.chosenScansOnPlan = [];
46
+ this.clearDivPlan();
47
+ this.addScanPoints();
48
+ }
49
+ }
50
+ setSweepsOfInputZone() {
51
+ this.navIDsZoneEdit = this.inputZone ? this.inputZone.sweepIDs : [];
52
+ if (this.multipleFloors) {
53
+ this.plans.forEach((plan) => {
54
+ if (!this.inputSweepsPerFloor.get(plan.zoneID)) {
55
+ this.inputSweepsPerFloor.set(plan.zoneID, this.navIDsZoneEdit.filter((sweep) => plan.zone.sweepIDs.includes(sweep)));
56
+ }
57
+ });
58
+ }
59
+ else {
60
+ if (this.inputZone) {
61
+ //filter plans only for the parent Zone
62
+ this.plans = this.plans.filter((p) => p.zoneID === this.inputZone.parentID);
63
+ }
64
+ }
65
+ }
66
+ async getPlans() {
67
+ this.plans = await this.planService.getSingedPlansForSpace(this.spaceID);
68
+ }
69
+ async onPlanClick(plan) {
70
+ const switchPlan = () => {
71
+ this.selectionChanged = false;
72
+ this.chosenPlan = plan;
73
+ this.chosenScansOnPlan = [];
74
+ this.clearDivPlan();
75
+ this.addScanPoints();
76
+ };
77
+ if (this.selectionChanged) {
78
+ const message = this.translate.instant("confirm.cancelModifZoneSweeps");
79
+ if (window.confirm(message)) {
80
+ switchPlan();
81
+ }
82
+ }
83
+ else {
84
+ switchPlan();
85
+ }
86
+ }
87
+ async addScanPoints() {
88
+ let wasModified = false;
89
+ if (this.multipleFloors) {
90
+ // check if we have already validated buttons for this floor
91
+ if (this.chosenSweepsPerFloor.get(this.chosenPlan.zoneID)) {
92
+ this.chosenScansOnPlan = this.chosenSweepsPerFloor.get(this.chosenPlan.zoneID);
93
+ wasModified = true;
94
+ }
95
+ }
96
+ this.divPlan = document.querySelector("#planDiv");
97
+ const zoneOfPlan = await this.zoneService.getZone(this.chosenPlan.zoneID);
98
+ const navigations = await this.navigationService.getNavigationsForZone(zoneOfPlan);
99
+ if (this.newZoneData)
100
+ await this.setScanByDraw(navigations);
101
+ this.buttonElements = await showScanPointsOnPlanInDiv(this.chosenPlan, this.divPlan, navigations);
102
+ for (const element of this.buttonElements) {
103
+ if (this.unavailableSweeps && this.unavailableSweeps.includes(element.id)) {
104
+ styleButton(element, SweepState.DISABLED);
105
+ }
106
+ else {
107
+ if (wasModified) {
108
+ if (this.chosenScansOnPlan.includes(element.id)) {
109
+ styleButton(element, SweepState.ADDED);
110
+ }
111
+ else {
112
+ styleButton(element, SweepState.REMOVED);
113
+ }
114
+ }
115
+ else {
116
+ if (this.navIDsZoneEdit.length > 0 &&
117
+ this.navIDsZoneEdit.includes(element.id)) {
118
+ styleButton(element, SweepState.ADDED);
119
+ if (!this.chosenScansOnPlan.includes(element.id)) {
120
+ this.chosenScansOnPlan.push(element.id);
121
+ }
122
+ }
123
+ else if (this.occupiedSweeps && this.occupiedSweeps.includes(element.id)) {
124
+ styleButton(element, SweepState.OCCUPIED);
125
+ }
126
+ else {
127
+ styleButton(element, SweepState.REMOVED);
128
+ }
129
+ }
130
+ //start point should be last condition
131
+ if (this.inputZone && this.inputZone.startSweepID === element.id) {
132
+ console.log("setting start point");
133
+ styleButton(element, SweepState.STARTPOINT);
134
+ }
135
+ element.addEventListener("click", (event) => this.onButtonScanClicked(event.target));
136
+ }
137
+ }
138
+ this.panZoom = panzoom(this.divPlan, {
139
+ bounds: true,
140
+ boundsPadding: 0,
141
+ maxZoom: 3.5,
142
+ beforeMouseDown(e) {
143
+ return (e.button === 2); /** Ignore event for right click (use for selecting) */
144
+ },
145
+ });
146
+ if (this.multipleFloors) {
147
+ this.chosenSweepsPerFloor.set(this.chosenPlan.zoneID, [...this.chosenScansOnPlan]);
148
+ }
149
+ }
150
+ /** Function if we are coming for svg editor workflow */
151
+ setScanByDraw(navigations) {
152
+ return new Promise(async (resolve) => {
153
+ const rect = {
154
+ width: this.newZoneData.width,
155
+ height: this.newZoneData.height,
156
+ };
157
+ const img = await getMetaForImage(this.chosenPlan.filepath);
158
+ const { coeffX, coeffY } = getCoefficientsForImage(img, rect);
159
+ const draw = this.newZoneData.elements;
160
+ draw.map(async (element) => {
161
+ switch (element.nodeName) {
162
+ case "rect":
163
+ await this.setScanInRect(img, coeffX, coeffY, element, navigations);
164
+ break;
165
+ case "ellipse":
166
+ await this.setScanInCircle(img, coeffX, coeffY, element, navigations);
167
+ break;
168
+ case "path":
169
+ await this.setScanInPolygon(img, coeffX, coeffY, element, navigations);
170
+ break;
171
+ default:
172
+ break;
173
+ }
174
+ });
175
+ resolve();
176
+ });
177
+ }
178
+ async setScanInRect(img, coeffX, coeffY, element, navigations) {
179
+ const calibrage = JSON.parse(this.chosenPlan.calibration);
180
+ navigations.map((navigation) => {
181
+ const positionsOnPlan = navigation.positionOnPlan.map((entry) => JSON.parse(entry));
182
+ const positionOnPlan = positionsOnPlan.find((data) => data.planID === this.chosenPlan.id);
183
+ if (positionOnPlan) {
184
+ const realWidth = img.width / coeffX;
185
+ const realHeight = img.height / coeffY;
186
+ const navY = (positionOnPlan.y * realHeight) / calibrage.imgHeight;
187
+ const navX = (positionOnPlan.x * realWidth) / calibrage.imgWidth;
188
+ if (navX > element.x &&
189
+ navX < element.x + element.width &&
190
+ navY > element.y &&
191
+ navY < element.y + element.height &&
192
+ !this.navIDsZoneEdit.includes(navigation.id)) {
193
+ this.navIDsZoneEdit.push(navigation.id);
194
+ }
195
+ }
196
+ // old calibration:
197
+ // const position = JSON.parse(navigation.position);
198
+ // let navX = (calibrage.offsetX + position.x * calibrage.x) / coeffX;
199
+ // let navY = (calibrage.offsetY + position.z * calibrage.y) / coeffY;
200
+ // if (element.angle) {
201
+ // const rotatePos = rotate(
202
+ // { x: navX, y: navY },
203
+ // { x: element.cx, y: element.cy },
204
+ // element.angle,
205
+ // );
206
+ // navX = rotatePos.x;
207
+ // navY = rotatePos.y;
208
+ // }
209
+ /**
210
+ * TODO calculer la rotation du rectangle
211
+ */
212
+ // if (
213
+ // navX > element.x &&
214
+ // navX < element.x + element.width &&
215
+ // navY > element.y &&
216
+ // navY < element.y + element.height &&
217
+ // !this.navIDsZoneEdit.includes(navigation.id)
218
+ // ) {
219
+ // this.navIDsZoneEdit.push(navigation.id);
220
+ // }
221
+ });
222
+ } // EO
223
+ async setScanInCircle(img, coeffX, coeffY, element, navigations) {
224
+ const calibrage = JSON.parse(this.chosenPlan.calibration);
225
+ navigations.map(navigation => {
226
+ const positionsOnPlan = navigation.positionOnPlan.map((entry) => JSON.parse(entry));
227
+ const positionOnPlan = positionsOnPlan.find((data) => data.planID === this.chosenPlan.id);
228
+ if (positionOnPlan) {
229
+ const realWidth = img.width / coeffX;
230
+ const realHeight = img.height / coeffY;
231
+ let navY = (positionOnPlan.y * realHeight) / calibrage.imgHeight;
232
+ let navX = (positionOnPlan.x * realWidth) / calibrage.imgWidth;
233
+ if (element.angle) {
234
+ const rotatePos = rotate({ x: navX, y: navY }, { x: element.cx, y: element.cy }, element.angle);
235
+ navX = rotatePos.x;
236
+ navY = rotatePos.y;
237
+ }
238
+ const valueX = Math.pow(navX - element.cx, 2) / Math.pow(element.rx, 2);
239
+ const valueY = Math.pow(navY - element.cy, 2) / Math.pow(element.ry, 2);
240
+ const result = valueX + valueY;
241
+ if (result <= 1 && !this.navIDsZoneEdit.includes(navigation.id)) {
242
+ this.navIDsZoneEdit.push(navigation.id);
243
+ }
244
+ }
245
+ // old calibration
246
+ // const position = JSON.parse(navigation.position);
247
+ // let navX = (calibrage.offsetX + position.x * calibrage.x) / coeffX;
248
+ // let navY = (calibrage.offsetY + position.z * calibrage.y) / coeffY;
249
+ // if (element.angle) {
250
+ // const rotatePos = rotate(
251
+ // { x: navX, y: navY },
252
+ // { x: element.cx, y: element.cy },
253
+ // element.angle,
254
+ // );
255
+ // navX = rotatePos.x;
256
+ // navY = rotatePos.y;
257
+ // }
258
+ // const valueX =
259
+ // Math.pow(navX - element.cx, 2) / Math.pow(element.rx, 2);
260
+ // const valueY =
261
+ // Math.pow(navY - element.cy, 2) / Math.pow(element.ry, 2);
262
+ // const result = valueX + valueY;
263
+ // if (result <= 1 && !this.navIDsZoneEdit.includes(navigation.id)) {
264
+ // this.navIDsZoneEdit.push(navigation.id);
265
+ // }
266
+ });
267
+ } // EO
268
+ async setScanInPolygon(img, coeffX, coeffY, element, navigations) {
269
+ const calibrage = JSON.parse(this.chosenPlan.calibration);
270
+ navigations.map(async (navigation) => {
271
+ const positionsOnPlan = navigation.positionOnPlan.map((entry) => JSON.parse(entry));
272
+ const positionOnPlan = positionsOnPlan.find((data) => data.planID === this.chosenPlan.id);
273
+ if (positionOnPlan) {
274
+ const realWidth = img.width / coeffX;
275
+ const realHeight = img.height / coeffY;
276
+ let navY = (positionOnPlan.y * realHeight) / calibrage.imgHeight;
277
+ let navX = (positionOnPlan.x * realWidth) / calibrage.imgWidth;
278
+ const p = {
279
+ x: navX,
280
+ y: navY,
281
+ };
282
+ if (isInPolygon(p, element.segList) &&
283
+ !this.navIDsZoneEdit.includes(navigation.id)) {
284
+ this.navIDsZoneEdit.push(navigation.id);
285
+ }
286
+ }
287
+ // old calibration
288
+ // const position = JSON.parse(navigation.position);
289
+ // const p = {
290
+ // x: (calibrage.offsetX + position.x * calibrage.x) / coeffX,
291
+ // y: (calibrage.offsetY + position.z * calibrage.y) / coeffY,
292
+ // };
293
+ // if (element.angle) {
294
+ // p = this.rotate(
295
+ // p,
296
+ // { x: element.cx, y: element.cy },
297
+ // element.angle,
298
+ // );
299
+ // }
300
+ // if (
301
+ // isInPolygon(p, element.segList) &&
302
+ // !this.navIDsZoneEdit.includes(navigation.id)
303
+ // ) {
304
+ // this.navIDsZoneEdit.push(navigation.id);
305
+ // }
306
+ });
307
+ }
308
+ clearDivPlan() {
309
+ if (this.divPlan)
310
+ this.divPlan.innerHTML = "";
311
+ }
312
+ /**
313
+ * Trigger each by the selectionComponent when selection change
314
+ * Update the current selected scan buttons
315
+ * @param selection new selection
316
+ */
317
+ onSelectionChanged(selection) {
318
+ const unselectedButtons = [];
319
+ const newSelectedButtons = [];
320
+ /** For each button, decide whether will be add to selected list or unselected list */
321
+ for (const button of this.buttonElements) {
322
+ const isSelected = buttonIsInSelection(button, selection);
323
+ if (this.buttonsInSelection.includes(button)) {
324
+ /** If the button is already in the selected list, we check if it should be unselect */
325
+ if (!isSelected) {
326
+ unselectedButtons.push(button);
327
+ }
328
+ }
329
+ else if (isSelected) {
330
+ newSelectedButtons.push(button);
331
+ }
332
+ }
333
+ /** Visually Update unselected list */
334
+ for (const button of unselectedButtons) {
335
+ setVisuallySelected(button, false);
336
+ }
337
+ /** Visually Update selected list */
338
+ for (const button of newSelectedButtons) {
339
+ setVisuallySelected(button, true);
340
+ }
341
+ /** Remove unselected list */
342
+ this.buttonsInSelection = this.buttonsInSelection.filter((button) => {
343
+ return !unselectedButtons.includes(button);
344
+ });
345
+ /** Add new selected buttons */
346
+ this.buttonsInSelection = [
347
+ ...this.buttonsInSelection,
348
+ ...newSelectedButtons,
349
+ ];
350
+ }
351
+ /**
352
+ * Trigger when the user click to add the selected scans
353
+ */
354
+ onSelectionAdd() {
355
+ for (const button of this.buttonsInSelection) {
356
+ if (!this.chosenScansOnPlan.includes(button.id)) {
357
+ this.onButtonScanClicked(button);
358
+ }
359
+ }
360
+ this.onSelectionChanged({ top: 0, left: 0, width: 0, height: 0 });
361
+ }
362
+ /**
363
+ * Trigger when the user click to remove the selected scans
364
+ */
365
+ onSelectionRemove() {
366
+ for (const button of this.buttonsInSelection) {
367
+ if (this.chosenScansOnPlan.includes(button.id)) {
368
+ this.onButtonScanClicked(button);
369
+ }
370
+ }
371
+ this.onSelectionChanged({ top: 0, left: 0, width: 0, height: 0 });
372
+ }
373
+ /**
374
+ * Trigger when the user click to select all scans
375
+ */
376
+ onSelectAll() {
377
+ this.buttonsInSelection = [...this.buttonElements];
378
+ for (const button of this.buttonsInSelection) {
379
+ setVisuallySelected(button, true);
380
+ }
381
+ }
382
+ /**
383
+ * Trigger when the user change the size of the scan points
384
+ * @param event
385
+ */
386
+ onChangeScanSize(event) {
387
+ const factor = event.target.value;
388
+ for (const button of this.buttonElements) {
389
+ button.style.transform = `scale(${factor})`;
390
+ }
391
+ }
392
+ /**
393
+ * When a button representing a scan is clicked
394
+ * @param button
395
+ */
396
+ onButtonScanClicked(button) {
397
+ this.selectionChanged = true;
398
+ if (this.isSettingStartSweep) {
399
+ if (this.startSweepID === button.id) {
400
+ // we deselect the starting point
401
+ button.style.backgroundImage = `url("https://api.iconify.design/mdi:adjust.svg?color=green&height=17&width=17")`;
402
+ this.startSweepID = null;
403
+ return;
404
+ }
405
+ button.style.backgroundImage = `url('https://api.iconify.design/ic/baseline-flag-circle.svg?color=white&width=17&height=17')`;
406
+ if (!this.chosenScansOnPlan.includes(button.id)) {
407
+ this.chosenScansOnPlan.push(button.id);
408
+ }
409
+ if (this.startSweepID) {
410
+ // we are changing start sweep
411
+ const btnChanged = this.buttonElements.find((btn) => btn.id === this.startSweepID);
412
+ btnChanged.style.backgroundImage = `url("https://api.iconify.design/mdi:adjust.svg?color=green&height=17&width=17")`;
413
+ }
414
+ this.startSweepID = button.id;
415
+ return;
416
+ }
417
+ if (!this.chosenScansOnPlan.includes(button.id)) {
418
+ // add to selection
419
+ button.style.backgroundImage = `url("https://api.iconify.design/mdi:adjust.svg?color=green&height=17&width=17")`;
420
+ this.chosenScansOnPlan.push(button.id);
421
+ }
422
+ else {
423
+ // remove from selection
424
+ if (this.occupiedSweeps.includes(button.id) && !this.navIDsZoneEdit.includes(button.id)) {
425
+ // the sweep belongs to another zone => set orange
426
+ button.style.backgroundImage = `url("https://api.iconify.design/mdi:adjust.svg?color=orange&height=17&width=17")`;
427
+ }
428
+ else {
429
+ button.style.backgroundImage = `url("https://api.iconify.design/mdi:close-circle-outline.svg?color=red&height=17&width=17")`;
430
+ }
431
+ const index = this.chosenScansOnPlan.indexOf(button.id);
432
+ this.chosenScansOnPlan.splice(index, 1);
433
+ }
434
+ }
435
+ onSaveSelection() {
436
+ if (this.multipleFloors) {
437
+ // rassemble all sweeps per floors
438
+ let finalSweeps = [];
439
+ Array.from(this.inputSweepsPerFloor.keys()).forEach(floorID => {
440
+ if (this.chosenSweepsPerFloor.get(floorID)) {
441
+ // the sweeps for this floor were modified, we take them
442
+ finalSweeps = [...finalSweeps, ...this.chosenSweepsPerFloor.get(floorID)];
443
+ }
444
+ else {
445
+ // was not modified, we take the previous values
446
+ finalSweeps = [...finalSweeps, ...this.inputSweepsPerFloor.get(floorID)];
447
+ }
448
+ });
449
+ // console.log("final sweeps", finalSweeps);
450
+ this.sweepsSelected.emit({ "sweeps": finalSweeps, "startSweepID": this.startSweepID });
451
+ }
452
+ else {
453
+ this.sweepsSelected.emit({ "sweeps": this.chosenScansOnPlan, "startSweepID": this.startSweepID });
454
+ }
455
+ }
456
+ onCancel() {
457
+ if (this.selectionChanged) {
458
+ const message = this.translate.instant("confirm.cancelModifZoneSweeps");
459
+ if (window.confirm(message)) {
460
+ this.sweepsSelected.emit(null);
461
+ }
462
+ }
463
+ else {
464
+ this.sweepsSelected.emit(null);
465
+ }
466
+ }
467
+ /**
468
+ * Adds current selection of sweeps for current floor (plan) for multifloor zone.
469
+ * It has to be saved anyway with onSaveSelection!
470
+ */
471
+ onValidateForFloor() {
472
+ if (this.multipleFloors) {
473
+ this.chosenSweepsPerFloor.set(this.chosenPlan.zoneID, [...this.chosenScansOnPlan]);
474
+ this.selectionChanged = false;
475
+ }
476
+ }
477
+ }
478
+ SweepPlanSelectionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: SweepPlanSelectionComponent, deps: [{ token: i1.ZoneService }, { token: i1.NavigationService }, { token: i1.PlanService }, { token: i2.TranslateService }], target: i0.ɵɵFactoryTarget.Component });
479
+ SweepPlanSelectionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.7", type: SweepPlanSelectionComponent, selector: "lib-sweep-plan-selection", inputs: { spaceID: "spaceID", chosenScansOnPlan: "chosenScansOnPlan", newZoneData: "newZoneData", occupiedSweeps: "occupiedSweeps", unavailableSweeps: "unavailableSweeps", editingAudioZone: "editingAudioZone", inputZone: "inputZone", multipleFloors: "multipleFloors" }, outputs: { sweepsSelected: "sweepsSelected" }, usesOnChanges: true, ngImport: i0, template: "<div ngbDropdown class=\"sp-row d-inline-block\">\n <div class=\"col-sm-3\" *ngIf=\"plans\">\n <button type=\"button\" class=\"btn btn-label-file rounded-pill\" id=\"dropdownBasic1\"\n ngbDropdownToggle>{{chosenPlan ?\n chosenPlan.name : ('Choose Plan' | translate) }}</button>\n <div ngbDropdownMenu aria-labelledby=\"dropdownBasic1\">\n <button type=\"button\" ngbDropdownItem *ngFor=\"let plan of plans\" (click)=\"onPlanClick(plan)\"\n [disabled]=\"!plan.calibration\">{{ plan.name }}\n </button>\n </div>\n </div>\n</div>\n<div class=\"sp-row\">\n <lib-selection class=\"col-md-8\" (onSelectionChanged)=\"onSelectionChanged($event)\">\n <lib-plan-legend [isAudioZone]=\"editingAudioZone\" *ngIf=\"buttonElements.length > 0\"></lib-plan-legend>\n <div class=\"selectZone\" oncontextmenu=\"return false;\">\n <div class=\"sp-row\">\n <div style=\"overflow: hidden;width:100%;\">\n <div style=\"height: 400px; width: 100%;\" id=\"planDiv\">\n </div>\n </div>\n </div>\n </div>\n </lib-selection>\n \n <div class=\"col-md-4 scanTool\" *ngIf=\"buttonElements.length > 0\">\n <div class=\"sp-row d-inline-block\">\n <h2>{{'selectTool.title' | translate}}</h2>\n <div class=\"protip\">{{'selectTool.tip' | translate}}.</div>\n </div>\n \n <div class=\"sp-row\">\n <div class=\"col-3\" style=\"padding:0px\">\n <label class=\"tool-label\" for=\"scanSize\">{{'selectTool.size' | translate}}</label>\n </div>\n <div class=\"col-9\">\n <input type=\"range\" class=\"form-range\" min=\"0.001\" max=\"5\" step=\"0.01\" value=\"1\"\n id=\"scanSize\" (input)=\"onChangeScanSize($event)\">\n </div>\n </div>\n \n <div class=\"sp-row\">\n <button class=\"btn btn-primary rounded-pill\" (click)=\"onSelectAll()\">{{'selectTool.selectAll' | translate}}</button>\n </div>\n \n <div *ngIf=\"buttonsInSelection.length > 0\" class=\"edit-selected\">\n <span class=\"tool-label\">{{'selectTool.edit' | translate}} : </span>\n <div class=\"sp-row\">\n <button class=\"btn rounded-pill btn-primary ms-3 me-2\" (click)=\"onSelectionAdd()\">{{'selectTool.add' | translate}}</button>\n <button class=\"btn btn-primary rounded-pill\" (click)=\"onSelectionRemove()\">{{'selectTool.undo' | translate}}</button>\n </div>\n </div>\n\n <div class=\"sp-row\">\n <div *ngIf=\"multipleFloors\"> \n {{ chosenSweepsPerFloor.get(chosenPlan.zoneID) ? chosenSweepsPerFloor.get(chosenPlan.zoneID).length : \"0\"}} {{'scan points selected on this floor' | translate}} \n <button class=\"btn btn-primary rounded-pill\" (click)=\"onValidateForFloor()\" [disabled]=\"!selectionChanged\">{{'Update selection for this floor' | translate}}</button>\n </div>\n <div *ngIf=\"!multipleFloors\">\n {{ chosenScansOnPlan.length }} {{'scan points chosen' | translate}} \n </div>\n </div>\n <div *ngIf=\"!editingAudioZone\" class=\"sp-row\">\n <lib-radio-button label=\"{{ 'selectTool.chooseStartPoint' | translate }}\" (isCheckedEvent)=\"isSettingStartSweep=!isSettingStartSweep\"></lib-radio-button>\n </div>\n <div class=\"sp-row\">\n <button class=\"btn btn-primary rounded-pill\" (click)=\"onSaveSelection()\">{{'selectTool.saveSelection' | translate}}</button>\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"onCancel()\">{{'selectTool.cancelSelection' | translate}}</button>\n </div>\n </div>\n\n</div>\n \n", styles: [".sp-row{display:flex;margin-bottom:1rem}.selectZone{border-radius:6px;overflow:hidden;background-color:var(--smarterplan-secondary)}.scanTool{margin:0px 1rem}.protip{color:gray;padding:0}.tool-label{font-size:1rem}\n"], components: [{ type: i3.SelectionComponent, selector: "lib-selection", outputs: ["onSelectionChanged"] }, { type: i4.PlanLegendComponent, selector: "lib-plan-legend", inputs: ["isAudioZone"] }, { type: i5.RadioButtonComponent, selector: "lib-radio-button", inputs: ["label"], outputs: ["isCheckedEvent"] }], directives: [{ type: i6.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { type: i6.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.NgbDropdownItem, selector: "[ngbDropdownItem]", inputs: ["disabled"] }], pipes: { "translate": i2.TranslatePipe } });
480
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: SweepPlanSelectionComponent, decorators: [{
481
+ type: Component,
482
+ args: [{ selector: 'lib-sweep-plan-selection', template: "<div ngbDropdown class=\"sp-row d-inline-block\">\n <div class=\"col-sm-3\" *ngIf=\"plans\">\n <button type=\"button\" class=\"btn btn-label-file rounded-pill\" id=\"dropdownBasic1\"\n ngbDropdownToggle>{{chosenPlan ?\n chosenPlan.name : ('Choose Plan' | translate) }}</button>\n <div ngbDropdownMenu aria-labelledby=\"dropdownBasic1\">\n <button type=\"button\" ngbDropdownItem *ngFor=\"let plan of plans\" (click)=\"onPlanClick(plan)\"\n [disabled]=\"!plan.calibration\">{{ plan.name }}\n </button>\n </div>\n </div>\n</div>\n<div class=\"sp-row\">\n <lib-selection class=\"col-md-8\" (onSelectionChanged)=\"onSelectionChanged($event)\">\n <lib-plan-legend [isAudioZone]=\"editingAudioZone\" *ngIf=\"buttonElements.length > 0\"></lib-plan-legend>\n <div class=\"selectZone\" oncontextmenu=\"return false;\">\n <div class=\"sp-row\">\n <div style=\"overflow: hidden;width:100%;\">\n <div style=\"height: 400px; width: 100%;\" id=\"planDiv\">\n </div>\n </div>\n </div>\n </div>\n </lib-selection>\n \n <div class=\"col-md-4 scanTool\" *ngIf=\"buttonElements.length > 0\">\n <div class=\"sp-row d-inline-block\">\n <h2>{{'selectTool.title' | translate}}</h2>\n <div class=\"protip\">{{'selectTool.tip' | translate}}.</div>\n </div>\n \n <div class=\"sp-row\">\n <div class=\"col-3\" style=\"padding:0px\">\n <label class=\"tool-label\" for=\"scanSize\">{{'selectTool.size' | translate}}</label>\n </div>\n <div class=\"col-9\">\n <input type=\"range\" class=\"form-range\" min=\"0.001\" max=\"5\" step=\"0.01\" value=\"1\"\n id=\"scanSize\" (input)=\"onChangeScanSize($event)\">\n </div>\n </div>\n \n <div class=\"sp-row\">\n <button class=\"btn btn-primary rounded-pill\" (click)=\"onSelectAll()\">{{'selectTool.selectAll' | translate}}</button>\n </div>\n \n <div *ngIf=\"buttonsInSelection.length > 0\" class=\"edit-selected\">\n <span class=\"tool-label\">{{'selectTool.edit' | translate}} : </span>\n <div class=\"sp-row\">\n <button class=\"btn rounded-pill btn-primary ms-3 me-2\" (click)=\"onSelectionAdd()\">{{'selectTool.add' | translate}}</button>\n <button class=\"btn btn-primary rounded-pill\" (click)=\"onSelectionRemove()\">{{'selectTool.undo' | translate}}</button>\n </div>\n </div>\n\n <div class=\"sp-row\">\n <div *ngIf=\"multipleFloors\"> \n {{ chosenSweepsPerFloor.get(chosenPlan.zoneID) ? chosenSweepsPerFloor.get(chosenPlan.zoneID).length : \"0\"}} {{'scan points selected on this floor' | translate}} \n <button class=\"btn btn-primary rounded-pill\" (click)=\"onValidateForFloor()\" [disabled]=\"!selectionChanged\">{{'Update selection for this floor' | translate}}</button>\n </div>\n <div *ngIf=\"!multipleFloors\">\n {{ chosenScansOnPlan.length }} {{'scan points chosen' | translate}} \n </div>\n </div>\n <div *ngIf=\"!editingAudioZone\" class=\"sp-row\">\n <lib-radio-button label=\"{{ 'selectTool.chooseStartPoint' | translate }}\" (isCheckedEvent)=\"isSettingStartSweep=!isSettingStartSweep\"></lib-radio-button>\n </div>\n <div class=\"sp-row\">\n <button class=\"btn btn-primary rounded-pill\" (click)=\"onSaveSelection()\">{{'selectTool.saveSelection' | translate}}</button>\n <button class=\"btn btn-outline-primary rounded-pill\" (click)=\"onCancel()\">{{'selectTool.cancelSelection' | translate}}</button>\n </div>\n </div>\n\n</div>\n \n", styles: [".sp-row{display:flex;margin-bottom:1rem}.selectZone{border-radius:6px;overflow:hidden;background-color:var(--smarterplan-secondary)}.scanTool{margin:0px 1rem}.protip{color:gray;padding:0}.tool-label{font-size:1rem}\n"] }]
483
+ }], ctorParameters: function () { return [{ type: i1.ZoneService }, { type: i1.NavigationService }, { type: i1.PlanService }, { type: i2.TranslateService }]; }, propDecorators: { spaceID: [{
484
+ type: Input
485
+ }], chosenScansOnPlan: [{
486
+ type: Input
487
+ }], newZoneData: [{
488
+ type: Input
489
+ }], occupiedSweeps: [{
490
+ type: Input
491
+ }], unavailableSweeps: [{
492
+ type: Input
493
+ }], editingAudioZone: [{
494
+ type: Input
495
+ }], inputZone: [{
496
+ type: Input
497
+ }], multipleFloors: [{
498
+ type: Input
499
+ }], sweepsSelected: [{
500
+ type: Output
501
+ }] } });
502
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3dlZXAtcGxhbi1zZWxlY3Rpb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvem9uZXMvYWRkLXpvbmUvc3dlZXAtcGxhbi1zZWxlY3Rpb24vc3dlZXAtcGxhbi1zZWxlY3Rpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvem9uZXMvYWRkLXpvbmUvc3dlZXAtcGxhbi1zZWxlY3Rpb24vc3dlZXAtcGxhbi1zZWxlY3Rpb24uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFVLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUvRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsZUFBZSxFQUE2Qyx5QkFBeUIsRUFBNEIsTUFBTSxtQ0FBbUMsQ0FBQztBQUM3TCxPQUFPLE9BQW9CLE1BQU0sU0FBUyxDQUFDO0FBQzNDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxXQUFXLEVBQWEsTUFBTSxFQUFFLG1CQUFtQixFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7Ozs7Ozs7O0FBTy9JLE1BQU0sT0FBTywyQkFBMkI7SUFvRHBDLFlBQ1ksV0FBd0IsRUFDeEIsaUJBQW9DLEVBQ3BDLFdBQXdCLEVBQ3hCLFNBQTJCO1FBSDNCLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ3hCLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7UUFDcEMsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFDeEIsY0FBUyxHQUFULFNBQVMsQ0FBa0I7UUFsRDlCLHNCQUFpQixHQUFhLEVBQUUs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QUcsS0FBSyxDQUFDO1NBQ2pDO0lBQ0wsQ0FBQzs7d0hBdGtCUSwyQkFBMkI7NEdBQTNCLDJCQUEyQixrWkNYeEMsNDJIQXlFQTsyRkQ5RGEsMkJBQTJCO2tCQUx2QyxTQUFTOytCQUNJLDBCQUEwQjsyTEFRM0IsT0FBTztzQkFBZixLQUFLO2dCQUVHLGlCQUFpQjtzQkFBekIsS0FBSztnQkFHRyxXQUFXO3NCQUFuQixLQUFLO2dCQUtHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBR0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUdHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFFRyxTQUFTO3NCQUFqQixLQUFLO2dCQUVHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBZ0JJLGNBQWM7c0JBQXZCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE9uSW5pdCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBnZXRDb2VmZmljaWVudHNGb3JJbWFnZSwgZ2V0TWV0YUZvckltYWdlLCBOYXZpZ2F0aW9uLCBOYXZpZ2F0aW9uU2VydmljZSwgUGxhbiwgWm9uZSwgc2hvd1NjYW5Qb2ludHNPblBsYW5JbkRpdiwgWm9uZVNlcnZpY2UsIFBsYW5TZXJ2aWNlIH0gZnJvbSAnQHNtYXJ0ZXJwbGFuL25neC1zbWFydGVycGxhbi1jb3JlJztcbmltcG9ydCBwYW56b29tLCB7IFBhblpvb20gfSBmcm9tICdwYW56b29tJztcbmltcG9ydCB7IGJ1dHRvbklzSW5TZWxlY3Rpb24sIGlzSW5Qb2x5Z29uLCBSZWN0YW5nbGUsIHJvdGF0ZSwgc2V0VmlzdWFsbHlTZWxlY3RlZCwgc3R5bGVCdXR0b24sIFN3ZWVwU3RhdGUgfSBmcm9tICcuLi8uLi8uLi8uLi9oZWxwZXIuc2VydmljZSc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnbGliLXN3ZWVwLXBsYW4tc2VsZWN0aW9uJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vc3dlZXAtcGxhbi1zZWxlY3Rpb24uY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3N3ZWVwLXBsYW4tc2VsZWN0aW9uLmNvbXBvbmVudC5zY3NzJ11cbn0pXG5leHBvcnQgY2xhc3MgU3dlZXBQbGFuU2VsZWN0aW9uQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcblxuICAgIHBsYW5zOiBQbGFuW107XG5cbiAgICBASW5wdXQoKSBzcGFjZUlEOiBzdHJpbmc7XG5cbiAgICBASW5wdXQoKSBjaG9zZW5TY2Fuc09uUGxhbjogc3RyaW5nW10gPSBbXTtcblxuICAgIC8qKiBpZiBjb21taW5nIGZyb20gRWRpdCBQbGFuIFNWRyBab25lIGNyZWF0aW9uICovXG4gICAgQElucHV0KCkgbmV3Wm9uZURhdGE6IGFueTtcblxuICAgIG5hdklEc1pvbmVFZGl0OiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gc3dlZXBzIGJlbG9uZ2luZyB0byBhbnkgYXVkaW8gem9uZVxuICAgIEBJbnB1dCgpIG9jY3VwaWVkU3dlZXBzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gc3dlZXBzIHVuYXZhaWxhYmxlIChjYW5ub3QgYmUgY2hvc2VuKVxuICAgIEBJbnB1dCgpIHVuYXZhaWxhYmxlU3dlZXBzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gaWYgY2hvb3Npbmcgc3dlZXBzIGZvciBhdWRpbyB6b25lXG4gICAgQElucHV0KCkgZWRpdGluZ0F1ZGlvWm9uZTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgQElucHV0KCkgaW5wdXRab25lOiBab25lO1xuXG4gICAgQElucHV0KCkgbXVsdGlwbGVGbG9vcnM6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIGNob3NlblBsYW46IFBsYW47XG5cbiAgICAvKiogcGFuWm9vbSBlbGVtZW50IGZvciBhZGRpbmcgc2NhbnMgKi9cbiAgICBwYW5ab29tOiBQYW5ab29tO1xuXG4gICAgLyoqIGRpdlBsYW4gKHVzZSBCeSBwYW5ab29tKSAqL1xuICAgIGRpdlBsYW46IEhUTUxFbGVtZW50O1xuXG4gICAgLyoqIGFsbCBzY2FuIGJ1dHRvbnMgRWxlbWVudCAqL1xuICAgIGJ1dHRvbkVsZW1lbnRzOiBIVE1MQnV0dG9uRWxlbWVudFtdID0gW107XG5cbiAgICAvKiogU2NhbiBidXR0b25zIHRoYXQgYXJlIGluIHRoZSBjdXJyZW50IHNlbGVjdGlvbiAqL1xuICAgIGJ1dHRvbnNJblNlbGVjdGlvbjogSFRNTEJ1dHRvbkVsZW1lbnRbXSA9IFtdO1xuXG4gICAgQE91dHB1dCgpIHN3ZWVwc1NlbGVjdGVkID0gbmV3IEV2ZW50RW1pdHRlcjx7IHN3ZWVwczogc3RyaW5nW107IHN0YXJ0U3dlZXBJRDogc3RyaW5nOyB9PigpO1xuXG4gICAgaXNTZXR0aW5nU3RhcnRTd2VlcCA9IGZhbHNlO1xuXG4gICAgc3RhcnRTd2VlcElEOiBzdHJpbmc7XG5cbiAgICBjaG9zZW5Td2VlcHNQZXJGbG9vciA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTsgLy8gbWFwIG1hdGNoaW5nIGZsb29ySUQgdG8gc3dlZXBzIHNlbGVjdGVkXG5cbiAgICBpbnB1dFN3ZWVwc1BlckZsb29yID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZ1tdPigpOyAvLyBtYXAgbWF0Y2hpbmcgZmxvb3JJRCB0byBzd2VlcHMgc2VsZWN0ZWQgZm9yIHpvbmUgaW4gZWRpdGlvblxuXG4gICAgc2VsZWN0aW9uQ2hhbmdlZCA9IGZhbHNlO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgem9uZVNlcnZpY2U6IFpvbmVTZXJ2aWNlLFxuICAgICAgICBwcml2YXRlIG5hdmlnYXRpb25TZXJ2aWNlOiBOYXZpZ2F0aW9uU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBwbGFuU2VydmljZTogUGxhblNlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgdHJhbnNsYXRlOiBUcmFuc2xhdGVTZXJ2aWNlLFxuICAgICkgeyB9XG5cbiAgICBhc3luYyBuZ09uSW5pdCgpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5nZXRQbGFucygpO1xuICAgICAgICB0aGlzLnNldFN3ZWVwc09mSW5wdXRab25lKCk7XG4gICAgfVxuXG4gICAgbmdPbkNoYW5nZXMoKSB7XG4gICAgICAgIGlmICh0aGlzLmNob3NlblBsYW4pIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3dlZXBzT2ZJbnB1dFpvbmUoKTtcbiAgICAgICAgICAgIHRoaXMuY2hvc2VuU2NhbnNPblBsYW4gPSBbXTtcbiAgICAgICAgICAgIHRoaXMuY2xlYXJEaXZQbGFuKCk7XG4gICAgICAgICAgICB0aGlzLmFkZFNjYW5Qb2ludHMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHNldFN3ZWVwc09mSW5wdXRab25lKCkge1xuICAgICAgICB0aGlzLm5hdklEc1pvbmVFZGl0ID0gdGhpcy5pbnB1dFpvbmUgPyB0aGlzLmlucHV0Wm9uZS5zd2VlcElEcyA6IFtdO1xuICAgICAgICBpZiAodGhpcy5tdWx0aXBsZUZsb29ycykge1xuICAgICAgICAgICAgdGhpcy5wbGFucy5mb3JFYWNoKChwbGFuKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmlucHV0U3dlZXBzUGVyRmxvb3IuZ2V0KHBsYW4uem9uZUlEKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmlucHV0U3dlZXBzUGVyRmxvb3Iuc2V0KHBsYW4uem9uZUlELFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5uYXZJRHNab25lRWRpdC5maWx0ZXIoKHN3ZWVwKSA9PiBwbGFuLnpvbmUuc3dlZXBJRHMuaW5jbHVkZXMoc3dlZXApKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodGhpcy5pbnB1dFpvbmUpIHtcbiAgICAgICAgICAgICAgICAvL2ZpbHRlciBwbGFucyBvbmx5IGZvciB0aGUgcGFyZW50IFpvbmVcbiAgICAgICAgICAgICAgICB0aGlzLnBsYW5zID0gdGhpcy5wbGFucy5maWx0ZXIoKHApID0+IHAuem9uZUlEID09PSB0aGlzLmlucHV0Wm9uZS5wYXJlbnRJRCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBnZXRQbGFucygpIHtcbiAgICAgICAgdGhpcy5wbGFucyA9IGF3YWl0IHRoaXMucGxhblNlcnZpY2UuZ2V0U2luZ2VkUGxhbnNGb3JTcGFjZShcbiAgICAgICAgICAgIHRoaXMuc3BhY2VJRCxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBhc3luYyBvblBsYW5DbGljayhwbGFuOiBQbGFuKSB7XG4gICAgICAgIGNvbnN0IHN3aXRjaFBsYW4gPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGlvbkNoYW5nZWQgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuY2hvc2VuUGxhbiA9IHBsYW47XG4gICAgICAgICAgICB0aGlzLmNob3NlblNjYW5zT25QbGFuID0gW107XG4gICAgICAgICAgICB0aGlzLmNsZWFyRGl2UGxhbigpO1xuICAgICAgICAgICAgdGhpcy5hZGRTY2FuUG9pbnRzKCk7XG4gICAgICAgIH07XG4gICAgICAgIGlmICh0aGlzLnNlbGVjdGlvbkNoYW5nZWQpIHtcbiAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2UgPSB0aGlzLnRyYW5zbGF0ZS5pbnN0YW50KFwiY29uZmlybS5jYW5jZWxNb2RpZlpvbmVTd2VlcHNcIik7XG4gICAgICAgICAgICBpZiAod2luZG93LmNvbmZpcm0obWVzc2FnZSkpIHtcbiAgICAgICAgICAgICAgICBzd2l0Y2hQbGFuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzd2l0Y2hQbGFuKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBhZGRTY2FuUG9pbnRzKCkge1xuICAgICAgICBsZXQgd2FzTW9kaWZpZWQgPSBmYWxzZTtcbiAgICAgICAgaWYgKHRoaXMubXVsdGlwbGVGbG9vcnMpIHtcbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIHdlIGhhdmUgYWxyZWFkeSB2YWxpZGF0ZWQgYnV0dG9ucyBmb3IgdGhpcyBmbG9vclxuICAgICAgICAgICAgaWYgKHRoaXMuY2hvc2VuU3dlZXBzUGVyRmxvb3IuZ2V0KHRoaXMuY2hvc2VuUGxhbi56b25lSUQpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jaG9zZW5TY2Fuc09uUGxhbiA9IHRoaXMuY2hvc2VuU3dlZXBzUGVyRmxvb3IuZ2V0KHRoaXMuY2hvc2VuUGxhbi56b25lSUQpO1xuICAgICAgICAgICAgICAgIHdhc01vZGlmaWVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRpdlBsYW4gPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFwiI3BsYW5EaXZcIikgYXMgSFRNTEVsZW1lbnQ7XG4gICAgICAgIGNvbnN0IHpvbmVPZlBsYW4gPSBhd2FpdCB0aGlzLnpvbmVTZXJ2aWNlLmdldFpvbmUoXG4gICAgICAgICAgICB0aGlzLmNob3NlblBsYW4uem9uZUlELFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBuYXZpZ2F0aW9ucyA9IGF3YWl0IHRoaXMubmF2aWdhdGlvblNlcnZpY2UuZ2V0TmF2aWdhdGlvbnNGb3Jab25lKFxuICAgICAgICAgICAgem9uZU9mUGxhbixcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKHRoaXMubmV3Wm9uZURhdGEpIGF3YWl0IHRoaXMuc2V0U2NhbkJ5RHJhdyhuYXZpZ2F0aW9ucyk7XG4gICAgICAgIHRoaXMuYnV0dG9uRWxlbWVudHMgPSBhd2FpdCBzaG93U2NhblBvaW50c09uUGxhbkluRGl2KFxuICAgICAgICAgICAgdGhpcy5jaG9zZW5QbGFuLFxuICAgICAgICAgICAgdGhpcy5kaXZQbGFuLFxuICAgICAgICAgICAgbmF2aWdhdGlvbnMsXG4gICAgICAgICk7XG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiB0aGlzLmJ1dHRvbkVsZW1lbnRzKSB7XG4gICAgICAgICAgICBpZiAodGhpcy51bmF2YWlsYWJsZVN3ZWVwcyAmJiB0aGlzLnVuYXZhaWxhYmxlU3dlZXBzLmluY2x1ZGVzKGVsZW1lbnQuaWQpKSB7XG4gICAgICAgICAgICAgICAgc3R5bGVCdXR0b24oZWxlbWVudCwgU3dlZXBTdGF0ZS5ESVNBQkxFRCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICAgICAgaWYgKHdhc01vZGlmaWVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmNob3NlblNjYW5zT25QbGFuLmluY2x1ZGVzKGVsZW1lbnQuaWQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdHlsZUJ1dHRvbihlbGVtZW50LCBTd2VlcFN0YXRlLkFEREVEKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlQnV0dG9uKGVsZW1lbnQsIFN3ZWVwU3RhdGUuUkVNT1ZFRCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm5hdklEc1pvbmVFZGl0Lmxlbmd0aCA+IDAgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubmF2SURzWm9uZUVkaXQuaW5jbHVkZXMoZWxlbWVudC5pZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlQnV0dG9uKGVsZW1lbnQsIFN3ZWVwU3RhdGUuQURERUQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNob3NlblNjYW5zT25QbGFuLmluY2x1ZGVzKGVsZW1lbnQuaWQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jaG9zZW5TY2Fuc09uUGxhbi5wdXNoKGVsZW1lbnQuaWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMub2NjdXBpZWRTd2VlcHMgJiYgdGhpcy5vY2N1cGllZFN3ZWVwcy5pbmNsdWRlcyhlbGVtZW50LmlkKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGVCdXR0b24oZWxlbWVudCwgU3dlZXBTdGF0ZS5PQ0NVUElFRCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdHlsZUJ1dHRvbihlbGVtZW50LCBTd2VlcFN0YXRlLlJFTU9WRUQpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy9zdGFydCBwb2ludCBzaG91bGQgYmUgbGFzdCBjb25kaXRpb24gXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaW5wdXRab25lICYmIHRoaXMuaW5wdXRab25lLnN0YXJ0U3dlZXBJRCA9PT0gZWxlbWVudC5pZCkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcInNldHRpbmcgc3RhcnQgcG9pbnRcIik7XG4gICAgICAgICAgICAgICAgICAgIHN0eWxlQnV0dG9uKGVsZW1lbnQsIFN3ZWVwU3RhdGUuU1RBUlRQT0lOVCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIChldmVudCkgPT5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vbkJ1dHRvblNjYW5DbGlja2VkKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLnBhblpvb20gPSBwYW56b29tKHRoaXMuZGl2UGxhbiwge1xuICAgICAgICAgICAgYm91bmRzOiB0cnVlLFxuICAgICAgICAgICAgYm91bmRzUGFkZGluZzogMCxcbiAgICAgICAgICAgIG1heFpvb206IDMuNSxcbiAgICAgICAgICAgIGJlZm9yZU1vdXNlRG93bihlOiBNb3VzZUV2ZW50KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICAgICAgZS5idXR0b24gPT09IDJcbiAgICAgICAgICAgICAgICApOyAvKiogSWdub3JlIGV2ZW50IGZvciByaWdodCBjbGljayAodXNlIGZvciBzZWxlY3RpbmcpICovXG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHRoaXMubXVsdGlwbGVGbG9vcnMpIHtcbiAgICAgICAgICAgIHRoaXMuY2hvc2VuU3dlZXBzUGVyRmxvb3Iuc2V0KHRoaXMuY2hvc2VuUGxhbi56b25lSUQsIFsuLi50aGlzLmNob3NlblNjYW5zT25QbGFuXSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogRnVuY3Rpb24gaWYgd2UgYXJlIGNvbWluZyBmb3Igc3ZnIGVkaXRvciB3b3JrZmxvdyAqL1xuICAgIHNldFNjYW5CeURyYXcobmF2aWdhdGlvbnM6IGFueVtdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShhc3luYyAocmVzb2x2ZSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcmVjdCA9IHtcbiAgICAgICAgICAgICAgICB3aWR0aDogdGhpcy5uZXdab25lRGF0YS53aWR0aCxcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IHRoaXMubmV3Wm9uZURhdGEuaGVpZ2h0LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IGltZyA9IGF3YWl0IGdldE1ldGFGb3JJbWFnZSh0aGlzLmNob3NlblBsYW4uZmlsZXBhdGgpO1xuICAgICAgICAgICAgY29uc3QgeyBjb2VmZlgsIGNvZWZmWSB9ID0gZ2V0Q29lZmZpY2llbnRzRm9ySW1hZ2UoaW1nLCByZWN0KTtcblxuICAgICAgICAgICAgY29uc3QgZHJhdyA9IHRoaXMubmV3Wm9uZURhdGEuZWxlbWVudHM7XG5cbiAgICAgICAgICAgIGRyYXcubWFwKGFzeW5jIChlbGVtZW50OiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKGVsZW1lbnQubm9kZU5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBcInJlY3RcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuc2V0U2NhbkluUmVjdChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZmZYLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWZmWSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hdmlnYXRpb25zLFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgXCJlbGxpcHNlXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNldFNjYW5JbkNpcmNsZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZmZYLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWZmWSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hdmlnYXRpb25zLFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgXCJwYXRoXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNldFNjYW5JblBvbHlnb24oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWZmWCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmZlksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYXZpZ2F0aW9ucyxcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGFzeW5jIHNldFNjYW5JblJlY3QoaW1nOiBhbnksIGNvZWZmWDogbnVtYmVyLCBjb2VmZlk6IG51bWJlcixcbiAgICAgICAgZWxlbWVudDogeyBhbmdsZTogYW55OyBjeDogYW55OyBjeTogYW55OyB4OiBudW1iZXI7IHdpZHRoOiBhbnk7IHk6IG51bWJlcjsgaGVpZ2h0OiBhbnk7IH0sIG5hdmlnYXRpb25zOiBhbnlbXSkge1xuICAgICAgICBjb25zdCBjYWxpYnJhZ2UgPSBKU09OLnBhcnNlKHRoaXMuY2hvc2VuUGxhbi5jYWxpYnJhdGlvbik7XG4gICAgICAgIG5hdmlnYXRpb25zLm1hcCgobmF2aWdhdGlvbikgPT4ge1xuICAgICAgICAgICAgY29uc3QgcG9zaXRpb25zT25QbGFuID0gbmF2aWdhdGlvbi5wb3NpdGlvbk9uUGxhbi5tYXAoKGVudHJ5KSA9PlxuICAgICAgICAgICAgICAgIEpTT04ucGFyc2UoZW50cnkpLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uT25QbGFuID0gcG9zaXRpb25zT25QbGFuLmZpbmQoXG4gICAgICAgICAgICAgICAgKGRhdGEpID0+IGRhdGEucGxhbklEID09PSB0aGlzLmNob3NlblBsYW4uaWQsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKHBvc2l0aW9uT25QbGFuKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcmVhbFdpZHRoID0gaW1nLndpZHRoIC8gY29lZmZYO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlYWxIZWlnaHQgPSBpbWcuaGVpZ2h0IC8gY29lZmZZO1xuICAgICAgICAgICAgICAgIGNvbnN0IG5hdlkgPSAocG9zaXRpb25PblBsYW4ueSAqIHJlYWxIZWlnaHQpIC8gY2FsaWJyYWdlLmltZ0hlaWdodDtcbiAgICAgICAgICAgICAgICBjb25zdCBuYXZYID0gKHBvc2l0aW9uT25QbGFuLnggKiByZWFsV2lkdGgpIC8gY2FsaWJyYWdlLmltZ1dpZHRoO1xuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgbmF2WCA+IGVsZW1lbnQueCAmJlxuICAgICAgICAgICAgICAgICAgICBuYXZYIDwgZWxlbWVudC54ICsgZWxlbWVudC53aWR0aCAmJlxuICAgICAgICAgICAgICAgICAgICBuYXZZID4gZWxlbWVudC55ICYmXG4gICAgICAgICAgICAgICAgICAgIG5hdlkgPCBlbGVtZW50LnkgKyBlbGVtZW50LmhlaWdodCAmJlxuICAgICAgICAgICAgICAgICAgICAhdGhpcy5uYXZJRHNab25lRWRpdC5pbmNsdWRlcyhuYXZpZ2F0aW9uLmlkKVxuICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm5hdklEc1pvbmVFZGl0LnB1c2gobmF2aWdhdGlvbi5pZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBvbGQgY2FsaWJyYXRpb246XG4gICAgICAgICAgICAvLyBjb25zdCBwb3NpdGlvbiA9IEpTT04ucGFyc2UobmF2aWdhdGlvbi5wb3NpdGlvbik7XG4gICAgICAgICAgICAvLyBsZXQgbmF2WCA9IChjYWxpYnJhZ2Uub2Zmc2V0WCArIHBvc2l0aW9uLnggKiBjYWxpYnJhZ2UueCkgLyBjb2VmZlg7XG4gICAgICAgICAgICAvLyBsZXQgbmF2WSA9IChjYWxpYnJhZ2Uub2Zmc2V0WSArIHBvc2l0aW9uLnogKiBjYWxpYnJhZ2UueSkgLyBjb2VmZlk7XG4gICAgICAgICAgICAvLyBpZiAoZWxlbWVudC5hbmdsZSkge1xuICAgICAgICAgICAgLy8gICAgIGNvbnN0IHJvdGF0ZVBvcyA9IHJvdGF0ZShcbiAgICAgICAgICAgIC8vICAgICAgICAgeyB4OiBuYXZYLCB5OiBuYXZZIH0sXG4gICAgICAgICAgICAvLyAgICAgICAgIHsgeDogZWxlbWVudC5jeCwgeTogZWxlbWVudC5jeSB9LFxuICAgICAgICAgICAgLy8gICAgICAgICBlbGVtZW50LmFuZ2xlLFxuICAgICAgICAgICAgLy8gICAgICk7XG4gICAgICAgICAgICAvLyAgICAgbmF2WCA9IHJvdGF0ZVBvcy54O1xuICAgICAgICAgICAgLy8gICAgIG5hdlkgPSByb3RhdGVQb3MueTtcbiAgICAgICAgICAgIC8vIH1cbiAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICogVE9ETyBjYWxjdWxlciBsYSByb3RhdGlvbiBkdSByZWN0YW5nbGVcbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgLy8gaWYgKFxuICAgICAgICAgICAgLy8gICAgIG5hdlggPiBlbGVtZW50LnggJiZcbiAgICAgICAgICAgIC8vICAgICBuYXZYIDwgZWxlbWVudC54ICsgZWxlbWVudC53aWR0aCAmJlxuICAgICAgICAgICAgLy8gICAgIG5hdlkgPiBlbGVtZW50LnkgJiZcbiAgICAgICAgICAgIC8vICAgICBuYXZZIDwgZWxlbWVudC55ICsgZWxlbWVudC5oZWlnaHQgJiZcbiAgICAgICAgICAgIC8vICAgICAhdGhpcy5uYXZJRHNab25lRWRpdC5pbmNsdWRlcyhuYXZpZ2F0aW9uLmlkKVxuICAgICAgICAgICAgLy8gKSB7XG4gICAgICAgICAgICAvLyAgICAgdGhpcy5uYXZJRHNab25lRWRpdC5wdXNoKG5hdmlnYXRpb24uaWQpO1xuICAgICAgICAgICAgLy8gfVxuICAgICAgICB9KTtcbiAgICB9IC8vIEVPXG5cbiAgICBhc3luYyBzZXRTY2FuSW5DaXJjbGUoaW1nOiBhbnksIGNvZWZmWDogbnVtYmVyLCBjb2VmZlk6IG51bWJlcixcbiAgICAgICAgZWxlbWVudDogeyBhbmdsZTogYW55OyBjeDogbnVtYmVyOyBjeTogbnVtYmVyOyByeDogbnVtYmVyOyByeTogbnVtYmVyOyB9LCBuYXZpZ2F0aW9uczogTmF2aWdhdGlvbltdKSB7XG4gICAgICAgIGNvbnN0IGNhbGlicmFnZSA9IEpTT04ucGFyc2UodGhpcy5jaG9zZW5QbGFuLmNhbGlicmF0aW9uKTtcbiAgICAgICAgbmF2aWdhdGlvbnMubWFwKG5hdmlnYXRpb24gPT4ge1xuICAgICAgICAgICAgY29uc3QgcG9zaXRpb25zT25QbGFuID0gbmF2aWdhdGlvbi5wb3NpdGlvbk9uUGxhbi5tYXAoKGVudHJ5KSA9PlxuICAgICAgICAgICAgICAgIEpTT04ucGFyc2UoZW50cnkpLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uT25QbGFuID0gcG9zaXRpb25zT25QbGFuLmZpbmQoXG4gICAgICAgICAgICAgICAgKGRhdGEpID0+IGRhdGEucGxhbklEID09PSB0aGlzLmNob3NlblBsYW4uaWQsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKHBvc2l0aW9uT25QbGFuKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcmVhbFdpZHRoID0gaW1nLndpZHRoIC8gY29lZmZYO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlYWxIZWlnaHQgPSBpbWcuaGVpZ2h0IC8gY29lZmZZO1xuICAgICAgICAgICAgICAgIGxldCBuYXZZID0gKHBvc2l0aW9uT25QbGFuLnkgKiByZWFsSGVpZ2h0KSAvIGNhbGlicmFnZS5pbWdIZWlnaHQ7XG4gICAgICAgICAgICAgICAgbGV0IG5hdlggPSAocG9zaXRpb25PblBsYW4ueCAqIHJlYWxXaWR0aCkgLyBjYWxpYnJhZ2UuaW1nV2lkdGg7XG4gICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQuYW5nbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgcm90YXRlUG9zID0gcm90YXRlKFxuICAgICAgICAgICAgICAgICAgICAgICAgeyB4OiBuYXZYLCB5OiBuYXZZIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7IHg6IGVsZW1lbnQuY3gsIHk6IGVsZW1lbnQuY3kgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuYW5nbGUsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIG5hdlggPSByb3RhdGVQb3MueDtcbiAgICAgICAgICAgICAgICAgICAgbmF2WSA9IHJvdGF0ZVBvcy55O1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlWCA9XG4gICAgICAgICAgICAgICAgICAgIE1hdGgucG93KG5hdlggLSBlbGVtZW50LmN4LCAyKSAvIE1hdGgucG93KGVsZW1lbnQucngsIDIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlWSA9XG4gICAgICAgICAgICAgICAgICAgIE1hdGgucG93KG5hdlkgLSBlbGVtZW50LmN5LCAyKSAvIE1hdGgucG93KGVsZW1lbnQucnksIDIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHZhbHVlWCArIHZhbHVlWTtcbiAgICAgICAgICAgICAgICBpZiAocmVzdWx0IDw9IDEgJiYgIXRoaXMubmF2SURzWm9uZUVkaXQuaW5jbHVkZXMobmF2aWdhdGlvbi5pZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5uYXZJRHNab25lRWRpdC5wdXNoKG5hdmlnYXRpb24uaWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gb2xkIGNhbGlicmF0aW9uXG4gICAgICAgICAgICAvLyBjb25zdCBwb3NpdGlvbiA9IEpTT04ucGFyc2UobmF2aWdhdGlvbi5wb3NpdGlvbik7XG4gICAgICAgICAgICAvLyBsZXQgbmF2WCA9IChjYWxpYnJhZ2Uub2Zmc2V0WCArIHBvc2l0aW9uLnggKiBjYWxpYnJhZ2UueCkgLyBjb2VmZlg7XG4gICAgICAgICAgICAvLyBsZXQgbmF2WSA9IChjYWxpYnJhZ2Uub2Zmc2V0WSArIHBvc2l0aW9uLnogKiBjYWxpYnJhZ2UueSkgLyBjb2VmZlk7XG4gICAgICAgICAgICAvLyBpZiAoZWxlbWVudC5hbmdsZSkge1xuICAgICAgICAgICAgLy8gICAgIGNvbnN0IHJvdGF0ZVBvcyA9IHJvdGF0ZShcbiAgICAgICAgICAgIC8vICAgICAgICAgeyB4OiBuYXZYLCB5OiBuYXZZIH0sXG4gICAgICAgICAgICAvLyAgICAgICAgIHsgeDogZWxlbWVudC5jeCwgeTogZWxlbWVudC5jeSB9LFxuICAgICAgICAgICAgLy8gICAgICAgICBlbGVtZW50LmFuZ2xlLFxuICAgICAgICAgICAgLy8gICAgICk7XG4gICAgICAgICAgICAvLyAgICAgbmF2WCA9IHJvdGF0ZVBvcy54O1xuICAgICAgICAgICAgLy8gICAgIG5hdlkgPSByb3RhdGVQb3MueTtcbiAgICAgICAgICAgIC8vIH1cblxuICAgICAgICAgICAgLy8gY29uc3QgdmFsdWVYID1cbiAgICAgICAgICAgIC8vICAgICBNYXRoLnBvdyhuYXZYIC0gZWxlbWVudC5jeCwgMikgLyBNYXRoLnBvdyhlbGVtZW50LnJ4LCAyKTtcbiAgICAgICAgICAgIC8vIGNvbnN0IHZhbHVlWSA9XG4gICAgICAgICAgICAvLyAgICAgTWF0aC5wb3cobmF2WSAtIGVsZW1lbnQuY3ksIDIpIC8gTWF0aC5wb3coZWxlbWVudC5yeSwgMik7XG4gICAgICAgICAgICAvLyBjb25zdCByZXN1bHQgPSB2YWx1ZVggKyB2YWx1ZVk7XG4gICAgICAgICAgICAvLyBpZiAocmVzdWx0IDw9IDEgJiYgIXRoaXMubmF2SURzWm9uZUVkaXQuaW5jbHVkZXMobmF2aWdhdGlvbi5pZCkpIHtcbiAgICAgICAgICAgIC8vICAgICB0aGlzLm5hdklEc1pvbmVFZGl0LnB1c2gobmF2aWdhdGlvbi5pZCk7XG4gICAgICAgICAgICAvLyB9XG4gICAgICAgIH0pO1xuICAgIH0gLy8gRU9cblxuICAgIGFzeW5jIHNldFNjYW5JblBvbHlnb24oaW1nOiBhbnksIGNvZWZmWDogbnVtYmVyLCBjb2VmZlk6IG51bWJlciwgZWxlbWVudDogeyBzZWdMaXN0OiBhbnk7IH0sIG5hdmlnYXRpb25zOiBhbnlbXSkge1xuICAgICAgICBjb25zdCBjYWxpYnJhZ2UgPSBKU09OLnBhcnNlKHRoaXMuY2hvc2VuUGxhbi5jYWxpYnJhdGlvbik7XG4gICAgICAgIG5hdmlnYXRpb25zLm1hcChhc3luYyAobmF2aWdhdGlvbikgPT4ge1xuXG4gICAgICAgICAgICBjb25zdCBwb3NpdGlvbnNPblBsYW4gPSBuYXZpZ2F0aW9uLnBvc2l0aW9uT25QbGFuLm1hcCgoZW50cnkpID0+XG4gICAgICAgICAgICAgICAgSlNPTi5wYXJzZShlbnRyeSksXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgcG9zaXRpb25PblBsYW4gPSBwb3NpdGlvbnNPblBsYW4uZmluZChcbiAgICAgICAgICAgICAgICAoZGF0YSkgPT4gZGF0YS5wbGFuSUQgPT09IHRoaXMuY2hvc2VuUGxhbi5pZCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAocG9zaXRpb25PblBsYW4pIHtcbiAgICAgICAgICAgICAgICBjb25zdCByZWFsV2lkdGggPSBpbWcud2lkdGggLyBjb2VmZlg7XG4gICAgICAgICAgICAgICAgY29uc3QgcmVhbEhlaWdodCA9IGltZy5oZWlnaHQgLyBjb2VmZlk7XG4gICAgICAgICAgICAgICAgbGV0IG5hdlkgPSAocG9zaXRpb25PblBsYW4ueSAqIHJlYWxIZWlnaHQpIC8gY2FsaWJyYWdlLmltZ0hlaWdodDtcbiAgICAgICAgICAgICAgICBsZXQgbmF2WCA9IChwb3NpdGlvbk9uUGxhbi54ICogcmVhbFdpZHRoKSAvIGNhbGlicmFnZS5pbWdXaWR0aDtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHAgPSB7XG4gICAgICAgICAgICAgICAgICAgIHg6IG5hdlgsXG4gICAgICAgICAgICAgICAgICAgIHk6IG5hdlksXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgIGlzSW5Qb2x5Z29uKHAsIGVsZW1lbnQuc2VnTGlzdCkgJiZcbiAgICAgICAgICAgICAgICAgICAgIXRoaXMubmF2SURzWm9uZUVkaXQuaW5jbHVkZXMobmF2aWdhdGlvbi5pZClcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5uYXZJRHNab25lRWRpdC5wdXNoKG5hdmlnYXRpb24uaWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gb2xkIGNhbGlicmF0aW9uXG4gICAgICAgICAgICAvLyBjb25zdCBwb3NpdGlvbiA9IEpTT04ucGFyc2UobmF2aWdhdGlvbi5wb3NpdGlvbik7XG4gICAgICAgICAgICAvLyBjb25zdCBwID0ge1xuICAgICAgICAgICAgLy8gICAgIHg6IChjYWxpYnJhZ2Uub2Zmc2V0WCArIHBvc2l0aW9uLnggKiBjYWxpYnJhZ2UueCkgLyBjb2VmZlgsXG4gICAgICAgICAgICAvLyAgICAgeTogKGNhbGlicmFnZS5vZmZzZXRZICsgcG9zaXRpb24ueiAqIGNhbGlicmFnZS55KSAvIGNvZWZmWSxcbiAgICAgICAgICAgIC8vIH07XG4gICAgICAgICAgICAvLyBpZiAoZWxlbWVudC5hbmdsZSkge1xuICAgICAgICAgICAgLy8gICAgIHAgPSB0aGlzLnJvdGF0ZShcbiAgICAgICAgICAgIC8vICAgICAgICAgcCxcbiAgICAgICAgICAgIC8vICAgICAgICAgeyB4OiBlbGVtZW50LmN4LCB5OiBlbGVtZW50LmN5IH0sXG4gICAgICAgICAgICAvLyAgICAgICAgIGVsZW1lbnQuYW5nbGUsXG4gICAgICAgICAgICAvLyAgICAgKTtcbiAgICAgICAgICAgIC8vIH1cbiAgICAgICAgICAgIC8vIGlmIChcbiAgICAgICAgICAgIC8vICAgICBpc0luUG9seWdvbihwLCBlbGVtZW50LnNlZ0xpc3QpICYmXG4gICAgICAgICAgICAvLyAgICAgIXRoaXMubmF2SURzWm9uZUVkaXQuaW5jbHVkZXMobmF2aWdhdGlvbi5pZClcbiAgICAgICAgICAgIC8vICkge1xuICAgICAgICAgICAgLy8gICAgIHRoaXMubmF2SURzWm9uZUVkaXQucHVzaChuYXZpZ2F0aW9uLmlkKTtcbiAgICAgICAgICAgIC8vIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgY2xlYXJEaXZQbGFuKCkge1xuICAgICAgICBpZiAodGhpcy5kaXZQbGFuKSB0aGlzLmRpdlBsYW4uaW5uZXJIVE1MID0gXCJcIjtcbiAgICB9XG5cblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZWFjaCBieSB0aGUgc2VsZWN0aW9uQ29tcG9uZW50IHdoZW4gc2VsZWN0aW9uIGNoYW5nZVxuICAgICAqIFVwZGF0ZSB0aGUgY3VycmVudCBzZWxlY3RlZCBzY2FuIGJ1dHRvbnNcbiAgICAgKiBAcGFyYW0gc2VsZWN0aW9uIG5ldyBzZWxlY3Rpb25cbiAgICAgKi9cbiAgICBvblNlbGVjdGlvbkNoYW5nZWQoc2VsZWN0aW9uOiBSZWN0YW5nbGUpIHtcbiAgICAgICAgY29uc3QgdW5zZWxlY3RlZEJ1dHRvbnM6IEhUTUxCdXR0b25FbGVtZW50W10gPSBbXTtcbiAgICAgICAgY29uc3QgbmV3U2VsZWN0ZWRCdXR0b25zID0gW107XG5cbiAgICAgICAgLyoqIEZvciBlYWNoIGJ1dHRvbiwgZGVjaWRlIHdoZXRoZXIgd2lsbCBiZSBhZGQgdG8gc2VsZWN0ZWQgbGlzdCBvciB1bnNlbGVjdGVkIGxpc3QgKi9cbiAgICAgICAgZm9yIChjb25zdCBidXR0b24gb2YgdGhpcy5idXR0b25FbGVtZW50cykge1xuICAgICAgICAgICAgY29uc3QgaXNTZWxlY3RlZCA9IGJ1dHRvbklzSW5TZWxlY3Rpb24oYnV0dG9uLCBzZWxlY3Rpb24pO1xuICAgICAgICAgICAgaWYgKHRoaXMuYnV0dG9uc0luU2VsZWN0aW9uLmluY2x1ZGVzKGJ1dHRvbikpIHtcbiAgICAgICAgICAgICAgICAvKiogSWYgdGhlIGJ1dHRvbiBpcyBhbHJlYWR5IGluIHRoZSBzZWxlY3RlZCBsaXN0LCB3ZSBjaGVjayBpZiBpdCBzaG91bGQgYmUgdW5zZWxlY3QgKi9cbiAgICAgICAgICAgICAgICBpZiAoIWlzU2VsZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdW5zZWxlY3RlZEJ1dHRvbnMucHVzaChidXR0b24pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoaXNTZWxlY3RlZCkge1xuICAgICAgICAgICAgICAgIG5ld1NlbGVjdGVkQnV0dG9ucy5wdXNoKGJ1dHRvbik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvKiogVmlzdWFsbHkgVXBkYXRlIHVuc2VsZWN0ZWQgbGlzdCAqL1xuICAgICAgICBmb3IgKGNvbnN0IGJ1dHRvbiBvZiB1bnNlbGVjdGVkQnV0dG9ucykge1xuICAgICAgICAgICAgc2V0VmlzdWFsbHlTZWxlY3RlZChidXR0b24sIGZhbHNlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKiBWaXN1YWxseSBVcGRhdGUgc2VsZWN0ZWQgbGlzdCAqL1xuICAgICAgICBmb3IgKGNvbnN0IGJ1dHRvbiBvZiBuZXdTZWxlY3RlZEJ1dHRvbnMpIHtcbiAgICAgICAgICAgIHNldFZpc3VhbGx5U2VsZWN0ZWQoYnV0dG9uLCB0cnVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKiBSZW1vdmUgIHVuc2VsZWN0ZWQgbGlzdCAqL1xuICAgICAgICB0aGlzLmJ1dHRvbnNJblNlbGVjdGlvbiA9IHRoaXMuYnV0dG9uc0luU2VsZWN0aW9uLmZpbHRlcigoYnV0dG9uKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gIXVuc2VsZWN0ZWRCdXR0b25zLmluY2x1ZGVzKGJ1dHRvbik7XG4gICAgICAgIH0pO1xuICAgICAgICAvKiogQWRkIG5ldyBzZWxlY3RlZCBidXR0b25zICovXG4gICAgICAgIHRoaXMuYnV0dG9uc0luU2VsZWN0aW9uID0gW1xuICAgICAgICAgICAgLi4udGhpcy5idXR0b25zSW5TZWxlY3Rpb24sXG4gICAgICAgICAgICAuLi5uZXdTZWxlY3RlZEJ1dHRvbnMsXG4gICAgICAgIF07XG4gICAgfVxuXG5cblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgd2hlbiB0aGUgdXNlciBjbGljayB0byBhZGQgdGhlIHNlbGVjdGVkIHNjYW5zXG4gICAgICovXG4gICAgb25TZWxlY3Rpb25BZGQoKSB7XG4gICAgICAgIGZvciAoY29uc3QgYnV0dG9uIG9mIHRoaXMuYnV0dG9uc0luU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuY2hvc2VuU2NhbnNPblBsYW4uaW5jbHVkZXMoYnV0dG9uLmlkKSkge1xuICAgICAgICAgICAgICAgIHRoaXMub25CdXR0b25TY2FuQ2xpY2tlZChidXR0b24pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5vblNlbGVjdGlvbkNoYW5nZWQoeyB0b3A6IDAsIGxlZnQ6IDAsIHdpZHRoOiAwLCBoZWlnaHQ6IDAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHJpZ2dlciB3aGVuIHRoZSB1c2VyIGNsaWNrIHRvIHJlbW92ZSB0aGUgc2VsZWN0ZWQgc2NhbnNcbiAgICAgKi9cbiAgICBvblNlbGVjdGlvblJlbW92ZSgpIHtcbiAgICAgICAgZm9yIChjb25zdCBidXR0b24gb2YgdGhpcy5idXR0b25zSW5TZWxlY3Rpb24pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmNob3NlblNjYW5zT25QbGFuLmluY2x1ZGVzKGJ1dHRvbi5pZCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm9uQnV0dG9uU2NhbkNsaWNrZWQoYnV0dG9uKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLm9uU2VsZWN0aW9uQ2hhbmdlZCh7IHRvcDogMCwgbGVmdDogMCwgd2lkdGg6IDAsIGhlaWdodDogMCB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIHdoZW4gdGhlIHVzZXIgY2xpY2sgdG8gc2VsZWN0IGFsbCBzY2Fuc1xuICAgICAqL1xuICAgIG9uU2VsZWN0QWxsKCkge1xuICAgICAgICB0aGlzLmJ1dHRvbnNJblNlbGVjdGlvbiA9IFsuLi50aGlzLmJ1dHRvbkVsZW1lbnRzXTtcbiAgICAgICAgZm9yIChjb25zdCBidXR0b24gb2YgdGhpcy5idXR0b25zSW5TZWxlY3Rpb24pIHtcbiAgICAgICAgICAgIHNldFZpc3VhbGx5U2VsZWN0ZWQoYnV0dG9uLCB0cnVlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgd2hlbiB0aGUgdXNlciBjaGFuZ2UgdGhlIHNpemUgb2YgdGhlIHNjYW4gcG9pbnRzXG4gICAgICogQHBhcmFtIGV2ZW50XG4gICAgICovXG4gICAgb25DaGFuZ2VTY2FuU2l6ZShldmVudDogYW55KSB7XG4gICAgICAgIGNvbnN0IGZhY3RvciA9IGV2ZW50LnRhcmdldC52YWx1ZTtcblxuICAgICAgICBmb3IgKGNvbnN0IGJ1dHRvbiBvZiB0aGlzLmJ1dHRvbkVsZW1lbnRzKSB7XG4gICAgICAgICAgICBidXR0b24uc3R5bGUudHJhbnNmb3JtID0gYHNjYWxlKCR7ZmFjdG9yfSlgO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2hlbiBhIGJ1dHRvbiByZXByZXNlbnRpbmcgYSBzY2FuIGlzIGNsaWNrZWRcbiAgICAgKiBAcGFyYW0gYnV0dG9uXG4gICAgICovXG4gICAgb25CdXR0b25TY2FuQ2xpY2tlZChidXR0b246IEhUTUxFbGVtZW50KSB7XG4gICAgICAgIHRoaXMuc2VsZWN0aW9uQ2hhbmdlZCA9IHRydWU7XG4gICAgICAgIGlmICh0aGlzLmlzU2V0dGluZ1N0YXJ0U3dlZXApIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXJ0U3dlZXBJRCA9PT0gYnV0dG9uLmlkKSB7XG4gICAgICAgICAgICAgICAgLy8gd2UgZGVzZWxlY3QgdGhlIHN0YXJ0aW5nIHBvaW50XG4gICAgICAgICAgICAgICAgYnV0dG9uLnN0eWxlLmJhY2tncm91bmRJbWFnZSA9IGB1cmwoXCJodHRwczovL2FwaS5pY29uaWZ5LmRlc2lnbi9tZGk6YWRqdXN0LnN2Zz9jb2xvcj1ncmVlbiZoZWlnaHQ9MTcmd2lkdGg9MTdcIilgO1xuICAgICAgICAgICAgICAgIHRoaXMuc3RhcnRTd2VlcElEID0gbnVsbDtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBidXR0b24uc3R5bGUuYmFja2dyb3VuZEltYWdlID0gYHVybCgnaHR0cHM6Ly9hcGkuaWNvbmlmeS5kZXNpZ24vaWMvYmFzZWxpbmUtZmxhZy1jaXJjbGUuc3ZnP2NvbG9yPXdoaXRlJndpZHRoPTE3JmhlaWdodD0xNycpYDtcbiAgICAgICAgICAgIGlmICghdGhpcy5jaG9zZW5TY2Fuc09uUGxhbi5pbmNsdWRlcyhidXR0b24uaWQpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jaG9zZW5TY2Fuc09uUGxhbi5wdXNoKGJ1dHRvbi5pZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5zdGFydFN3ZWVwSUQpIHtcbiAgICAgICAgICAgICAgICAvLyB3ZSBhcmUgY2hhbmdpbmcgc3RhcnQgc3dlZXBcbiAgICAgICAgICAgICAgICBjb25zdCBidG5DaGFuZ2VkID0gdGhpcy5idXR0b25FbGVtZW50cy5maW5kKChidG4pID0+IGJ0bi5pZCA9PT0gdGhpcy5zdGFydFN3ZWVwSUQpO1xuICAgICAgICAgICAgICAgIGJ0bkNoYW5nZWQuc3R5bGUuYmFja2dyb3VuZEltYWdlID0gYHVybChcImh0dHBzOi8vYXBpLmljb25pZnkuZGVzaWduL21kaTphZGp1c3Quc3ZnP2NvbG9yPWdyZWVuJmhlaWdodD0xNyZ3aWR0aD0xN1wiKWA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnN0YXJ0U3dlZXBJRCA9IGJ1dHRvbi5pZDtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMuY2hvc2VuU2NhbnNPblBsYW4uaW5jbHVkZXMoYnV0dG9uLmlkKSkge1xuICAgICAgICAgICAgLy8gYWRkIHRvIHNlbGVjdGlvblxuICAgICAgICAgICAgYnV0dG9uLnN0eWxlLmJhY2tncm91bmRJbWFnZSA9IGB1cmwoXCJodHRwczovL2FwaS5pY29uaWZ5LmRlc2lnbi9tZGk6YWRqdXN0LnN2Zz9jb2xvcj1ncmVlbiZoZWlnaHQ9MTcmd2lkdGg9MTdcIilgO1xuICAgICAgICAgICAgdGhpcy5jaG9zZW5TY2Fuc09uUGxhbi5wdXNoKGJ1dHRvbi5pZCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyByZW1vdmUgZnJvbSBzZWxlY3Rpb25cbiAgICAgICAgICAgIGlmICh0aGlzLm9jY3VwaWVkU3dlZXBzLmluY2x1ZGVzKGJ1dHRvbi5pZCkgJiYgIXRoaXMubmF2SURzWm9uZUVkaXQuaW5jbHVkZXMoYnV0dG9uLmlkKSkge1xuICAgICAgICAgICAgICAgIC8vIHRoZSBzd2VlcCBiZWxvbmdzIHRvIGFub3RoZXIgem9uZSA9PiBzZXQgb3JhbmdlXG4gICAgICAgICAgICAgICAgYnV0dG9uLnN0eWxlLmJhY2tncm91bmRJbWFnZSA9IGB1cmwoXCJodHRwczovL2FwaS5pY29uaWZ5LmRlc2lnbi9tZGk6YWRqdXN0LnN2Zz9jb2xvcj1vcmFuZ2UmaGVpZ2h0PTE3JndpZHRoPTE3XCIpYDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYnV0dG9uLnN0eWxlLmJhY2tncm91bmRJbWFnZSA9IGB1cmwoXCJodHRwczovL2FwaS5pY29uaWZ5LmRlc2lnbi9tZGk6Y2xvc2UtY2lyY2xlLW91dGxpbmUuc3ZnP2NvbG9yPXJlZCZoZWlnaHQ9MTcmd2lkdGg9MTdcIilgO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgaW5kZXggPSB0aGlzLmNob3NlblNjYW5zT25QbGFuLmluZGV4T2YoYnV0dG9uLmlkKTtcbiAgICAgICAgICAgIHRoaXMuY2hvc2VuU2NhbnNPblBsYW4uc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uU2F2ZVNlbGVjdGlvbigpIHtcbiAgICAgICAgaWYgKHRoaXMubXVsdGlwbGVGbG9vcnMpIHtcbiAgICAgICAgICAgIC8vIHJhc3NlbWJsZSBhbGwgc3dlZXBzIHBlciBmbG9vcnNcbiAgICAgICAgICAgIGxldCBmaW5hbFN3ZWVwcyA9IFtdO1xuICAgICAgICAgICAgQXJyYXkuZnJvbSh0aGlzLmlucHV0U3dlZXBzUGVyRmxvb3Iua2V5cygpKS5mb3JFYWNoKGZsb29ySUQgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNob3NlblN3ZWVwc1BlckZsb29yLmdldChmbG9vcklEKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgc3dlZXBzIGZvciB0aGlzIGZsb29yIHdlcmUgbW9kaWZpZWQsIHdlIHRha2UgdGhlbVxuICAgICAgICAgICAgICAgICAgICBmaW5hbFN3ZWVwcyA9IFsuLi5maW5hbFN3ZWVwcywgLi4udGhpcy5jaG9zZW5Td2VlcHNQZXJGbG9vci5nZXQoZmxvb3JJRCldO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHdhcyBub3QgbW9kaWZpZWQsIHdlIHRha2UgdGhlIHByZXZpb3VzIHZhbHVlc1xuICAgICAgICAgICAgICAgICAgICBmaW5hbFN3ZWVwcyA9IFsuLi5maW5hbFN3ZWVwcywgLi4udGhpcy5pbnB1dFN3ZWVwc1BlckZsb29yLmdldChmbG9vcklEKV07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhcImZpbmFsIHN3ZWVwc1wiLCBmaW5hbFN3ZWVwcyk7XG4gICAgICAgICAgICB0aGlzLnN3ZWVwc1NlbGVjdGVkLmVtaXQoeyBcInN3ZWVwc1wiOiBmaW5hbFN3ZWVwcywgXCJzdGFydFN3ZWVwSURcIjogdGhpcy5zdGFydFN3ZWVwSUQgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnN3ZWVwc1NlbGVjdGVkLmVtaXQoeyBcInN3ZWVwc1wiOiB0aGlzLmNob3NlblNjYW5zT25QbGFuLCBcInN0YXJ0U3dlZXBJRFwiOiB0aGlzLnN0YXJ0U3dlZXBJRCB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uQ2FuY2VsKCkge1xuICAgICAgICBpZiAodGhpcy5zZWxlY3Rpb25DaGFuZ2VkKSB7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gdGhpcy50cmFuc2xhdGUuaW5zdGFudChcImNvbmZpcm0uY2FuY2VsTW9kaWZab25lU3dlZXBzXCIpO1xuICAgICAgICAgICAgaWYgKHdpbmRvdy5jb25maXJtKG1lc3NhZ2UpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zd2VlcHNTZWxlY3RlZC5lbWl0KG51bGwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zd2VlcHNTZWxlY3RlZC5lbWl0KG51bGwpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkcyBjdXJyZW50IHNlbGVjdGlvbiBvZiBzd2VlcHMgZm9yIGN1cnJlbnQgZmxvb3IgKHBsYW4pIGZvciBtdWx0aWZsb29yIHpvbmUuXG4gICAgICogSXQgaGFzIHRvIGJlIHNhdmVkIGFueXdheSB3aXRoIG9uU2F2ZVNlbGVjdGlvbiFcbiAgICAgKi9cbiAgICBvblZhbGlkYXRlRm9yRmxvb3IoKSB7XG4gICAgICAgIGlmICh0aGlzLm11bHRpcGxlRmxvb3JzKSB7XG4gICAgICAgICAgICB0aGlzLmNob3NlblN3ZWVwc1BlckZsb29yLnNldCh0aGlzLmNob3NlblBsYW4uem9uZUlELCBbLi4udGhpcy5jaG9zZW5TY2Fuc09uUGxhbl0pO1xuICAgICAgICAgICAgdGhpcy5zZWxlY3Rpb25DaGFuZ2VkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCI8ZGl2IG5nYkRyb3Bkb3duIGNsYXNzPVwic3Atcm93IGQtaW5saW5lLWJsb2NrXCI+XG4gICAgPGRpdiBjbGFzcz1cImNvbC1zbS0zXCIgKm5nSWY9XCJwbGFuc1wiPlxuICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLWxhYmVsLWZpbGUgcm91bmRlZC1waWxsXCIgaWQ9XCJkcm9wZG93bkJhc2ljMVwiXG4gICAgICAgICAgICAgICAgbmdiRHJvcGRvd25Ub2dnbGU+e3tjaG9zZW5QbGFuID9cbiAgICAgICAgICAgICAgICBjaG9zZW5QbGFuLm5hbWUgOiAoJ0Nob29zZSBQbGFuJyB8IHRyYW5zbGF0ZSkgfX08L2J1dHRvbj5cbiAgICAgICAgICAgIDxkaXYgbmdiRHJvcGRvd25NZW51IGFyaWEtbGFiZWxsZWRieT1cImRyb3Bkb3duQmFzaWMxXCI+XG4gICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgbmdiRHJvcGRvd25JdGVtICpuZ0Zvcj1cImxldCBwbGFuIG9mIHBsYW5zXCIgKGNsaWNrKT1cIm9uUGxhbkNsaWNrKHBsYW4pXCJcbiAgICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFwbGFuLmNhbGlicmF0aW9uXCI+e3sgcGxhbi5uYW1lIH19XG4gICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbjwvZGl2PlxuPGRpdiBjbGFzcz1cInNwLXJvd1wiPlxuICAgIDxsaWItc2VsZWN0aW9uIGNsYXNzPVwiY29sLW1kLThcIiAob25TZWxlY3Rpb25DaGFuZ2VkKT1cIm9uU2VsZWN0aW9uQ2hhbmdlZCgkZXZlbnQpXCI+XG4gICAgICAgIDxsaWItcGxhbi1sZWdlbmQgW2lzQXVkaW9ab25lXT1cImVkaXRpbmdBdWRpb1pvbmVcIiAqbmdJZj1cImJ1dHRvbkVsZW1lbnRzLmxlbmd0aCA+IDBcIj48L2xpYi1wbGFuLWxlZ2VuZD5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNlbGVjdFpvbmVcIiBvbmNvbnRleHRtZW51PVwicmV0dXJuIGZhbHNlO1wiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNwLXJvd1wiPlxuICAgICAgICAgICAgICAgIDxkaXYgc3R5bGU9XCJvdmVyZmxvdzogaGlkZGVuO3dpZHRoOjEwMCU7XCI+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgc3R5bGU9XCJoZWlnaHQ6IDQwMHB4OyB3aWR0aDogMTAwJTtcIiBpZD1cInBsYW5EaXZcIj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9saWItc2VsZWN0aW9uPlxuICAgIFxuICAgIDxkaXYgY2xhc3M9XCJjb2wtbWQtNCBzY2FuVG9vbFwiICpuZ0lmPVwiYnV0dG9uRWxlbWVudHMubGVuZ3RoID4gMFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic3Atcm93IGQtaW5saW5lLWJsb2NrXCI+XG4gICAgICAgICAgICA8aDI+e3snc2VsZWN0VG9vbC50aXRsZScgfCB0cmFuc2xhdGV9fTwvaDI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwicHJvdGlwXCI+e3snc2VsZWN0VG9vbC50aXAnIHwgdHJhbnNsYXRlfX0uPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgIFxuICAgICAgICA8ZGl2IGNsYXNzPVwic3Atcm93XCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLTNcIiBzdHlsZT1cInBhZGRpbmc6MHB4XCI+XG4gICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwidG9vbC1sYWJlbFwiIGZvcj1cInNjYW5TaXplXCI+e3snc2VsZWN0VG9vbC5zaXplJyB8IHRyYW5zbGF0ZX19PC9sYWJlbD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC05XCI+XG4gICAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJyYW5nZVwiIGNsYXNzPVwiZm9ybS1yYW5nZVwiIG1pbj1cIjAuMDAxXCIgbWF4PVwiNVwiIHN0ZXA9XCIwLjAxXCIgdmFsdWU9XCIxXCJcbiAgICAgICAgICAgICAgICAgICAgaWQ9XCJzY2FuU2l6ZVwiIChpbnB1dCk9XCJvbkNoYW5nZVNjYW5TaXplKCRldmVudClcIj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICBcbiAgICAgICAgPGRpdiBjbGFzcz1cInNwLXJvd1wiPlxuICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25TZWxlY3RBbGwoKVwiPnt7J3NlbGVjdFRvb2wuc2VsZWN0QWxsJyB8IHRyYW5zbGF0ZX19PC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgIFxuICAgICAgICA8ZGl2ICpuZ0lmPVwiYnV0dG9uc0luU2VsZWN0aW9uLmxlbmd0aCA+IDBcIiBjbGFzcz1cImVkaXQtc2VsZWN0ZWRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidG9vbC1sYWJlbFwiPnt7J3NlbGVjdFRvb2wuZWRpdCcgfCB0cmFuc2xhdGV9fSA6IDwvc3Bhbj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzcC1yb3dcIj5cbiAgICAgICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIHJvdW5kZWQtcGlsbCBidG4tcHJpbWFyeSBtcy0zIG1lLTJcIiAoY2xpY2spPVwib25TZWxlY3Rpb25BZGQoKVwiPnt7J3NlbGVjdFRvb2wuYWRkJyB8IHRyYW5zbGF0ZX19PC9idXR0b24+XG4gICAgICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25TZWxlY3Rpb25SZW1vdmUoKVwiPnt7J3NlbGVjdFRvb2wudW5kbycgfCB0cmFuc2xhdGV9fTwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJzcC1yb3dcIj5cbiAgICAgICAgICAgIDxkaXYgKm5nSWY9XCJtdWx0aXBsZUZsb29yc1wiPiBcbiAgICAgICAgICAgICAgICB7eyBjaG9zZW5Td2VlcHNQZXJGbG9vci5nZXQoY2hvc2VuUGxhbi56b25lSUQpID8gY2hvc2VuU3dlZXBzUGVyRmxvb3IuZ2V0KGNob3NlblBsYW4uem9uZUlEKS5sZW5ndGggOiBcIjBcIn19IHt7J3NjYW4gcG9pbnRzIHNlbGVjdGVkIG9uIHRoaXMgZmxvb3InIHwgdHJhbnNsYXRlfX0gXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25WYWxpZGF0ZUZvckZsb29yKClcIiBbZGlzYWJsZWRdPVwiIXNlbGVjdGlvbkNoYW5nZWRcIj57eydVcGRhdGUgc2VsZWN0aW9uIGZvciB0aGlzIGZsb29yJyB8IHRyYW5zbGF0ZX19PC9idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxkaXYgKm5nSWY9XCIhbXVsdGlwbGVGbG9vcnNcIj5cbiAgICAgICAgICAgICAgICB7eyBjaG9zZW5TY2Fuc09uUGxhbi5sZW5ndGggfX0ge3snc2NhbiBwb2ludHMgY2hvc2VuJyB8IHRyYW5zbGF0ZX19ICBcbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiAqbmdJZj1cIiFlZGl0aW5nQXVkaW9ab25lXCIgY2xhc3M9XCJzcC1yb3dcIj5cbiAgICAgICAgICAgIDxsaWItcmFkaW8tYnV0dG9uICBsYWJlbD1cInt7ICdzZWxlY3RUb29sLmNob29zZVN0YXJ0UG9pbnQnICB8IHRyYW5zbGF0ZSB9fVwiIChpc0NoZWNrZWRFdmVudCk9XCJpc1NldHRpbmdTdGFydFN3ZWVwPSFpc1NldHRpbmdTdGFydFN3ZWVwXCI+PC9saWItcmFkaW8tYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNwLXJvd1wiPlxuICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25TYXZlU2VsZWN0aW9uKClcIj57eydzZWxlY3RUb29sLnNhdmVTZWxlY3Rpb24nIHwgdHJhbnNsYXRlfX08L2J1dHRvbj5cbiAgICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJidG4gYnRuLW91dGxpbmUtcHJpbWFyeSByb3VuZGVkLXBpbGxcIiAoY2xpY2spPVwib25DYW5jZWwoKVwiPnt7J3NlbGVjdFRvb2wuY2FuY2VsU2VsZWN0aW9uJyB8IHRyYW5zbGF0ZX19PC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG48L2Rpdj5cbiAgIFxuIl19