@smarterplan/ngx-smarterplan-core 1.4.14 → 1.4.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +24 -24
  2. package/esm2022/lib/components/csv-export/csv-export.component.mjs +3 -3
  3. package/esm2022/lib/components/loader/loader.component.mjs +3 -3
  4. package/esm2022/lib/components/menu-bar/avatar/avatar.component.mjs +1 -1
  5. package/esm2022/lib/components/menu-bar/menu-bar.component.mjs +3 -3
  6. package/esm2022/lib/components/menu-bar/navigation-bar/navigation-bar.component.mjs +3 -3
  7. package/esm2022/lib/components/modal-switch-visit/modal-switch-visit.component.mjs +3 -3
  8. package/esm2022/lib/components/search-bar/search-bar.component.mjs +3 -3
  9. package/esm2022/lib/components/support-modal/support-modal.component.mjs +3 -3
  10. package/esm2022/lib/config.mjs +1 -1
  11. package/esm2022/lib/helpers.service.mjs +46 -1
  12. package/esm2022/lib/matterport-extensions/nest-thermostat/CanvasImage.mjs +1 -1
  13. package/esm2022/lib/matterport-extensions/nest-thermostat/CanvasRenderer.mjs +1 -1
  14. package/esm2022/lib/matterport-extensions/nest-thermostat/NestThermostat.mjs +1 -1
  15. package/esm2022/lib/matterport-extensions/nest-thermostat/PlaneRenderer.mjs +1 -1
  16. package/esm2022/lib/matterport-extensions/scene-component/SceneComponent.mjs +1 -1
  17. package/esm2022/lib/matterport-extensions/security-camera/SecurityCamera.mjs +22 -22
  18. package/esm2022/lib/matterport-extensions/tv-player/TvPlayer.mjs +1 -1
  19. package/esm2022/lib/matterport-extensions/view-frustum-mesh/ViewFrustumMesh.mjs +22 -22
  20. package/esm2022/lib/mattertagData.mjs +1 -1
  21. package/esm2022/lib/ngx-smarterplan-core.module.mjs +1 -1
  22. package/esm2022/lib/ngx-smarterplan-core.service.mjs +1 -1
  23. package/esm2022/lib/pipes/duration-to-string.pipe.mjs +1 -1
  24. package/esm2022/lib/pipes/format-date-number-to-digits.pipe.mjs +1 -1
  25. package/esm2022/lib/pipes/safe-url.pipe.mjs +1 -1
  26. package/esm2022/lib/pipes/time-date-to-local-string.pipe.mjs +1 -1
  27. package/esm2022/lib/pipes/username-from-id.pipe.mjs +1 -1
  28. package/esm2022/lib/services/amplify-cache.service.mjs +1 -1
  29. package/esm2022/lib/services/base-tab.service.mjs +1 -1
  30. package/esm2022/lib/services/baseVisibility.service.mjs +1 -1
  31. package/esm2022/lib/services/content.service.mjs +1 -1
  32. package/esm2022/lib/services/filter.service.mjs +1 -1
  33. package/esm2022/lib/services/intervention.service.mjs +1 -1
  34. package/esm2022/lib/services/locale.service.mjs +1 -1
  35. package/esm2022/lib/services/matterport-import.service.mjs +1 -1
  36. package/esm2022/lib/services/matterport-measurement.service.mjs +1 -1
  37. package/esm2022/lib/services/matterport-navigation.service.mjs +1 -1
  38. package/esm2022/lib/services/matterport-object3d.service.mjs +1 -1
  39. package/esm2022/lib/services/matterport-pointer.service.mjs +6 -6
  40. package/esm2022/lib/services/matterport-tag-copy.service.mjs +448 -62
  41. package/esm2022/lib/services/matterport-tag.service.mjs +1 -1
  42. package/esm2022/lib/services/matterport.service.mjs +17 -17
  43. package/esm2022/lib/services/models/affectation.service.mjs +1 -1
  44. package/esm2022/lib/services/models/base-object.service.mjs +1 -1
  45. package/esm2022/lib/services/models/capture.service.mjs +1 -1
  46. package/esm2022/lib/services/models/comment.service.mjs +1 -1
  47. package/esm2022/lib/services/models/domain.service.mjs +20 -1
  48. package/esm2022/lib/services/models/equipment.service.mjs +4 -2
  49. package/esm2022/lib/services/models/event.service.mjs +1 -1
  50. package/esm2022/lib/services/models/feature.service.mjs +1 -7
  51. package/esm2022/lib/services/models/hashtag.service.mjs +1 -1
  52. package/esm2022/lib/services/models/layer.service.mjs +1 -1
  53. package/esm2022/lib/services/models/measurement.service.mjs +1 -1
  54. package/esm2022/lib/services/models/mission.service.mjs +17 -1
  55. package/esm2022/lib/services/models/navigation.service.mjs +1 -1
  56. package/esm2022/lib/services/models/node.service.mjs +1 -1
  57. package/esm2022/lib/services/models/object3D.service.mjs +1 -1
  58. package/esm2022/lib/services/models/operation.service.mjs +1 -1
  59. package/esm2022/lib/services/models/organisation.service.mjs +1 -1
  60. package/esm2022/lib/services/models/plan.service.mjs +1 -1
  61. package/esm2022/lib/services/models/poi.service.mjs +27 -27
  62. package/esm2022/lib/services/models/profile.service.mjs +1 -1
  63. package/esm2022/lib/services/models/property.service.mjs +1 -1
  64. package/esm2022/lib/services/models/space.service.mjs +25 -6
  65. package/esm2022/lib/services/models/template.service.mjs +1 -1
  66. package/esm2022/lib/services/models/ticket.service.mjs +1 -1
  67. package/esm2022/lib/services/models/visit.service.mjs +17 -5
  68. package/esm2022/lib/services/models/zone.service.mjs +1 -1
  69. package/esm2022/lib/services/navigator.service.mjs +1 -1
  70. package/esm2022/lib/services/s3.service.mjs +18 -1
  71. package/esm2022/lib/services/search.service.mjs +1 -1
  72. package/esm2022/lib/services/support.service.mjs +1 -1
  73. package/esm2022/lib/services/tag.service.mjs +16 -16
  74. package/esm2022/lib/services/threejs-import.service.mjs +151 -0
  75. package/esm2022/lib/services/threejs.service.mjs +1306 -0
  76. package/esm2022/lib/services/user.service.mjs +1 -1
  77. package/esm2022/lib/services/utils/matterport-transform.util.mjs +1 -1
  78. package/esm2022/lib/services/validators.service.mjs +1 -1
  79. package/esm2022/lib/services/viewer.service.mjs +263 -5
  80. package/esm2022/lib/services/zone-drawer.service.mjs +1 -1
  81. package/esm2022/lib/services/zoneChange.service.mjs +1 -1
  82. package/esm2022/lib/tokens/matterport-sdk-key.token.mjs +1 -1
  83. package/esm2022/lib/types.service.mjs +2 -1
  84. package/esm2022/lib/validators/email.directive.mjs +1 -1
  85. package/esm2022/lib/validators/no-empty.directive.mjs +1 -1
  86. package/esm2022/lib/validators/number.directive.mjs +1 -1
  87. package/esm2022/lib/validators/text.directive.mjs +1 -1
  88. package/esm2022/public-api.mjs +3 -1
  89. package/fesm2022/smarterplan-ngx-smarterplan-core.mjs +2759 -551
  90. package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
  91. package/lib/helpers.service.d.ts +43 -0
  92. package/lib/services/matterport-tag-copy.service.d.ts +137 -17
  93. package/lib/services/models/domain.service.d.ts +8 -0
  94. package/lib/services/models/feature.service.d.ts +0 -6
  95. package/lib/services/models/mission.service.d.ts +5 -0
  96. package/lib/services/models/space.service.d.ts +15 -1
  97. package/lib/services/models/visit.service.d.ts +9 -1
  98. package/lib/services/s3.service.d.ts +8 -0
  99. package/lib/services/threejs-import.service.d.ts +31 -0
  100. package/lib/services/threejs.service.d.ts +423 -0
  101. package/lib/services/viewer.service.d.ts +114 -1
  102. package/lib/types.service.d.ts +7 -1
  103. package/package.json +1 -1
  104. package/public-api.d.ts +2 -0
  105. package/src/assets/vs-app.json +67 -67
@@ -0,0 +1,151 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { removeNullKeysFromObject, parseThreeJsPlacement } from '../helpers.service';
3
+ import { LevelStatus, } from '../types.service';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "./models/navigation.service";
7
+ import * as i2 from "./models/zone.service";
8
+ import * as i3 from "./models/layer.service";
9
+ import * as i4 from "./user.service";
10
+ import * as i5 from "./models/plan.service";
11
+ /** File extensions the Three.js viewer can load as a base model. */
12
+ const SUPPORTED_MODEL_EXTENSIONS = ['.glb', '.gltf'];
13
+ export class ThreeJsImportService {
14
+ navigationService;
15
+ zoneService;
16
+ layerService;
17
+ userService;
18
+ planService;
19
+ _spaceID;
20
+ get spaceID() {
21
+ return this._spaceID;
22
+ }
23
+ set spaceID(value) {
24
+ this._spaceID = value;
25
+ }
26
+ constructor(navigationService, zoneService, layerService, userService, planService) {
27
+ this.navigationService = navigationService;
28
+ this.zoneService = zoneService;
29
+ this.layerService = layerService;
30
+ this.userService = userService;
31
+ this.planService = planService;
32
+ }
33
+ /**
34
+ * Checks that an S3 key points at something the viewer can actually load.
35
+ *
36
+ * Returns the reason it can't, or null when it's fine. This runs before anything is written, so a
37
+ * mistyped key fails on the form rather than creating zones and navigation for a model that will
38
+ * 404 the first time someone opens the visit.
39
+ */
40
+ validateModelKey(key) {
41
+ if (!key || !key.trim()) {
42
+ return 'A 3D model file (.glb) is required for a Three.js visit.';
43
+ }
44
+ const trimmed = key.trim();
45
+ if (!SUPPORTED_MODEL_EXTENSIONS.some((extension) => trimmed.toLowerCase().endsWith(extension))) {
46
+ return `The 3D model must be a ${SUPPORTED_MODEL_EXTENSIONS.join(' or ')} file.`;
47
+ }
48
+ // A full https:// URL is a signed link that expires; the stored value has to be the key itself
49
+ // so a fresh URL can be signed on every visit.
50
+ if (/^https?:\/\//i.test(trimmed)) {
51
+ return 'Enter the S3 key of the file (e.g. visits/my-model.glb), not a full URL.';
52
+ }
53
+ return null;
54
+ }
55
+ async importData(spaceID, surface, reloading = false, node = null, overrideExisting = true, placementMetadata = null) {
56
+ if (reloading) {
57
+ // Reloading is not fully applicable to static 3D models the same way as Matterport
58
+ return Promise.resolve(true);
59
+ }
60
+ const keyError = this.validateModelKey(node?.model3D);
61
+ if (keyError) {
62
+ return Promise.reject(new Error(keyError));
63
+ }
64
+ this.spaceID = spaceID;
65
+ const zones = await this.zoneService.getZonesBySpace(spaceID);
66
+ const mainZone = zones.find((z) => !z.parentID);
67
+ if (!mainZone) {
68
+ return Promise.reject(new Error('Missing data (no main Building Zone)'));
69
+ }
70
+ console.log('[ThreeJsImportService] Importing data for Three.js model');
71
+ // 1. Check/create layer of building type
72
+ const layerBuilding = await this.getLayerByName('BUILDING');
73
+ // We generate a dummy ID to act as our single "sweep" equivalent
74
+ const dummySweepID = uuidv4();
75
+ // 2. Create the default Zone
76
+ const createdDefaultZone = await this.createZone(node.metadata || 'Three.js 3D Model', layerBuilding.id, surface, mainZone.id, [dummySweepID], node);
77
+ if (!createdDefaultZone) {
78
+ return Promise.resolve(false);
79
+ }
80
+ // 3. Create a blank Plan for the model (to ensure consistency in the app structure)
81
+ const plan = {
82
+ name: `plan_threejs_${node.id}`,
83
+ annexe: '', // No floorplan image generated automatically yet
84
+ zoneID: createdDefaultZone.id,
85
+ spaceID: this.spaceID,
86
+ isCurrentForZone: true,
87
+ isModified: false,
88
+ isImportedMatterport: false, // Explicitly not matterport
89
+ };
90
+ await this.planService.createPlan(plan);
91
+ // 4. Create the single Navigation entry this model is viewed from.
92
+ // Matterport derives these from its sweeps; a static model has no sweeps, so the placement
93
+ // comes from the metadata entered on the form, falling back to the origin.
94
+ const placement = parseThreeJsPlacement(placementMetadata);
95
+ const origin = { x: 0, y: 0, z: 0 };
96
+ const navigationInput = {
97
+ matterportSweepID: dummySweepID,
98
+ position: JSON.stringify(placement?.cameraPosition ?? origin),
99
+ rotation: JSON.stringify(placement?.rotation ?? origin),
100
+ level: LevelStatus.LOW,
101
+ nodeID: node.id,
102
+ spaceID,
103
+ };
104
+ const nav = await this.navigationService.createNavigation(navigationInput);
105
+ if (!nav) {
106
+ console.log('Could not create navigation for', navigationInput);
107
+ }
108
+ console.log('[ThreeJsImportService] Import done.');
109
+ return Promise.resolve(true);
110
+ }
111
+ async createZone(name, layerID, surface = null, parentID = null, sweeps = [], node = null, metadata = null) {
112
+ const zoneInput = {
113
+ name,
114
+ spaceID: this.spaceID,
115
+ layerID,
116
+ sweepIDs: sweeps,
117
+ nodeIDs: node ? [node.id] : null,
118
+ };
119
+ removeNullKeysFromObject(zoneInput);
120
+ if (surface) {
121
+ zoneInput.surface = surface;
122
+ }
123
+ if (parentID) {
124
+ zoneInput.parentID = parentID;
125
+ }
126
+ if (metadata) {
127
+ zoneInput.metadata = metadata;
128
+ }
129
+ const newLocal = await this.zoneService.create(zoneInput);
130
+ return newLocal;
131
+ }
132
+ async getLayerByName(name) {
133
+ const mission = this.userService.currentMission(this.spaceID);
134
+ const currentOrgId = mission.organisationID;
135
+ const layers = await this.layerService.getLayerByNameForOrganisation(name, currentOrgId);
136
+ if (layers.length > 0) {
137
+ return layers[0];
138
+ }
139
+ // Create it if it doesn't exist
140
+ return this.layerService.createLayerForOrganisation(name, currentOrgId);
141
+ }
142
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ThreeJsImportService, deps: [{ token: i1.NavigationService }, { token: i2.ZoneService }, { token: i3.LayerService }, { token: i4.BaseUserService }, { token: i5.PlanService }], target: i0.ɵɵFactoryTarget.Injectable });
143
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ThreeJsImportService, providedIn: 'root' });
144
+ }
145
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ThreeJsImportService, decorators: [{
146
+ type: Injectable,
147
+ args: [{
148
+ providedIn: 'root',
149
+ }]
150
+ }], ctorParameters: () => [{ type: i1.NavigationService }, { type: i2.ZoneService }, { type: i3.LayerService }, { type: i4.BaseUserService }, { type: i5.PlanService }] });
151
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyZWVqcy1pbXBvcnQuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1zbWFydGVycGxhbi1jb3JlL3NyYy9saWIvc2VydmljZXMvdGhyZWVqcy1pbXBvcnQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3JGLE9BQU8sRUFDTCxXQUFXLEdBTVosTUFBTSxrQkFBa0IsQ0FBQztBQU0xQixPQUFPLEVBQUUsRUFBRSxJQUFJLE1BQU0sRUFBRSxNQUFNLE1BQU0sQ0FBQzs7Ozs7OztBQUVwQyxvRUFBb0U7QUFDcEUsTUFBTSwwQkFBMEIsR0FBRyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztBQUtyRCxNQUFNLE9BQU8sb0JBQW9CO0lBWXJCO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFmRixRQUFRLENBQVM7SUFFekIsSUFBVyxPQUFPO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN2QixDQUFDO0lBRUQsSUFBVyxPQUFPLENBQUMsS0FBYTtRQUM5QixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDO0lBRUQsWUFDVSxpQkFBb0MsRUFDcEMsV0FBd0IsRUFDeEIsWUFBMEIsRUFDMUIsV0FBNEIsRUFDNUIsV0FBd0I7UUFKeEIsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQUNwQyxnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQUN4QixpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUMxQixnQkFBVyxHQUFYLFdBQVcsQ0FBaUI7UUFDNUIsZ0JBQVcsR0FBWCxXQUFXLENBQWE7SUFDL0IsQ0FBQztJQUVKOzs7Ozs7T0FNRztJQUNILGdCQUFnQixDQUFDLEdBQVc7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QUNELGdDQUFnQztRQUNoQyxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsMEJBQTBCLENBQUMsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQzFFLENBQUM7d0dBeEtVLG9CQUFvQjs0R0FBcEIsb0JBQW9CLGNBRm5CLE1BQU07OzRGQUVQLG9CQUFvQjtrQkFIaEMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyByZW1vdmVOdWxsS2V5c0Zyb21PYmplY3QsIHBhcnNlVGhyZWVKc1BsYWNlbWVudCB9IGZyb20gJy4uL2hlbHBlcnMuc2VydmljZSc7XG5pbXBvcnQge1xuICBMZXZlbFN0YXR1cyxcbiAgTGF5ZXIsXG4gIE5vZGUsXG4gIFpvbmUsXG4gIE5hdmlnYXRpb24sXG4gIFBsYW4sXG59IGZyb20gJy4uL3R5cGVzLnNlcnZpY2UnO1xuaW1wb3J0IHsgTGF5ZXJTZXJ2aWNlIH0gZnJvbSAnLi9tb2RlbHMvbGF5ZXIuc2VydmljZSc7XG5pbXBvcnQgeyBOYXZpZ2F0aW9uU2VydmljZSB9IGZyb20gJy4vbW9kZWxzL25hdmlnYXRpb24uc2VydmljZSc7XG5pbXBvcnQgeyBQbGFuU2VydmljZSB9IGZyb20gJy4vbW9kZWxzL3BsYW4uc2VydmljZSc7XG5pbXBvcnQgeyBab25lU2VydmljZSB9IGZyb20gJy4vbW9kZWxzL3pvbmUuc2VydmljZSc7XG5pbXBvcnQgeyBCYXNlVXNlclNlcnZpY2UgfSBmcm9tICcuL3VzZXIuc2VydmljZSc7XG5pbXBvcnQgeyB2NCBhcyB1dWlkdjQgfSBmcm9tICd1dWlkJztcblxuLyoqIEZpbGUgZXh0ZW5zaW9ucyB0aGUgVGhyZWUuanMgdmlld2VyIGNhbiBsb2FkIGFzIGEgYmFzZSBtb2RlbC4gKi9cbmNvbnN0IFNVUFBPUlRFRF9NT0RFTF9FWFRFTlNJT05TID0gWycuZ2xiJywgJy5nbHRmJ107XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBUaHJlZUpzSW1wb3J0U2VydmljZSB7XG4gIHByaXZhdGUgX3NwYWNlSUQ6IHN0cmluZztcblxuICBwdWJsaWMgZ2V0IHNwYWNlSUQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fc3BhY2VJRDtcbiAgfVxuXG4gIHB1YmxpYyBzZXQgc3BhY2VJRCh2YWx1ZTogc3RyaW5nKSB7XG4gICAgdGhpcy5fc3BhY2VJRCA9IHZhbHVlO1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBuYXZpZ2F0aW9uU2VydmljZTogTmF2aWdhdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSB6b25lU2VydmljZTogWm9uZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBsYXllclNlcnZpY2U6IExheWVyU2VydmljZSxcbiAgICBwcml2YXRlIHVzZXJTZXJ2aWNlOiBCYXNlVXNlclNlcnZpY2UsXG4gICAgcHJpdmF0ZSBwbGFuU2VydmljZTogUGxhblNlcnZpY2VcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBDaGVja3MgdGhhdCBhbiBTMyBrZXkgcG9pbnRzIGF0IHNvbWV0aGluZyB0aGUgdmlld2VyIGNhbiBhY3R1YWxseSBsb2FkLlxuICAgKlxuICAgKiBSZXR1cm5zIHRoZSByZWFzb24gaXQgY2FuJ3QsIG9yIG51bGwgd2hlbiBpdCdzIGZpbmUuIFRoaXMgcnVucyBiZWZvcmUgYW55dGhpbmcgaXMgd3JpdHRlbiwgc28gYVxuICAgKiBtaXN0eXBlZCBrZXkgZmFpbHMgb24gdGhlIGZvcm0gcmF0aGVyIHRoYW4gY3JlYXRpbmcgem9uZXMgYW5kIG5hdmlnYXRpb24gZm9yIGEgbW9kZWwgdGhhdCB3aWxsXG4gICAqIDQwNCB0aGUgZmlyc3QgdGltZSBzb21lb25lIG9wZW5zIHRoZSB2aXNpdC5cbiAgICovXG4gIHZhbGlkYXRlTW9kZWxLZXkoa2V5OiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcbiAgICBpZiAoIWtleSB8fCAha2V5LnRyaW0oKSkge1xuICAgICAgcmV0dXJuICdBIDNEIG1vZGVsIGZpbGUgKC5nbGIpIGlzIHJlcXVpcmVkIGZvciBhIFRocmVlLmpzIHZpc2l0Lic7XG4gICAgfVxuICAgIGNvbnN0IHRyaW1tZWQgPSBrZXkudHJpbSgpO1xuICAgIGlmICghU1VQUE9SVEVEX01PREVMX0VYVEVOU0lPTlMuc29tZSgoZXh0ZW5zaW9uKSA9PiB0cmltbWVkLnRvTG93ZXJDYXNlKCkuZW5kc1dpdGgoZXh0ZW5zaW9uKSkpIHtcbiAgICAgIHJldHVybiBgVGhlIDNEIG1vZGVsIG11c3QgYmUgYSAke1NVUFBPUlRFRF9NT0RFTF9FWFRFTlNJT05TLmpvaW4oJyBvciAnKX0gZmlsZS5gO1xuICAgIH1cbiAgICAvLyBBIGZ1bGwgaHR0cHM6Ly8gVVJMIGlzIGEgc2lnbmVkIGxpbmsgdGhhdCBleHBpcmVzOyB0aGUgc3RvcmVkIHZhbHVlIGhhcyB0byBiZSB0aGUga2V5IGl0c2VsZlxuICAgIC8vIHNvIGEgZnJlc2ggVVJMIGNhbiBiZSBzaWduZWQgb24gZXZlcnkgdmlzaXQuXG4gICAgaWYgKC9eaHR0cHM/OlxcL1xcLy9pLnRlc3QodHJpbW1lZCkpIHtcbiAgICAgIHJldHVybiAnRW50ZXIgdGhlIFMzIGtleSBvZiB0aGUgZmlsZSAoZS5nLiB2aXNpdHMvbXktbW9kZWwuZ2xiKSwgbm90IGEgZnVsbCBVUkwuJztcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBhc3luYyBpbXBvcnREYXRhKFxuICAgIHNwYWNlSUQ6IHN0cmluZyxcbiAgICBzdXJmYWNlOiBudW1iZXIsXG4gICAgcmVsb2FkaW5nOiBib29sZWFuID0gZmFsc2UsXG4gICAgbm9kZTogTm9kZSA9IG51bGwsXG4gICAgb3ZlcnJpZGVFeGlzdGluZyA9IHRydWUsXG4gICAgcGxhY2VtZW50TWV0YWRhdGE6IHN0cmluZyA9IG51bGxcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKHJlbG9hZGluZykge1xuICAgICAgLy8gUmVsb2FkaW5nIGlzIG5vdCBmdWxseSBhcHBsaWNhYmxlIHRvIHN0YXRpYyAzRCBtb2RlbHMgdGhlIHNhbWUgd2F5IGFzIE1hdHRlcnBvcnRcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUodHJ1ZSk7XG4gICAgfVxuXG4gICAgY29uc3Qga2V5RXJyb3IgPSB0aGlzLnZhbGlkYXRlTW9kZWxLZXkobm9kZT8ubW9kZWwzRCk7XG4gICAgaWYgKGtleUVycm9yKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IEVycm9yKGtleUVycm9yKSk7XG4gICAgfVxuXG4gICAgdGhpcy5zcGFjZUlEID0gc3BhY2VJRDtcbiAgICBjb25zdCB6b25lcyA9IGF3YWl0IHRoaXMuem9uZVNlcnZpY2UuZ2V0Wm9uZXNCeVNwYWNlKHNwYWNlSUQpO1xuICAgIGNvbnN0IG1haW5ab25lID0gem9uZXMuZmluZCgoeikgPT4gIXoucGFyZW50SUQpO1xuICAgIGlmICghbWFpblpvbmUpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoJ01pc3NpbmcgZGF0YSAobm8gbWFpbiBCdWlsZGluZyBab25lKScpKTtcbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZygnW1RocmVlSnNJbXBvcnRTZXJ2aWNlXSBJbXBvcnRpbmcgZGF0YSBmb3IgVGhyZWUuanMgbW9kZWwnKTtcblxuICAgIC8vIDEuIENoZWNrL2NyZWF0ZSBsYXllciBvZiBidWlsZGluZyB0eXBlXG4gICAgY29uc3QgbGF5ZXJCdWlsZGluZyA9IGF3YWl0IHRoaXMuZ2V0TGF5ZXJCeU5hbWUoJ0JVSUxESU5HJyk7XG4gICAgXG4gICAgLy8gV2UgZ2VuZXJhdGUgYSBkdW1teSBJRCB0byBhY3QgYXMgb3VyIHNpbmdsZSBcInN3ZWVwXCIgZXF1aXZhbGVudFxuICAgIGNvbnN0IGR1bW15U3dlZXBJRCA9IHV1aWR2NCgpO1xuXG4gICAgLy8gMi4gQ3JlYXRlIHRoZSBkZWZhdWx0IFpvbmVcbiAgICBjb25zdCBjcmVhdGVkRGVmYXVsdFpvbmUgPSBhd2FpdCB0aGlzLmNyZWF0ZVpvbmUoXG4gICAgICBub2RlLm1ldGFkYXRhIHx8ICdUaHJlZS5qcyAzRCBNb2RlbCcsXG4gICAgICBsYXllckJ1aWxkaW5nLmlkLFxuICAgICAgc3VyZmFjZSxcbiAgICAgIG1haW5ab25lLmlkLFxuICAgICAgW2R1bW15U3dlZXBJRF0sXG4gICAgICBub2RlXG4gICAgKTtcblxuICAgIGlmICghY3JlYXRlZERlZmF1bHRab25lKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTtcbiAgICB9XG5cbiAgICAvLyAzLiBDcmVhdGUgYSBibGFuayBQbGFuIGZvciB0aGUgbW9kZWwgKHRvIGVuc3VyZSBjb25zaXN0ZW5jeSBpbiB0aGUgYXBwIHN0cnVjdHVyZSlcbiAgICBjb25zdCBwbGFuID0ge1xuICAgICAgbmFtZTogYHBsYW5fdGhyZWVqc18ke25vZGUuaWR9YCxcbiAgICAgIGFubmV4ZTogJycsIC8vIE5vIGZsb29ycGxhbiBpbWFnZSBnZW5lcmF0ZWQgYXV0b21hdGljYWxseSB5ZXRcbiAgICAgIHpvbmVJRDogY3JlYXRlZERlZmF1bHRab25lLmlkLFxuICAgICAgc3BhY2VJRDogdGhpcy5zcGFjZUlELFxuICAgICAgaXNDdXJyZW50Rm9yWm9uZTogdHJ1ZSxcbiAgICAgIGlzTW9kaWZpZWQ6IGZhbHNlLFxuICAgICAgaXNJbXBvcnRlZE1hdHRlcnBvcnQ6IGZhbHNlLCAvLyBFeHBsaWNpdGx5IG5vdCBtYXR0ZXJwb3J0XG4gICAgfSBhcyBQbGFuO1xuICAgIGF3YWl0IHRoaXMucGxhblNlcnZpY2UuY3JlYXRlUGxhbihwbGFuKTtcblxuICAgIC8vIDQuIENyZWF0ZSB0aGUgc2luZ2xlIE5hdmlnYXRpb24gZW50cnkgdGhpcyBtb2RlbCBpcyB2aWV3ZWQgZnJvbS5cbiAgICAvLyBNYXR0ZXJwb3J0IGRlcml2ZXMgdGhlc2UgZnJvbSBpdHMgc3dlZXBzOyBhIHN0YXRpYyBtb2RlbCBoYXMgbm8gc3dlZXBzLCBzbyB0aGUgcGxhY2VtZW50XG4gICAgLy8gY29tZXMgZnJvbSB0aGUgbWV0YWRhdGEgZW50ZXJlZCBvbiB0aGUgZm9ybSwgZmFsbGluZyBiYWNrIHRvIHRoZSBvcmlnaW4uXG4gICAgY29uc3QgcGxhY2VtZW50ID0gcGFyc2VUaHJlZUpzUGxhY2VtZW50KHBsYWNlbWVudE1ldGFkYXRhKTtcbiAgICBjb25zdCBvcmlnaW4gPSB7IHg6IDAsIHk6IDAsIHo6IDAgfTtcbiAgICBjb25zdCBuYXZpZ2F0aW9uSW5wdXQgPSB7XG4gICAgICBtYXR0ZXJwb3J0U3dlZXBJRDogZHVtbXlTd2VlcElELFxuICAgICAgcG9zaXRpb246IEpTT04uc3RyaW5naWZ5KHBsYWNlbWVudD8uY2FtZXJhUG9zaXRpb24gPz8gb3JpZ2luKSxcbiAgICAgIHJvdGF0aW9uOiBKU09OLnN0cmluZ2lmeShwbGFjZW1lbnQ/LnJvdGF0aW9uID8/IG9yaWdpbiksXG4gICAgICBsZXZlbDogTGV2ZWxTdGF0dXMuTE9XLFxuICAgICAgbm9kZUlEOiBub2RlLmlkLFxuICAgICAgc3BhY2VJRCxcbiAgICB9IGFzIE5hdmlnYXRpb247XG4gICAgXG4gICAgY29uc3QgbmF2ID0gYXdhaXQgdGhpcy5uYXZpZ2F0aW9uU2VydmljZS5jcmVhdGVOYXZpZ2F0aW9uKG5hdmlnYXRpb25JbnB1dCk7XG4gICAgaWYgKCFuYXYpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdDb3VsZCBub3QgY3JlYXRlIG5hdmlnYXRpb24gZm9yJywgbmF2aWdhdGlvbklucHV0KTtcbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZygnW1RocmVlSnNJbXBvcnRTZXJ2aWNlXSBJbXBvcnQgZG9uZS4nKTtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRydWUpO1xuICB9XG5cbiAgYXN5bmMgY3JlYXRlWm9uZShcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgbGF5ZXJJRDogc3RyaW5nLFxuICAgIHN1cmZhY2U6IG51bWJlciA9IG51bGwsXG4gICAgcGFyZW50SUQ6IHN0cmluZyA9IG51bGwsXG4gICAgc3dlZXBzOiBzdHJpbmdbXSA9IFtdLFxuICAgIG5vZGU6IE5vZGUgPSBudWxsLFxuICAgIG1ldGFkYXRhOiBzdHJpbmcgPSBudWxsXG4gICk6IFByb21pc2U8Wm9uZT4ge1xuICAgIGNvbnN0IHpvbmVJbnB1dCA9IHtcbiAgICAgIG5hbWUsXG4gICAgICBzcGFjZUlEOiB0aGlzLnNwYWNlSUQsXG4gICAgICBsYXllcklELFxuICAgICAgc3dlZXBJRHM6IHN3ZWVwcyxcbiAgICAgIG5vZGVJRHM6IG5vZGUgPyBbbm9kZS5pZF0gOiBudWxsLFxuICAgIH0gYXMgWm9uZTtcbiAgICBcbiAgICByZW1vdmVOdWxsS2V5c0Zyb21PYmplY3Qoem9uZUlucHV0KTtcbiAgICBpZiAoc3VyZmFjZSkge1xuICAgICAgem9uZUlucHV0LnN1cmZhY2UgPSBzdXJmYWNlO1xuICAgIH1cbiAgICBpZiAocGFyZW50SUQpIHtcbiAgICAgIHpvbmVJbnB1dC5wYXJlbnRJRCA9IHBhcmVudElEO1xuICAgIH1cbiAgICBpZiAobWV0YWRhdGEpIHtcbiAgICAgIHpvbmVJbnB1dC5tZXRhZGF0YSA9IG1ldGFkYXRhO1xuICAgIH1cbiAgICBcbiAgICBjb25zdCBuZXdMb2NhbCA9IGF3YWl0IHRoaXMuem9uZVNlcnZpY2UuY3JlYXRlKHpvbmVJbnB1dCk7XG4gICAgcmV0dXJuIG5ld0xvY2FsO1xuICB9XG5cbiAgYXN5bmMgZ2V0TGF5ZXJCeU5hbWUobmFtZTogc3RyaW5nKTogUHJvbWlzZTxMYXllcj4ge1xuICAgIGNvbnN0IG1pc3Npb24gPSB0aGlzLnVzZXJTZXJ2aWNlLmN1cnJlbnRNaXNzaW9uKHRoaXMuc3BhY2VJRCk7XG4gICAgY29uc3QgY3VycmVudE9yZ0lkID0gbWlzc2lvbi5vcmdhbmlzYXRpb25JRDtcbiAgICBjb25zdCBsYXllcnMgPSBhd2FpdCB0aGlzLmxheWVyU2VydmljZS5nZXRMYXllckJ5TmFtZUZvck9yZ2FuaXNhdGlvbihcbiAgICAgIG5hbWUsXG4gICAgICBjdXJyZW50T3JnSWRcbiAgICApO1xuICAgIGlmIChsYXllcnMubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIGxheWVyc1swXTtcbiAgICB9XG4gICAgLy8gQ3JlYXRlIGl0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcbiAgICByZXR1cm4gdGhpcy5sYXllclNlcnZpY2UuY3JlYXRlTGF5ZXJGb3JPcmdhbmlzYXRpb24obmFtZSwgY3VycmVudE9yZ0lkKTtcbiAgfVxufVxuIl19