@smarterplan/ngx-smarterplan-core 1.4.11 → 1.4.13
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/esm2022/lib/services/matterport-import.service.mjs +2 -57
- package/esm2022/lib/services/matterport-navigation.service.mjs +131 -1
- package/esm2022/lib/services/matterport-tag-copy.service.mjs +865 -0
- package/esm2022/lib/services/matterport-tag.service.mjs +175 -54
- package/esm2022/lib/services/matterport.service.mjs +267 -39
- package/esm2022/lib/services/models/equipment.service.mjs +16 -1
- package/esm2022/lib/services/models/navigation.service.mjs +4 -1
- package/esm2022/lib/services/models/poi.service.mjs +86 -8
- package/esm2022/lib/services/models/ticket.service.mjs +3 -2
- package/esm2022/lib/services/s3.service.mjs +12 -1
- package/esm2022/lib/services/utils/matterport-transform.util.mjs +39 -0
- package/esm2022/lib/services/viewer.service.mjs +8 -1
- package/esm2022/lib/types.service.mjs +9 -1
- package/esm2022/public-api.mjs +4 -1
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs +1590 -156
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
- package/lib/services/matterport-navigation.service.d.ts +25 -0
- package/lib/services/matterport-tag-copy.service.d.ts +129 -0
- package/lib/services/matterport-tag.service.d.ts +61 -7
- package/lib/services/matterport.service.d.ts +81 -1
- package/lib/services/models/equipment.service.d.ts +8 -0
- package/lib/services/models/poi.service.d.ts +14 -0
- package/lib/services/s3.service.d.ts +8 -0
- package/lib/services/utils/matterport-transform.util.d.ts +21 -0
- package/lib/types.service.d.ts +18 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
|
@@ -0,0 +1,865 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject } from 'rxjs';
|
|
3
|
+
import { copyFileInS3 } from './s3.service'; // see s3.service.ts: copyFileInS3 must NOT swallow errors (needed to detect NoSuchKey below)
|
|
4
|
+
import { computeRigidTransform, applyRigidTransformToPoint, applyRigidTransformToYRotationDeg } from './utils/matterport-transform.util';
|
|
5
|
+
import { CommentType, PoiType, SpModule } from '../types.service';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
import * as i1 from "./models/navigation.service";
|
|
8
|
+
import * as i2 from "./user.service";
|
|
9
|
+
import * as i3 from "./models/poi.service";
|
|
10
|
+
import * as i4 from "./models/ticket.service";
|
|
11
|
+
import * as i5 from "./models/equipment.service";
|
|
12
|
+
import * as i6 from "./models/object3D.service";
|
|
13
|
+
import * as i7 from "./models/feature.service";
|
|
14
|
+
import * as i8 from "./models/measurement.service";
|
|
15
|
+
import * as i9 from "./models/comment.service";
|
|
16
|
+
import * as i10 from "@ngx-translate/core";
|
|
17
|
+
/** Safely extracts a readable message from an unknown catch value, including Amplify's
|
|
18
|
+
* GraphQL error shape ({ data, errors: [{ errorType, message }] }). */
|
|
19
|
+
function toErrorMessage(err) {
|
|
20
|
+
if (err && typeof err === 'object') {
|
|
21
|
+
const anyErr = err;
|
|
22
|
+
if (Array.isArray(anyErr.errors) && anyErr.errors.length > 0) {
|
|
23
|
+
return anyErr.errors
|
|
24
|
+
.map((e) => {
|
|
25
|
+
const title = e.errorType ? `${e.errorType}: ` : '';
|
|
26
|
+
return `${title}${e.message || 'Unknown error'}`;
|
|
27
|
+
})
|
|
28
|
+
.join(' | ');
|
|
29
|
+
}
|
|
30
|
+
if (err instanceof Error) {
|
|
31
|
+
return err.message;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (typeof err === 'string') {
|
|
35
|
+
return err;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
return JSON.stringify(err);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return String(err);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Thrown when the referenced S3 source file doesn't exist (orphaned DB reference —
|
|
45
|
+
* e.g. the file was deleted or renamed on S3 without updating the database).
|
|
46
|
+
* Kept distinct from other copy failures so the calling loop can log a clear,
|
|
47
|
+
* specific message and skip the whole item instead of a generic error. */
|
|
48
|
+
class MissingS3FileError extends Error {
|
|
49
|
+
sourceKey;
|
|
50
|
+
contextLabel;
|
|
51
|
+
constructor(sourceKey, contextLabel) {
|
|
52
|
+
super(`Source file missing on S3: "${sourceKey}" (${contextLabel})`);
|
|
53
|
+
this.sourceKey = sourceKey;
|
|
54
|
+
this.contextLabel = contextLabel;
|
|
55
|
+
this.name = 'MissingS3FileError';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export class MatterportTagCopyService {
|
|
59
|
+
navigationService;
|
|
60
|
+
userService;
|
|
61
|
+
poiService;
|
|
62
|
+
ticketService;
|
|
63
|
+
equipmentService;
|
|
64
|
+
object3DService;
|
|
65
|
+
featureService;
|
|
66
|
+
measurementService;
|
|
67
|
+
commentService;
|
|
68
|
+
translate;
|
|
69
|
+
// Emits progress updates during copyTagsFromVisit(); null when idle
|
|
70
|
+
copyProgress$ = new BehaviorSubject(null);
|
|
71
|
+
// Emits the accumulated log lines during copyTagsFromVisit(); [] when idle
|
|
72
|
+
copyLog$ = new BehaviorSubject([]);
|
|
73
|
+
spModule;
|
|
74
|
+
log = [];
|
|
75
|
+
errorSeq = 0;
|
|
76
|
+
constructor(navigationService, userService, poiService, ticketService, equipmentService, object3DService, featureService, measurementService, commentService, translate) {
|
|
77
|
+
this.navigationService = navigationService;
|
|
78
|
+
this.userService = userService;
|
|
79
|
+
this.poiService = poiService;
|
|
80
|
+
this.ticketService = ticketService;
|
|
81
|
+
this.equipmentService = equipmentService;
|
|
82
|
+
this.object3DService = object3DService;
|
|
83
|
+
this.featureService = featureService;
|
|
84
|
+
this.measurementService = measurementService;
|
|
85
|
+
this.commentService = commentService;
|
|
86
|
+
this.translate = translate;
|
|
87
|
+
this.spModule = userService.getSpModule();
|
|
88
|
+
}
|
|
89
|
+
//
|
|
90
|
+
// ---------- Public API ----------
|
|
91
|
+
//
|
|
92
|
+
async copyTagsFromVisit(sourceSpaceId, targetSpaceId, landmarkSourceA, landmarkTargetA, landmarkSourceB, landmarkTargetB) {
|
|
93
|
+
let errorCount = 0;
|
|
94
|
+
this.resetLog();
|
|
95
|
+
try {
|
|
96
|
+
console.log(`Copying Tags from source ${sourceSpaceId} to target ${targetSpaceId}`);
|
|
97
|
+
this.setStepProgress('collecting', 'collecting', 0);
|
|
98
|
+
this.copyProgress$.next({
|
|
99
|
+
phase: 'collecting',
|
|
100
|
+
processedInPhase: 0, totalInPhase: 0,
|
|
101
|
+
processedOverall: 0, totalOverall: 0,
|
|
102
|
+
percent: 0, errorCount: 0
|
|
103
|
+
});
|
|
104
|
+
const targetMission = this.userService.currentMission(targetSpaceId);
|
|
105
|
+
const targetMissionId = targetMission ? targetMission.id : null;
|
|
106
|
+
const transform = computeRigidTransform(landmarkSourceA, landmarkTargetA, landmarkSourceB, landmarkTargetB);
|
|
107
|
+
console.log('Rigid transform computed:', {
|
|
108
|
+
rotationYDeg: transform.rotationYRad * (180 / Math.PI),
|
|
109
|
+
refSource: transform.refSource,
|
|
110
|
+
refTarget: transform.refTarget
|
|
111
|
+
});
|
|
112
|
+
const sourceSweepIds = await this.navigationService.getAllowedSweepsIDsForUserInSpace(sourceSpaceId);
|
|
113
|
+
const targetSweepIds = await this.navigationService.getAllowedSweepsIDsForUserInSpace(targetSpaceId);
|
|
114
|
+
this.setStepProgress('collecting', 'collecting', 30);
|
|
115
|
+
const [sourceNavPositions, targetNavPositions] = await Promise.all([
|
|
116
|
+
this.buildNavigationPositionMap(sourceSpaceId, sourceSweepIds),
|
|
117
|
+
this.buildNavigationPositionMap(targetSpaceId, targetSweepIds)
|
|
118
|
+
]);
|
|
119
|
+
const elementIds = {};
|
|
120
|
+
let sourceTickets = [];
|
|
121
|
+
let sourceEquipments = [];
|
|
122
|
+
let targetTickets = [];
|
|
123
|
+
let targetEquipments = [];
|
|
124
|
+
let sourceMeasurements = [];
|
|
125
|
+
let targetMeasurements = [];
|
|
126
|
+
if (this.spModule == SpModule.IMMO) {
|
|
127
|
+
sourceTickets = await this.ticketService.getTicketsBySpace(sourceSpaceId);
|
|
128
|
+
sourceEquipments = await this.equipmentService.getEquipmentsForSpace(sourceSpaceId);
|
|
129
|
+
targetTickets = await this.ticketService.getTicketsBySpace(targetSpaceId);
|
|
130
|
+
targetEquipments = await this.equipmentService.getEquipmentsForSpace(targetSpaceId);
|
|
131
|
+
}
|
|
132
|
+
this.setStepProgress('collecting', 'collecting', 55);
|
|
133
|
+
const sourceObjects3D = await this.object3DService.getObjects3DBySpace(sourceSpaceId);
|
|
134
|
+
const targetObjects3D = await this.object3DService.getObjects3DBySpace(targetSpaceId);
|
|
135
|
+
const sourceFeatures = await this.featureService.getFeaturesBySpaceWithoutFiltering(sourceSpaceId);
|
|
136
|
+
const targetFeatures = await this.featureService.getFeaturesBySpaceWithoutFiltering(targetSpaceId);
|
|
137
|
+
this.setStepProgress('collecting', 'collecting', 75);
|
|
138
|
+
if (this.spModule == SpModule.IMMO) {
|
|
139
|
+
sourceMeasurements = await this.measurementService.getMeasurementsForSpaceForUser(sourceSpaceId);
|
|
140
|
+
targetMeasurements = await this.measurementService.getMeasurementsForSpaceForUser(targetSpaceId);
|
|
141
|
+
}
|
|
142
|
+
this.setStepProgress('collecting', 'collecting', 90);
|
|
143
|
+
const sourcePoisAll = await this.poiService.getPoisByMatterportSweeps(sourceSweepIds);
|
|
144
|
+
const targetPoisAll = await this.poiService.getPoisByMatterportSweeps(targetSweepIds);
|
|
145
|
+
const handledPoiTypes = new Set([
|
|
146
|
+
PoiType.TICKET, PoiType.EQUIPMENT, PoiType.DATA, PoiType.DESK,
|
|
147
|
+
PoiType.OBJECT3D, PoiType.MEASURE
|
|
148
|
+
]);
|
|
149
|
+
const sourcePois = sourcePoisAll.filter(p => !handledPoiTypes.has(p.type));
|
|
150
|
+
const targetPois = targetPoisAll.filter(p => !handledPoiTypes.has(p.type));
|
|
151
|
+
this.setStepProgress('collecting', 'collecting', 100);
|
|
152
|
+
const totalOverall = sourceTickets.length + sourceEquipments.length + sourcePois.length
|
|
153
|
+
+ sourceObjects3D.length + sourceFeatures.length + sourceMeasurements.length;
|
|
154
|
+
let processedOverall = 0;
|
|
155
|
+
const emitProgress = (phase, processedInPhase, totalInPhase) => {
|
|
156
|
+
this.copyProgress$.next({
|
|
157
|
+
phase,
|
|
158
|
+
processedInPhase,
|
|
159
|
+
totalInPhase,
|
|
160
|
+
processedOverall,
|
|
161
|
+
totalOverall,
|
|
162
|
+
percent: totalOverall > 0 ? Math.round((processedOverall / totalOverall) * 100) : 0,
|
|
163
|
+
errorCount
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
if (this.spModule == SpModule.IMMO) {
|
|
167
|
+
// TICKETS
|
|
168
|
+
for (let i = 0; i < sourceTickets.length; i++) {
|
|
169
|
+
const sourceObj = sourceTickets[i];
|
|
170
|
+
try {
|
|
171
|
+
const existsInTarget = this.matchesExisting(sourceObj, targetTickets);
|
|
172
|
+
if (!existsInTarget) {
|
|
173
|
+
const rawSource = sourceObj;
|
|
174
|
+
const ticketInput = {
|
|
175
|
+
title: rawSource.title,
|
|
176
|
+
friendlyLabel: rawSource.friendlyLabel,
|
|
177
|
+
status: rawSource.status,
|
|
178
|
+
type: rawSource.type,
|
|
179
|
+
priority: rawSource.priority,
|
|
180
|
+
description: rawSource.description,
|
|
181
|
+
level: rawSource.level,
|
|
182
|
+
metadata: rawSource.metadata || null,
|
|
183
|
+
read: rawSource.read || null,
|
|
184
|
+
projectID: rawSource.projectID || null,
|
|
185
|
+
problemCode: rawSource.problemCode || null,
|
|
186
|
+
archivedForMissionID: rawSource.archivedForMissionID || null,
|
|
187
|
+
spaceID: targetSpaceId,
|
|
188
|
+
parentID: null,
|
|
189
|
+
domainID: null,
|
|
190
|
+
ownerMissionID: targetMissionId
|
|
191
|
+
};
|
|
192
|
+
const createdObj = await this.ticketService.createTicket(ticketInput);
|
|
193
|
+
if (createdObj && createdObj.id) {
|
|
194
|
+
elementIds[sourceObj.id] = createdObj.id;
|
|
195
|
+
}
|
|
196
|
+
if (sourceObj.pois.items && sourceObj.pois.items.length > 0) {
|
|
197
|
+
const sourcePoi = sourceObj.pois.items[0];
|
|
198
|
+
const targetSweepId = this.findClosestTargetSweepId(sourcePoi.matterportSweepID, sourceNavPositions, targetNavPositions, transform);
|
|
199
|
+
const adjustedCoordinate = this.getAdjustedCoordinates(sourcePoi.coordinate, transform);
|
|
200
|
+
const poiInput = {
|
|
201
|
+
coordinate: JSON.stringify(adjustedCoordinate),
|
|
202
|
+
type: sourcePoi.type,
|
|
203
|
+
elementID: createdObj.id,
|
|
204
|
+
metadata: sourcePoi.metadata,
|
|
205
|
+
matterportSweepID: targetSweepId
|
|
206
|
+
};
|
|
207
|
+
await this.poiService.createPOIForSpaceID(poiInput);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (itemError) {
|
|
212
|
+
console.error(`Error copying ticket "${sourceObj?.title}" (id: ${sourceObj?.id}):`, itemError);
|
|
213
|
+
errorCount++;
|
|
214
|
+
this.logCopyItemError(itemError, 'errorTicket', sourceObj?.title || sourceObj?.id);
|
|
215
|
+
}
|
|
216
|
+
processedOverall++;
|
|
217
|
+
emitProgress('tickets', i + 1, sourceTickets.length);
|
|
218
|
+
const pct = sourceTickets.length > 0 ? Math.round(((i + 1) / sourceTickets.length) * 100) : 100;
|
|
219
|
+
this.setStepProgress('tickets', 'tickets', pct);
|
|
220
|
+
}
|
|
221
|
+
// EQUIPMENTS (title, POI, PHOTO and NOTES/documents all copied — files physically
|
|
222
|
+
// duplicated in S3 first, so the copy stays independent from the source)
|
|
223
|
+
for (let i = 0; i < sourceEquipments.length; i++) {
|
|
224
|
+
const sourceObj = sourceEquipments[i];
|
|
225
|
+
try {
|
|
226
|
+
const existsInTarget = this.matchesExisting(sourceObj, targetEquipments);
|
|
227
|
+
if (!existsInTarget) {
|
|
228
|
+
const rawSource = sourceObj;
|
|
229
|
+
let copiedPhotoKey = null;
|
|
230
|
+
if (rawSource.photo) {
|
|
231
|
+
copiedPhotoKey = await this.copyS3KeyIfPresent(rawSource.photo, `equipment photo "${rawSource.title}"`);
|
|
232
|
+
}
|
|
233
|
+
const equipmentInput = {
|
|
234
|
+
title: rawSource.title,
|
|
235
|
+
status: rawSource.status,
|
|
236
|
+
description: rawSource.description,
|
|
237
|
+
archivedForMissionID: rawSource.archivedForMissionID || null,
|
|
238
|
+
spaceID: targetSpaceId,
|
|
239
|
+
domainID: null,
|
|
240
|
+
photo: copiedPhotoKey,
|
|
241
|
+
};
|
|
242
|
+
const createdObj = await this.equipmentService.createEquipment(equipmentInput, null, null);
|
|
243
|
+
if (createdObj && createdObj.id) {
|
|
244
|
+
elementIds[sourceObj.id] = createdObj.id;
|
|
245
|
+
}
|
|
246
|
+
// Copy notes (documents, technical/financial/other/contractual/image notes)
|
|
247
|
+
if (createdObj && rawSource.notes?.items && rawSource.notes.items.length > 0) {
|
|
248
|
+
for (const sourceNote of rawSource.notes.items) {
|
|
249
|
+
try {
|
|
250
|
+
if (!sourceNote.attachment) {
|
|
251
|
+
continue; // nothing to duplicate for this note
|
|
252
|
+
}
|
|
253
|
+
const copiedKey = await this.copyS3KeyIfPresent(sourceNote.attachment, `equipment note for "${sourceObj?.title}"`);
|
|
254
|
+
await this.equipmentService.createNoteWithExistingAttachment(createdObj.id, copiedKey, sourceNote.type, targetMissionId);
|
|
255
|
+
}
|
|
256
|
+
catch (noteError) {
|
|
257
|
+
console.error(`Error copying note for equipment "${sourceObj?.title}":`, noteError);
|
|
258
|
+
errorCount++;
|
|
259
|
+
this.logCopyItemError(noteError, 'errorEquipmentNote', sourceObj?.title || sourceObj?.id);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (sourceObj.pois.items && sourceObj.pois.items.length > 0) {
|
|
264
|
+
const sourcePoi = sourceObj.pois.items[0];
|
|
265
|
+
const targetSweepId = this.findClosestTargetSweepId(sourcePoi.matterportSweepID, sourceNavPositions, targetNavPositions, transform);
|
|
266
|
+
const adjustedCoordinate = this.getAdjustedCoordinates(sourcePoi.coordinate, transform);
|
|
267
|
+
const poiInput = {
|
|
268
|
+
coordinate: JSON.stringify(adjustedCoordinate),
|
|
269
|
+
type: sourcePoi.type,
|
|
270
|
+
elementID: createdObj.id,
|
|
271
|
+
metadata: sourcePoi.metadata,
|
|
272
|
+
matterportSweepID: targetSweepId
|
|
273
|
+
};
|
|
274
|
+
await this.poiService.createPOIForSpaceID(poiInput);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch (itemError) {
|
|
279
|
+
console.error(`Error copying equipment "${sourceObj?.title}" (id: ${sourceObj?.id}):`, itemError);
|
|
280
|
+
errorCount++;
|
|
281
|
+
this.logCopyItemError(itemError, 'errorEquipment', sourceObj?.title || sourceObj?.id);
|
|
282
|
+
}
|
|
283
|
+
processedOverall++;
|
|
284
|
+
emitProgress('equipments', i + 1, sourceEquipments.length);
|
|
285
|
+
const pct = sourceEquipments.length > 0 ? Math.round(((i + 1) / sourceEquipments.length) * 100) : 100;
|
|
286
|
+
this.setStepProgress('equipments', 'equipments', pct);
|
|
287
|
+
}
|
|
288
|
+
// Second pass: remap subequipmentsIDs on newly created equipments to point to
|
|
289
|
+
// their copied counterparts. IDs with no copied counterpart (source equipment
|
|
290
|
+
// wasn't copied — e.g. it already existed in target, or was skipped) are dropped
|
|
291
|
+
// rather than left dangling or pointing back at the source space's equipment.
|
|
292
|
+
for (const sourceObj of sourceEquipments) {
|
|
293
|
+
const rawSource = sourceObj;
|
|
294
|
+
const newId = elementIds[sourceObj.id];
|
|
295
|
+
if (newId && rawSource.subequipmentsIDs && rawSource.subequipmentsIDs.length > 0) {
|
|
296
|
+
const remapped = rawSource.subequipmentsIDs
|
|
297
|
+
.map((subId) => elementIds[subId])
|
|
298
|
+
.filter((id) => !!id);
|
|
299
|
+
if (remapped.length > 0) {
|
|
300
|
+
try {
|
|
301
|
+
await this.equipmentService.updateEquipment({ id: newId, subequipmentsIDs: remapped });
|
|
302
|
+
}
|
|
303
|
+
catch (subEquipError) {
|
|
304
|
+
console.error(`Error remapping sub-equipments for "${sourceObj?.title}":`, subEquipError);
|
|
305
|
+
errorCount++;
|
|
306
|
+
this.logCopyItemError(subEquipError, 'errorEquipmentSubEquip', sourceObj?.title || sourceObj?.id);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// POIS (standalone — types already handled above are excluded)
|
|
313
|
+
for (let i = 0; i < sourcePois.length; i++) {
|
|
314
|
+
const sourcePoi = sourcePois[i];
|
|
315
|
+
try {
|
|
316
|
+
const existsInTarget = targetPois.some(tp => tp.coordinate === sourcePoi.coordinate && tp.tagDescription === sourcePoi.tagDescription);
|
|
317
|
+
if (!existsInTarget) {
|
|
318
|
+
const targetSweepId = this.findClosestTargetSweepId(sourcePoi.matterportSweepID, sourceNavPositions, targetNavPositions, transform);
|
|
319
|
+
const adjustedCoordinate = this.getAdjustedCoordinates(sourcePoi.coordinate, transform);
|
|
320
|
+
let elementID = sourcePoi.elementID;
|
|
321
|
+
if (elementID && elementIds[elementID]) {
|
|
322
|
+
elementID = elementIds[elementID];
|
|
323
|
+
}
|
|
324
|
+
const copiedTagIcon = await this.duplicateTagIcon(sourcePoi.tagIcon);
|
|
325
|
+
const copiedTagImageID = await this.duplicateTagImageID(sourcePoi.tagImageID);
|
|
326
|
+
const newPoi = {
|
|
327
|
+
coordinate: JSON.stringify(adjustedCoordinate),
|
|
328
|
+
type: sourcePoi.type,
|
|
329
|
+
elementID: elementID,
|
|
330
|
+
tagDescription: sourcePoi.tagDescription,
|
|
331
|
+
tagIcon: copiedTagIcon,
|
|
332
|
+
tagImageID: copiedTagImageID,
|
|
333
|
+
virtual: sourcePoi.virtual,
|
|
334
|
+
xRotation: sourcePoi.xRotation,
|
|
335
|
+
yRotation: sourcePoi.yRotation,
|
|
336
|
+
metadata: sourcePoi.metadata,
|
|
337
|
+
matterportSweepID: targetSweepId
|
|
338
|
+
};
|
|
339
|
+
await this.poiService.createPOIForSpaceID(newPoi);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
catch (itemError) {
|
|
343
|
+
console.error(`Error copying POI (sweep: ${sourcePoi?.matterportSweepID}):`, itemError);
|
|
344
|
+
errorCount++;
|
|
345
|
+
this.logCopyItemError(itemError, 'errorPoi', sourcePoi?.matterportSweepID);
|
|
346
|
+
}
|
|
347
|
+
processedOverall++;
|
|
348
|
+
emitProgress('pois', i + 1, sourcePois.length);
|
|
349
|
+
const pct = sourcePois.length > 0 ? Math.round(((i + 1) / sourcePois.length) * 100) : 100;
|
|
350
|
+
this.setStepProgress('pois', 'pois', pct);
|
|
351
|
+
}
|
|
352
|
+
// OBJECTS 3D (the 3D model file itself — `path` — is physically duplicated in S3)
|
|
353
|
+
for (let i = 0; i < sourceObjects3D.length; i++) {
|
|
354
|
+
const sourceObj = sourceObjects3D[i];
|
|
355
|
+
try {
|
|
356
|
+
const existsInTarget = targetObjects3D.some(targetObj => targetObj.name === sourceObj.name);
|
|
357
|
+
if (!existsInTarget) {
|
|
358
|
+
const rawSource = sourceObj;
|
|
359
|
+
let copiedPath = rawSource.path;
|
|
360
|
+
if (rawSource.path) {
|
|
361
|
+
copiedPath = await this.copyS3KeyIfPresent(rawSource.path, `3D object "${rawSource.name}"`);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Strict parser to ensure [float, float, float] format for GraphQL.
|
|
365
|
+
* Forces numbers, handles potential DynamoDB object structures,
|
|
366
|
+
* and ensures we never send [0,0,0] for scale.
|
|
367
|
+
*/
|
|
368
|
+
const toFloatArray = (val, defaultVal = [0, 0, 0]) => {
|
|
369
|
+
let array = [];
|
|
370
|
+
if (Array.isArray(val)) {
|
|
371
|
+
// If DB format [ {N: "1"}, ... ]
|
|
372
|
+
if (val.length > 0 && typeof val[0] === 'object' && 'N' in val[0]) {
|
|
373
|
+
array = val.map(item => parseFloat(item.N));
|
|
374
|
+
}
|
|
375
|
+
// If already standard array [1, 1, 1]
|
|
376
|
+
else {
|
|
377
|
+
array = val.map(item => parseFloat(item));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// If object {x, y, z}
|
|
381
|
+
else if (val && typeof val === 'object') {
|
|
382
|
+
array = [parseFloat(val.x), parseFloat(val.y), parseFloat(val.z)];
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
return defaultVal;
|
|
386
|
+
}
|
|
387
|
+
// Ensure we return valid numbers
|
|
388
|
+
return array.map(n => isNaN(n) ? 0 : n);
|
|
389
|
+
};
|
|
390
|
+
const object3DInput = {
|
|
391
|
+
path: copiedPath,
|
|
392
|
+
name: rawSource.name,
|
|
393
|
+
description: rawSource.description || "",
|
|
394
|
+
viewFrustum: !!rawSource.viewFrustum,
|
|
395
|
+
spaceID: targetSpaceId,
|
|
396
|
+
position: toFloatArray(rawSource.position, [0, 0, 0]),
|
|
397
|
+
rotation: toFloatArray(rawSource.rotation, [0, 0, 0]),
|
|
398
|
+
// Enforce scale to be at least 1.0 if it's invalid
|
|
399
|
+
scale: toFloatArray(rawSource.scale, [1, 1, 1])
|
|
400
|
+
};
|
|
401
|
+
// Debugging: Inspect the exact object sent to the mutation
|
|
402
|
+
console.log(`[DEBUG] Sending Object3D "${rawSource.name}" to API:`, JSON.stringify(object3DInput));
|
|
403
|
+
const createdObj = await this.object3DService.create(object3DInput);
|
|
404
|
+
if (createdObj && createdObj.id) {
|
|
405
|
+
elementIds[sourceObj.id] = createdObj.id;
|
|
406
|
+
}
|
|
407
|
+
if (sourceObj.pois?.items && sourceObj.pois.items.length > 0) {
|
|
408
|
+
const sourcePoi = sourceObj.pois.items[0];
|
|
409
|
+
const targetSweepId = this.findClosestTargetSweepId(sourcePoi.matterportSweepID, sourceNavPositions, targetNavPositions, transform);
|
|
410
|
+
const adjustedCoordinate = this.getAdjustedCoordinates(sourcePoi.coordinate, transform);
|
|
411
|
+
const poiInput = {
|
|
412
|
+
coordinate: JSON.stringify(adjustedCoordinate),
|
|
413
|
+
type: sourcePoi.type,
|
|
414
|
+
elementID: createdObj.id,
|
|
415
|
+
metadata: sourcePoi.metadata,
|
|
416
|
+
matterportSweepID: targetSweepId
|
|
417
|
+
};
|
|
418
|
+
await this.poiService.createPOIForSpaceID(poiInput);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
catch (itemError) {
|
|
423
|
+
console.error(`Error copying object3D "${sourceObj?.name}":`, itemError);
|
|
424
|
+
errorCount++;
|
|
425
|
+
this.logCopyItemError(itemError, 'errorObject3d', sourceObj?.name || sourceObj?.id);
|
|
426
|
+
}
|
|
427
|
+
processedOverall++;
|
|
428
|
+
emitProgress('objects3d', i + 1, sourceObjects3D.length);
|
|
429
|
+
const pct = sourceObjects3D.length > 0 ? Math.round(((i + 1) / sourceObjects3D.length) * 100) : 100;
|
|
430
|
+
this.setStepProgress('objects3d', 'objects3d', pct);
|
|
431
|
+
}
|
|
432
|
+
// FEATURES (title, POI, and attached comments — images/videos/docs/links — all copied,
|
|
433
|
+
// each file physically duplicated in S3 first)
|
|
434
|
+
for (let i = 0; i < sourceFeatures.length; i++) {
|
|
435
|
+
const sourceObj = sourceFeatures[i];
|
|
436
|
+
try {
|
|
437
|
+
const existsInTarget = this.matchesExisting(sourceObj, targetFeatures);
|
|
438
|
+
if (!existsInTarget) {
|
|
439
|
+
const rawSource = sourceObj;
|
|
440
|
+
const featureInput = {
|
|
441
|
+
title: rawSource.title,
|
|
442
|
+
shortDescription: rawSource.shortDescription,
|
|
443
|
+
level: rawSource.level,
|
|
444
|
+
type: rawSource.type,
|
|
445
|
+
archivedForMissionID: rawSource.archivedForMissionID || null,
|
|
446
|
+
stripeProductID: rawSource.stripeProductID || null,
|
|
447
|
+
stripePriceID: rawSource.stripePriceID || null,
|
|
448
|
+
bookingPriceMetadata: rawSource.bookingPriceMetadata || null,
|
|
449
|
+
locale: rawSource.locale || null,
|
|
450
|
+
hashtags: rawSource.hashtags || null,
|
|
451
|
+
description: rawSource.description || null,
|
|
452
|
+
domainID: null,
|
|
453
|
+
spaceID: targetSpaceId,
|
|
454
|
+
ownerMissionID: targetMissionId
|
|
455
|
+
};
|
|
456
|
+
const createdObj = await this.featureService.createFeature(featureInput);
|
|
457
|
+
if (createdObj && createdObj.id) {
|
|
458
|
+
elementIds[sourceObj.id] = createdObj.id;
|
|
459
|
+
}
|
|
460
|
+
if (createdObj && sourceObj.comments?.items && sourceObj.comments.items.length > 0) {
|
|
461
|
+
for (const sourceComment of sourceObj.comments.items) {
|
|
462
|
+
try {
|
|
463
|
+
const rawComment = sourceComment;
|
|
464
|
+
let copiedAnnexe = null;
|
|
465
|
+
if (rawComment.annexe) {
|
|
466
|
+
copiedAnnexe = await this.copyS3KeyIfPresent(rawComment.annexe, `feature attachment "${rawComment.title}"`);
|
|
467
|
+
}
|
|
468
|
+
const commentInput = {
|
|
469
|
+
title: rawComment.title,
|
|
470
|
+
type: rawComment.type,
|
|
471
|
+
annexe: copiedAnnexe,
|
|
472
|
+
externalLink: rawComment.externalLink || null,
|
|
473
|
+
dimensions: rawComment.dimensions || null,
|
|
474
|
+
index: rawComment.index,
|
|
475
|
+
shownInTag: rawComment.shownInTag,
|
|
476
|
+
isCoverImage: rawComment.isCoverImage,
|
|
477
|
+
featureID: createdObj.id,
|
|
478
|
+
spaceID: targetSpaceId,
|
|
479
|
+
ownerID: targetMissionId
|
|
480
|
+
};
|
|
481
|
+
await this.commentService.createComment(commentInput);
|
|
482
|
+
}
|
|
483
|
+
catch (attachmentError) {
|
|
484
|
+
console.error(`Error copying attachment "${sourceComment?.title}" for feature "${sourceObj?.title}":`, attachmentError);
|
|
485
|
+
errorCount++;
|
|
486
|
+
this.logCopyItemError(attachmentError, 'errorFeatureAttachment', sourceComment?.title || sourceComment?.id);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (sourceObj.pois?.items && sourceObj.pois.items.length > 0) {
|
|
491
|
+
const sourcePoi = sourceObj.pois.items[0];
|
|
492
|
+
const targetSweepId = this.findClosestTargetSweepId(sourcePoi.matterportSweepID, sourceNavPositions, targetNavPositions, transform);
|
|
493
|
+
const adjustedCoordinate = this.getAdjustedCoordinates(sourcePoi.coordinate, transform);
|
|
494
|
+
const poiInput = {
|
|
495
|
+
coordinate: JSON.stringify(adjustedCoordinate),
|
|
496
|
+
type: sourcePoi.type,
|
|
497
|
+
elementID: createdObj.id,
|
|
498
|
+
metadata: sourcePoi.metadata,
|
|
499
|
+
matterportSweepID: targetSweepId
|
|
500
|
+
};
|
|
501
|
+
await this.poiService.createPOIForSpaceID(poiInput);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
catch (itemError) {
|
|
506
|
+
console.error(`Error copying feature "${sourceObj?.title}" (id: ${sourceObj?.id}):`, itemError);
|
|
507
|
+
errorCount++;
|
|
508
|
+
this.logCopyItemError(itemError, 'errorFeature', sourceObj?.title || sourceObj?.id);
|
|
509
|
+
}
|
|
510
|
+
processedOverall++;
|
|
511
|
+
emitProgress('features', i + 1, sourceFeatures.length);
|
|
512
|
+
const pct = sourceFeatures.length > 0 ? Math.round(((i + 1) / sourceFeatures.length) * 100) : 100;
|
|
513
|
+
this.setStepProgress('features', 'features', pct);
|
|
514
|
+
}
|
|
515
|
+
// MEASUREMENTS (IMMO only — a Comment + a positional-only POI, no rotation;
|
|
516
|
+
// the screenshot file is physically duplicated in S3 first)
|
|
517
|
+
if (this.spModule == SpModule.IMMO) {
|
|
518
|
+
for (let i = 0; i < sourceMeasurements.length; i++) {
|
|
519
|
+
const sourceMeasurement = sourceMeasurements[i];
|
|
520
|
+
try {
|
|
521
|
+
const existsInTarget = targetMeasurements.some(tm => tm.comment.title === sourceMeasurement.comment.title);
|
|
522
|
+
if (!existsInTarget) {
|
|
523
|
+
const rawComment = sourceMeasurement.comment;
|
|
524
|
+
let copiedAnnexe = null;
|
|
525
|
+
if (rawComment.annexe) {
|
|
526
|
+
copiedAnnexe = await this.copyS3KeyIfPresent(rawComment.annexe, `measurement screenshot "${rawComment.title}"`);
|
|
527
|
+
}
|
|
528
|
+
const commentInput = {
|
|
529
|
+
title: rawComment.title,
|
|
530
|
+
type: CommentType.MEASURE,
|
|
531
|
+
dimensions: rawComment.dimensions || null,
|
|
532
|
+
annexe: copiedAnnexe,
|
|
533
|
+
spaceID: targetSpaceId,
|
|
534
|
+
};
|
|
535
|
+
const createdComment = await this.commentService.createComment(commentInput);
|
|
536
|
+
if (createdComment && sourceMeasurement.poi) {
|
|
537
|
+
const targetSweepId = this.findClosestTargetSweepId(sourceMeasurement.poi.matterportSweepID, sourceNavPositions, targetNavPositions, transform);
|
|
538
|
+
const adjustedPosition = this.getAdjustedPositionOnly(sourceMeasurement.poi.coordinate, transform);
|
|
539
|
+
const poiInput = {
|
|
540
|
+
coordinate: JSON.stringify(adjustedPosition),
|
|
541
|
+
type: PoiType.MEASURE,
|
|
542
|
+
elementID: createdComment.id,
|
|
543
|
+
metadata: sourceMeasurement.poi.metadata,
|
|
544
|
+
matterportSweepID: targetSweepId
|
|
545
|
+
};
|
|
546
|
+
await this.poiService.createPOIForSpaceID(poiInput);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
catch (itemError) {
|
|
551
|
+
console.error(`Error copying measurement "${sourceMeasurement?.comment?.title}":`, itemError);
|
|
552
|
+
errorCount++;
|
|
553
|
+
this.logCopyItemError(itemError, 'errorMeasurement', sourceMeasurement?.comment?.title || sourceMeasurement?.id);
|
|
554
|
+
}
|
|
555
|
+
processedOverall++;
|
|
556
|
+
emitProgress('measurements', i + 1, sourceMeasurements.length);
|
|
557
|
+
const pct = sourceMeasurements.length > 0 ? Math.round(((i + 1) / sourceMeasurements.length) * 100) : 100;
|
|
558
|
+
this.setStepProgress('measurements', 'measurements', pct);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
this.copyProgress$.next({
|
|
562
|
+
phase: 'done',
|
|
563
|
+
processedInPhase: 0, totalInPhase: 0,
|
|
564
|
+
processedOverall, totalOverall,
|
|
565
|
+
percent: 100, errorCount
|
|
566
|
+
});
|
|
567
|
+
this.setStepLog('done', errorCount > 0
|
|
568
|
+
? this.translate.instant('matterportCopy.doneWithErrors', { count: errorCount })
|
|
569
|
+
: this.translate.instant('matterportCopy.done'));
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
console.error('Error copying POIs:', error);
|
|
574
|
+
this.appendErrorLog(this.translate.instant('matterportCopy.errorGeneral', { error: toErrorMessage(error) }));
|
|
575
|
+
this.copyProgress$.next(null);
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
//
|
|
580
|
+
// ---------- Progress / log helpers ----------
|
|
581
|
+
//
|
|
582
|
+
/** Adds or updates a step line (identified by stepId) with new text, then republishes the log. */
|
|
583
|
+
setStepLog(stepId, text) {
|
|
584
|
+
const existingIndex = this.log.findIndex(e => e.type === 'step' && e.id === stepId);
|
|
585
|
+
const entry = { id: stepId, type: 'step', text };
|
|
586
|
+
if (existingIndex >= 0) {
|
|
587
|
+
this.log[existingIndex] = entry;
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
this.log.push(entry);
|
|
591
|
+
}
|
|
592
|
+
this.copyLog$.next([...this.log]);
|
|
593
|
+
}
|
|
594
|
+
/** Appends a new, permanent log line (never overwritten), then republishes the log. */
|
|
595
|
+
appendErrorLog(text) {
|
|
596
|
+
this.errorSeq++;
|
|
597
|
+
this.log.push({ id: `error-${this.errorSeq}`, type: 'error', text });
|
|
598
|
+
this.copyLog$.next([...this.log]);
|
|
599
|
+
}
|
|
600
|
+
/** Resets the log for a new run. */
|
|
601
|
+
resetLog() {
|
|
602
|
+
this.log = [];
|
|
603
|
+
this.errorSeq = 0;
|
|
604
|
+
this.copyLog$.next([]);
|
|
605
|
+
}
|
|
606
|
+
/** Builds and sets a step's log line as "<translated label>: <percent>%", no step numbering. */
|
|
607
|
+
setStepProgress(stepId, translationKey, percent) {
|
|
608
|
+
const label = this.translate.instant(`matterportCopy.${translationKey}`);
|
|
609
|
+
this.setStepLog(stepId, `${label}: ${percent}%`);
|
|
610
|
+
}
|
|
611
|
+
/** Logs a translated, parameterized error line for a single failed item. */
|
|
612
|
+
logItemError(translationKey, params) {
|
|
613
|
+
const text = this.translate.instant(`matterportCopy.${translationKey}`, params);
|
|
614
|
+
this.appendErrorLog(text);
|
|
615
|
+
}
|
|
616
|
+
/** Logs an item-level error, using a specific "missing file / orphaned reference"
|
|
617
|
+
* translation key when the cause is a MissingS3FileError, and the generic per-type
|
|
618
|
+
* key otherwise. Keeps the copy log readable: a missing file is not a bug to
|
|
619
|
+
* investigate the same way a network/permission error is. */
|
|
620
|
+
logCopyItemError(error, genericKey, itemLabel) {
|
|
621
|
+
if (error instanceof MissingS3FileError) {
|
|
622
|
+
this.logItemError('errorMissingS3FileSkipped', {
|
|
623
|
+
name: itemLabel,
|
|
624
|
+
file: error.sourceKey
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
this.logItemError(genericKey, { name: itemLabel, error: toErrorMessage(error) });
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
//
|
|
632
|
+
// ---------- Duplicate detection ----------
|
|
633
|
+
//
|
|
634
|
+
/**
|
|
635
|
+
* Heuristic duplicate-detection: compares title AND description together instead of
|
|
636
|
+
* title alone, to reduce false positives when several source items happen to share
|
|
637
|
+
* the same title. Not a perfect guarantee, but meaningfully more robust.
|
|
638
|
+
*/
|
|
639
|
+
matchesExisting(source, targetList) {
|
|
640
|
+
return targetList.some(t => t.title === source.title && (t.description || null) === (source.description || null));
|
|
641
|
+
}
|
|
642
|
+
//
|
|
643
|
+
// ---------- Sweep positions / rigid transform ----------
|
|
644
|
+
//
|
|
645
|
+
/**
|
|
646
|
+
* Fetches the position of every sweep in a space and returns it as a Map for O(1) lookup.
|
|
647
|
+
* Uses allSettled so a single failing sweep lookup doesn't abort the whole map —
|
|
648
|
+
* that sweep is simply absent from the resulting map (and skipped later).
|
|
649
|
+
*/
|
|
650
|
+
async buildNavigationPositionMap(spaceId, sweepIds) {
|
|
651
|
+
const map = new Map();
|
|
652
|
+
const results = await Promise.allSettled(sweepIds.map(async (sid) => {
|
|
653
|
+
const navs = await this.navigationService.getNavigationsForMatterportIDForSpace(sid, spaceId);
|
|
654
|
+
if (navs && navs.length > 0 && navs[0].position) {
|
|
655
|
+
return { sid, position: JSON.parse(navs[0].position) };
|
|
656
|
+
}
|
|
657
|
+
return null;
|
|
658
|
+
}));
|
|
659
|
+
for (const result of results) {
|
|
660
|
+
if (result.status === 'fulfilled' && result.value) {
|
|
661
|
+
map.set(result.value.sid, result.value.position);
|
|
662
|
+
}
|
|
663
|
+
else if (result.status === 'rejected') {
|
|
664
|
+
console.warn('Failed to fetch a sweep position, skipping it:', result.reason);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return map;
|
|
668
|
+
}
|
|
669
|
+
/** Applies the rigid transform to a POI coordinate (position + orientation). */
|
|
670
|
+
getAdjustedCoordinates(coordinate, transform) {
|
|
671
|
+
if (coordinate === "null") {
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
if (!coordinate || typeof coordinate !== 'string') {
|
|
675
|
+
return coordinate;
|
|
676
|
+
}
|
|
677
|
+
const parsed = JSON.parse(coordinate);
|
|
678
|
+
const rotatedPos = applyRigidTransformToPoint({ x: parsed.x, y: parsed.y, z: parsed.z }, transform);
|
|
679
|
+
return {
|
|
680
|
+
x: rotatedPos.x,
|
|
681
|
+
y: rotatedPos.y,
|
|
682
|
+
z: rotatedPos.z,
|
|
683
|
+
xRotation: parsed.xRotation,
|
|
684
|
+
yRotation: applyRigidTransformToYRotationDeg(parsed.yRotation, transform)
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Applies the rigid transform's translation+rotation to a plain {x,y,z} position,
|
|
689
|
+
* WITHOUT adding xRotation/yRotation keys. Used for measurements, whose stored
|
|
690
|
+
* coordinate is a bare position (no orientation), unlike other POI types.
|
|
691
|
+
*/
|
|
692
|
+
getAdjustedPositionOnly(coordinate, transform) {
|
|
693
|
+
if (!coordinate || typeof coordinate !== 'string' || coordinate === 'null') {
|
|
694
|
+
return coordinate;
|
|
695
|
+
}
|
|
696
|
+
const parsed = JSON.parse(coordinate);
|
|
697
|
+
return applyRigidTransformToPoint({ x: parsed.x, y: parsed.y, z: parsed.z }, transform);
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Finds the closest target sweep, comparing positions in the SAME coordinate frame.
|
|
701
|
+
* Pure in-memory lookup — no network call, thanks to the pre-built position maps.
|
|
702
|
+
*/
|
|
703
|
+
findClosestTargetSweepId(sourceSweepID, sourceNavPositions, targetNavPositions, transform) {
|
|
704
|
+
if (!sourceSweepID)
|
|
705
|
+
return null;
|
|
706
|
+
const sourcePos = sourceNavPositions.get(sourceSweepID);
|
|
707
|
+
if (!sourcePos)
|
|
708
|
+
return null;
|
|
709
|
+
const sourcePosInTargetFrame = applyRigidTransformToPoint(sourcePos, transform);
|
|
710
|
+
let closestSweepID = null;
|
|
711
|
+
let minDistance = Infinity;
|
|
712
|
+
for (const [targetSweepId, targetPos] of targetNavPositions.entries()) {
|
|
713
|
+
const dx = targetPos.x - sourcePosInTargetFrame.x;
|
|
714
|
+
const dy = targetPos.y - sourcePosInTargetFrame.y;
|
|
715
|
+
const dz = targetPos.z - sourcePosInTargetFrame.z;
|
|
716
|
+
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
717
|
+
if (dist < minDistance) {
|
|
718
|
+
minDistance = dist;
|
|
719
|
+
closestSweepID = targetSweepId;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return closestSweepID;
|
|
723
|
+
}
|
|
724
|
+
//
|
|
725
|
+
// ---------- S3 file duplication ----------
|
|
726
|
+
//
|
|
727
|
+
/** Generates a short random id, used to give each copied S3 file a fresh, collision-safe key. */
|
|
728
|
+
generateShortId() {
|
|
729
|
+
return Math.random().toString(36).slice(2, 10);
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Builds a new S3 key for a copied attachment and sanitizes the filename
|
|
733
|
+
* to prevent AWS Amplify SignatureDoesNotMatch errors.
|
|
734
|
+
*/
|
|
735
|
+
buildCopiedAttachmentKey(sourceAnnexe) {
|
|
736
|
+
const lastSlash = sourceAnnexe.lastIndexOf('/');
|
|
737
|
+
const folder = sourceAnnexe.substring(0, lastSlash + 1);
|
|
738
|
+
let filename = sourceAnnexe.substring(lastSlash + 1);
|
|
739
|
+
// Strip a leading "<8 hex chars>_" id prefix if present
|
|
740
|
+
const prefixMatch = filename.match(/^[0-9a-fA-F-]{8}_(.+)$/);
|
|
741
|
+
if (prefixMatch) {
|
|
742
|
+
filename = prefixMatch[1];
|
|
743
|
+
}
|
|
744
|
+
// SANITIZATION: Replace spaces, parentheses, and accents with underscores
|
|
745
|
+
// Crucial to prevent Amplify's Storage.copy from failing the signature calculation
|
|
746
|
+
filename = filename.replace(/[^a-zA-Z0-9.\-_]/g, '_');
|
|
747
|
+
const newPrefix = `${this.generateShortId()}_`;
|
|
748
|
+
return `${folder}${newPrefix}${filename}`;
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Duplicates an S3 object if a key is present.
|
|
752
|
+
* - If the source file is genuinely missing from S3 (NoSuchKey / orphaned DB reference),
|
|
753
|
+
* throws a MissingS3FileError so the caller can log a clear, specific message and
|
|
754
|
+
* skip the whole item entirely, rather than creating a record with a broken file link.
|
|
755
|
+
* - Any other kind of failure (permissions, network, etc.) still throws a generic Error.
|
|
756
|
+
*/
|
|
757
|
+
async copyS3KeyIfPresent(key, contextLabel) {
|
|
758
|
+
if (!key) {
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
const sourceKey = this.extractS3KeyFromValue(key);
|
|
762
|
+
const destKey = this.buildCopiedAttachmentKey(sourceKey);
|
|
763
|
+
// Log the source key to ensure it matches the real S3 object path
|
|
764
|
+
console.log(`[DEBUG] Attempting S3 copy from source: "${sourceKey}" to dest: "${destKey}"`);
|
|
765
|
+
try {
|
|
766
|
+
const copied = await copyFileInS3(sourceKey, destKey);
|
|
767
|
+
if (!copied) {
|
|
768
|
+
throw new MissingS3FileError(sourceKey, contextLabel);
|
|
769
|
+
}
|
|
770
|
+
return copied;
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
const isMissingFile = error instanceof MissingS3FileError
|
|
774
|
+
|| error?.code === 'NoSuchKey'
|
|
775
|
+
|| /NoSuchKey|does not exist/i.test(toErrorMessage(error));
|
|
776
|
+
if (isMissingFile) {
|
|
777
|
+
console.warn(`[MatterportTagCopyService] Orphaned S3 reference, skipping item: "${sourceKey}" (${contextLabel})`);
|
|
778
|
+
throw new MissingS3FileError(sourceKey, contextLabel);
|
|
779
|
+
}
|
|
780
|
+
throw error;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Duplicates the file referenced by a POI's tagIcon (a JSON string shaped like
|
|
785
|
+
* { src, opacity }, per form-feature.component.ts). If the JSON can't be parsed or
|
|
786
|
+
* has no `src`, the value is returned unchanged rather than risk corrupting it.
|
|
787
|
+
*/
|
|
788
|
+
async duplicateTagIcon(tagIconRaw) {
|
|
789
|
+
if (!tagIconRaw) {
|
|
790
|
+
return tagIconRaw;
|
|
791
|
+
}
|
|
792
|
+
try {
|
|
793
|
+
const parsed = JSON.parse(tagIconRaw);
|
|
794
|
+
if (parsed && parsed.src) {
|
|
795
|
+
parsed.src = await this.copyS3KeyIfPresent(parsed.src, 'tag icon');
|
|
796
|
+
}
|
|
797
|
+
return JSON.stringify(parsed);
|
|
798
|
+
}
|
|
799
|
+
catch {
|
|
800
|
+
// Not JSON, or unexpected shape — leave untouched rather than guess.
|
|
801
|
+
return tagIconRaw;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Duplicates tagImageID if it looks like a reference to a file (contains a path
|
|
806
|
+
* separator, whether raw key or pre-signed URL). UNCONFIRMED ASSUMPTION: this
|
|
807
|
+
* field's exact semantics weren't verified — if it's actually an opaque reference
|
|
808
|
+
* to another DB record rather than a file, this heuristic may incorrectly attempt
|
|
809
|
+
* a copy. Confirm the real structure to tighten this if it causes issues.
|
|
810
|
+
*/
|
|
811
|
+
async duplicateTagImageID(tagImageID) {
|
|
812
|
+
if (!tagImageID || !tagImageID.includes('/')) {
|
|
813
|
+
return tagImageID;
|
|
814
|
+
}
|
|
815
|
+
return this.copyS3KeyIfPresent(tagImageID, 'tag image');
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Extracts and normalizes the raw S3 key from a stored value (which may be a full URL
|
|
819
|
+
* or already a raw key).
|
|
820
|
+
* IMPORTANT: this must return the RAW (decoded, non URL-encoded) key. Amplify's
|
|
821
|
+
* Storage.copy() already builds and encodes the 'x-amz-copy-source' header internally
|
|
822
|
+
* from the key we give it. Pre-encoding it here caused a double-encoding bug (e.g. a
|
|
823
|
+
* space became "%2520" instead of "%20"), so Storage.copy() looked for a key that never
|
|
824
|
+
* existed on S3, resulting in a NoSuchKey error.
|
|
825
|
+
*/
|
|
826
|
+
extractS3KeyFromValue(value) {
|
|
827
|
+
if (!value) {
|
|
828
|
+
return '';
|
|
829
|
+
}
|
|
830
|
+
let extracted = value;
|
|
831
|
+
// 1. Extract path from URL and drop query params
|
|
832
|
+
if (value.startsWith('http://') || value.startsWith('https://')) {
|
|
833
|
+
try {
|
|
834
|
+
const url = new URL(value);
|
|
835
|
+
extracted = decodeURIComponent(url.pathname);
|
|
836
|
+
}
|
|
837
|
+
catch {
|
|
838
|
+
extracted = value.split('?')[0];
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
else {
|
|
842
|
+
extracted = value.split('?')[0];
|
|
843
|
+
}
|
|
844
|
+
// 2. Remove leading slash
|
|
845
|
+
if (extracted.startsWith('/')) {
|
|
846
|
+
extracted = extracted.substring(1);
|
|
847
|
+
}
|
|
848
|
+
// 3. Remove 'public/' prefix
|
|
849
|
+
// Amplify prepends this automatically; we must strip it from the input
|
|
850
|
+
// to avoid the 'public/public/' double-prefix issue.
|
|
851
|
+
if (extracted.startsWith('public/')) {
|
|
852
|
+
extracted = extracted.substring('public/'.length);
|
|
853
|
+
}
|
|
854
|
+
// Return the raw key as-is — Storage.copy() takes care of properly encoding it
|
|
855
|
+
// for the CopySource header. Do NOT re-encode it here.
|
|
856
|
+
return extracted;
|
|
857
|
+
}
|
|
858
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagCopyService, deps: [{ token: i1.NavigationService }, { token: i2.BaseUserService }, { token: i3.PoiService }, { token: i4.TicketsService }, { token: i5.EquipmentService }, { token: i6.Object3DService }, { token: i7.FeatureService }, { token: i8.MeasurementService }, { token: i9.CommentService }, { token: i10.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
859
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagCopyService, providedIn: 'root' });
|
|
860
|
+
}
|
|
861
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagCopyService, decorators: [{
|
|
862
|
+
type: Injectable,
|
|
863
|
+
args: [{ providedIn: 'root' }]
|
|
864
|
+
}], ctorParameters: () => [{ type: i1.NavigationService }, { type: i2.BaseUserService }, { type: i3.PoiService }, { type: i4.TicketsService }, { type: i5.EquipmentService }, { type: i6.Object3DService }, { type: i7.FeatureService }, { type: i8.MeasurementService }, { type: i9.CommentService }, { type: i10.TranslateService }] });
|
|
865
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWF0dGVycG9ydC10YWctY29weS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWNvcmUvc3JjL2xpYi9zZXJ2aWNlcy9tYXR0ZXJwb3J0LXRhZy1jb3B5LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBWXZDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxjQUFjLENBQUMsQ0FBQyw2RkFBNkY7QUFDMUksT0FBTyxFQUNILHFCQUFxQixFQUFFLDBCQUEwQixFQUNqRCxpQ0FBaUMsRUFDcEMsTUFBTSxtQ0FBbUMsQ0FBQztBQUMzQyxPQUFPLEVBQTJDLFdBQVcsRUFBRSxPQUFPLEVBQWEsUUFBUSxFQUFVLE1BQU0sa0JBQWtCLENBQUM7Ozs7Ozs7Ozs7OztBQW9COUg7d0VBQ3dFO0FBQ3hFLFNBQVMsY0FBYyxDQUFDLEdBQVk7SUFDaEMsSUFBSSxHQUFHLElBQUksT0FBTyxHQUFHLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDakMsTUFBTSxNQUFNLEdBQUcsR0FBVSxDQUFDO1FBQzFCLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDM0QsT0FBTyxNQUFNLENBQUMsTUFBTTtpQkFDZixHQUFHLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRTtnQkFDWixNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxTQUFTLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUNwRCxPQUFPLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FB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QVMsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0RCxDQUFDO1FBRUQsK0VBQStFO1FBQy9FLHVEQUF1RDtRQUN2RCxPQUFPLFNBQVMsQ0FBQztJQUNyQixDQUFDO3dHQTM2QlEsd0JBQXdCOzRHQUF4Qix3QkFBd0IsY0FEWCxNQUFNOzs0RkFDbkIsd0JBQXdCO2tCQURwQyxVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0IH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcclxuaW1wb3J0IHsgUE9JIH0gZnJvbSAnLi4vdHlwZXMuc2VydmljZSc7XHJcbmltcG9ydCB7IE5hdmlnYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9tb2RlbHMvbmF2aWdhdGlvbi5zZXJ2aWNlJztcclxuaW1wb3J0IHsgUG9pU2VydmljZSB9IGZyb20gJy4vbW9kZWxzL3BvaS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVGlja2V0c1NlcnZpY2UgfSBmcm9tICcuL21vZGVscy90aWNrZXQuc2VydmljZSc7XHJcbmltcG9ydCB7IEVxdWlwbWVudFNlcnZpY2UgfSBmcm9tICcuL21vZGVscy9lcXVpcG1lbnQuc2VydmljZSc7XHJcbmltcG9ydCB7IE9iamVjdDNEU2VydmljZSB9IGZyb20gJy4vbW9kZWxzL29iamVjdDNELnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBGZWF0dXJlU2VydmljZSB9IGZyb20gJy4vbW9kZWxzL2ZlYXR1cmUuc2VydmljZSc7XHJcbmltcG9ydCB7IE1lYXN1cmVtZW50U2VydmljZSB9IGZyb20gJy4vbW9kZWxzL21lYXN1cmVtZW50LnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBDb21tZW50U2VydmljZSB9IGZyb20gJy4vbW9kZWxzL2NvbW1lbnQuc2VydmljZSc7XHJcbmltcG9ydCB7IEJhc2VVc2VyU2VydmljZSB9IGZyb20gJy4vdXNlci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgY29weUZpbGVJblMzIH0gZnJvbSAnLi9zMy5zZXJ2aWNlJzsgLy8gc2VlIHMzLnNlcnZpY2UudHM6IGNvcHlGaWxlSW5TMyBtdXN0IE5PVCBzd2FsbG93IGVycm9ycyAobmVlZGVkIHRvIGRldGVjdCBOb1N1Y2hLZXkgYmVsb3cpXHJcbmltcG9ydCB7XHJcbiAgICBjb21wdXRlUmlnaWRUcmFuc2Zvcm0sIGFwcGx5UmlnaWRUcmFuc2Zvcm1Ub1BvaW50LFxyXG4gICAgYXBwbHlSaWdpZFRyYW5zZm9ybVRvWVJvdGF0aW9uRGVnLCBSaWdpZFRyYW5zZm9ybSwgVmVjM1xyXG59IGZyb20gJy4vdXRpbHMvbWF0dGVycG9ydC10cmFuc2Zvcm0udXRpbCc7XHJcbmltcG9ydCB7IE9iamVjdDNELCBGZWF0dXJlLCBNZWFzdXJlbWVudCwgQ29tbWVudCwgQ29tbWVudFR5cGUsIFBvaVR5cGUsIEVxdWlwbWVudCwgU3BNb2R1bGUsIFRpY2tldCB9IGZyb20gJy4uL3R5cGVzLnNlcnZpY2UnO1xyXG5cclxuLyoqIFByb2dyZXNzIHNuYXBzaG90IGVtaXR0ZWQgZHVyaW5nIGNvcHlUYWdzRnJvbVZpc2l0KCksIHNvIHRoZSBVSSBjYW4gc2hvdyBhIGxpdmUgc3RhdHVzLiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIENvcHlQcm9ncmVzcyB7XHJcbiAgICBwaGFzZTogJ2NvbGxlY3RpbmcnIHwgJ3RpY2tldHMnIHwgJ2VxdWlwbWVudHMnIHwgJ3BvaXMnIHwgJ29iamVjdHMzZCcgfCAnZmVhdHVyZXMnIHwgJ21lYXN1cmVtZW50cycgfCAnZG9uZSc7XHJcbiAgICBwcm9jZXNzZWRJblBoYXNlOiBudW1iZXI7XHJcbiAgICB0b3RhbEluUGhhc2U6IG51bWJlcjtcclxuICAgIHByb2Nlc3NlZE92ZXJhbGw6IG51bWJlcjtcclxuICAgIHRvdGFsT3ZlcmFsbDogbnVtYmVyO1xyXG4gICAgcGVyY2VudDogbnVtYmVyO1xyXG4gICAgZXJyb3JDb3VudDogbnVtYmVyO1xyXG59XHJcblxyXG4vKiogQSBzaW5nbGUgbGluZSBpbiB0aGUgY29weSBsb2cg4oCUIGVpdGhlciBhIHN0ZXAgc3RhdHVzICh1cGRhdGVkIGluIHBsYWNlKSBvciBhbiBlcnJvciAoYXBwZW5kZWQgb25jZSkuICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgQ29weUxvZ0VudHJ5IHtcclxuICAgIGlkOiBzdHJpbmc7ICAgICAgIC8vIHN0YWJsZSBpZCBmb3Igc3RlcCBsaW5lcyAoc28gdGhleSB1cGRhdGUgaW4gcGxhY2UpLCB1bmlxdWUgZm9yIGVycm9yIGxpbmVzXHJcbiAgICB0eXBlOiAnc3RlcCcgfCAnZXJyb3InO1xyXG4gICAgdGV4dDogc3RyaW5nO1xyXG59XHJcblxyXG4vKiogU2FmZWx5IGV4dHJhY3RzIGEgcmVhZGFibGUgbWVzc2FnZSBmcm9tIGFuIHVua25vd24gY2F0Y2ggdmFsdWUsIGluY2x1ZGluZyBBbXBsaWZ5J3NcclxuICogIEdyYXBoUUwgZXJyb3Igc2hhcGUgKHsgZGF0YSwgZXJyb3JzOiBbeyBlcnJvclR5cGUsIG1lc3NhZ2UgfV0gfSkuICovXHJcbmZ1bmN0aW9uIHRvRXJyb3JNZXNzYWdlKGVycjogdW5rbm93bik6IHN0cmluZyB7XHJcbiAgICBpZiAoZXJyICYmIHR5cGVvZiBlcnIgPT09ICdvYmplY3QnKSB7XHJcbiAgICAgICAgY29uc3QgYW55RXJyID0gZXJyIGFzIGFueTtcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShhbnlFcnIuZXJyb3JzKSAmJiBhbnlFcnIuZXJyb3JzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgcmV0dXJuIGFueUVyci5lcnJvcnNcclxuICAgICAgICAgICAgICAgIC5tYXAoKGU6IGFueSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRpdGxlID0gZS5lcnJvclR5cGUgPyBgJHtlLmVycm9yVHlwZX06IGAgOiAnJztcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYCR7dGl0bGV9JHtlLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InfWA7XHJcbiAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgLmpvaW4oJyB8ICcpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGVyci5tZXNzYWdlO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGlmICh0eXBlb2YgZXJyID09PSAnc3RyaW5nJykge1xyXG4gICAgICAgIHJldHVybiBlcnI7XHJcbiAgICB9XHJcbiAgICB0cnkge1xyXG4gICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShlcnIpO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgICAgcmV0dXJuIFN0cmluZyhlcnIpO1xyXG4gICAgfVxyXG59XHJcblxyXG4vKiogVGhyb3duIHdoZW4gdGhlIHJlZmVyZW5jZWQgUzMgc291cmNlIGZpbGUgZG9lc24ndCBleGlzdCAob3JwaGFuZWQgREIgcmVmZXJlbmNlIOKAlFxyXG4gKiAgZS5nLiB0aGUgZmlsZSB3YXMgZGVsZXRlZCBvciByZW5hbWVkIG9uIFMzIHdpdGhvdXQgdXBkYXRpbmcgdGhlIGRhdGFiYXNlKS5cclxuICogIEtlcHQgZGlzdGluY3QgZnJvbSBvdGhlciBjb3B5IGZhaWx1cmVzIHNvIHRoZSBjYWxsaW5nIGxvb3AgY2FuIGxvZyBhIGNsZWFyLFxyXG4gKiAgc3BlY2lmaWMgbWVzc2FnZSBhbmQgc2tpcCB0aGUgd2hvbGUgaXRlbSBpbnN0ZWFkIG9mIGEgZ2VuZXJpYyBlcnJvci4gKi9cclxuY2xhc3MgTWlzc2luZ1MzRmlsZUVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gICAgY29uc3RydWN0b3IocHVibGljIHJlYWRvbmx5IHNvdXJjZUtleTogc3RyaW5nLCBwdWJsaWMgcmVhZG9ubHkgY29udGV4dExhYmVsOiBzdHJpbmcpIHtcclxuICAgICAgICBzdXBlcihgU291cmNlIGZpbGUgbWlzc2luZyBvbiBTMzogXCIke3NvdXJjZUtleX1cIiAoJHtjb250ZXh0TGFiZWx9KWApO1xyXG4gICAgICAgIHRoaXMubmFtZSA9ICdNaXNzaW5nUzNGaWxlRXJyb3InO1xyXG4gICAgfVxyXG59XHJcblxyXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxyXG5leHBvcnQgY2xhc3MgTWF0dGVycG9ydFRhZ0NvcHlTZXJ2aWNlIHtcclxuXHJcbiAgICAvLyBFbWl0cyBwcm9ncmVzcyB1cGRhdGVzIGR1cmluZyBjb3B5VGFnc0Zyb21WaXNpdCgpOyBudWxsIHdoZW4gaWRsZVxyXG4gICAgcHVibGljIGNvcHlQcm9ncmVzcyQ6IEJlaGF2aW9yU3ViamVjdDxDb3B5UHJvZ3Jlc3MgfCBudWxsPiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Q29weVByb2dyZXNzIHwgbnVsbD4obnVsbCk7XHJcblxyXG4gICAgLy8gRW1pdHMgdGhlIGFjY3VtdWxhdGVkIGxvZyBsaW5lcyBkdXJpbmcgY29weVRhZ3NGcm9tVmlzaXQoKTsgW10gd2hlbiBpZGxlXHJcbiAgICBwdWJsaWMgY29weUxvZyQ6IEJlaGF2aW9yU3ViamVjdDxDb3B5TG9nRW50cnlbXT4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENvcHlMb2dFbnRyeVtdPihbXSk7XHJcblxyXG4gICAgcHJpdmF0ZSBzcE1vZHVsZTogU3BNb2R1bGU7XHJcbiAgICBwcml2YXRlIGxvZzogQ29weUxvZ0VudHJ5W10gPSBbXTtcclxuICAgIHByaXZhdGUgZXJyb3JTZXEgPSAwO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHByaXZhdGUgbmF2aWdhdGlvblNlcnZpY2U6IE5hdmlnYXRpb25TZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgdXNlclNlcnZpY2U6IEJhc2VVc2VyU2VydmljZSxcclxuICAgICAgICBwcml2YXRlIHBvaVNlcnZpY2U6IFBvaVNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSB0aWNrZXRTZXJ2aWNlOiBUaWNrZXRzU2VydmljZSxcclxuICAgICAgICBwcml2YXRlIGVxdWlwbWVudFNlcnZpY2U6IEVxdWlwbWVudFNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSBvYmplY3QzRFNlcnZpY2U6IE9iamVjdDNEU2VydmljZSxcclxuICAgICAgICBwcml2YXRlIGZlYXR1cmVTZXJ2aWNlOiBGZWF0dXJlU2VydmljZSxcclxuICAgICAgICBwcml2YXRlIG1lYXN1cmVtZW50U2VydmljZTogTWVhc3VyZW1lbnRTZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgY29tbWVudFNlcnZpY2U6IENvbW1lbnRTZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgdHJhbnNsYXRlOiBUcmFuc2xhdGVTZXJ2aWNlXHJcbiAgICApIHtcclxuICAgICAgICB0aGlzLnNwTW9kdWxlID0gdXNlclNlcnZpY2UuZ2V0U3BNb2R1bGUoKTtcclxuICAgIH1cclxuXHJcbiAgICAvL1xyXG4gICAgLy8gLS0tLS0tLS0tLSBQdWJsaWMgQVBJIC0tLS0tLS0tLS1cclxuICAgIC8vXHJcblxyXG4gICAgYXN5bmMgY29weVRhZ3NGcm9tVmlzaXQoXHJcbiAgICAgICAgc291cmNlU3BhY2VJZDogc3RyaW5nLFxyXG4gICAgICAgIHRhcmdldFNwYWNlSWQ6IHN0cmluZyxcclxuICAgICAgICBsYW5kbWFya1NvdXJjZUE6IFZlYzMsIGxhbmRtYXJrVGFyZ2V0QTogVmVjMyxcclxuICAgICAgICBsYW5kbWFya1NvdXJjZUI6IFZlYzMsIGxhbmRtYXJrVGFyZ2V0QjogVmVjM1xyXG4gICAgKTogUHJvbWlzZTxib29sZWFuPiB7XHJcbiAgICAgICAgbGV0IGVycm9yQ291bnQgPSAwO1xyXG4gICAgICAgIHRoaXMucmVzZXRMb2coKTtcclxuXHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc29sZS5sb2coYENvcHlpbmcgVGFncyBmcm9tIHNvdXJjZSAke3NvdXJjZVNwYWNlSWR9IHRvIHRhcmdldCAke3RhcmdldFNwYWNlSWR9YCk7XHJcblxyXG4gICAgICAgICAgICB0aGlzLnNldFN0ZXBQcm9ncmVzcygnY29sbGVjdGluZycsICdjb2xsZWN0aW5nJywgMCk7XHJcbiAgICAgICAgICAgIHRoaXMuY29weVByb2dyZXNzJC5uZXh0KHtcclxuICAgICAgICAgICAgICAgIHBoYXNlOiAnY29sbGVjdGluZycsXHJcbiAgICAgICAgICAgICAgICBwcm9jZXNzZWRJblBoYXNlOiAwLCB0b3RhbEluUGhhc2U6IDAsXHJcbiAgICAgICAgICAgICAgICBwcm9jZXNzZWRPdmVyYWxsOiAwLCB0b3RhbE92ZXJhbGw6IDAsXHJcbiAgICAgICAgICAgICAgICBwZXJjZW50OiAwLCBlcnJvckNvdW50OiAwXHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgY29uc3QgdGFyZ2V0TWlzc2lvbiA9IHRoaXMudXNlclNlcnZpY2UuY3VycmVudE1pc3Npb24odGFyZ2V0U3BhY2VJZCk7XHJcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldE1pc3Npb25JZCA9IHRhcmdldE1pc3Npb24gPyB0YXJnZXRNaXNzaW9uLmlkIDogbnVsbDtcclxuXHJcbiAgICAgICAgICAgIGNvbnN0IHRyYW5zZm9ybTogUmlnaWRUcmFuc2Zvcm0gPSBjb21wdXRlUmlnaWRUcmFuc2Zvcm0oXHJcbiAgICAgICAgICAgICAgICBsYW5kbWFya1NvdXJjZUEsIGxhbmRtYXJrVGFyZ2V0QSxcclxuICAgICAgICAgICAgICAgIGxhbmRtYXJrU291cmNlQiwgbGFuZG1hcmtUYXJnZXRCXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdSaWdpZCB0cmFuc2Zvcm0gY29tcHV0ZWQ6Jywge1xyXG4gICAgICAgICAgICAgICAgcm90YXRpb25ZRGVnOiB0cmFuc2Zvcm0ucm90YXRpb25ZUmFkICogKDE4MCAvIE1hdGguUEkpLFxyXG4gICAgICAgICAgICAgICAgcmVmU291cmNlOiB0cmFuc2Zvcm0ucmVmU291cmNlLFxyXG4gICAgICAgICAgICAgICAgcmVmVGFyZ2V0OiB0cmFuc2Zvcm0ucmVmVGFyZ2V0XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgY29uc3Qgc291cmNlU3dlZXBJZHMgPSBhd2FpdCB0aGlzLm5hdmlnYXRpb25TZXJ2aWNlLmdldEFsbG93ZWRTd2VlcHNJRHNGb3JVc2VySW5TcGFjZShzb3VyY2VTcGFjZUlkKTtcclxuICAgICAgICAgICAgY29uc3QgdGFyZ2V0U3dlZXBJZHMgPSBhd2FpdCB0aGlzLm5hdmlnYXRpb25TZXJ2aWNlLmdldEFsbG93ZWRTd2VlcHNJRHNGb3JVc2VySW5TcGFjZSh0YXJnZXRTcGFjZUlkKTtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuc2V0U3RlcFByb2dyZXNzKCdjb2xsZWN0aW5nJywgJ2NvbGxlY3RpbmcnLCAzMCk7XHJcblxyXG4gICAgICAgICAgICBjb25zdCBbc291cmNlTmF2UG9zaXRpb25zLCB0YXJnZXROYXZQb3NpdGlvbnNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xyXG4gICAgICAgICAgICAgICAgdGhpcy5idWlsZE5hdmlnYXRpb25Qb3NpdGlvbk1hcChzb3VyY2VTcGFjZUlkLCBzb3VyY2VTd2VlcElkcyksXHJcbiAgICAgICAgICAgICAgICB0aGlzLmJ1aWxkTmF2aWdhdGlvblBvc2l0aW9uTWFwKHRhcmdldFNwYWNlSWQsIHRhcmdldFN3ZWVwSWRzKVxyXG4gICAgICAgICAgICBdKTtcclxuXHJcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRJZHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcclxuXHJcbiAgICAgICAgICAgIGxldCBzb3VyY2VUaWNrZXRzOiBUaWNrZXRbXSA9IFtdO1xyXG4gICAgICAgICAgICBsZXQgc291cmNlRXF1aXBtZW50czogRXF1aXBtZW50W10gPSBbXTtcclxuICAgICAgICAgICAgbGV0IHRhcmdldFRpY2tldHM6IFRpY2tldFtdID0gW107XHJcbiAgICAgICAgICAgIGxldCB0YXJnZXRFcXVpcG1lbnRzOiBFcXVpcG1lbnRbXSA9IFtdO1xyXG4gICAgICAgICAgICBsZXQgc291cmNlTWVhc3VyZW1lbnRzOiBNZWFzdXJlbWVudFtdID0gW107XHJcbiAgICAgICAgICAgIGxldCB0YXJnZXRNZWFzdXJlbWVudHM6IE1lYXN1cmVtZW50W10gPSBbXTtcclxuXHJcbiAgICAgICAgICAgIGlmICh0aGlzLnNwTW9kdWxlID09IFNwTW9kdWxlLklNTU8pIHtcclxuICAgICAgICAgICAgICAgIHNvdXJjZVRpY2tldHMgPSBhd2FpdCB0aGlzLnRpY2tldFNlcnZpY2UuZ2V0VGlja2V0c0J5U3BhY2Uoc291cmNlU3BhY2VJZCk7XHJcbiAgICAgICAgICAgICAgICBzb3VyY2VFcXVpcG1lbnRzID0gYXdhaXQgdGhpcy5lcXVpcG1lbnRTZXJ2aWNlLmdldEVxdWlwbWVudHNGb3JTcGFjZShzb3VyY2VTcGFjZUlkKTtcclxuICAgICAgICAgICAgICAgIHRhcmdldFRpY2tldHMgPSBhd2FpdCB0aGlzLnRpY2tldFNlcnZpY2UuZ2V0VGlja2V0c0J5U3BhY2UodGFyZ2V0U3BhY2VJZCk7XHJcbiAgICAgICAgICAgICAgICB0YXJnZXRFcXVpcG1lbnRzID0gYXdhaXQgdGhpcy5lcXVpcG1lbnRTZXJ2aWNlLmdldEVxdWlwbWVudHNGb3JTcGFjZSh0YXJnZXRTcGFjZUlkKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgdGhpcy5zZXRTdGVwUHJvZ3Jlc3MoJ2NvbGxlY3RpbmcnLCAnY29sbGVjdGluZycsIDU1KTtcclxuXHJcbiAgICAgICAgICAgIGNvbnN0IHNvdXJjZU9iamVjdHMzRCA9IGF3YWl0IHRoaXMub2JqZWN0M0RTZXJ2aWNlLmdldE9iamVjdHMzREJ5U3BhY2Uoc291cmNlU3BhY2VJZCk7XHJcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldE9iamVjdHMzRCA9IGF3YWl0IHRoaXMub2JqZWN0M0RTZXJ2aWNlLmdldE9iamVjdHMzREJ5U3BhY2UodGFyZ2V0U3BhY2VJZCk7XHJcblxyXG4gICAgICAgICAgICBjb25zdCBzb3VyY2VGZWF0dXJlcyA9IGF3YWl0IHRoaXMuZmVhdHVyZVNlcnZpY2UuZ2V0RmVhdHVyZXNCeVNwYWNlV2l0aG91dEZpbHRlcmluZyhzb3VyY2VTcGFjZUlkKTtcclxuICAgICAgICAgICAgY29uc3QgdGFyZ2V0RmVhdHVyZXMgPSBhd2FpdCB0aGlzLmZlYXR1cmVTZXJ2aWNlLmdldEZlYXR1cmVzQnlTcGFjZVdpdGhvdXRGaWx0ZXJpbmcodGFyZ2V0U3BhY2VJZCk7XHJcblxyXG4gICAgICAgICAgICB0aGlzLnNldFN0ZXBQcm9ncmVzcygnY29sbGVjdGluZycsICdjb2xsZWN0aW5nJywgNzUpO1xyXG5cclxuICAgICAgICAgICAgaWYgKHRoaXMuc3BNb2R1bGUgPT0gU3BNb2R1bGUuSU1NTykge1xyXG4gICAgICAgICAgICAgICAgc291cmNlTWVhc3VyZW1lbnRzID0gYXdhaXQgdGhpcy5tZWFzdXJlbWVudFNlcnZpY2UuZ2V0TWVhc3VyZW1lbnRzRm9yU3BhY2VGb3JVc2VyKHNvdXJjZVNwYWNlSWQpO1xyXG4gICAgICAgICAgICAgICAgdGFyZ2V0TWVhc3VyZW1lbnRzID0gYXdhaXQgdGhpcy5tZWFzdXJlbWVudFNlcnZpY2UuZ2V0TWVhc3VyZW1lbnRzRm9yU3BhY2VGb3JVc2VyKHRhcmdldFNwYWNlSWQpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICB0aGlzLnNldFN0ZXBQcm9ncmVzcygnY29sbGVjdGluZycsICdjb2xsZWN0aW5nJywgOTApO1xyXG5cclxuICAgICAgICAgICAgY29uc3Qgc291cmNlUG9pc0FsbCA9IGF3YWl0IHRoaXMucG9pU2VydmljZS5nZXRQb2lzQnlNYXR0ZXJwb3J0U3dlZXBzKHNvdXJjZVN3ZWVwSWRzKTtcclxuICAgICAgICAgICAgY29uc3QgdGFyZ2V0UG9pc0FsbCA9IGF3YWl0IHRoaXMucG9pU2VydmljZS5nZXRQb2lzQnlNYXR0ZXJwb3J0U3dlZXBzKHRhcmdldFN3ZWVwSWRzKTtcclxuXHJcbiAgICAgICAgICAgIGNvbnN0IGhhbmRsZWRQb2lUeXBlcyA9IG5ldyBTZXQ8c3RyaW5nPihbXHJcbiAgICAgICAgICAgICAgICBQb2lUeXBlLlRJQ0tFVCwgUG9pVHlwZS5FUVVJUE1FTlQsIFBvaVR5cGUuREFUQSwgUG9pVHlwZS5ERVNLLFxyXG4gICAgICAgICAgICAgICAgUG9pVHlwZS5PQkpFQ1QzRCwgUG9pVHlwZS5NRUFTVVJFXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgICAgICBjb25zdCBzb3VyY2VQb2lzID0gc291cmNlUG9pc0FsbC5maWx0ZXIocCA9PiAhaGFuZGxlZFBvaVR5cGVzLmhhcyhwLnR5cGUgYXMgc3RyaW5nKSk7XHJcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldFBvaXMgPSB0YXJnZXRQb2lzQWxsLmZpbHRlcihwID0+ICFoYW5kbGVkUG9pVHlwZXMuaGFzKHAudHlwZSBhcyBzdHJpbmcpKTtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuc2V0U3RlcFByb2dyZXNzKCdjb2xsZWN0aW5nJywgJ2NvbGxlY3RpbmcnLCAxMDApO1xyXG5cclxuICAgICAgICAgICAgY29uc3QgdG90YWxPdmVyYWxsID0gc291cmNlVGlja2V0cy5sZW5ndGggKyBzb3VyY2VFcXVpcG1lbnRzLmxlbmd0aCArIHNvdXJjZVBvaXMubGVuZ3RoXHJcbiAgICAgICAgICAgICAgICArIHNvdXJjZU9iamVjdHMzRC5sZW5ndGggKyBzb3VyY2VGZWF0dXJlcy5sZW5ndGggKyBzb3VyY2VNZWFzdXJlbWVudHMubGVuZ3RoO1xyXG4gICAgICAgICAgICBsZXQgcHJvY2Vzc2VkT3ZlcmFsbCA9IDA7XHJcblxyXG4gICAgICAgICAgICBjb25zdCBlbWl0UHJvZ3Jlc3MgPSAocGhhc2U6IENvcHlQcm9ncmVzc1sncGhhc2UnXSwgcHJvY2Vzc2VkSW5QaGFzZTogbnVtYmVyLCB0b3RhbEluUGhhc2U6IG51bWJlcikgPT4ge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5jb3B5UHJvZ3Jlc3MkLm5leHQoe1xyXG4gICAgICAgICAgICAgICAgICAgIHBoYXNlLFxyXG4gICAgICAgICAgICAgICAgICAgIHByb2Nlc3NlZEluUGhhc2UsXHJcbiAgICAgICAgICAgICAgICAgICAgdG90YWxJblBoYXNlLFxyXG4gICAgICAgICAgICAgICAgICAgIHByb2Nlc3NlZE92ZXJhbGwsXHJcbiAgICAgICAgICAgICAgICAgICAgdG90YWxPdmVyYWxsLFxyXG4gICAgICAgICAgICAgICAgICAgIHBlcmNlbnQ6IHRvdGFsT3ZlcmFsbCA+IDAgPyBNYXRoLnJvdW5kKChwcm9jZXNzZWRPdmVyYWxsIC8gdG90YWxPdmVyYWxsKSAqIDEwMCkgOiAwLFxyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yQ291bnRcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgaWYgKHRoaXMuc3BNb2R1bGUgPT0gU3BNb2R1bGUuSU1NTykge1xyXG4gICAgICAgICAgICAgICAgLy8gVElDS0VUU1xyXG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzb3VyY2VUaWNrZXRzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc291cmNlT2JqID0gc291cmNlVGlja2V0c1tpXTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXhpc3RzSW5UYXJnZXQgPSB0aGlzLm1hdGNoZXNFeGlzdGluZyhzb3VyY2VPYmogYXMgYW55LCB0YXJnZXRUaWNrZXRzIGFzIGFueSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWV4aXN0c0luVGFyZ2V0KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdTb3VyY2UgPSBzb3VyY2VPYmogYXMgYW55O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRpY2tldElucHV0OiBhbnkgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU6IHJhd1NvdXJjZS50aXRsZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcmllbmRseUxhYmVsOiByYXdTb3VyY2UuZnJpZW5kbHlMYWJlbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXM6IHJhd1NvdXJjZS5zdGF0dXMsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogcmF3U291cmNlLnR5cGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3JpdHk6IHJhd1NvdXJjZS5wcmlvcml0eSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogcmF3U291cmNlLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsOiByYXdTb3VyY2UubGV2ZWwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE6IHJhd1NvdXJjZS5tZXRhZGF0YSB8fCBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlYWQ6IHJhd1NvdXJjZS5yZWFkIHx8IG51bGwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvamVjdElEOiByYXdTb3VyY2UucHJvamVjdElEIHx8IG51bGwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYmxlbUNvZGU6IHJhd1NvdXJjZS5wcm9ibGVtQ29kZSB8fCBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyY2hpdmVkRm9yTWlzc2lvbklEOiByYXdTb3VyY2UuYXJjaGl2ZWRGb3JNaXNzaW9uSUQgfHwgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGFjZUlEOiB0YXJnZXRTcGFjZUlkLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmVudElEOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbklEOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG93bmVyTWlzc2lvbklEOiB0YXJnZXRNaXNzaW9uSWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY3JlYXRlZE9iaiA9IGF3YWl0IHRoaXMudGlja2V0U2VydmljZS5jcmVhdGVUaWNrZXQodGlja2V0SW5wdXQpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjcmVhdGVkT2JqICYmIGNyZWF0ZWRPYmouaWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50SWRzW3NvdXJjZU9iai5pZF0gPSBjcmVhdGVkT2JqLmlkO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzb3VyY2VPYmoucG9pcy5pdGVtcyAmJiBzb3VyY2VPYmoucG9pcy5pdGVtcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc291cmNlUG9pID0gc291cmNlT2JqLnBvaXMuaXRlbXNbMF07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0U3dlZXBJZCA9IHRoaXMuZmluZENsb3Nlc3RUYXJnZXRTd2VlcElkKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VQb2kubWF0dGVycG9ydFN3ZWVwSUQsIHNvdXJjZU5hdlBvc2l0aW9ucywgdGFyZ2V0TmF2UG9zaXRpb25zLCB0cmFuc2Zvcm1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGFkanVzdGVkQ29vcmRpbmF0ZSA9IHRoaXMuZ2V0QWRqdXN0ZWRDb29yZGluYXRlcyhzb3VyY2VQb2kuY29vcmRpbmF0ZSwgdHJhbnNmb3JtKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwb2lJbnB1dDogUE9JID0ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb29yZGluYXRlOiBKU09OLnN0cmluZ2lmeShhZGp1c3RlZENvb3JkaW5hdGUpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBzb3VyY2VQb2kudHlwZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudElEOiBjcmVhdGVkT2JqLmlkLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YTogc291cmNlUG9pLm1ldGFkYXRhLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXR0ZXJwb3J0U3dlZXBJRDogdGFyZ2V0U3dlZXBJZFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wb2lTZXJ2aWNlLmNyZWF0ZVBPSUZvclNwYWNlSUQocG9pSW5wdXQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoaXRlbUVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIGNvcHlpbmcgdGlja2V0IFwiJHtzb3VyY2VPYmo/LnRpdGxlfVwiIChpZDogJHtzb3VyY2VPYmo/LmlkfSk6YCwgaXRlbUVycm9yKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JDb3VudCsrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZ0NvcHlJdGVtRXJyb3IoaXRlbUVycm9yLCAnZXJyb3JUaWNrZXQnLCBzb3VyY2VPYmo/LnRpdGxlIHx8IHNvdXJjZU9iaj8uaWQpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgcHJvY2Vzc2VkT3ZlcmFsbCsrO1xyXG4gICAgICAgICAgICAgICAgICAgIGVtaXRQcm9ncmVzcygndGlja2V0cycsIGkgKyAxLCBzb3VyY2VUaWNrZXRzLmxlbmd0aCk7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGN0ID0gc291cmNlVGlja2V0cy5sZW5ndGggPiAwID8gTWF0aC5yb3VuZCgoKGkgKyAxKSAvIHNvdXJjZVRpY2tldHMubGVuZ3RoKSAqIDEwMCkgOiAxMDA7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRTdGVwUHJvZ3Jlc3MoJ3RpY2tldHMnLCAndGlja2V0cycsIHBjdCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gRVFVSVBNRU5UUyAodGl0bGUsIFBPSSwgUEhPVE8gYW5kIE5PVEVTL2RvY3VtZW50cyBhbGwgY29waWVkIOKAlCBmaWxlcyBwaHlzaWNhbGx5XHJcbiAgICAgICAgICAgICAgICAvLyBkdXBsaWNhdGVkIGluIFMzIGZpcnN0LCBzbyB0aGUgY29weSBzdGF5cyBpbmRlcGVuZGVudCBmcm9tIHRoZSBzb3VyY2UpXHJcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNvdXJjZUVxdWlwbWVudHMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBzb3VyY2VPYmogPSBzb3VyY2VFcXVpcG1lbnRzW2ldO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBleGlzdHNJblRhcmdldCA9IHRoaXMubWF0Y2hlc0V4aXN0aW5nKHNvdXJjZU9iaiBhcyBhbnksIHRhcmdldEVxdWlwbWVudHMgYXMgYW55KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZXhpc3RzSW5UYXJnZXQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHJhd1NvdXJjZSA9IHNvdXJjZU9iaiBhcyBhbnk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGNvcGllZFBob3RvS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyYXdTb3VyY2UucGhvdG8pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3BpZWRQaG90b0tleSA9IGF3YWl0IHRoaXMuY29weVMzS2V5SWZQcmVzZW50KHJhd1NvdXJjZS5waG90bywgYGVxdWlwbWVudCBwaG90byBcIiR7cmF3U291cmNlLnRpdGxlfVwiYCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXF1aXBtZW50SW5wdXQ6IGFueSA9IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZTogcmF3U291cmNlLnRpdGxlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1czogcmF3U291cmNlLnN0YXR1cyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogcmF3U291cmNlLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyY2hpdmVkRm9yTWlzc2lvbklEOiByYXdTb3VyY2UuYXJjaGl2ZWRGb3JNaXNzaW9uSUQgfHwgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGFjZUlEOiB0YXJnZXRTcGFjZUlkLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbklEOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBob3RvOiBjb3BpZWRQaG90b0tleSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY3JlYXRlZE9iajogYW55ID0gYXdhaXQgdGhpcy5lcXVpcG1lbnRTZXJ2aWNlLmNyZWF0ZUVxdWlwbWVudChlcXVpcG1lbnRJbnB1dCwgbnVsbCwgbnVsbCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNyZWF0ZWRPYmogJiYgY3JlYXRlZE9iai5pZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRJZHNbc291cmNlT2JqLmlkXSA9IGNyZWF0ZWRPYmouaWQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ29weSBub3RlcyAoZG9jdW1lbnRzLCB0ZWNobmljYWwvZmluYW5jaWFsL290aGVyL2NvbnRyYWN0dWFsL2ltYWdlIG5vdGVzKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNyZWF0ZWRPYmogJiYgcmF3U291cmNlLm5vdGVzPy5pdGVtcyAmJiByYXdTb3VyY2Uubm90ZXMuaXRlbXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgc291cmNlTm90ZSBvZiByYXdTb3VyY2Uubm90ZXMuaXRlbXMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghc291cmNlTm90ZS5hdHRhY2htZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7IC8vIG5vdGhpbmcgdG8gZHVwbGljYXRlIGZvciB0aGlzIG5vdGVcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvcGllZEtleSA9IGF3YWl0IHRoaXMuY29weVMzS2V5SWZQcmVzZW50KHNvdXJjZU5vdGUuYXR0YWNobWVudCwgYGVxdWlwbWVudCBub3RlIGZvciBcIiR7c291cmNlT2JqPy50aXRsZX1cImApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5lcXVpcG1lbnRTZXJ2aWNlLmNyZWF0ZU5vdGVXaXRoRXhpc3RpbmdBdHRhY2htZW50KFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZWRPYmouaWQsIGNvcGllZEtleSwgc291cmNlTm90ZS50eXBlLCB0YXJnZXRNaXNzaW9uSWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKG5vdGVFcnJvcikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgY29weWluZyBub3RlIGZvciBlcXVpcG1lbnQgXCIke3NvdXJjZU9iaj8udGl0bGV9XCI6YCwgbm90ZUVycm9yKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yQ291bnQrKztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubG9nQ29weUl0ZW1FcnJvcihub3RlRXJyb3IsICdlcnJvckVxdWlwbWVudE5vdGUnLCBzb3VyY2VPYmo/LnRpdGxlIHx8IHNvdXJjZU9iaj8uaWQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzb3VyY2VPYmoucG9pcy5pdGVtcyAmJiBzb3VyY2VPYmoucG9pcy5pdGVtcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc291cmNlUG9pID0gc291cmNlT2JqLnBvaXMuaXRlbXNbMF07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0U3dlZXBJZCA9IHRoaXMuZmluZENsb3Nlc3RUYXJnZXRTd2VlcElkKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VQb2kubWF0dGVycG9ydFN3ZWVwSUQsIHNvdXJjZU5hdlBvc2l0aW9ucywgdGFyZ2V0TmF2UG9zaXRpb25zLCB0cmFuc2Zvcm1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGFkanVzdGVkQ29vcmRpbmF0ZSA9IHRoaXMuZ2V0QWRqdXN0ZWRDb29yZGluYXRlcyhzb3VyY2VQb2kuY29vcmRpbmF0ZSwgdHJhbnNmb3JtKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwb2lJbnB1dDogUE9JID0ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb29yZGluYXRlOiBKU09OLnN0cmluZ2lmeShhZGp1c3RlZENvb3JkaW5hdGUpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBzb3VyY2VQb2kudHlwZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudElEOiBjcmVhdGVkT2JqLmlkLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YTogc291cmNlUG9pLm1ldGFkYXRhLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXR0ZXJwb3J0U3dlZXBJRDogdGFyZ2V0U3dlZXBJZFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wb2lTZXJ2aWNlLmNyZWF0ZVBPSUZvclNwYWNlSUQocG9pSW5wdXQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoaXRlbUVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIGNvcHlpbmcgZXF1aXBtZW50IFwiJHtzb3VyY2VPYmo/LnRpdGxlfVwiIChpZDogJHtzb3VyY2VPYmo/LmlkfSk6YCwgaXRlbUVycm9yKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JDb3VudCsrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZ0NvcHlJdGVtRXJyb3IoaXRlbUVycm9yLCAnZXJyb3JFcXVpcG1lbnQnLCBzb3VyY2VPYmo/LnRpdGxlIHx8IHNvdXJjZU9iaj8uaWQpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgcHJvY2Vzc2VkT3ZlcmFsbCsrO1xyXG4gICAgICAgICAgICAgICAgICAgIGVtaXRQcm9ncmVzcygnZXF1aXBtZW50cycsIGkgKyAxLCBzb3VyY2VFcXVpcG1lbnRzLmxlbmd0aCk7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGN0ID0gc291cmNlRXF1aXBtZW50cy5sZW5ndGggPiAwID8gTWF0aC5yb3VuZCgoKGkgKyAxKSAvIHNvdXJjZUVxdWlwbWVudHMubGVuZ3RoKSAqIDEwMCkgOiAxMDA7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRTdGVwUHJvZ3Jlc3MoJ2VxdWlwbWVudHMnLCAnZXF1aXBtZW50cycsIHBjdCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gU2Vjb25kIHBhc3M6IHJlbWFwIHN1YmVxdWlwbWVudHNJRHMgb24gbmV3bHkgY3JlYXRlZCBlcXVpcG1lbnRzIHRvIHBvaW50IHRvXHJcbiAgICAgICAgICAgICAgICAvLyB0aGVpciBjb3BpZWQgY291bnRlcnBhcnRzLiBJRHMgd2l0aCBubyBjb3BpZWQgY291bnRlcnBhcnQgKHNvdXJjZSBlcXVpcG1lbnRcclxuICAgICAgICAgICAgICAgIC8vIHdhc24ndCBjb3BpZWQg4oCUIGUuZy4gaXQgYWxyZWFkeSBleGlzdGVkIGluIHRhcmdldCwgb3Igd2FzIHNraXBwZWQpIGFyZSBkcm9wcGVkXHJcbiAgICAgICAgICAgICAgICAvLyByYXRoZXIgdGhhbiBsZWZ0IGRhbmdsaW5nIG9yIHBvaW50aW5nIGJhY2sgYXQgdGhlIHNvdXJjZSBzcGFjZSdzIGVxdWlwbWVudC5cclxuICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgc291cmNlT2JqIG9mIHNvdXJjZUVxdWlwbWVudHMpIHtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdTb3VyY2UgPSBzb3VyY2VPYmogYXMgYW55O1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5ld0lkID0gZWxlbWVudElkc1tzb3VyY2VPYmouaWRdO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChuZXdJZCAmJiByYXdTb3VyY2Uuc3ViZXF1aXBtZW50c0lEcyAmJiByYXdTb3VyY2Uuc3ViZXF1aXBtZW50c0lEcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlbWFwcGVkID0gcmF3U291cmNlLnN1YmVxdWlwbWVudHNJRHNcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKHN1YklkOiBzdHJpbmcpID0+IGVsZW1lbnRJZHNbc3ViSWRdKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZpbHRlcigoaWQ6IHN0cmluZyB8IHVuZGVmaW5lZCkgPT4gISFpZCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVtYXBwZWQubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmVxdWlwbWVudFNlcnZpY2UudXBkYXRlRXF1aXBtZW50KHsgaWQ6IG5ld0lkLCBzdWJlcXVpcG1lbnRzSURzOiByZW1hcHBlZCB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKHN1YkVxdWlwRXJyb3IpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciByZW1hcHBpbmcgc3ViLWVxdWlwbWVudHMgZm9yIFwiJHtzb3VyY2VPYmo/LnRpdGxlfVwiOmAsIHN1YkVxdWlwRXJyb3IpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yQ291bnQrKztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZ0NvcHlJdGVtRXJyb3Ioc3ViRXF1aXBFcnJvciwgJ2Vycm9yRXF1aXBtZW50U3ViRXF1aXAnLCBzb3VyY2VPYmo/LnRpdGxlIHx8IHNvdXJjZU9iaj8uaWQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBQT0lTIChzdGFuZGFsb25lIOKAlCB0eXBlcyBhbHJlYWR5IGhhbmRsZWQgYWJvdmUgYXJlIGV4Y2x1ZGVkKVxyXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNvdXJjZVBvaXMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHNvdXJjZVBvaSA9IHNvdXJjZVBvaXNbaV07XHJcblxyXG4gICAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBleGlzdHNJblRhcmdldCA9IHRhcmdldFBvaXMuc29tZShcclxuICAgICAgICAgICAgICAgICAgICAgICAgdHAgPT4gdHAuY29vcmRpbmF0ZSA9PT0gc291cmNlUG9pLmNvb3JkaW5hdGUgJiYgdHAudGFnRGVzY3JpcHRpb24gPT09IHNvdXJjZVBvaS50YWdEZXNjcmlwdGlvblxyXG4gICAgICAgICAgICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGlmICghZXhpc3RzSW5UYXJnZXQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0U3dlZXBJZCA9IHRoaXMuZmluZENsb3Nlc3RUYXJnZXRTd2VlcElkKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlUG9pLm1hdHRlcnBvcnRTd2VlcElELCBzb3VyY2VOYXZQb3NpdGlvbnMsIHRhcmdldE5hdlBvc2l0aW9ucywgdHJhbnNmb3JtXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGFkanVzdGVkQ29vcmRpbmF0ZSA9IHRoaXMuZ2V0QWRqdXN0ZWRDb29yZGluYXRlcyhzb3VyY2VQb2kuY29vcmRpbmF0ZSwgdHJhbnNmb3JtKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBlbGVtZW50SUQgPSBzb3VyY2VQb2kuZWxlbWVudElEO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudElEICYmIGVsZW1lbnRJZHNbZWxlbWVudElEXSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudElEID0gZWxlbWVudElkc1tlbGVtZW50SURdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjb3BpZWRUYWdJY29uID0gYXdhaXQgdGhpcy5kdXBsaWNhdGVUYWdJY29uKHNvdXJjZVBvaS50YWdJY29uKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY29waWVkVGFnSW1hZ2VJRCA9IGF3YWl0IHRoaXMuZHVwbGljYXRlVGFnSW1hZ2VJRChzb3VyY2VQb2kudGFnSW1hZ2VJRCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBuZXdQb2k6IFBPSSA9IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvb3JkaW5hdGU6IEpTT04uc3RyaW5naWZ5KGFkanVzdGVkQ29vcmRpbmF0ZSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBzb3VyY2VQb2kudHlwZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRJRDogZWxlbWVudElELFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFnRGVzY3JpcHRpb246IHNvdXJjZVBvaS50YWdEZXNjcmlwdGlvbixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhZ0ljb246IGNvcGllZFRhZ0ljb24sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWdJbWFnZUlEOiBjb3BpZWRUYWdJbWFnZUlELFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlydHVhbDogc291cmNlUG9pLnZpcnR1YWwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Um90YXRpb246IHNvdXJjZVBvaS54Um90YXRpb24sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5Um90YXRpb246IHNvdXJjZVBvaS55Um90YXRpb24sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YTogc291cmNlUG9pLm1ldGFkYXRhLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0dGVycG9ydFN3ZWVwSUQ6IHRhcmdldFN3ZWVwSWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wb2lTZXJ2aWNlLmNyZWF0ZVBPSUZvclNwYWNlSUQobmV3UG9pKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9IGNhdGNoIChpdGVtRXJyb3IpIHtcclxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciBjb3B5aW5nIFBPSSAoc3dlZXA6ICR7c291cmNlUG9pPy5tYXR0ZXJwb3J0U3dlZXBJRH0pOmAsIGl0ZW1FcnJvcik7XHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JDb3VudCsrO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nQ29weUl0ZW1FcnJvcihpdGVtRXJyb3IsICdlcnJvclBvaScsIHNvdXJjZVBvaT8ubWF0dGVycG9ydFN3ZWVwSUQpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIHByb2Nlc3NlZE92ZXJhbGwrKztcclxuICAgICAgICAgICAgICAgIGVtaXRQcm9ncmVzcygncG9pcycsIGkgKyAxLCBzb3VyY2VQb2lzLmxlbmd0aCk7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBwY3QgPSBzb3VyY2VQb2lzLmxlbmd0aCA+IDAgPyBNYXRoLnJvdW5kKCgoaSArIDEpIC8gc291cmNlUG9pcy5sZW5ndGgpICogMTAwKSA6IDEwMDtcclxuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RlcFByb2dyZXNzKCdwb2lzJywgJ3BvaXMnLCBwY3QpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBPQkpFQ1RTIDNEICh0aGUgM0QgbW9kZWwgZmlsZSBpdHNlbGYg4oCUIGBwYXRoYCDigJQgaXMgcGh5c2ljYWxseSBkdXBsaWNhdGVkIGluIFMzKVxyXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNvdXJjZU9iamVjdHMzRC5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICAgICAgY29uc3Qgc291cmNlT2JqID0gc291cmNlT2JqZWN0czNEW2ldO1xyXG5cclxuICAgICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZXhpc3RzSW5UYXJnZXQgPSB0YXJnZXRPYmplY3RzM0Quc29tZSh0YXJnZXRPYmogPT4gdGFyZ2V0T2JqLm5hbWUgPT09IHNvdXJjZU9iai5uYW1lKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFleGlzdHNJblRhcmdldCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdTb3VyY2UgPSBzb3VyY2VPYmogYXMgYW55O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGNvcGllZFBhdGggPSByYXdTb3VyY2UucGF0aDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJhd1NvdXJjZS5wYXRoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3BpZWRQYXRoID0gYXdhaXQgdGhpcy5jb3B5UzNLZXlJZlByZXNlbnQocmF3U291cmNlLnBhdGgsIGAzRCBvYmplY3QgXCIke3Jhd1NvdXJjZS5uYW1lfVwiYCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8qKlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgKiBTdHJpY3QgcGFyc2VyIHRvIGVuc3VyZSBbZmxvYXQsIGZsb2F0LCBmbG9hdF0gZm9ybWF0IGZvciBHcmFwaFFMLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgKiBGb3JjZXMgbnVtYmVycywgaGFuZGxlcyBwb3RlbnRpYWwgRHluYW1vREIgb2JqZWN0IHN0cnVjdHVyZXMsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAqIGFuZCBlbnN1cmVzIHdlIG5ldmVyIHNlbmQgWzAsMCwwXSBmb3Igc2NhbGUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAqL1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0b0Zsb2F0QXJyYXkgPSAodmFsOiBhbnksIGRlZmF1bHRWYWw6IG51bWJlcltdID0gWzAsIDAsIDBdKTogbnVtYmVyW10gPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGFycmF5OiBudW1iZXJbXSA9IFtdO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBEQiBmb3JtYXQgWyB7TjogXCIxXCJ9LCAuLi4gXVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2YWwubGVuZ3RoID4gMCAmJiB0eXBlb2YgdmFsWzBdID09PSAnb2JqZWN0JyAmJiAnTicgaW4gdmFsWzBdKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmF5ID0gdmFsLm1hcChpdGVtID0+IHBhcnNlRmxvYXQoaXRlbS5OKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIGFscmVhZHkgc3RhbmRhcmQgYXJyYXkgWzEsIDEsIDFdXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmF5ID0gdmFsLm1hcChpdGVtID0+IHBhcnNlRmxvYXQoaXRlbSkpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIG9iamVjdCB7eCwgeSwgen1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHZhbCAmJiB0eXBlb2YgdmFsID09PSAnb2JqZWN0Jykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmF5ID0gW3BhcnNlRmxvYXQodmFsLngpLCBwYXJzZUZsb2F0KHZhbC55KSwgcGFyc2VGbG9hdCh2YWwueildO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGVmYXVsdFZhbDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBFbnN1cmUgd2UgcmV0dXJuIHZhbGlkIG51bWJlcnNcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBhcnJheS5tYXAobiA9PiBpc05hTihuKSA/IDAgOiBuKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG9iamVjdDNESW5wdXQ6IGFueSA9IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGg6IGNvcGllZFBhdGgsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiByYXdTb3VyY2UubmFtZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiByYXdTb3VyY2UuZGVzY3JpcHRpb24gfHwgXCJcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXdGcnVzdHVtOiAhIXJhd1NvdXJjZS52aWV3RnJ1c3R1bSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwYWNlSUQ6IHRhcmdldFNwYWNlSWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbjogdG9GbG9hdEFycmF5KHJhd1NvdXJjZS5wb3NpdGlvbiwgWzAsIDAsIDBdKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdGF0aW9uOiB0b0Zsb2F0QXJyYXkocmF3U291cmNlLnJvdGF0aW9uLCBbMCwgMCwgMF0pLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRW5mb3JjZSBzY2FsZSB0byBiZSBhdCBsZWFzdCAxLjAgaWYgaXQncyBpbnZhbGlkXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZTogdG9GbG9hdEFycmF5KHJhd1NvdXJjZS5zY2FsZSwgWzEsIDEsIDFdKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGVidWdnaW5nOiBJbnNwZWN0IHRoZSBleGFjdCBvYmplY3Qgc2VudCB0byB0aGUgbXV0YXRpb25cclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coYFtERUJVR10gU2VuZGluZyBPYmplY3QzRCBcIiR7cmF3U291cmNlLm5hbWV9XCIgdG8gQVBJOmAsIEpTT04uc3RyaW5naWZ5KG9iamVjdDNESW5wdXQpKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNyZWF0ZWRPYmogPSBhd2FpdCB0aGlzLm9iamVjdDNEU2VydmljZS5jcmVhdGUob2JqZWN0M0RJbnB1dCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3JlYXRlZE9iaiAmJiBjcmVhdGVkT2JqLmlkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50SWRzW3NvdXJjZU9iai5pZF0gPSBjcmVhdGVkT2JqLmlkO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc291cmNlT2JqLnBvaXM/Lml0ZW1zICYmIHNvdXJjZU9iai5wb2lzLml0ZW1zLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNvdXJjZVBvaSA9IHNvdXJjZU9iai5wb2lzLml0ZW1zWzBdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0U3dlZXBJZCA9IHRoaXMuZmluZENsb3Nlc3RUYXJnZXRTd2VlcElkKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZVBvaS5tYXR0ZXJwb3J0U3dlZXBJRCwgc291cmNlTmF2UG9zaXRpb25zLCB0YXJnZXROYXZQb3NpdGlvbnMsIHRyYW5zZm9ybVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGFkanVzdGVkQ29vcmRpbmF0ZSA9IHRoaXMuZ2V0QWRqdXN0ZWRDb29yZGluYXRlcyhzb3VyY2VQb2kuY29vcmRpbmF0ZSwgdHJhbnNmb3JtKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBvaUlucHV0OiBQT0kgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29vcmRpbmF0ZTogSlNPTi5zdHJpbmdpZnkoYWRqdXN0ZWRDb29yZGluYXRlKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBzb3VyY2VQb2kudHlwZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50SUQ6IGNyZWF0ZWRPYmouaWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE6IHNvdXJjZVBvaS5tZXRhZGF0YSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXR0ZXJwb3J0U3dlZXBJRDogdGFyZ2V0U3dlZXBJZFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucG9pU2VydmljZS5jcmVhdGVQT0lGb3JTcGFjZUlEKHBvaUlucHV0KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGl0ZW1FcnJvcikge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIGNvcHlpbmcgb2JqZWN0M0QgXCIke3NvdXJjZU9iaj8ubmFtZX1cIjpgLCBpdGVtRXJyb3IpO1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yQ291bnQrKztcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZ0NvcHlJdGVtRXJyb3IoaXRlbUVycm9yLCAnZXJyb3JPYmplY3QzZCcsIHNvdXJjZU9iaj8ubmFtZSB8fCBzb3VyY2VPYmo/LmlkKTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICBwcm9jZXNzZWRPdmVyYWxsKys7XHJcbiAgICAgICAgICAgICAgICBlbWl0UHJvZ3Jlc3MoJ29iamVjdHMzZCcsIGkgKyAxLCBzb3VyY2VPYmplY3RzM0QubGVuZ3RoKTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHBjdCA9IHNvdXJjZU9iamVjdHMzRC5sZW5ndGggPiAwID8gTWF0aC5yb3VuZCgoKGkgKyAxKSAvIHNvdXJjZU9iamVjdHMzRC5sZW5ndGgpICogMTAwKSA6IDEwMDtcclxuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RlcFByb2dyZXNzKCdvYmplY3RzM2QnLCAnb2JqZWN0czNkJywgcGN0KTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gRkVBVFVSRVMgKHRpdGxlLCBQT0ksIGFuZCBhdHRhY2hlZCBjb21tZW50cyDigJQgaW1hZ2VzL3ZpZGVvcy9kb2NzL2xpbmtzIOKAlCBhbGwgY29waWVkLFxyXG4gICAgICAgICAgICAvLyBlYWNoIGZpbGUgcGh5c2ljYWxseSBkdXBsaWNhdGVkIGluIFMzIGZpcnN0KVxyXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNvdXJjZUZlYXR1cmVzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBzb3VyY2VPYmogPSBzb3VyY2VGZWF0dXJlc1tpXTtcclxuXHJcbiAgICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4aXN0c0luVGFyZ2V0ID0gdGhpcy5tYXRjaGVzRXhpc3Rpbmcoc291cmNlT2JqIGFzIGFueSwgdGFyZ2V0RmVhdHVyZXMgYXMgYW55KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFleGlzdHNJblRhcmdldCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdTb3VyY2UgPSBzb3VyY2VPYmogYXMgYW55O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZmVhdHVyZUlucHV0OiBhbnkgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZTogcmF3U291cmNlLnRpdGxlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvcnREZXNjcmlwdGlvbjogcmF3U291cmNlLnNob3J0RGVzY3JpcHRpb24sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbDogcmF3U291cmNlLmxldmVsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogcmF3U291cmNlLnR5cGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmNoaXZlZEZvck1pc3Npb25JRDogcmF3U291cmNlLmFyY2hpdmVkRm9yTWlzc2lvbklEIHx8IG51bGwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcGVQcm9kdWN0SUQ6IHJhd1NvdXJjZS5zdHJpcGVQcm9kdWN0SUQgfHwgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmlwZVByaWNlSUQ6IHJhd1NvdXJjZS5zdHJpcGVQcmljZUlEIHx8IG51bGwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib29raW5nUHJpY2VNZXRhZGF0YTogcmF3U291cmNlLmJvb2tpbmdQcmljZU1ldGFkYXRhIHx8IG51bGwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhbGU6IHJhd1NvdXJjZS5sb2NhbGUgfHwgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhc2h0YWdzOiByYXdTb3VyY2UuaGFzaHRhZ3MgfHwgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiByYXdTb3VyY2UuZGVzY3JpcHRpb24gfHwgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbklEOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BhY2VJRDogdGFyZ2V0U3BhY2VJZCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG93bmVyTWlzc2lvbklEOiB0YXJnZXRNaXNzaW9uSWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNyZWF0ZWRPYmogPSBhd2FpdCB0aGlzLmZlYXR1cmVTZXJ2aWNlLmNyZWF0ZUZlYXR1cmUoZmVhdHVyZUlucHV0KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjcmVhdGVkT2JqICYmIGNyZWF0ZWRPYmouaWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRJZHNbc291cmNlT2JqLmlkXSA9IGNyZWF0ZWRPYmouaWQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjcmVhdGVkT2JqICYmIHNvdXJjZU9iai5jb21tZW50cz8uaXRlbXMgJiYgc291cmNlT2JqLmNvbW1lbnRzLml0ZW1zLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgc291cmNlQ29tbWVudCBvZiBzb3VyY2VPYmouY29tbWVudHMuaXRlbXMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdDb21tZW50ID0gc291cmNlQ29tbWVudCBhcyBhbnk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXQgY29waWVkQW5uZXhlOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJhd0NvbW1lbnQuYW5uZXhlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3BpZWRBbm5leGUgPSBhd2FpdCB0aGlzLmNvcHlTM0tleUlmUHJlc2VudChyYXdDb21tZW50LmFubmV4ZSwgYGZlYXR1cmUgYXR0YWNobWVudCBcIiR7cmF3Q29tbWVudC50aXRsZX1cImApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjb21tZW50SW5wdXQ6IGFueSA9IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlOiByYXdDb21tZW50LnRpdGxlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogcmF3Q29tbWVudC50eXBlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5uZXhlOiBjb3BpZWRBbm5leGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRlcm5hbExpbms6IHJhd0NvbW1lbnQuZXh0ZXJuYWxMaW5rIHx8IG51bGwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1lbnNpb25zOiByYXdDb21tZW50LmRpbWVuc2lvbnMgfHwgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4OiByYXdDb21tZW50LmluZGV4LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd25JblRhZzogcmF3Q29tbWVudC5zaG93bkluVGFnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNDb3ZlckltYWdlOiByYXdDb21tZW50LmlzQ292ZXJJbWFnZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVJRDogY3JlYXRlZE9iai5pZCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwYWNlSUQ6IHRhcmdldFNwYWNlSWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvd25lcklEOiB0YXJnZXRNaXNzaW9uSWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuY29tbWVudFNlcnZpY2UuY3JlYXRlQ29tbWVudChjb21tZW50SW5wdXQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGF0dGFjaG1lbnRFcnJvcikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciBjb3B5aW5nIGF0dGFjaG1lbnQgXCIke3NvdXJjZUNvbW1lbnQ/LnRpdGxlfVwiIGZvciBmZWF0dXJlIFwiJHtzb3VyY2VPYmo/LnRpdGxlfVwiOmAsIGF0dGFjaG1lbnRFcnJvcik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yQ291bnQrKztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2dDb3B5SXRlbUVycm9yKGF0dGFjaG1lbnRFcnJvciwgJ2Vycm9yRmVhdHVyZUF0dGFjaG1lbnQnLCBzb3VyY2VDb21tZW50Py50aXRsZSB8fCBzb3VyY2VDb21tZW50Py5pZCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc291cmNlT2JqLnBvaXM/Lml0ZW1zICYmIHNvdXJjZU9iai5wb2lzLml0ZW1zLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNvdXJjZVBvaSA9IHNvdXJjZU9iai5wb2lzLml0ZW1zWzBdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0U3dlZXBJZCA9IHRoaXMuZmluZENsb3Nlc3RUYXJnZXRTd2VlcElkKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZVBvaS5tYXR0ZXJwb3J0U3dlZXBJRCwgc291cmNlTmF2UG9zaXRpb25zLCB0YXJnZXROYXZQb3NpdGlvbnMsIHRyYW5zZm9ybVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGFkanVzdGVkQ29vcmRpbmF0ZSA9IHRoaXMuZ2V0QWRqdXN0ZWRDb29yZGluYXRlcyhzb3VyY2VQb2kuY29vcmRpbmF0ZSwgdHJhbnNmb3JtKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBvaUlucHV0OiBQT0kgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29vcmRpbmF0ZTogSlNPTi5zdHJpbmdpZnkoYWRqdXN0ZWRDb29yZGluYXRlKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBzb3VyY2VQb2kudHlwZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50SUQ6IGNyZWF0ZWRPYmouaWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE6IHNvdXJjZVBvaS5tZXRhZGF0YSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXR0ZXJwb3J0U3dlZXBJRDogdGFyZ2V0U3dlZXBJZFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucG9pU2VydmljZS5jcmVhdGVQT0lGb3JTcGFjZUlEKHBvaUlucHV0KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGl0ZW1FcnJvcikge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIGNvcHlpbmcgZmVhdHVyZSBcIiR7c291cmNlT2JqPy50aXRsZX1cIiAoaWQ6ICR7c291cmNlT2JqPy5pZH0pOmAsIGl0ZW1FcnJvcik7XHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JDb3VudCsrO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nQ29weUl0ZW1FcnJvcihpdGVtRXJyb3IsICdlcnJvckZlYXR1cmUnLCBzb3VyY2VPYmo/LnRpdGxlIHx8IHNvdXJjZU9iaj8uaWQpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIHByb2Nlc3NlZE92ZXJhbGwrKztcclxuICAgICAgICAgICAgICAgIGVtaXRQcm9ncmVzcygnZmVhdHVyZXMnLCBpICsgMSwgc291cmNlRmVhdHVyZXMubGVuZ3RoKTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHBjdCA9IHNvdXJjZUZlYXR1cmVzLmxlbmd0aCA+IDAgPyBNYXRoLnJvdW5kKCgoaSArIDEpIC8gc291cmNlRmVhdHVyZXMubGVuZ3RoKSAqIDEwMCkgOiAxMDA7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0ZXBQcm9ncmVzcygnZmVhdHVyZXMnLCAnZmVhdHVyZXMnLCBwY3QpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBNRUFTVVJFTUVOVFMgKElNTU8gb25seSDigJQgYSBDb21tZW50ICsgYSBwb3NpdGlvbmFsLW9ubHkgUE9JLCBubyByb3RhdGlvbjtcclxuICAgICAgICAgICAgLy8gdGhlIHNjcmVlbnNob3QgZmlsZSBpcyBwaHlzaWNhbGx5IGR1cGxpY2F0ZWQgaW4gUzMgZmlyc3QpXHJcbiAgICAgICAgICAgIGlmICh0aGlzLnNwTW9kdWxlID09IFNwTW9kdWxlLklNTU8pIHtcclxuICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc291cmNlTWVhc3VyZW1lbnRzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc291cmNlTWVhc3VyZW1lbnQgPSBzb3VyY2VNZWFzdXJlbWVudHNbaV07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4aXN0c0luVGFyZ2V0ID0gdGFyZ2V0TWVhc3VyZW1lbnRzLnNvbWUoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bSA9PiB0bS5jb21tZW50LnRpdGxlID09PSBzb3VyY2VNZWFzdXJlbWVudC5jb21tZW50LnRpdGxlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWV4aXN0c0luVGFyZ2V0KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdDb21tZW50ID0gc291cmNlTWVhc3VyZW1lbnQuY29tbWVudCBhcyBhbnk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGNvcGllZEFubmV4ZTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocmF3Q29tbWVudC5hbm5leGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3BpZWRBbm5leGUgPSBhd2FpdCB0aGlzLmNvcHlTM0tleUlmUHJlc2VudChyYXdDb21tZW50LmFubmV4ZSwgYG1lYXN1cmVtZW50IHNjcmVlbnNob3QgXCIke3Jhd0NvbW1lbnQudGl0bGV9XCJgKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjb21tZW50SW5wdXQ6IGFueSA9IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZTogcmF3Q29tbWVudC50aXRsZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBDb21tZW50VHlwZS5NRUFTVVJFLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbWVuc2lvbnM6IHJhd0NvbW1lbnQuZGltZW5zaW9ucyB8fCBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubmV4ZTogY29waWVkQW5uZXhlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwYWNlSUQ6IHRhcmdldFNwYWNlSWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNyZWF0ZWRDb21tZW50OiBDb21tZW50ID0gYXdhaXQgdGhpcy5jb21tZW50U2VydmljZS5jcmVhdGVDb21tZW50KGNvbW1lbnRJbnB1dCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNyZWF0ZWRDb21tZW50ICYmIHNvdXJjZU1lYXN1cmVtZW50LnBvaSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRhcmdldFN3ZWVwSWQgPSB0aGlzLmZpbmRDbG9zZXN0VGFyZ2V0U3dlZXBJZChcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlTWVhc3VyZW1lbnQucG9pLm1hdHRlcnBvcnRTd2VlcElELCBzb3VyY2VOYXZQb3NpdGlvbnMsIHRhcmdldE5hdlBvc2l0aW9ucywgdHJhbnNmb3JtXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBhZGp1c3RlZFBvc2l0aW9uID0gdGhpcy5nZXRBZGp1c3RlZFBvc2l0aW9uT25seShzb3VyY2VNZWFzdXJlbWVudC5wb2kuY29vcmRpbmF0ZSwgdHJhbnNmb3JtKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwb2lJbnB1dDogUE9JID0ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb29yZGluYXRlOiBKU09OLnN0cmluZ2lmeShhZGp1c3RlZFBvc2l0aW9uKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogUG9pVHlwZS5NRUFTVVJFLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50SUQ6IChjcmVhdGVkQ29tbWVudCBhcyBhbnkpLmlkLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YTogc291cmNlTWVhc3VyZW1lbnQucG9pLm1ldGFkYXRhLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXR0ZXJwb3J0U3dlZXBJRDogdGFyZ2V0U3dlZXBJZFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wb2lTZXJ2aWNlLmNyZWF0ZVBPSUZvclNwYWNlSUQocG9pSW5wdXQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoaXRlbUVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIGNvcHlpbmcgbWVhc3VyZW1lbnQgXCIke3NvdXJjZU1lYXN1cmVtZW50Py5jb21tZW50Py50aXRsZX1cIjpgLCBpdGVtRXJyb3IpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvckNvdW50Kys7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubG9nQ29weUl0ZW1FcnJvcihpdGVtRXJyb3IsICdlcnJvck1lYXN1cmVtZW50Jywgc291cmNlTWVhc3VyZW1lbnQ/LmNvbW1lbnQ/LnRpdGxlIHx8IHNvdXJjZU1lYXN1cmVtZW50Py5pZCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICBwcm9jZXNzZWRPdmVyYWxsKys7XHJcbiAgICAgICAgICAgICAgICAgICAgZW1pdFByb2dyZXNzKCdtZWFzdXJlbWVudHMnLCBpICsgMSwgc291cmNlTWVhc3VyZW1lbnRzLmxlbmd0aCk7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGN0ID0gc291cmNlTWVhc3VyZW1lbnRzLmxlbmd0aCA+IDAgPyBNYXRoLnJvdW5kKCgoaSArIDEpIC8gc291cmNlTWVhc3VyZW1lbnRzLmxlbmd0aCkgKiAxMDApIDogMTAwO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RlcFByb2dyZXNzKCdtZWFzdXJlbWVudHMnLCAnbWVhc3VyZW1lbnRzJywgcGN0KTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgdGhpcy5jb3B5UHJvZ3Jlc3MkLm5leHQoe1xyXG4gICAgICAgICAgICAgICAgcGhhc2U6ICdkb25lJyxcclxuICAgICAgICAgICAgICAgIHByb2Nlc3NlZEluUGhhc2U6IDAsIHRvdGFsSW5QaGFzZTogMCxcclxuICAgICAgICAgICAgICAgIHByb2Nlc3NlZE92ZXJhbGwsIHRvdGFsT3ZlcmFsbCxcclxuICAgICAgICAgICAgICAgIHBlcmNlbnQ6IDEwMCwgZXJyb3JDb3VudFxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgdGhpcy5zZXRTdGVwTG9nKCdkb25lJywgZXJyb3JDb3VudCA+IDBcclxuICAgICAgICAgICAgICAgID8gdGhpcy50cmFuc2xhdGUuaW5zdGFudCgnbWF0dGVycG9ydENvcHkuZG9uZVdpdGhFcnJvcnMnLCB7IGNvdW50OiBlcnJvckNvdW50IH0pXHJcbiAgICAgICAgICAgICAgICA6IHRoaXMudHJhbnNsYXRlLmluc3RhbnQoJ21hdHRlcnBvcnRDb3B5LmRvbmUnKSk7XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBjb3B5aW5nIFBPSXM6JywgZXJyb3IpO1xyXG4gICAgICAgICAgICB0aGlzLmFwcGVuZEVycm9yTG9nKHRoaXMudHJhbnNsYXRlLmluc3RhbnQoJ21hdHRlcnBvcnRDb3B5LmVycm9yR2VuZXJhbCcsIHsgZXJyb3I6IHRvRXJyb3JNZXNzYWdlKGVycm9yKSB9KSk7XHJcbiAgICAgICAgICAgIHRoaXMuY29weVByb2dyZXNzJC5uZXh0KG51bGwpO1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vXHJcbiAgICAvLyAtLS0tLS0tLS0tIFByb2dyZXNzIC8gbG9nIGhlbHBlcnMgLS0tLS0tLS0tLVxyXG4gICAgLy9cclxuXHJcbiAgICAvKiogQWRkcyBvciB1cGRhdGVzIGEgc3RlcCBsaW5lIChpZGVudGlmaWVkIGJ5IHN0ZXBJZCkgd2l0aCBuZXcgdGV4dCwgdGhlbiByZXB1Ymxpc2hlcyB0aGUgbG9nLiAqL1xyXG4gICAgcHJpdmF0ZSBzZXRTdGVwTG9nKHN0ZXBJZDogc3RyaW5nLCB0ZXh0OiBzdHJpbmcpIHtcclxuICAgICAgICBjb25zdCBleGlzdGluZ0luZGV4ID0gdGhpcy5sb2cuZmluZEluZGV4KGUgPT4gZS50eXBlID09PSAnc3RlcCcgJiYgZS5pZCA9PT0gc3RlcElkKTtcclxuICAgICAgICBjb25zdCBlbnRyeTogQ29weUxvZ0VudHJ5ID0geyBpZDogc3RlcElkLCB0eXBlOiAnc3RlcCcsIHRleHQgfTtcclxuICAgICAgICBpZiAoZXhpc3RpbmdJbmRleCA+PSAwKSB7XHJcbiAgICAgICAgICAgIHRoaXMubG9nW2V4aXN0aW5nSW5kZXhdID0gZW50cnk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5sb2cucHVzaChlbnRyeSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuY29weUxvZyQubmV4dChbLi4udGhpcy5sb2ddKTtcclxuICAgIH1cclxuXHJcbiAgICAvKiogQXBwZW5kcyBhIG5ldywgcGVybWFuZW50IGxvZyBsaW5lIChuZXZlciBvdmVyd3JpdHRlbiksIHRoZW4gcmVwdWJsaXNoZXMgdGhlIGxvZy4gKi9cclxuICAgIHByaXZhdGUgYXBwZW5kRXJyb3JMb2codGV4dDogc3RyaW5nKSB7XHJcbiAgICAgICAgdGhpcy5lcnJvclNlcSsrO1xyXG4gICAgICAgIHRoaXMubG9nLnB1c2goeyBpZDogYGVycm9yLSR7dGhpcy5lcnJvclNlcX1gLCB0eXBlOiAnZXJyb3InLCB0ZXh0IH0pO1xyXG4gICAgICAgIHRoaXMuY29weUxvZyQubmV4dChbLi4udGhpcy5sb2ddKTtcclxuICAgIH1cclxuXHJcbiAgICAvKiogUmVzZXRzIHRoZSBsb2cgZm9yIGEgbmV3IHJ1bi4gKi9cclxuICAgIHByaXZhdGUgcmVzZXRMb2coKSB7XHJcbiAgICAgICAgdGhpcy5sb2cgPSBbXTtcclxuICAgICAgICB0aGlzLmVycm9yU2VxID0gMDtcclxuICAgICAgICB0aGlzLmNvcHlMb2ckLm5leHQoW10pO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKiBCdWlsZHMgYW5kIHNldHMgYSBzdGVwJ3MgbG9nIGxpbmUgYXMgXCI8dHJhbnNsYXRlZCBsYWJlbD46IDxwZXJjZW50PiVcIiwgbm8gc3RlcCBudW1iZXJpbmcuICovXHJcbiAgICBwcml2YXRlIHNldFN0ZXBQcm9ncmVzcyhzdGVwSWQ6IHN0cmluZywgdHJhbnNsYXRpb25LZXk6IHN0cmluZywgcGVyY2VudDogbnVtYmVyKSB7XHJcbiAgICAgICAgY29uc3QgbGFiZWwgPSB0aGlzLnRyYW5zbGF0ZS5pbnN0YW50KGBtYXR0ZXJwb3J0Q29weS4ke3RyYW5zbGF0aW9uS2V5fWApO1xyXG4gICAgICAgIHRoaXMuc2V0U3RlcExvZyhzdGVwSWQsIGAke2xhYmVsfTogJHtwZXJjZW50fSVgKTtcclxuICAgIH1cclxuXHJcbiAgICAvKiogTG9ncyBhIHRyYW5zbGF0ZWQsIHBhcmFtZXRlcml6ZWQgZXJyb3IgbGluZSBmb3IgYSBzaW5nbGUgZmFpbGVkIGl0ZW0uICovXHJcbiAgICBwcml2YXRlIGxvZ0l0ZW1FcnJvcih0cmFuc2xhdGlvbktleTogc3RyaW5nLCBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIGFueT4pIHtcclxuICAgICAgICBjb25zdCB0ZXh0ID0gdGhpcy50cmFuc2xhdGUuaW5zdGFudChgbWF0dGVycG9ydENvcHkuJHt0cmFuc2xhdGlvbktleX1gLCBwYXJhbXMpO1xyXG4gICAgICAgIHRoaXMuYXBwZW5kRXJyb3JMb2codGV4dCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIExvZ3MgYW4gaXRlbS1sZXZlbCBlcnJvciwgdXNpbmcgYSBzcGVjaWZpYyBcIm1pc3NpbmcgZmlsZSAvIG9ycGhhbmVkIHJlZmVyZW5jZVwiXHJcbiAgICAgKiAgdHJhbnNsYXRpb24ga2V5IHdoZW4gdGhlIGNhdXNlIGlzIGEgTWlzc2luZ1MzRmlsZUVycm9yLCBhbmQgdGhlIGdlbmVyaWMgcGVyLXR5cGVcclxuICAgICAqICBrZXkgb3RoZXJ3aXNlLiBLZWVwcyB0aGUgY29weSBsb2cgcmVhZGFibGU6IGEgbWlzc2luZyBmaWxlIGlzIG5vdCBhIGJ1ZyB0b1xyXG4gICAgICogIGludmVzdGlnYXRlIHRoZSBzYW1lIHdheSBhIG5ldHdvcmsvcGVybWlzc2lvbiBlcnJvciBpcy4gKi9cclxuICAgIHByaXZhdGUgbG9nQ29weUl0ZW1FcnJvcihlcnJvcjogdW5rbm93biwgZ2VuZXJpY0tleTogc3RyaW5nLCBpdGVtTGFiZWw6IHN0cmluZykge1xyXG4gICAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIE1pc3NpbmdTM0ZpbGVFcnJvcikge1xyXG4gICAgICAgICAgICB0aGlzLmxvZ0l0ZW1FcnJvcignZXJyb3JNaXNzaW5nUzNGaWxlU2tpcHBlZCcsIHtcclxuICAgICAgICAgICAgICAgIG5hbWU6IGl0ZW1MYWJlbCxcclxuICAgICAgICAgICAgICAgIGZpbGU6IGVycm9yLnNvdXJjZUtleVxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLmxvZ0l0ZW1FcnJvcihnZW5lcmljS2V5LCB7IG5hbWU6IGl0ZW1MYWJlbCwgZXJyb3I6IHRvRXJyb3JNZXNzYWdlKGVycm9yKSB9KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy9cclxuICAgIC8vIC0tLS0tLS0tLS0gRHVwbGljYXRlIGRldGVjdGlvbiAtLS0tLS0tLS0tXHJcbiAgICAvL1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogSGV1cmlzdGljIGR1cGxpY2F0ZS1kZXRlY3Rpb246IGNvbXBhcmVzIHRpdGxlIEFORCBkZXNjcmlwdGlvbiB0b2dldGhlciBpbnN0ZWFkIG9mXHJcbiAgICAgKiB0aXRsZSBhbG9uZSwgdG8gcmVkdWNlIGZhbHNlIHBvc2l0aXZlcyB3aGVuIHNldmVyYWwgc291cmNlIGl0ZW1zIGhhcHBlbiB0byBzaGFyZVxyXG4gICAgICogdGhlIHNhbWUgdGl0bGUuIE5vdCBhIHBlcmZlY3QgZ3VhcmFudGVlLCBidXQgbWVhbmluZ2Z1bGx5IG1vcmUgcm9idXN0LlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIG1hdGNoZXNFeGlzdGluZzxUIGV4dGVuZHMgeyB0aXRsZT86IHN0cmluZzsgZGVzY3JpcHRpb24/OiBzdHJpbmcgfT4oc291cmNlOiBULCB0YXJnZXRMaXN0OiBUW10pOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGFyZ2V0TGlzdC5zb21lKHQgPT5cclxuICAgICAgICAgICAgdC50aXRsZSA9PT0gc291cmNlLnRpdGxlICYmICh0LmRlc2NyaXB0aW9uIHx8IG51bGwpID09PSAoc291cmNlLmRlc2NyaXB0aW9uIHx8IG51bGwpXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvL1xyXG4gICAgLy8gLS0tLS0tLS0tLSBTd2VlcCBwb3NpdGlvbnMgLyByaWdpZCB0cmFuc2Zvcm0gLS0tLS0tLS0tLVxyXG4gICAgLy9cclxuXHJcbiAgICAvKipcclxuICAgICAqIEZldGNoZXMgdGhlIHBvc2l0aW9uIG9mIGV2ZXJ5IHN3ZWVwIGluIGEgc3BhY2UgYW5kIHJldHVybnMgaXQgYXMgYSBNYXAgZm9yIE8oMSkgbG9va3VwLlxyXG4gICAgICogVXNlcyBhbGxTZXR0bGVkIHNvIGEgc2luZ2xlIGZhaWxpbmcgc3dlZXAgbG9va3VwIGRvZXNuJ3QgYWJvcnQgdGhlIHdob2xlIG1hcCDigJRcclxuICAgICAqIHRoYXQgc3dlZXAgaXMgc2ltcGx5IGFic2VudCBmcm9tIHRoZSByZXN1bHRpbmcgbWFwIChhbmQgc2tpcHBlZCBsYXRlcikuXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgYXN5bmMgYnVpbGROYXZpZ2F0aW9uUG9zaXRpb25NYXAoc3BhY2VJZDogc3RyaW5nLCBzd2VlcElkczogc3RyaW5nW10pOiBQcm9taXNlPE1hcDxzdHJpbmcsIFZlYzM+PiB7XHJcbiAgICAgICAgY29uc3QgbWFwID0gbmV3IE1hcDxzdHJpbmcsIFZlYzM+KCk7XHJcblxyXG4gICAgICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoXHJcbiAgICAgICAgICAgIHN3ZWVwSWRzLm1hcChhc3luYyAoc2lkKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBuYXZzID0gYXdhaXQgdGhpcy5uYXZpZ2F0aW9uU2VydmljZS5nZXROYXZpZ2F0aW9uc0Zvck1hdHRlcnBvcnRJREZvclNwYWNlKHNpZCwgc3BhY2VJZCk7XHJcbiAgICAgICAgICAgICAgICBpZiAobmF2cyAmJiBuYXZzLmxlbmd0aCA+IDAgJiYgbmF2c1swXS5wb3NpdGlvbikge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7IHNpZCwgcG9zaXRpb246IEpTT04ucGFyc2UobmF2c1swXS5wb3NpdGlvbikgYXMgVmVjMyB9O1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgZm9yIChjb25zdCByZXN1bHQgb2YgcmVzdWx0cykge1xyXG4gICAgICAgICAgICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcgJiYgcmVzdWx0LnZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgICBtYXAuc2V0KHJlc3VsdC52YWx1ZS5zaWQsIHJlc3VsdC52YWx1ZS5wb3NpdGlvbik7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAocmVzdWx0LnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xyXG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdGYWlsZWQgdG8gZmV0Y2ggYSBzd2VlcCBwb3NpdGlvbiwgc2tpcHBpbmcgaXQ6JywgcmVzdWx0LnJlYXNvbik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBtYXA7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIEFwcGxpZXMgdGhlIHJpZ2lkIHRyYW5zZm9ybSB0byBhIFBPSSBjb29yZGluYXRlIChwb3NpdGlvbiArIG9yaWVudGF0aW9uKS4gKi9cclxuICAgIHByaXZhdGUgZ2V0QWRqdXN0ZWRDb29yZGluYXRlcyhjb29yZGluYXRlOiBzdHJpbmcsIHRyYW5zZm9ybTogUmlnaWRUcmFuc2Zvcm0pOiBhbnkge1xyXG4gICAgICAgIGlmIChjb29yZGluYXRlID09PSBcIm51bGxcIikge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKCFjb29yZGluYXRlIHx8IHR5cGVvZiBjb29yZGluYXRlICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAgICAgICByZXR1cm4gY29vcmRpbmF0ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UoY29vcmRpbmF0ZSk7XHJcbiAgICAgICAgY29uc3Qgcm90YXRlZFBvcyA9IGFwcGx5UmlnaWRUcmFuc2Zvcm1Ub1BvaW50KFxyXG4gICAgICAgICAgICB7IHg6IHBhcnNlZC54LCB5OiBwYXJzZWQueSwgejogcGFyc2VkLnogfSxcclxuICAgICAgICAgICAgdHJhbnNmb3JtXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgeDogcm90YXRlZFBvcy54LFxyXG4gICAgICAgICAgICB5OiByb3RhdGVkUG9zLnksXHJcbiAgICAgICAgICAgIHo6IHJvdGF0ZWRQb3MueixcclxuICAgICAgICAgICAgeFJvdGF0aW9uOiBwYXJzZWQueFJvdGF0aW9uLFxyXG4gICAgICAgICAgICB5Um90YXRpb246IGFwcGx5UmlnaWRUcmFuc2Zvcm1Ub1lSb3RhdGlvbkRlZyhwYXJzZWQueVJvdGF0aW9uLCB0cmFuc2Zvcm0pXHJcbiAgICAgICAgfTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEFwcGxpZXMgdGhlIHJpZ2lkIHRyYW5zZm9ybSdzIHRyYW5zbGF0aW9uK3JvdGF0aW9uIHRvIGEgcGxhaW4ge3gseSx6fSBwb3NpdGlvbixcclxuICAgICAqIFdJVEhPVVQgYWRkaW5nIHhSb3RhdGlvbi95Um90YXRpb24ga2V5cy4gVXNlZCBmb3IgbWVhc3VyZW1lbnRzLCB3aG9zZSBzdG9yZWRcclxuICAgICAqIGNvb3JkaW5hdGUgaXMgYSBiYXJlIHBvc2l0aW9uIChubyBvcmllbnRhdGlvbiksIHVubGlrZSBvdGhlciBQT0kgdHlwZXMuXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgZ2V0QWRqdXN0ZWRQb3NpdGlvbk9ubHkoY29vcmRpbmF0ZTogc3RyaW5nLCB0cmFuc2Zvcm06IFJpZ2lkVHJhbnNmb3JtKTogYW55IHtcclxuICAgICAgICBpZiAoIWNvb3JkaW5hdGUgfHwgdHlwZW9mIGNvb3JkaW5hdGUgIT09ICdzdHJpbmcnIHx8IGNvb3JkaW5hdGUgPT09ICdudWxsJykge1xyXG4gICAgICAgICAgICByZXR1cm4gY29vcmRpbmF0ZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZShjb29yZGluYXRlKTtcclxuICAgICAgICByZXR1cm4gYXBwbHlSaWdpZFRyYW5zZm9ybVRvUG9pbnQoeyB4OiBwYXJzZWQueCwgeTogcGFyc2VkLnksIHo6IHBhcnNlZC56IH0sIHRyYW5zZm9ybSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBGaW5kcyB0aGUgY2xvc2VzdCB0YXJnZXQgc3dlZXAsIGNvbXBhcmluZyBwb3NpdGlvbnMgaW4gdGhlIFNBTUUgY29vcmRpbmF0ZSBmcmFtZS5cclxuICAgICAqIFB1cmUgaW4tbWVtb3J5IGxvb2t1cCDigJQgbm8gbmV0d29yayBjYWxsLCB0aGFua3MgdG8gdGhlIHByZS1idWlsdCBwb3NpdGlvbiBtYXBzLlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGZpbmRDbG9zZXN0VGFyZ2V0U3dlZXBJZChcclxuICAgICAgICBzb3VyY2VTd2VlcElEOiBzdHJpbmcsXHJcbiAgICAgICAgc291cmNlTmF2UG9zaXRpb25zOiBNYXA8c3RyaW5nLCBWZWMzPixcclxuICAgICAgICB0YXJnZXROYXZQb3NpdGlvbnM6IE1hcDxzdHJpbmcsIFZlYzM+LFxyXG4gICAgICAgIHRyYW5zZm9ybTogUmlnaWRUcmFuc2Zvcm1cclxuICAgICk6IHN0cmluZyB8IG51bGwge1xyXG4gICAgICAgIGlmICghc291cmNlU3dlZXBJRCkgcmV0dXJuIG51bGw7XHJcblxyXG4gICAgICAgIGNvbnN0IHNvdXJjZVBvcyA9IHNvdXJjZU5hdlBvc2l0aW9ucy5nZXQoc291cmNlU3dlZXBJRCk7XHJcbiAgICAgICAgaWYgKCFzb3VyY2VQb3MpIHJldHVybiBudWxsO1xyXG5cclxuICAgICAgICBjb25zdCBzb3VyY2VQb3NJblRhcmdldEZyYW1lID0gYXBwbHlSaWdpZFRyYW5zZm9ybVRvUG9pbnQoc291cmNlUG9zLCB0cmFuc2Zvcm0pO1xyXG5cclxuICAgICAgICBsZXQgY2xvc2VzdFN3ZWVwSUQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xyXG4gICAgICAgIGxldCBtaW5EaXN0YW5jZSA9IEluZmluaXR5O1xyXG5cclxuICAgICAgICBmb3IgKGNvbnN0IFt0YXJnZXRTd2VlcElkLCB0YXJnZXRQb3NdIG9mIHRhcmdldE5hdlBvc2l0aW9ucy5lbnRyaWVzKCkpIHtcclxuICAgICAgICAgICAgY29uc3QgZHggPSB0YXJnZXRQb3MueCAtIHNvdXJjZVBvc0luVGFyZ2V0RnJhbWUueDtcclxuICAgICAgICAgICAgY29uc3QgZHkgPSB0YXJnZXRQb3MueSAtIHNvdXJjZVBvc0luVGFyZ2V0RnJhbWUueTtcclxuICAgICAgICAgICAgY29uc3QgZHogPSB0YXJnZXRQb3MueiAtIHNvdXJjZVBvc0luVGFyZ2V0RnJhbWUuejtcclxuICAgICAgICAgICAgY29uc3QgZGlzdCA9IE1hdGguc3FydChkeCAqIGR4ICsgZHkgKiBkeSArIGR6ICogZHopO1xyXG5cclxuICAgICAgICAgICAgaWYgKGRpc3QgPCBtaW5EaXN0YW5jZSkge1xyXG4gICAgICAgICAgICAgICAgbWluRGlzdGFuY2UgPSBkaXN0O1xyXG4gICAgICAgICAgICAgICAgY2xvc2VzdFN3ZWVwSUQgPSB0YXJnZXRTd2VlcElkO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gY2xvc2VzdFN3ZWVwSUQ7XHJcbiAgICB9XHJcblxyXG4gICAgLy9cclxuICAgIC8vIC0tLS0tLS0tLS0gUzMgZmlsZSBkdXBsaWNhdGlvbiAtLS0tLS0tLS0tXHJcbiAgICAvL1xyXG5cclxuICAgIC8qKiBHZW5lcmF0ZXMgYSBzaG9ydCByYW5kb20gaWQsIHVzZWQgdG8gZ2l2ZSBlYWNoIGNvcGllZCBTMyBmaWxlIGEgZnJlc2gsIGNvbGxpc2lvbi1zYWZlIGtleS4gKi9cclxuICAgIHByaXZhdGUgZ2VuZXJhdGVTaG9ydElkKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIsIDEwKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEJ1aWxkcyBhIG5ldyBTMyBrZXkgZm9yIGEgY29waWVkIGF0dGFjaG1lbnQgYW5kIHNhbml0aXplcyB0aGUgZmlsZW5hbWVcclxuICAgICAqIHRvIHByZXZlbnQgQVdTIEFtcGxpZnkgU2lnbmF0dXJlRG9lc05vdE1hdGNoIGVycm9ycy5cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBidWlsZENvcGllZEF0dGFjaG1lbnRLZXkoc291cmNlQW5uZXhlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgICAgIGNvbnN0IGxhc3RTbGFzaCA9IHNvdXJjZUFubmV4ZS5sYXN0SW5kZXhPZignLycpO1xyXG4gICAgICAgIGNvbnN0IGZvbGRlciA9IHNvdXJjZUFubmV4ZS5zdWJzdHJpbmcoMCwgbGFzdFNsYXNoICsgMSk7XHJcbiAgICAgICAgbGV0IGZpbGVuYW1lID0gc291cmNlQW5uZXhlLnN1YnN0cmluZyhsYXN0U2xhc2ggKyAxKTtcclxuXHJcbiAgICAgICAgLy8gU3RyaXAgYSBsZWFkaW5nIFwiPDggaGV4IGNoYXJzPl9cIiBpZCBwcmVmaXggaWYgcHJlc2VudFxyXG4gICAgICAgIGNvbnN0IHByZWZpeE1hdGNoID0gZmlsZW5hbWUubWF0Y2goL15bMC05YS1mQS1GLV17OH1fKC4rKSQvKTtcclxuICAgICAgICBpZiAocHJlZml4TWF0Y2gpIHtcclxuICAgICAgICAgICAgZmlsZW5hbWUgPSBwcmVmaXhNYXRjaFsxXTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNBTklUSVpBVElPTjogUmVwbGFjZSBzcGFjZXMsIHBhcmVudGhlc2VzLCBhbmQgYWNjZW50cyB3aXRoIHVuZGVyc2NvcmVzXHJcbiAgICAgICAgLy8gQ3J1Y2lhbCB0byBwcmV2ZW50IEFtcGxpZnkncyBTdG9yYWdlLmNvcHkgZnJvbSBmYWlsaW5nIHRoZSBzaWduYXR1cmUgY2FsY3VsYXRpb25cclxuICAgICAgICBmaWxlbmFtZSA9IGZpbGVuYW1lLnJlcGxhY2UoL1teYS16QS1aMC05LlxcLV9dL2csICdfJyk7XHJcblxyXG4gICAgICAgIGNvbnN0IG5ld1ByZWZpeCA9IGAke3RoaXMuZ2VuZXJhdGVTaG9ydElkKCl9X2A7XHJcbiAgICAgICAgcmV0dXJuIGAke2ZvbGRlcn0ke25ld1ByZWZpeH0ke2ZpbGVuYW1lfWA7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEdXBsaWNhdGVzIGFuIFMzIG9iamVjdCBpZiBhIGtleSBpcyBwcmVzZW50LlxyXG4gICAgICogLSBJZiB0aGUgc291cmNlIGZpbGUgaXMgZ2VudWluZWx5IG1pc3NpbmcgZnJvbSBTMyAoTm9TdWNoS2V5IC8gb3JwaGFuZWQgREIgcmVmZXJlbmNlKSxcclxuICAgICAqICAgdGhyb3dzIGEgTWlzc2luZ1MzRmlsZUVycm9yIHNvIHRoZSBjYWxsZXIgY2FuIGxvZyBhIGNsZWFyLCBzcGVjaWZpYyBtZXNzYWdlIGFuZFxyXG4gICAgICogICBza2lwIHRoZSB3aG9sZSBpdGVtIGVudGlyZWx5LCByYXRoZXIgdGhhbiBjcmVhdGluZyBhIHJlY29yZCB3aXRoIGEgYnJva2VuIGZpbGUgbGluay5cclxuICAgICAqIC0gQW55IG90aGVyIGtpbmQgb2YgZmFpbHVyZSAocGVybWlzc2lvbnMsIG5ldHdvcmssIGV0Yy4pIHN0aWxsIHRocm93cyBhIGdlbmVyaWMgRXJyb3IuXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgYXN5bmMgY29weVMzS2V5SWZQcmVzZW50KGtleTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCwgY29udGV4dExhYmVsOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcclxuICAgICAgICBpZiAoIWtleSkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3Qgc291cmNlS2V5ID0gdGhpcy5leHRyYWN0UzNLZXlGcm9tVmFsdWUoa2V5KTtcclxuICAgICAgICBjb25zdCBkZXN0S2V5ID0gdGhpcy5idWlsZENvcGllZEF0dGFjaG1lbnRLZXkoc291cmNlS2V5KTtcclxuXHJcbiAgICAgICAgLy8gTG9nIHRoZSBzb3VyY2Uga2V5IHRvIGVuc3VyZSBpdCBtYXRjaGVzIHRoZSByZWFsIFMzIG9iamVjdCBwYXRoXHJcbiAgICAgICAgY29uc29sZS5sb2coYFtERUJVR10gQXR0ZW1wdGluZyBTMyBjb3B5IGZyb20gc291cmNlOiBcIiR7c291cmNlS2V5fVwiIHRvIGRlc3Q6IFwiJHtkZXN0S2V5fVwiYCk7XHJcblxyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGNvcGllZCA9IGF3YWl0IGNvcHlGaWxlSW5TMyhzb3VyY2VLZXksIGRlc3RLZXkpO1xyXG4gICAgICAgICAgICBpZiAoIWNvcGllZCkge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IE1pc3NpbmdTM0ZpbGVFcnJvcihzb3VyY2VLZXksIGNvbnRleHRMYWJlbCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcmV0dXJuIGNvcGllZDtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGlzTWlzc2luZ0ZpbGUgPSBlcnJvciBpbnN0YW5jZW9mIE1pc3NpbmdTM0ZpbGVFcnJvclxyXG4gICAgICAgICAgICAgICAgfHwgZXJyb3I/LmNvZGUgPT09ICdOb1N1Y2hLZXknXHJcbiAgICAgICAgICAgICAgICB8fCAvTm9TdWNoS2V5fGRvZXMgbm90IGV4aXN0L2kudGVzdCh0b0Vycm9yTWVzc2FnZShlcnJvcikpO1xyXG4gICAgICAgICAgICBpZiAoaXNNaXNzaW5nRmlsZSkge1xyXG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKGBbTWF0dGVycG9ydFRhZ0NvcHlTZXJ2aWNlXSBPcnBoYW5lZCBTMyByZWZlcmVuY2UsIHNraXBwaW5nIGl0ZW06IFwiJHtzb3VyY2VLZXl9XCIgKCR7Y29udGV4dExhYmVsfSlgKTtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBNaXNzaW5nUzNGaWxlRXJyb3Ioc291cmNlS2V5LCBjb250ZXh0TGFiZWwpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIER1cGxpY2F0ZXMgdGhlIGZpbGUgcmVmZXJlbmNlZCBieSBhIFBPSSdzIHRhZ0ljb24gKGEgSlNPTiBzdHJpbmcgc2hhcGVkIGxpa2VcclxuICAgICAqIHsgc3JjLCBvcGFjaXR5IH0sIHBlciBmb3JtLWZlYXR1cmUuY29tcG9uZW50LnRzKS4gSWYgdGhlIEpTT04gY2FuJ3QgYmUgcGFyc2VkIG9yXHJcbiAgICAgKiBoYXMgbm8gYHNyY2AsIHRoZSB2YWx1ZSBpcyByZXR1cm5lZCB1bmNoYW5nZWQgcmF0aGVyIHRoYW4gcmlzayBjb3JydXB0aW5nIGl0LlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGFzeW5jIGR1cGxpY2F0ZVRhZ0ljb24odGFnSWNvblJhdzogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCk6IFByb21pc2U8c3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZD4ge1xyXG4gICAgICAgIGlmICghdGFnSWNvblJhdykge1xyXG4gICAgICAgICAgICByZXR1cm4gdGFnSWNvblJhdztcclxuICAgICAgICB9XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZSh0YWdJY29uUmF3KTtcclxuICAgICAgICAgICAgaWYgKHBhcnNlZCAmJiBwYXJzZWQuc3JjKSB7XHJcbiAgICAgICAgICAgICAgICBwYXJzZWQuc3JjID0gYXdhaXQgdGhpcy5jb3B5UzNLZXlJZlByZXNlbnQocGFyc2VkLnNyYywgJ3RhZyBpY29uJyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZCk7XHJcbiAgICAgICAgfSBjYXRjaCB7XHJcbiAgICAgICAgICAgIC8vIE5vdCBKU09OLCBvciB1bmV4cGVjdGVkIHNoYXBlIOKAlCBsZWF2ZSB1bnRvdWNoZWQgcmF0aGVyIHRoYW4gZ3Vlc3MuXHJcbiAgICAgICAgICAgIHJldHVybiB0YWdJY29uUmF3O1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIER1cGxpY2F0ZXMgdGFnSW1hZ2VJRCBpZiBpdCBsb29rcyBsaWtlIGEgcmVmZXJlbmNlIHRvIGEgZmlsZSAoY29udGFpbnMgYSBwYXRoXHJcbiAgICAgKiBzZXBhcmF0b3IsIHdoZXRoZXIgcmF3IGtleSBvciBwcmUtc2lnbmVkIFVSTCkuIFVOQ09ORklSTUVEIEFTU1VNUFRJT046IHRoaXNcclxuICAgICAqIGZpZWxkJ3MgZXhhY3Qgc2VtYW50aWNzIHdlcmVuJ3QgdmVyaWZpZWQg4oCUIGlmIGl0J3MgYWN0dWFsbHkgYW4gb3BhcXVlIHJlZmVyZW5jZVxyXG4gICAgICogdG8gYW5vdGhlciBEQiByZWNvcmQgcmF0aGVyIHRoYW4gYSBmaWxlLCB0aGlzIGhldXJpc3RpYyBtYXkgaW5jb3JyZWN0bHkgYXR0ZW1wdFxyXG4gICAgICogYSBjb3B5LiBDb25maXJtIHRoZSByZWFsIHN0cnVjdHVyZSB0byB0aWdodGVuIHRoaXMgaWYgaXQgY2F1c2VzIGlzc3Vlcy5cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBhc3luYyBkdXBsaWNhdGVUYWdJbWFnZUlEKHRhZ0ltYWdlSUQ6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBQcm9taXNlPHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQ+IHtcclxuICAgICAgICBpZiAoIXRhZ0ltYWdlSUQgfHwgIXRhZ0ltYWdlSUQuaW5jbHVkZXMoJy8nKSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGFnSW1hZ2VJRDtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29weVMzS2V5SWZQcmVzZW50KHRhZ0ltYWdlSUQsICd0YWcgaW1hZ2UnKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEV4dHJhY3RzIGFuZCBub3JtYWxpemVzIHRoZSByYXcgUzMga2V5IGZyb20gYSBzdG9yZWQgdmFsdWUgKHdoaWNoIG1heSBiZSBhIGZ1bGwgVVJMXHJcbiAgICAgKiBvciBhbHJlYWR5IGEgcmF3IGtleSkuXHJcbiAgICAgKiBJTVBPUlRBTlQ6IHRoaXMgbXVzdCByZXR1cm4gdGhlIFJBVyAoZGVjb2RlZCwgbm9uIFVSTC1lbmNvZGVkKSBrZXkuIEFtcGxpZnknc1xyXG4gICAgICogU3RvcmFnZS5jb3B5KCkgYWxyZWFkeSBidWlsZHMgYW5kIGVuY29kZXMgdGhlICd4LWFtei1jb3B5LXNvdXJjZScgaGVhZGVyIGludGVybmFsbHlcclxuICAgICAqIGZyb20gdGhlIGtleSB3ZSBnaXZlIGl0LiBQcmUtZW5jb2RpbmcgaXQgaGVyZSBjYXVzZWQgYSBkb3VibGUtZW5jb2RpbmcgYnVnIChlLmcuIGFcclxuICAgICAqIHNwYWNlIGJlY2FtZSBcIiUyNTIwXCIgaW5zdGVhZCBvZiBcIiUyMFwiKSwgc28gU3RvcmFnZS5jb3B5KCkgbG9va2VkIGZvciBhIGtleSB0aGF0IG5ldmVyXHJcbiAgICAgKiBleGlzdGVkIG9uIFMzLCByZXN1bHRpbmcgaW4gYSBOb1N1Y2hLZXkgZXJyb3IuXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgZXh0cmFjdFMzS2V5RnJvbVZhbHVlKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgICAgIGlmICghdmFsdWUpIHtcclxuICAgICAgICAgICAgcmV0dXJuICcnO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgbGV0IGV4dHJhY3RlZCA9IHZhbHVlO1xyXG5cclxuICAgICAgICAvLyAxLiBFeHRyYWN0IHBhdGggZnJvbSBVUkwgYW5kIGRyb3AgcXVlcnkgcGFyYW1zXHJcbiAgICAgICAgaWYgKHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdodHRwczovLycpKSB7XHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKHZhbHVlKTtcclxuICAgICAgICAgICAgICAgIGV4dHJhY3RlZCA9IGRlY29kZVVSSUNvbXBvbmVudCh1cmwucGF0aG5hbWUpO1xyXG4gICAgICAgICAgICB9IGNhdGNoIHtcclxuICAgICAgICAgICAgICAgIGV4dHJhY3RlZCA9IHZhbHVlLnNwbGl0KCc/JylbMF07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBleHRyYWN0ZWQgPSB2YWx1ZS5zcGxpdCgnPycpWzBdO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gMi4gUmVtb3ZlIGxlYWRpbmcgc2xhc2hcclxuICAgICAgICBpZiAoZXh0cmFjdGVkLnN0YXJ0c1dpdGgoJy8nKSkge1xyXG4gICAgICAgICAgICBleHRyYWN0ZWQgPSBleHRyYWN0ZWQuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gMy4gUmVtb3ZlICdwdWJsaWMvJyBwcmVmaXhcclxuICAgICAgICAvLyBBbXBsaWZ5IHByZXBlbmRzIHRoaXMgYXV0b21hdGljYWxseTsgd2UgbXVzdCBzdHJpcCBpdCBmcm9tIHRoZSBpbnB1dFxyXG4gICAgICAgIC8vIHRvIGF2b2lkIHRoZSAncHVibGljL3B1YmxpYy8nIGRvdWJsZS1wcmVmaXggaXNzdWUuXHJcbiAgICAgICAgaWYgKGV4dHJhY3RlZC5zdGFydHNXaXRoKCdwdWJsaWMvJykpIHtcclxuICAgICAgICAgICAgZXh0cmFjdGVkID0gZXh0cmFjdGVkLnN1YnN0cmluZygncHVibGljLycubGVuZ3RoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFJldHVybiB0aGUgcmF3IGtleSBhcy1pcyDigJQgU3RvcmFnZS5jb3B5KCkgdGFrZXMgY2FyZSBvZiBwcm9wZXJseSBlbmNvZGluZyBpdFxyXG4gICAgICAgIC8vIGZvciB0aGUgQ29weVNvdXJjZSBoZWFkZXIuIERvIE5PVCByZS1lbmNvZGUgaXQgaGVyZS5cclxuICAgICAgICByZXR1cm4gZXh0cmFjdGVkO1xyXG4gICAgfVxyXG59Il19
|