@smarterplan/ngx-smarterplan-locations 0.3.4 → 0.4.2

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 (82) hide show
  1. package/esm2022/lib/components/carousel/carousel.component.mjs +30 -0
  2. package/esm2022/lib/components/chevron/chevron.component.mjs +18 -0
  3. package/esm2022/lib/components/detail-location/detail-location.component.mjs +183 -0
  4. package/{esm2020 → esm2022}/lib/components/form-location/form-location.component.mjs +254 -237
  5. package/esm2022/lib/components/images/images.component.mjs +120 -0
  6. package/esm2022/lib/components/locations/locations.component.mjs +157 -0
  7. package/esm2022/lib/components/locations/map/map-popup/map-popup.component.mjs +72 -0
  8. package/esm2022/lib/components/locations/map/map.component.mjs +92 -0
  9. package/esm2022/lib/components/plan-legend/plan-legend.component.mjs +49 -0
  10. package/esm2022/lib/components/plans/calibration/calibration.component.mjs +494 -0
  11. package/esm2022/lib/components/plans/edit-plan/edit-plan.component.mjs +350 -0
  12. package/{esm2020 → esm2022}/lib/components/plans/plans.component.mjs +243 -225
  13. package/esm2022/lib/components/tab-navigation/tab-navigation.component.mjs +43 -0
  14. package/esm2022/lib/components/visits/visits.component.mjs +294 -0
  15. package/esm2022/lib/components/zones/add-audio-zone/add-audio-zone.component.mjs +250 -0
  16. package/esm2022/lib/components/zones/add-zone/add-zone.component.mjs +333 -0
  17. package/esm2022/lib/components/zones/add-zone/selection/selection.component.mjs +81 -0
  18. package/esm2022/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.mjs +518 -0
  19. package/esm2022/lib/components/zones/zones.component.mjs +291 -0
  20. package/{esm2020 → esm2022}/lib/helper.service.mjs +133 -133
  21. package/esm2022/lib/ngx-smarterplan-location-routing.module.mjs +50 -0
  22. package/esm2022/lib/ngx-smarterplan-locations.module.mjs +124 -0
  23. package/esm2022/lib/ngx-smarterplan-locations.service.mjs +15 -0
  24. package/esm2022/lib/pipes/count-audio-sweeps.pipe.mjs +29 -0
  25. package/esm2022/lib/radio-button/radio-button.component.mjs +28 -0
  26. package/{esm2020 → esm2022}/public-api.mjs +8 -8
  27. package/{esm2020 → esm2022}/smarterplan-ngx-smarterplan-locations.mjs +4 -4
  28. package/{fesm2020 → fesm2022}/smarterplan-ngx-smarterplan-locations.mjs +3959 -3738
  29. package/fesm2022/smarterplan-ngx-smarterplan-locations.mjs.map +1 -0
  30. package/index.d.ts +5 -5
  31. package/lib/components/carousel/carousel.component.d.ts +12 -12
  32. package/lib/components/chevron/chevron.component.d.ts +9 -9
  33. package/lib/components/detail-location/detail-location.component.d.ts +55 -55
  34. package/lib/components/form-location/form-location.component.d.ts +45 -45
  35. package/lib/components/images/images.component.d.ts +33 -33
  36. package/lib/components/locations/locations.component.d.ts +51 -51
  37. package/lib/components/locations/map/map-popup/map-popup.component.d.ts +22 -22
  38. package/lib/components/locations/map/map.component.d.ts +21 -22
  39. package/lib/components/plan-legend/plan-legend.component.d.ts +14 -14
  40. package/lib/components/plans/calibration/calibration.component.d.ts +140 -140
  41. package/lib/components/plans/edit-plan/edit-plan.component.d.ts +55 -55
  42. package/lib/components/plans/plans.component.d.ts +63 -63
  43. package/lib/components/tab-navigation/tab-navigation.component.d.ts +13 -13
  44. package/lib/components/visits/visits.component.d.ts +63 -63
  45. package/lib/components/zones/add-audio-zone/add-audio-zone.component.d.ts +63 -63
  46. package/lib/components/zones/add-zone/add-zone.component.d.ts +69 -69
  47. package/lib/components/zones/add-zone/selection/selection.component.d.ts +44 -44
  48. package/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.d.ts +107 -107
  49. package/lib/components/zones/zones.component.d.ts +73 -73
  50. package/lib/helper.service.d.ts +53 -53
  51. package/lib/ngx-smarterplan-location-routing.module.d.ts +7 -7
  52. package/lib/ngx-smarterplan-locations.module.d.ts +36 -36
  53. package/lib/ngx-smarterplan-locations.service.d.ts +6 -6
  54. package/lib/pipes/count-audio-sweeps.pipe.d.ts +10 -10
  55. package/lib/radio-button/radio-button.component.d.ts +12 -12
  56. package/package.json +13 -19
  57. package/public-api.d.ts +4 -4
  58. package/esm2020/lib/components/carousel/carousel.component.mjs +0 -28
  59. package/esm2020/lib/components/chevron/chevron.component.mjs +0 -18
  60. package/esm2020/lib/components/detail-location/detail-location.component.mjs +0 -168
  61. package/esm2020/lib/components/images/images.component.mjs +0 -107
  62. package/esm2020/lib/components/locations/locations.component.mjs +0 -145
  63. package/esm2020/lib/components/locations/map/map-popup/map-popup.component.mjs +0 -66
  64. package/esm2020/lib/components/locations/map/map.component.mjs +0 -91
  65. package/esm2020/lib/components/plan-legend/plan-legend.component.mjs +0 -47
  66. package/esm2020/lib/components/plans/calibration/calibration.component.mjs +0 -468
  67. package/esm2020/lib/components/plans/edit-plan/edit-plan.component.mjs +0 -324
  68. package/esm2020/lib/components/tab-navigation/tab-navigation.component.mjs +0 -41
  69. package/esm2020/lib/components/visits/visits.component.mjs +0 -275
  70. package/esm2020/lib/components/zones/add-audio-zone/add-audio-zone.component.mjs +0 -230
  71. package/esm2020/lib/components/zones/add-zone/add-zone.component.mjs +0 -315
  72. package/esm2020/lib/components/zones/add-zone/selection/selection.component.mjs +0 -77
  73. package/esm2020/lib/components/zones/add-zone/sweep-plan-selection/sweep-plan-selection.component.mjs +0 -502
  74. package/esm2020/lib/components/zones/zones.component.mjs +0 -268
  75. package/esm2020/lib/ngx-smarterplan-location-routing.module.mjs +0 -49
  76. package/esm2020/lib/ngx-smarterplan-locations.module.mjs +0 -123
  77. package/esm2020/lib/ngx-smarterplan-locations.service.mjs +0 -14
  78. package/esm2020/lib/pipes/count-audio-sweeps.pipe.mjs +0 -27
  79. package/esm2020/lib/radio-button/radio-button.component.mjs +0 -26
  80. package/fesm2015/smarterplan-ngx-smarterplan-locations.mjs +0 -3983
  81. package/fesm2015/smarterplan-ngx-smarterplan-locations.mjs.map +0 -1
  82. package/fesm2020/smarterplan-ngx-smarterplan-locations.mjs.map +0 -1
@@ -1,225 +1,243 @@
1
- import { Component } from '@angular/core';
2
- import { Validators } from '@angular/forms';
3
- import { getMetaForImage, getSignedFile, downloadFileAsObject, downloadBlob } from '@smarterplan/ngx-smarterplan-core';
4
- import panzoom from 'panzoom';
5
- import { Subject, takeUntil } from 'rxjs';
6
- import * as i0 from "@angular/core";
7
- import * as i1 from "@angular/router";
8
- import * as i2 from "@smarterplan/ngx-smarterplan-core";
9
- import * as i3 from "@angular/forms";
10
- import * as i4 from "@ngx-translate/core";
11
- import * as i5 from "@ng-bootstrap/ng-bootstrap";
12
- import * as i6 from "@angular/common";
13
- import * as i7 from "../tab-navigation/tab-navigation.component";
14
- export class PlansComponent {
15
- constructor(route, router, spaceService, planService, fb, translate, navigatorService) {
16
- this.route = route;
17
- this.router = router;
18
- this.spaceService = spaceService;
19
- this.planService = planService;
20
- this.fb = fb;
21
- this.translate = translate;
22
- this.navigatorService = navigatorService;
23
- // chosenPlan: Plan;
24
- this.indexDetails = -1;
25
- this.loading = false;
26
- this.uploadingPlan = false;
27
- this.isCurrentPlanForZone = false;
28
- this.chosenPlanIsPdf = false;
29
- this.menuItems = [];
30
- this.destroy$ = new Subject();
31
- this.navigatorService.locationIDChange
32
- .pipe(takeUntil(this.destroy$))
33
- .subscribe((spaceID) => {
34
- this.router.navigate(["dashboard/localisation", spaceID, "plans"]);
35
- });
36
- this.route.params.subscribe((params) => {
37
- this.spaceID = params.id;
38
- this.getPlans();
39
- });
40
- }
41
- ngOnInit() {
42
- if (this.planService.getPlanFileCache() &&
43
- this.planService.getChosenPlan()) {
44
- this.addPlanFromCache(this.planService.getPlanFileCache(), this.planService.getChosenPlan());
45
- this.planService.setPlanFileCache(null);
46
- }
47
- this.planService.setChosenPlan(null);
48
- }
49
- ngOnDestroy() {
50
- this.destroy$.next(true);
51
- this.destroy$.complete();
52
- }
53
- setupMenuItems() {
54
- this.menuItems = [
55
- { label: "Locations", url: "/localisation" },
56
- {
57
- label: this.currentSpace.name,
58
- url: `/localisation/${this.currentSpace.id}`,
59
- },
60
- {
61
- label: "Plans",
62
- url: `/localisation/${this.currentSpace.id}/plans`,
63
- },
64
- ];
65
- }
66
- onGoBack() { }
67
- async onPlanClick(plan) {
68
- if (plan)
69
- this.planService.setChosenPlan(plan);
70
- this.chosenPlanIsPdf = plan.annexe.includes("pdf");
71
- if (!this.chosenPlanIsPdf) {
72
- setTimeout(() => {
73
- this.configureCanvas().then(() => {
74
- this.panzoom = panzoom(this.canvas, {
75
- bounds: true,
76
- boundsPadding: 0,
77
- maxZoom: 3.5,
78
- minZoom: 0.1,
79
- initialZoom: 0.5,
80
- });
81
- });
82
- }, 500);
83
- }
84
- }
85
- async configureCanvas() {
86
- this.uploadingPlan = true;
87
- const canvas = document.querySelector("#canvas");
88
- const image = await getMetaForImage(this.getChoosenPlan().filepath);
89
- canvas.width = image.width;
90
- canvas.height = image.height;
91
- this.canvas = canvas;
92
- this.drawImage(this.getChoosenPlan().filepath);
93
- this.uploadingPlan = false;
94
- }
95
- drawImage(url, x = 0, y = 0) {
96
- const image = new Image();
97
- const context = this.canvas.getContext("2d");
98
- const imageWidth = this.canvas.width;
99
- const imageHeight = this.canvas.height;
100
- image.addEventListener("load", () => {
101
- context.drawImage(image, 0, 0, image.width, image.height, x, y, imageWidth, imageHeight);
102
- });
103
- image.src = url;
104
- // image.crossOrigin = "*"; //need to download as png,
105
- // BUT: https://stackoverflow.com/questions/49503171/the-image-tag-with-crossorigin-anonymous-cant-load-success-from-s3
106
- }
107
- async getPlans() {
108
- this.loading = true;
109
- this.currentSpace = await this.spaceService.getSpace(this.spaceID);
110
- this.setupMenuItems();
111
- this.zones = this.currentSpace.zones.items;
112
- this.plans = await this.planService.getSingedPlansForSpace(this.spaceID);
113
- this.loading = false;
114
- if (this.plans.length === 1) {
115
- this.onPlanClick(this.plans[0]);
116
- }
117
- }
118
- getChoosenPlan() {
119
- return this.planService.getChosenPlan();
120
- }
121
- removeImage() {
122
- const context = this.canvas.getContext("2d");
123
- context.clearRect(0, 0, 4096, 4096);
124
- }
125
- /**
126
- *
127
- */
128
- onCalibrateClick() {
129
- if (this.getChoosenPlan()) {
130
- this.router.navigate(["/dashboard/localisation", this.spaceID, "plan-calibration"], { queryParams: { spaceID: this.spaceID } });
131
- }
132
- }
133
- /**
134
- *
135
- */
136
- onEditClick() {
137
- if (this.getChoosenPlan()) {
138
- this.router.navigate(["/dashboard/localisation", this.spaceID, "plan-edit"], { queryParams: { spaceID: this.spaceID } });
139
- }
140
- }
141
- onUploadClick() {
142
- const inputFile = document.querySelector("#upload-file");
143
- inputFile.click();
144
- }
145
- addPlan(target) {
146
- this.fileToUpload = target.files[0];
147
- this.planForm = this.fb.group({
148
- name: [this.fileToUpload.name, [Validators.required]],
149
- zoneID: [null, [Validators.required]],
150
- spaceID: this.spaceID,
151
- isModified: false,
152
- calibration: "",
153
- });
154
- }
155
- addPlanFromCache(file, plan) {
156
- this.fileToUpload = file;
157
- this.planForm = this.fb.group({
158
- name: [this.fileToUpload.name, [Validators.required]],
159
- zoneID: [plan ? plan.zoneID : null, [Validators.required]],
160
- spaceID: this.spaceID,
161
- isModified: !!plan,
162
- calibration: plan && plan.isModified && plan.calibration
163
- ? plan.calibration
164
- : "",
165
- });
166
- }
167
- async onSavePlan() {
168
- const formValue = this.planForm.value;
169
- formValue.isCurrentForZone = this.isCurrentPlanForZone;
170
- const createdPlan = await this.planService.createPlanWithAnnexe(formValue, this.fileToUpload);
171
- const filepath = await getSignedFile(createdPlan.annexe);
172
- if (filepath) {
173
- createdPlan.filepath = filepath;
174
- }
175
- if (formValue.isCurrentForZone) {
176
- // set all other plans to not current
177
- this.planService.setAllPlansForZoneNotCurrent(createdPlan.zoneID, createdPlan.id);
178
- }
179
- this.plans.push(createdPlan);
180
- this.planForm = null;
181
- this.fileToUpload = null;
182
- }
183
- onCancelUpload() {
184
- this.fileToUpload = null;
185
- this.planForm = null;
186
- }
187
- async onCurrentPlanClick() {
188
- await this.planService.updatePlan({
189
- id: this.getChoosenPlan().id,
190
- isCurrentForZone: this.getChoosenPlan().isCurrentForZone,
191
- });
192
- if (this.getChoosenPlan().isCurrentForZone) {
193
- this.planService.setAllPlansForZoneNotCurrent(this.getChoosenPlan().zoneID, this.getChoosenPlan().id);
194
- }
195
- }
196
- async onDownloadClick() {
197
- const signedFile = await downloadFileAsObject(this.getChoosenPlan().annexe);
198
- if (signedFile) {
199
- // @ts-ignore
200
- downloadBlob(signedFile.Body, this.getChoosenPlan().name);
201
- }
202
- }
203
- async onDownloadAsPng() {
204
- const canvas = document.querySelector("#canvas");
205
- canvas.toBlob(function (blob) {
206
- downloadBlob(blob, "plan-as-png.png");
207
- });
208
- }
209
- async onRemoveClick() {
210
- const message = this.translate.instant("confirm.deletePlan");
211
- if (window.confirm(message)) {
212
- await this.planService.deletePlan(this.getChoosenPlan());
213
- this.removeImage();
214
- this.planService.setChosenPlan(null);
215
- this.getPlans();
216
- }
217
- }
218
- }
219
- PlansComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PlansComponent, deps: [{ token: i1.ActivatedRoute }, { token: i1.Router }, { token: i2.SpaceService }, { token: i2.PlanService }, { token: i3.UntypedFormBuilder }, { token: i4.TranslateService }, { token: i2.NavigatorService }], target: i0.ɵɵFactoryTarget.Component });
220
- PlansComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PlansComponent, selector: "lib-plans", ngImport: i0, template: "<div class=\"container-fluid\" *ngIf=\"currentSpace\" class=\"dashboard-tab\">\r\n <div class=\"m-3\">\r\n <lib-tab-navigation [menuItems]='menuItems' (onGoBack)=\"onGoBack()\"></lib-tab-navigation>\r\n </div>\r\n <div class=\"d-flex justify-content-center\" *ngIf=\"loading\">\r\n <div class=\"spinner-border\" role=\"status\">\r\n <span class=\"visually-hidden\">Loading...</span>\r\n </div>\r\n </div>\r\n <div class=\"mt-3\" *ngIf=\"!plans && !loading\">\r\n <h4 style=\"font-weight: bold;\">{{'No imported plans' | translate }}</h4>\r\n <p>{{'For import from 3D visit: go Virtual Visits => Import Images' | translate}}</p>\r\n </div>\r\n <div class=\"row ms-1\">\r\n <div ngbDropdown class=\"d-inline-block me-3\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownBasic1\" ngbDropdownToggle>{{getChoosenPlan() ?\r\n getChoosenPlan().name: ('Choose Plan' | translate) }}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownBasic1\">\r\n <button ngbDropdownItem *ngFor=\"let plan of plans\" (click)=\"onPlanClick(plan)\">{{plan.name }}\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"d-inline-block\" ngbDropdown #myDrop=\"ngbDropdown\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownManual\" ngbDropdownToggle>{{'Choose action' |\r\n translate}}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownManual\">\r\n <button (click)=\"onCalibrateClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Calibrate' |\r\n translate}}</button>\r\n <button (click)=\"onEditClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Edit plan' |\r\n translate}}\r\n </button>\r\n <button (click)=\"onUploadClick()\" ngbDropdownItem>{{'Upload new plan' | translate}}</button>\r\n <button (click)=\"onDownloadClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Download plan' |\r\n translate}}</button>\r\n <button (click)=\"onRemoveClick()\" ngbDropdownItem\r\n [disabled]=\"!getChoosenPlan() || getChoosenPlan().isImportedMatterport\">{{'Delete plan' |\r\n translate}}</button>\r\n <!-- <button (click)=\"onDownloadAsPng()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">\r\n {{'Download plan as PNG' | translate}}</button> -->\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"row mt-3 ms-0\">\r\n <h4 *ngIf=\"fileToUpload\">{{'New plan' | translate }}</h4>\r\n <input class=\"hidden\" type=\"file\" id=\"upload-file\" name=\"upload-file\" accept=\"image/png, image/jpeg, .pdf, .svg\"\r\n ngf-max-size=\"6MB\" (change)=\"addPlan($event.target)\">\r\n </div>\r\n <div class=\"col-md-6 mt-3\" *ngIf=\"planForm\">\r\n <form (ngSubmit)=\"onSavePlan()\" [formGroup]=\"planForm\">\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Name' | translate}} </label>\r\n <div class=\"col-sm-9\">\r\n <input type=\"text\" class=\"form-control\" formControlName=\"name\">\r\n </div>\r\n </div>\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Zone' | translate}} </label>\r\n <div class=\"col-sm-9\">\r\n <select class=\"form-control\" formControlName=\"zoneID\">\r\n <option *ngFor=\"let zone of zones\" [ngValue]=\"zone.id\">\r\n {{ zone.name }}\r\n </option>\r\n </select>\r\n </div>\r\n </div>\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Set as current plan for zone' | translate}}</label>\r\n <div class=\"col-sm-3\">\r\n <input type=\"checkbox\" [(ngModel)]=\"isCurrentPlanForZone\" [ngModelOptions]=\"{standalone: true}\">\r\n </div>\r\n </div>\r\n <button [disabled]=\"planForm.invalid\" type='submit' class=\"btn btn-label-file rounded-pill\">{{'Save' |\r\n translate}}</button>\r\n <button class=\"btn btn-label-file rounded-pill ms-3\" type=\"button\" (click)=\"onCancelUpload()\">{{'Cancel' |\r\n translate}}</button>\r\n </form>\r\n </div>\r\n <ul class=\"col-md-6 list-group list-group-flush\" *ngIf=\"getChoosenPlan()\">\r\n <li class=\"list-group-item bg-transparent\">{{'Name' | translate }} : {{getChoosenPlan().name}} </li>\r\n <li class=\"list-group-item bg-transparent\"> {{'Plan is ' | translate }} :\r\n {{getChoosenPlan().calibration ? ('Calibrated' | translate) : ('Not calibrated' | translate)}}</li>\r\n <li class=\"list-group-item bg-transparent\">{{'Attributed to zone ' | translate }} :\r\n {{getChoosenPlan().zone ? getChoosenPlan().zone.name : 'None'}}</li>\r\n <li class=\"list-group-item bg-transparent\">{{'Is current plan for zone ' | translate }} :\r\n <input type=\"checkbox\" [(ngModel)]=\"getChoosenPlan().isCurrentForZone\" (change)=\"onCurrentPlanClick()\">\r\n </li>\r\n\r\n </ul>\r\n\r\n <div class=\"row mt-4\">\r\n <div class=\"col-md-10\">\r\n <embed *ngIf=\"getChoosenPlan() && chosenPlanIsPdf\" [src]=\"getChoosenPlan().filepath | safeUrl\"\r\n type=\"application/pdf\" frameBorder=\"0\" scrolling=\"auto\" height=\"650px;\" width=\"100%\" />\r\n <div *ngIf=\"!chosenPlanIsPdf\" class=\"row\" style=\"height: 500px; overflow: hidden;\" id=\"canvasDiv\">\r\n <canvas id=\"canvas\" width=\"4096px\" height=\"4096px\">\r\n <!-- <img *ngIf=\"chosenPlan\" id=\"plan-image\" [src]=\"chosenPlan.filepath\" style=\"width: 100%;\"> -->\r\n </canvas>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".button-visit{display:none;height:30px;width:30px;position:absolute;background:url(https://api.iconify.design/mdi:map-marker-check.svg?color=red&height=30) no-repeat scroll 0 0 transparent;border:none}#button-visit-left{left:350px;top:550px}#button-visit-right{left:500px;top:600px}.hidden{visibility:hidden;width:1px;height:1px}\n"], dependencies: [{ kind: "directive", type: i5.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "popperOptions", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { kind: "directive", type: i5.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { kind: "directive", type: i5.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { kind: "directive", type: i5.NgbDropdownItem, selector: "[ngbDropdownItem]", inputs: ["disabled"] }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i7.TabNavigationComponent, selector: "lib-tab-navigation", inputs: ["menuItems"], outputs: ["onGoBack"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }, { kind: "pipe", type: i2.SafeUrlPipe, name: "safeUrl" }] });
221
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PlansComponent, decorators: [{
222
- type: Component,
223
- args: [{ selector: 'lib-plans', template: "<div class=\"container-fluid\" *ngIf=\"currentSpace\" class=\"dashboard-tab\">\r\n <div class=\"m-3\">\r\n <lib-tab-navigation [menuItems]='menuItems' (onGoBack)=\"onGoBack()\"></lib-tab-navigation>\r\n </div>\r\n <div class=\"d-flex justify-content-center\" *ngIf=\"loading\">\r\n <div class=\"spinner-border\" role=\"status\">\r\n <span class=\"visually-hidden\">Loading...</span>\r\n </div>\r\n </div>\r\n <div class=\"mt-3\" *ngIf=\"!plans && !loading\">\r\n <h4 style=\"font-weight: bold;\">{{'No imported plans' | translate }}</h4>\r\n <p>{{'For import from 3D visit: go Virtual Visits => Import Images' | translate}}</p>\r\n </div>\r\n <div class=\"row ms-1\">\r\n <div ngbDropdown class=\"d-inline-block me-3\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownBasic1\" ngbDropdownToggle>{{getChoosenPlan() ?\r\n getChoosenPlan().name: ('Choose Plan' | translate) }}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownBasic1\">\r\n <button ngbDropdownItem *ngFor=\"let plan of plans\" (click)=\"onPlanClick(plan)\">{{plan.name }}\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"d-inline-block\" ngbDropdown #myDrop=\"ngbDropdown\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownManual\" ngbDropdownToggle>{{'Choose action' |\r\n translate}}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownManual\">\r\n <button (click)=\"onCalibrateClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Calibrate' |\r\n translate}}</button>\r\n <button (click)=\"onEditClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Edit plan' |\r\n translate}}\r\n </button>\r\n <button (click)=\"onUploadClick()\" ngbDropdownItem>{{'Upload new plan' | translate}}</button>\r\n <button (click)=\"onDownloadClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Download plan' |\r\n translate}}</button>\r\n <button (click)=\"onRemoveClick()\" ngbDropdownItem\r\n [disabled]=\"!getChoosenPlan() || getChoosenPlan().isImportedMatterport\">{{'Delete plan' |\r\n translate}}</button>\r\n <!-- <button (click)=\"onDownloadAsPng()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">\r\n {{'Download plan as PNG' | translate}}</button> -->\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"row mt-3 ms-0\">\r\n <h4 *ngIf=\"fileToUpload\">{{'New plan' | translate }}</h4>\r\n <input class=\"hidden\" type=\"file\" id=\"upload-file\" name=\"upload-file\" accept=\"image/png, image/jpeg, .pdf, .svg\"\r\n ngf-max-size=\"6MB\" (change)=\"addPlan($event.target)\">\r\n </div>\r\n <div class=\"col-md-6 mt-3\" *ngIf=\"planForm\">\r\n <form (ngSubmit)=\"onSavePlan()\" [formGroup]=\"planForm\">\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Name' | translate}} </label>\r\n <div class=\"col-sm-9\">\r\n <input type=\"text\" class=\"form-control\" formControlName=\"name\">\r\n </div>\r\n </div>\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Zone' | translate}} </label>\r\n <div class=\"col-sm-9\">\r\n <select class=\"form-control\" formControlName=\"zoneID\">\r\n <option *ngFor=\"let zone of zones\" [ngValue]=\"zone.id\">\r\n {{ zone.name }}\r\n </option>\r\n </select>\r\n </div>\r\n </div>\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Set as current plan for zone' | translate}}</label>\r\n <div class=\"col-sm-3\">\r\n <input type=\"checkbox\" [(ngModel)]=\"isCurrentPlanForZone\" [ngModelOptions]=\"{standalone: true}\">\r\n </div>\r\n </div>\r\n <button [disabled]=\"planForm.invalid\" type='submit' class=\"btn btn-label-file rounded-pill\">{{'Save' |\r\n translate}}</button>\r\n <button class=\"btn btn-label-file rounded-pill ms-3\" type=\"button\" (click)=\"onCancelUpload()\">{{'Cancel' |\r\n translate}}</button>\r\n </form>\r\n </div>\r\n <ul class=\"col-md-6 list-group list-group-flush\" *ngIf=\"getChoosenPlan()\">\r\n <li class=\"list-group-item bg-transparent\">{{'Name' | translate }} : {{getChoosenPlan().name}} </li>\r\n <li class=\"list-group-item bg-transparent\"> {{'Plan is ' | translate }} :\r\n {{getChoosenPlan().calibration ? ('Calibrated' | translate) : ('Not calibrated' | translate)}}</li>\r\n <li class=\"list-group-item bg-transparent\">{{'Attributed to zone ' | translate }} :\r\n {{getChoosenPlan().zone ? getChoosenPlan().zone.name : 'None'}}</li>\r\n <li class=\"list-group-item bg-transparent\">{{'Is current plan for zone ' | translate }} :\r\n <input type=\"checkbox\" [(ngModel)]=\"getChoosenPlan().isCurrentForZone\" (change)=\"onCurrentPlanClick()\">\r\n </li>\r\n\r\n </ul>\r\n\r\n <div class=\"row mt-4\">\r\n <div class=\"col-md-10\">\r\n <embed *ngIf=\"getChoosenPlan() && chosenPlanIsPdf\" [src]=\"getChoosenPlan().filepath | safeUrl\"\r\n type=\"application/pdf\" frameBorder=\"0\" scrolling=\"auto\" height=\"650px;\" width=\"100%\" />\r\n <div *ngIf=\"!chosenPlanIsPdf\" class=\"row\" style=\"height: 500px; overflow: hidden;\" id=\"canvasDiv\">\r\n <canvas id=\"canvas\" width=\"4096px\" height=\"4096px\">\r\n <!-- <img *ngIf=\"chosenPlan\" id=\"plan-image\" [src]=\"chosenPlan.filepath\" style=\"width: 100%;\"> -->\r\n </canvas>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".button-visit{display:none;height:30px;width:30px;position:absolute;background:url(https://api.iconify.design/mdi:map-marker-check.svg?color=red&height=30) no-repeat scroll 0 0 transparent;border:none}#button-visit-left{left:350px;top:550px}#button-visit-right{left:500px;top:600px}.hidden{visibility:hidden;width:1px;height:1px}\n"] }]
224
- }], ctorParameters: function () { return [{ type: i1.ActivatedRoute }, { type: i1.Router }, { type: i2.SpaceService }, { type: i2.PlanService }, { type: i3.UntypedFormBuilder }, { type: i4.TranslateService }, { type: i2.NavigatorService }]; } });
225
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxhbnMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvcGxhbnMvcGxhbnMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvcGxhbnMvcGxhbnMuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBVSxNQUFNLGVBQWUsQ0FBQztBQUNsRCxPQUFPLEVBQXdDLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBR2xGLE9BQU8sRUFBMEQsZUFBZSxFQUFFLGFBQWEsRUFBRSxvQkFBb0IsRUFBRSxZQUFZLEVBQW9CLE1BQU0sbUNBQW1DLENBQUM7QUFDak0sT0FBTyxPQUFPLE1BQU0sU0FBUyxDQUFDO0FBQzlCLE9BQU8sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDOzs7Ozs7Ozs7QUFPMUMsTUFBTSxPQUFPLGNBQWM7SUFzQ3ZCLFlBQ1ksS0FBcUIsRUFDckIsTUFBYyxFQUNkLFlBQTBCLEVBQzFCLFdBQXdCLEVBQ3hCLEVBQXNCLEVBQ3RCLFNBQTJCLEVBQzNCLGdCQUFrQztRQU5sQyxVQUFLLEdBQUwsS0FBSyxDQUFnQjtRQUNyQixXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQ2QsaUJBQVksR0FBWixZQUFZLENBQWM7UUFDMUIsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFDeEIsT0FBRSxHQUFGLEVBQUUsQ0FBb0I7UUFDdEIsY0FBUyxHQUFULFNBQVMsQ0FBa0I7UUFDM0IscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQXJDOUMsb0JBQW9CO1FBRXBCLGlCQUFZLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFFbEIsWUFB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LE1BQU0sR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBc0IsQ0FBQztRQUN0RSxNQUFNLENBQUMsTUFBTSxDQUFDLFVBQVUsSUFBSTtZQUN4QixZQUFZLENBQUMsSUFBSSxFQUFFLGlCQUFpQixDQUFDLENBQUM7UUFDMUMsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWE7UUFDZixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQzdELElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRTtZQUN6QixNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO1lBQ3pELElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNyQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7U0FDbkI7SUFDTCxDQUFDOzs0R0FsU1EsY0FBYztnR0FBZCxjQUFjLGlEQ2IzQix5bE1Bc0dBOzRGRHpGYSxjQUFjO2tCQUwxQixTQUFTOytCQUNJLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBVbnR5cGVkRm9ybUdyb3VwLCBVbnR5cGVkRm9ybUJ1aWxkZXIsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xyXG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XHJcbmltcG9ydCB7IFpvbmUsIFNwYWNlLCBQbGFuLCBNZW51SXRlbSwgU3BhY2VTZXJ2aWNlLCBQbGFuU2VydmljZSwgZ2V0TWV0YUZvckltYWdlLCBnZXRTaWduZWRGaWxlLCBkb3dubG9hZEZpbGVBc09iamVjdCwgZG93bmxvYWRCbG9iLCBOYXZpZ2F0b3JTZXJ2aWNlIH0gZnJvbSAnQHNtYXJ0ZXJwbGFuL25neC1zbWFydGVycGxhbi1jb3JlJztcclxuaW1wb3J0IHBhbnpvb20gZnJvbSAncGFuem9vbSc7XHJcbmltcG9ydCB7IFN1YmplY3QsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgICBzZWxlY3RvcjogJ2xpYi1wbGFucycsXHJcbiAgICB0ZW1wbGF0ZVVybDogJy4vcGxhbnMuY29tcG9uZW50Lmh0bWwnLFxyXG4gICAgc3R5bGVVcmxzOiBbJy4vcGxhbnMuY29tcG9uZW50LnNjc3MnXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgUGxhbnNDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xyXG5cclxuICAgIHNwYWNlSUQ6IHN0cmluZztcclxuXHJcbiAgICBjdXJyZW50U3BhY2U6IFNwYWNlO1xyXG5cclxuICAgIHBsYW5zOiBQbGFuW107XHJcblxyXG4gICAgLy8gY2hvc2VuUGxhbjogUGxhbjtcclxuXHJcbiAgICBpbmRleERldGFpbHMgPSAtMTtcclxuXHJcbiAgICBsb2FkaW5nID0gZmFsc2U7XHJcblxyXG4gICAgdXBsb2FkaW5nUGxhbiA9IGZhbHNlO1xyXG5cclxuICAgIHBsYW5Gb3JtOiBVbnR5cGVkRm9ybUdyb3VwO1xyXG5cclxuICAgIGlzQ3VycmVudFBsYW5Gb3Jab25lID0gZmFsc2U7XHJcblxyXG4gICAgY2FudmFzO1xyXG5cclxuICAgIHNjYWxlOiBudW1iZXI7XHJcblxyXG4gICAgcGFuem9vbTogYW55O1xyXG5cclxuICAgIGN1cnJlbnRab25lOiBab25lO1xyXG5cclxuICAgIGZpbGVUb1VwbG9hZDogRmlsZTtcclxuXHJcbiAgICBjaG9zZW5QbGFuSXNQZGYgPSBmYWxzZTtcclxuXHJcbiAgICB6b25lczogWm9uZVtdO1xyXG5cclxuICAgIG1lbnVJdGVtczogTWVudUl0ZW1bXSA9IFtdO1xyXG5cclxuICAgIGRlc3Ryb3kkID0gbmV3IFN1YmplY3QoKTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwcml2YXRlIHJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSxcclxuICAgICAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxyXG4gICAgICAgIHByaXZhdGUgc3BhY2VTZXJ2aWNlOiBTcGFjZVNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSBwbGFuU2VydmljZTogUGxhblNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSBmYjogVW50eXBlZEZvcm1CdWlsZGVyLFxyXG4gICAgICAgIHByaXZhdGUgdHJhbnNsYXRlOiBUcmFuc2xhdGVTZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgbmF2aWdhdG9yU2VydmljZTogTmF2aWdhdG9yU2VydmljZVxyXG4gICAgKSB7XHJcbiAgICAgICAgdGhpcy5uYXZpZ2F0b3JTZXJ2aWNlLmxvY2F0aW9uSURDaGFuZ2VcclxuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxyXG4gICAgICAgICAgICAuc3Vic2NyaWJlKChzcGFjZUlEKSA9PiB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbXCJkYXNoYm9hcmQvbG9jYWxpc2F0aW9uXCIsIHNwYWNlSUQsIFwicGxhbnNcIl0pO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgdGhpcy5yb3V0ZS5wYXJhbXMuc3Vic2NyaWJlKChwYXJhbXMpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5zcGFjZUlEID0gcGFyYW1zLmlkO1xyXG4gICAgICAgICAgICB0aGlzLmdldFBsYW5zKCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgICB0aGlzLnBsYW5TZXJ2aWNlLmdldFBsYW5GaWxlQ2FjaGUoKSAmJlxyXG4gICAgICAgICAgICB0aGlzLnBsYW5TZXJ2aWNlLmdldENob3NlblBsYW4oKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgICB0aGlzLmFkZFBsYW5Gcm9tQ2FjaGUoXHJcbiAgICAgICAgICAgICAgICB0aGlzLnBsYW5TZXJ2aWNlLmdldFBsYW5GaWxlQ2FjaGUoKSxcclxuICAgICAgICAgICAgICAgIHRoaXMucGxhblNlcnZpY2UuZ2V0Q2hvc2VuUGxhbigpLFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB0aGlzLnBsYW5TZXJ2aWNlLnNldFBsYW5GaWxlQ2FjaGUobnVsbCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMucGxhblNlcnZpY2Uuc2V0Q2hvc2VuUGxhbihudWxsKTtcclxuICAgIH1cclxuXHJcbiAgICBuZ09uRGVzdHJveSgpIHtcclxuICAgICAgICB0aGlzLmRlc3Ryb3kkLm5leHQodHJ1ZSk7XHJcbiAgICAgICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHNldHVwTWVudUl0ZW1zKCkge1xyXG4gICAgICAgIHRoaXMubWVudUl0ZW1zID0gW1xyXG4gICAgICAgICAgICB7IGxhYmVsOiBcIkxvY2F0aW9uc1wiLCB1cmw6IFwiL2xvY2FsaXNhdGlvblwiIH0sXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIGxhYmVsOiB0aGlzLmN1cnJlbnRTcGFjZS5uYW1lLFxyXG4gICAgICAgICAgICAgICAgdXJsOiBgL2xvY2FsaXNhdGlvbi8ke3RoaXMuY3VycmVudFNwYWNlLmlkfWAsXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIGxhYmVsOiBcIlBsYW5zXCIsXHJcbiAgICAgICAgICAgICAgICB1cmw6IGAvbG9jYWxpc2F0aW9uLyR7dGhpcy5jdXJyZW50U3BhY2UuaWR9L3BsYW5zYCxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIG9uR29CYWNrKCkgeyB9XHJcblxyXG4gICAgYXN5bmMgb25QbGFuQ2xpY2socGxhbj86IFBsYW4pIHtcclxuICAgICAgICBpZiAocGxhbikgdGhpcy5wbGFuU2VydmljZS5zZXRDaG9zZW5QbGFuKHBsYW4pO1xyXG4gICAgICAgIHRoaXMuY2hvc2VuUGxhbklzUGRmID0gcGxhbi5hbm5leGUuaW5jbHVkZXMoXCJwZGZcIik7XHJcbiAgICAgICAgaWYgKCF0aGlzLmNob3NlblBsYW5Jc1BkZikge1xyXG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlndXJlQ2FudmFzKCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wYW56b29tID0gcGFuem9vbSh0aGlzLmNhbnZhcywge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBib3VuZHM6IHRydWUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kc1BhZGRpbmc6IDAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heFpvb206IDMuNSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWluWm9vbTogMC4xLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsWm9vbTogMC41LFxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0sIDUwMCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIGNvbmZpZ3VyZUNhbnZhcygpIHtcclxuICAgICAgICB0aGlzLnVwbG9hZGluZ1BsYW4gPSB0cnVlO1xyXG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXCIjY2FudmFzXCIpIGFzIEhUTUxDYW52YXNFbGVtZW50O1xyXG4gICAgICAgIGNvbnN0IGltYWdlID0gYXdhaXQgZ2V0TWV0YUZvckltYWdlKHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5maWxlcGF0aCk7XHJcbiAgICAgICAgY2FudmFzLndpZHRoID0gaW1hZ2Uud2lkdGg7XHJcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IGltYWdlLmhlaWdodDtcclxuICAgICAgICB0aGlzLmNhbnZhcyA9IGNhbnZhcztcclxuICAgICAgICB0aGlzLmRyYXdJbWFnZSh0aGlzLmdldENob29zZW5QbGFuKCkuZmlsZXBhdGgpO1xyXG4gICAgICAgIHRoaXMudXBsb2FkaW5nUGxhbiA9IGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIGRyYXdJbWFnZSh1cmw6IHN0cmluZywgeCA9IDAsIHkgPSAwKSB7XHJcbiAgICAgICAgY29uc3QgaW1hZ2UgPSBuZXcgSW1hZ2UoKTtcclxuICAgICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xyXG4gICAgICAgIGNvbnN0IGltYWdlV2lkdGggPSB0aGlzLmNhbnZhcy53aWR0aDtcclxuICAgICAgICBjb25zdCBpbWFnZUhlaWdodCA9IHRoaXMuY2FudmFzLmhlaWdodDtcclxuICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKFwibG9hZFwiLCAoKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnRleHQuZHJhd0ltYWdlKFxyXG4gICAgICAgICAgICAgICAgaW1hZ2UsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIGltYWdlLndpZHRoLFxyXG4gICAgICAgICAgICAgICAgaW1hZ2UuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgICAgeCxcclxuICAgICAgICAgICAgICAgIHksXHJcbiAgICAgICAgICAgICAgICBpbWFnZVdpZHRoLFxyXG4gICAgICAgICAgICAgICAgaW1hZ2VIZWlnaHQsXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaW1hZ2Uuc3JjID0gdXJsO1xyXG4gICAgICAgIC8vIGltYWdlLmNyb3NzT3JpZ2luID0gXCIqXCI7IC8vbmVlZCB0byBkb3dubG9hZCBhcyBwbmcsXHJcbiAgICAgICAgLy8gQlVUOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80OTUwMzE3MS90aGUtaW1hZ2UtdGFnLXdpdGgtY3Jvc3NvcmlnaW4tYW5vbnltb3VzLWNhbnQtbG9hZC1zdWNjZXNzLWZyb20tczNcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBnZXRQbGFucygpIHtcclxuICAgICAgICB0aGlzLmxvYWRpbmcgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMuY3VycmVudFNwYWNlID0gYXdhaXQgdGhpcy5zcGFjZVNlcnZpY2UuZ2V0U3BhY2UodGhpcy5zcGFjZUlEKTtcclxuICAgICAgICB0aGlzLnNldHVwTWVudUl0ZW1zKCk7XHJcblxyXG4gICAgICAgIHRoaXMuem9uZXMgPSB0aGlzLmN1cnJlbnRTcGFjZS56b25lcy5pdGVtcztcclxuICAgICAgICB0aGlzLnBsYW5zID0gYXdhaXQgdGhpcy5wbGFuU2VydmljZS5nZXRTaW5nZWRQbGFuc0ZvclNwYWNlKHRoaXMuc3BhY2VJRCk7XHJcbiAgICAgICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XHJcbiAgICAgICAgaWYgKHRoaXMucGxhbnMubGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIHRoaXMub25QbGFuQ2xpY2sodGhpcy5wbGFuc1swXSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGdldENob29zZW5QbGFuKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnBsYW5TZXJ2aWNlLmdldENob3NlblBsYW4oKTtcclxuICAgIH1cclxuXHJcbiAgICByZW1vdmVJbWFnZSgpIHtcclxuICAgICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xyXG4gICAgICAgIGNvbnRleHQuY2xlYXJSZWN0KDAsIDAsIDQwOTYsIDQwOTYpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICpcclxuICAgICAqL1xyXG4gICAgb25DYWxpYnJhdGVDbGljaygpIHtcclxuICAgICAgICBpZiAodGhpcy5nZXRDaG9vc2VuUGxhbigpKSB7XHJcbiAgICAgICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFxyXG4gICAgICAgICAgICAgICAgW1wiL2Rhc2hib2FyZC9sb2NhbGlzYXRpb25cIiwgdGhpcy5zcGFjZUlELCBcInBsYW4tY2FsaWJyYXRpb25cIl0sXHJcbiAgICAgICAgICAgICAgICB7IHF1ZXJ5UGFyYW1zOiB7IHNwYWNlSUQ6IHRoaXMuc3BhY2VJRCB9IH0sXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICpcclxuICAgICAqL1xyXG4gICAgb25FZGl0Q2xpY2soKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZ2V0Q2hvb3NlblBsYW4oKSkge1xyXG4gICAgICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShcclxuICAgICAgICAgICAgICAgIFtcIi9kYXNoYm9hcmQvbG9jYWxpc2F0aW9uXCIsIHRoaXMuc3BhY2VJRCwgXCJwbGFuLWVkaXRcIl0sXHJcbiAgICAgICAgICAgICAgICB7IHF1ZXJ5UGFyYW1zOiB7IHNwYWNlSUQ6IHRoaXMuc3BhY2VJRCB9IH0sXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIG9uVXBsb2FkQ2xpY2soKSB7XHJcbiAgICAgICAgY29uc3QgaW5wdXRGaWxlID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcclxuICAgICAgICAgICAgXCIjdXBsb2FkLWZpbGVcIixcclxuICAgICAgICApIGFzIEhUTUxJbnB1dEVsZW1lbnQ7XHJcbiAgICAgICAgaW5wdXRGaWxlLmNsaWNrKCk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkUGxhbih0YXJnZXQ6IEV2ZW50VGFyZ2V0KSB7XHJcbiAgICAgICAgdGhpcy5maWxlVG9VcGxvYWQgPSAodGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQpLmZpbGVzWzBdO1xyXG4gICAgICAgIHRoaXMucGxhbkZvcm0gPSB0aGlzLmZiLmdyb3VwKHtcclxuICAgICAgICAgICAgbmFtZTogW3RoaXMuZmlsZVRvVXBsb2FkLm5hbWUsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXV0sXHJcbiAgICAgICAgICAgIHpvbmVJRDogW251bGwsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXV0sXHJcbiAgICAgICAgICAgIHNwYWNlSUQ6IHRoaXMuc3BhY2VJRCxcclxuICAgICAgICAgICAgaXNNb2RpZmllZDogZmFsc2UsXHJcbiAgICAgICAgICAgIGNhbGlicmF0aW9uOiBcIlwiLFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZFBsYW5Gcm9tQ2FjaGUoZmlsZTogRmlsZSwgcGxhbjogUGxhbikge1xyXG4gICAgICAgIHRoaXMuZmlsZVRvVXBsb2FkID0gZmlsZTtcclxuICAgICAgICB0aGlzLnBsYW5Gb3JtID0gdGhpcy5mYi5ncm91cCh7XHJcbiAgICAgICAgICAgIG5hbWU6IFt0aGlzLmZpbGVUb1VwbG9hZC5uYW1lLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF1dLFxyXG4gICAgICAgICAgICB6b25lSUQ6IFtwbGFuID8gcGxhbi56b25lSUQgOiBudWxsLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF1dLFxyXG4gICAgICAgICAgICBzcGFjZUlEOiB0aGlzLnNwYWNlSUQsXHJcbiAgICAgICAgICAgIGlzTW9kaWZpZWQ6ICEhcGxhbixcclxuICAgICAgICAgICAgY2FsaWJyYXRpb246XHJcbiAgICAgICAgICAgICAgICBwbGFuICYmIHBsYW4uaXNNb2RpZmllZCAmJiBwbGFuLmNhbGlicmF0aW9uXHJcbiAgICAgICAgICAgICAgICAgICAgPyBwbGFuLmNhbGlicmF0aW9uXHJcbiAgICAgICAgICAgICAgICAgICAgOiBcIlwiLFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uU2F2ZVBsYW4oKSB7XHJcbiAgICAgICAgY29uc3QgZm9ybVZhbHVlID0gdGhpcy5wbGFuRm9ybS52YWx1ZSBhcyBQbGFuO1xyXG4gICAgICAgIGZvcm1WYWx1ZS5pc0N1cnJlbnRGb3Jab25lID0gdGhpcy5pc0N1cnJlbnRQbGFuRm9yWm9uZTtcclxuICAgICAgICBjb25zdCBjcmVhdGVkUGxhbiA9IGF3YWl0IHRoaXMucGxhblNlcnZpY2UuY3JlYXRlUGxhbldpdGhBbm5leGUoXHJcbiAgICAgICAgICAgIGZvcm1WYWx1ZSxcclxuICAgICAgICAgICAgdGhpcy5maWxlVG9VcGxvYWQsXHJcbiAgICAgICAgKTtcclxuICAgICAgICBjb25zdCBmaWxlcGF0aCA9IGF3YWl0IGdldFNpZ25lZEZpbGUoY3JlYXRlZFBsYW4uYW5uZXhlKTtcclxuICAgICAgICBpZiAoZmlsZXBhdGgpIHtcclxuICAgICAgICAgICAgY3JlYXRlZFBsYW4uZmlsZXBhdGggPSBmaWxlcGF0aDtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGZvcm1WYWx1ZS5pc0N1cnJlbnRGb3Jab25lKSB7XHJcbiAgICAgICAgICAgIC8vIHNldCBhbGwgb3RoZXIgcGxhbnMgdG8gbm90IGN1cnJlbnRcclxuICAgICAgICAgICAgdGhpcy5wbGFuU2VydmljZS5zZXRBbGxQbGFuc0ZvclpvbmVOb3RDdXJyZW50KFxyXG4gICAgICAgICAgICAgICAgY3JlYXRlZFBsYW4uem9uZUlELFxyXG4gICAgICAgICAgICAgICAgY3JlYXRlZFBsYW4uaWQsXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMucGxhbnMucHVzaChjcmVhdGVkUGxhbik7XHJcbiAgICAgICAgdGhpcy5wbGFuRm9ybSA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5maWxlVG9VcGxvYWQgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIG9uQ2FuY2VsVXBsb2FkKCkge1xyXG4gICAgICAgIHRoaXMuZmlsZVRvVXBsb2FkID0gbnVsbDtcclxuICAgICAgICB0aGlzLnBsYW5Gb3JtID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvbkN1cnJlbnRQbGFuQ2xpY2soKSB7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5wbGFuU2VydmljZS51cGRhdGVQbGFuKHtcclxuICAgICAgICAgICAgaWQ6IHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5pZCxcclxuICAgICAgICAgICAgaXNDdXJyZW50Rm9yWm9uZTogdGhpcy5nZXRDaG9vc2VuUGxhbigpLmlzQ3VycmVudEZvclpvbmUsXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaWYgKHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5pc0N1cnJlbnRGb3Jab25lKSB7XHJcbiAgICAgICAgICAgIHRoaXMucGxhblNlcnZpY2Uuc2V0QWxsUGxhbnNGb3Jab25lTm90Q3VycmVudChcclxuICAgICAgICAgICAgICAgIHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS56b25lSUQsXHJcbiAgICAgICAgICAgICAgICB0aGlzLmdldENob29zZW5QbGFuKCkuaWQsXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uRG93bmxvYWRDbGljaygpIHtcclxuICAgICAgICBjb25zdCBzaWduZWRGaWxlID0gYXdhaXQgZG93bmxvYWRGaWxlQXNPYmplY3QoXHJcbiAgICAgICAgICAgIHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5hbm5leGUsXHJcbiAgICAgICAgKTtcclxuICAgICAgICBpZiAoc2lnbmVkRmlsZSkge1xyXG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgICAgICAgIGRvd25sb2FkQmxvYihzaWduZWRGaWxlLkJvZHksIHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5uYW1lKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgb25Eb3dubG9hZEFzUG5nKCkge1xyXG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXCIjY2FudmFzXCIpIGFzIEhUTUxDYW52YXNFbGVtZW50O1xyXG4gICAgICAgIGNhbnZhcy50b0Jsb2IoZnVuY3Rpb24gKGJsb2IpIHtcclxuICAgICAgICAgICAgZG93bmxvYWRCbG9iKGJsb2IsIFwicGxhbi1hcy1wbmcucG5nXCIpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uUmVtb3ZlQ2xpY2soKSB7XHJcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IHRoaXMudHJhbnNsYXRlLmluc3RhbnQoXCJjb25maXJtLmRlbGV0ZVBsYW5cIik7XHJcbiAgICAgICAgaWYgKHdpbmRvdy5jb25maXJtKG1lc3NhZ2UpKSB7XHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGxhblNlcnZpY2UuZGVsZXRlUGxhbih0aGlzLmdldENob29zZW5QbGFuKCkpO1xyXG4gICAgICAgICAgICB0aGlzLnJlbW92ZUltYWdlKCk7XHJcbiAgICAgICAgICAgIHRoaXMucGxhblNlcnZpY2Uuc2V0Q2hvc2VuUGxhbihudWxsKTtcclxuICAgICAgICAgICAgdGhpcy5nZXRQbGFucygpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCI8ZGl2IGNsYXNzPVwiY29udGFpbmVyLWZsdWlkXCIgKm5nSWY9XCJjdXJyZW50U3BhY2VcIiBjbGFzcz1cImRhc2hib2FyZC10YWJcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJtLTNcIj5cclxuICAgICAgICA8bGliLXRhYi1uYXZpZ2F0aW9uIFttZW51SXRlbXNdPSdtZW51SXRlbXMnIChvbkdvQmFjayk9XCJvbkdvQmFjaygpXCI+PC9saWItdGFiLW5hdmlnYXRpb24+XHJcbiAgICA8L2Rpdj5cclxuICAgIDxkaXYgY2xhc3M9XCJkLWZsZXgganVzdGlmeS1jb250ZW50LWNlbnRlclwiICpuZ0lmPVwibG9hZGluZ1wiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJzcGlubmVyLWJvcmRlclwiIHJvbGU9XCJzdGF0dXNcIj5cclxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ2aXN1YWxseS1oaWRkZW5cIj5Mb2FkaW5nLi4uPC9zcGFuPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbiAgICA8ZGl2IGNsYXNzPVwibXQtM1wiICpuZ0lmPVwiIXBsYW5zICYmICFsb2FkaW5nXCI+XHJcbiAgICAgICAgPGg0IHN0eWxlPVwiZm9udC13ZWlnaHQ6IGJvbGQ7XCI+e3snTm8gaW1wb3J0ZWQgcGxhbnMnIHwgdHJhbnNsYXRlIH19PC9oND5cclxuICAgICAgICA8cD57eydGb3IgaW1wb3J0IGZyb20gM0QgdmlzaXQ6IGdvIFZpcnR1YWwgVmlzaXRzID0+IEltcG9ydCBJbWFnZXMnIHwgdHJhbnNsYXRlfX08L3A+XHJcbiAgICA8L2Rpdj5cclxuICAgIDxkaXYgY2xhc3M9XCJyb3cgbXMtMVwiPlxyXG4gICAgICAgIDxkaXYgbmdiRHJvcGRvd24gY2xhc3M9XCJkLWlubGluZS1ibG9jayBtZS0zXCI+XHJcbiAgICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJidG4gYnRuLWxhYmVsLWZpbGUgcm91bmRlZC1waWxsXCIgaWQ9XCJkcm9wZG93bkJhc2ljMVwiIG5nYkRyb3Bkb3duVG9nZ2xlPnt7Z2V0Q2hvb3NlblBsYW4oKSA/XHJcbiAgICAgICAgICAgICAgICBnZXRDaG9vc2VuUGxhbigpLm5hbWU6ICgnQ2hvb3NlIFBsYW4nIHwgdHJhbnNsYXRlKSB9fTwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8ZGl2IG5nYkRyb3Bkb3duTWVudSBhcmlhLWxhYmVsbGVkYnk9XCJkcm9wZG93bkJhc2ljMVwiPlxyXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiBuZ2JEcm9wZG93bkl0ZW0gKm5nRm9yPVwibGV0IHBsYW4gb2YgcGxhbnNcIiAoY2xpY2spPVwib25QbGFuQ2xpY2socGxhbilcIj57e3BsYW4ubmFtZSB9fVxyXG4gICAgICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJkLWlubGluZS1ibG9ja1wiIG5nYkRyb3Bkb3duICNteURyb3A9XCJuZ2JEcm9wZG93blwiPlxyXG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1sYWJlbC1maWxlIHJvdW5kZWQtcGlsbFwiIGlkPVwiZHJvcGRvd25NYW51YWxcIiBuZ2JEcm9wZG93blRvZ2dsZT57eydDaG9vc2UgYWN0aW9uJyB8XHJcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8ZGl2IG5nYkRyb3Bkb3duTWVudSBhcmlhLWxhYmVsbGVkYnk9XCJkcm9wZG93bk1hbnVhbFwiPlxyXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiAoY2xpY2spPVwib25DYWxpYnJhdGVDbGljaygpXCIgbmdiRHJvcGRvd25JdGVtIFtkaXNhYmxlZF09XCIhZ2V0Q2hvb3NlblBsYW4oKVwiPnt7J0NhbGlicmF0ZScgfFxyXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19PC9idXR0b24+XHJcbiAgICAgICAgICAgICAgICA8YnV0dG9uIChjbGljayk9XCJvbkVkaXRDbGljaygpXCIgbmdiRHJvcGRvd25JdGVtIFtkaXNhYmxlZF09XCIhZ2V0Q2hvb3NlblBsYW4oKVwiPnt7J0VkaXQgcGxhbicgfFxyXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19XHJcbiAgICAgICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cIm9uVXBsb2FkQ2xpY2soKVwiIG5nYkRyb3Bkb3duSXRlbT57eydVcGxvYWQgbmV3IHBsYW4nIHwgdHJhbnNsYXRlfX08L2J1dHRvbj5cclxuICAgICAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cIm9uRG93bmxvYWRDbGljaygpXCIgbmdiRHJvcGRvd25JdGVtIFtkaXNhYmxlZF09XCIhZ2V0Q2hvb3NlblBsYW4oKVwiPnt7J0Rvd25sb2FkIHBsYW4nIHxcclxuICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiAoY2xpY2spPVwib25SZW1vdmVDbGljaygpXCIgbmdiRHJvcGRvd25JdGVtXHJcbiAgICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFnZXRDaG9vc2VuUGxhbigpIHx8IGdldENob29zZW5QbGFuKCkuaXNJbXBvcnRlZE1hdHRlcnBvcnRcIj57eydEZWxldGUgcGxhbicgfFxyXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19PC9idXR0b24+XHJcbiAgICAgICAgICAgICAgICA8IS0tIDxidXR0b24gKGNsaWNrKT1cIm9uRG93bmxvYWRBc1BuZygpXCIgbmdiRHJvcGRvd25JdGVtIFtkaXNhYmxlZF09XCIhZ2V0Q2hvb3NlblBsYW4oKVwiPlxyXG4gICAgICAgICAgICAgICAgICAgIHt7J0Rvd25sb2FkIHBsYW4gYXMgUE5HJyB8IHRyYW5zbGF0ZX19PC9idXR0b24+IC0tPlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgIDwvZGl2PlxyXG4gICAgPGRpdiBjbGFzcz1cInJvdyBtdC0zIG1zLTBcIj5cclxuICAgICAgICA8aDQgKm5nSWY9XCJmaWxlVG9VcGxvYWRcIj57eydOZXcgcGxhbicgfCB0cmFuc2xhdGUgfX08L2g0PlxyXG4gICAgICAgIDxpbnB1dCBjbGFzcz1cImhpZGRlblwiIHR5cGU9XCJmaWxlXCIgaWQ9XCJ1cGxvYWQtZmlsZVwiIG5hbWU9XCJ1cGxvYWQtZmlsZVwiIGFjY2VwdD1cImltYWdlL3BuZywgaW1hZ2UvanBlZywgLnBkZiwgLnN2Z1wiXHJcbiAgICAgICAgICAgIG5nZi1tYXgtc2l6ZT1cIjZNQlwiIChjaGFuZ2UpPVwiYWRkUGxhbigkZXZlbnQudGFyZ2V0KVwiPlxyXG4gICAgPC9kaXY+XHJcbiAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTYgbXQtM1wiICpuZ0lmPVwicGxhbkZvcm1cIj5cclxuICAgICAgICA8Zm9ybSAobmdTdWJtaXQpPVwib25TYXZlUGxhbigpXCIgW2Zvcm1Hcm91cF09XCJwbGFuRm9ybVwiPlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibWItMyByb3dcIj5cclxuICAgICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNvbC1zbS0zXCI+e3snTmFtZScgfCB0cmFuc2xhdGV9fSA8L2xhYmVsPlxyXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1zbS05XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBmb3JtQ29udHJvbE5hbWU9XCJuYW1lXCI+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtYi0zIHJvd1wiPlxyXG4gICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY29sLXNtLTNcIj57eydab25lJyB8IHRyYW5zbGF0ZX19IDwvbGFiZWw+XHJcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLXNtLTlcIj5cclxuICAgICAgICAgICAgICAgICAgICA8c2VsZWN0IGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZm9ybUNvbnRyb2xOYW1lPVwiem9uZUlEXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gKm5nRm9yPVwibGV0IHpvbmUgb2Ygem9uZXNcIiBbbmdWYWx1ZV09XCJ6b25lLmlkXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7eyB6b25lLm5hbWUgfX1cclxuICAgICAgICAgICAgICAgICAgICAgICAgPC9vcHRpb24+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9zZWxlY3Q+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtYi0zIHJvd1wiPlxyXG4gICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY29sLXNtLTNcIj57eydTZXQgYXMgY3VycmVudCBwbGFuIGZvciB6b25lJyB8IHRyYW5zbGF0ZX19PC9sYWJlbD5cclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtc20tM1wiPlxyXG4gICAgICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBbKG5nTW9kZWwpXT1cImlzQ3VycmVudFBsYW5Gb3Jab25lXCIgW25nTW9kZWxPcHRpb25zXT1cIntzdGFuZGFsb25lOiB0cnVlfVwiPlxyXG4gICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8YnV0dG9uIFtkaXNhYmxlZF09XCJwbGFuRm9ybS5pbnZhbGlkXCIgdHlwZT0nc3VibWl0JyBjbGFzcz1cImJ0biBidG4tbGFiZWwtZmlsZSByb3VuZGVkLXBpbGxcIj57eydTYXZlJyB8XHJcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1sYWJlbC1maWxlIHJvdW5kZWQtcGlsbCBtcy0zXCIgdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJvbkNhbmNlbFVwbG9hZCgpXCI+e3snQ2FuY2VsJyB8XHJcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxyXG4gICAgICAgIDwvZm9ybT5cclxuICAgIDwvZGl2PlxyXG4gICAgPHVsIGNsYXNzPVwiY29sLW1kLTYgbGlzdC1ncm91cCBsaXN0LWdyb3VwLWZsdXNoXCIgKm5nSWY9XCJnZXRDaG9vc2VuUGxhbigpXCI+XHJcbiAgICAgICAgPGxpIGNsYXNzPVwibGlzdC1ncm91cC1pdGVtIGJnLXRyYW5zcGFyZW50XCI+e3snTmFtZScgfCB0cmFuc2xhdGUgfX0gOiB7e2dldENob29zZW5QbGFuKCkubmFtZX19IDwvbGk+XHJcbiAgICAgICAgPGxpIGNsYXNzPVwibGlzdC1ncm91cC1pdGVtIGJnLXRyYW5zcGFyZW50XCI+IHt7J1BsYW4gaXMgJyB8IHRyYW5zbGF0ZSB9fSA6XHJcbiAgICAgICAgICAgIHt7Z2V0Q2hvb3NlblBsYW4oKS5jYWxpYnJhdGlvbiA/ICgnQ2FsaWJyYXRlZCcgfCB0cmFuc2xhdGUpIDogKCdOb3QgY2FsaWJyYXRlZCcgfCB0cmFuc2xhdGUpfX08L2xpPlxyXG4gICAgICAgIDxsaSBjbGFzcz1cImxpc3QtZ3JvdXAtaXRlbSBiZy10cmFuc3BhcmVudFwiPnt7J0F0dHJpYnV0ZWQgdG8gem9uZSAnIHwgdHJhbnNsYXRlIH19IDpcclxuICAgICAgICAgICAge3tnZXRDaG9vc2VuUGxhbigpLnpvbmUgPyBnZXRDaG9vc2VuUGxhbigpLnpvbmUubmFtZSA6ICdOb25lJ319PC9saT5cclxuICAgICAgICA8bGkgY2xhc3M9XCJsaXN0LWdyb3VwLWl0ZW0gYmctdHJhbnNwYXJlbnRcIj57eydJcyBjdXJyZW50IHBsYW4gZm9yIHpvbmUgJyB8IHRyYW5zbGF0ZSB9fSA6XHJcbiAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBbKG5nTW9kZWwpXT1cImdldENob29zZW5QbGFuKCkuaXNDdXJyZW50Rm9yWm9uZVwiIChjaGFuZ2UpPVwib25DdXJyZW50UGxhbkNsaWNrKClcIj5cclxuICAgICAgICA8L2xpPlxyXG5cclxuICAgIDwvdWw+XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cInJvdyBtdC00XCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1tZC0xMFwiPlxyXG4gICAgICAgICAgICA8ZW1iZWQgKm5nSWY9XCJnZXRDaG9vc2VuUGxhbigpICYmIGNob3NlblBsYW5Jc1BkZlwiIFtzcmNdPVwiZ2V0Q2hvb3NlblBsYW4oKS5maWxlcGF0aCB8IHNhZmVVcmxcIlxyXG4gICAgICAgICAgICAgICAgdHlwZT1cImFwcGxpY2F0aW9uL3BkZlwiIGZyYW1lQm9yZGVyPVwiMFwiIHNjcm9sbGluZz1cImF1dG9cIiBoZWlnaHQ9XCI2NTBweDtcIiB3aWR0aD1cIjEwMCVcIiAvPlxyXG4gICAgICAgICAgICA8ZGl2ICpuZ0lmPVwiIWNob3NlblBsYW5Jc1BkZlwiIGNsYXNzPVwicm93XCIgc3R5bGU9XCJoZWlnaHQ6IDUwMHB4OyBvdmVyZmxvdzogaGlkZGVuO1wiIGlkPVwiY2FudmFzRGl2XCI+XHJcbiAgICAgICAgICAgICAgICA8Y2FudmFzIGlkPVwiY2FudmFzXCIgd2lkdGg9XCI0MDk2cHhcIiBoZWlnaHQ9XCI0MDk2cHhcIj5cclxuICAgICAgICAgICAgICAgICAgICA8IS0tIDxpbWcgKm5nSWY9XCJjaG9zZW5QbGFuXCIgaWQ9XCJwbGFuLWltYWdlXCIgW3NyY109XCJjaG9zZW5QbGFuLmZpbGVwYXRoXCIgc3R5bGU9XCJ3aWR0aDogMTAwJTtcIj4gLS0+XHJcbiAgICAgICAgICAgICAgICA8L2NhbnZhcz5cclxuXHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbjwvZGl2PlxyXG4iXX0=
1
+ import { Component } from '@angular/core';
2
+ import { Validators } from '@angular/forms';
3
+ import { getMetaForImage, getSignedFile, downloadFileAsObject, downloadBlob } from '@smarterplan/ngx-smarterplan-core';
4
+ import panzoom from 'panzoom';
5
+ import { Subject, takeUntil } from 'rxjs';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@angular/router";
8
+ import * as i2 from "@smarterplan/ngx-smarterplan-core";
9
+ import * as i3 from "@angular/forms";
10
+ import * as i4 from "@ngx-translate/core";
11
+ import * as i5 from "@ng-bootstrap/ng-bootstrap";
12
+ import * as i6 from "@angular/common";
13
+ import * as i7 from "../tab-navigation/tab-navigation.component";
14
+ class PlansComponent {
15
+ route;
16
+ router;
17
+ spaceService;
18
+ planService;
19
+ fb;
20
+ translate;
21
+ navigatorService;
22
+ spaceID;
23
+ currentSpace;
24
+ plans;
25
+ // chosenPlan: Plan;
26
+ indexDetails = -1;
27
+ loading = false;
28
+ uploadingPlan = false;
29
+ planForm;
30
+ isCurrentPlanForZone = false;
31
+ canvas;
32
+ scale;
33
+ panzoom;
34
+ currentZone;
35
+ fileToUpload;
36
+ chosenPlanIsPdf = false;
37
+ zones;
38
+ menuItems = [];
39
+ destroy$ = new Subject();
40
+ constructor(route, router, spaceService, planService, fb, translate, navigatorService) {
41
+ this.route = route;
42
+ this.router = router;
43
+ this.spaceService = spaceService;
44
+ this.planService = planService;
45
+ this.fb = fb;
46
+ this.translate = translate;
47
+ this.navigatorService = navigatorService;
48
+ this.navigatorService.locationIDChange
49
+ .pipe(takeUntil(this.destroy$))
50
+ .subscribe((spaceID) => {
51
+ this.router.navigate(["dashboard/localisation", spaceID, "plans"]);
52
+ });
53
+ this.route.params.subscribe((params) => {
54
+ this.spaceID = params.id;
55
+ this.getPlans();
56
+ });
57
+ }
58
+ ngOnInit() {
59
+ if (this.planService.getPlanFileCache() &&
60
+ this.planService.getChosenPlan()) {
61
+ this.addPlanFromCache(this.planService.getPlanFileCache(), this.planService.getChosenPlan());
62
+ this.planService.setPlanFileCache(null);
63
+ }
64
+ this.planService.setChosenPlan(null);
65
+ }
66
+ ngOnDestroy() {
67
+ this.destroy$.next(true);
68
+ this.destroy$.complete();
69
+ }
70
+ setupMenuItems() {
71
+ this.menuItems = [
72
+ { label: "Locations", url: "/localisation" },
73
+ {
74
+ label: this.currentSpace.name,
75
+ url: `/localisation/${this.currentSpace.id}`,
76
+ },
77
+ {
78
+ label: "Plans",
79
+ url: `/localisation/${this.currentSpace.id}/plans`,
80
+ },
81
+ ];
82
+ }
83
+ onGoBack() { }
84
+ async onPlanClick(plan) {
85
+ if (plan)
86
+ this.planService.setChosenPlan(plan);
87
+ this.chosenPlanIsPdf = plan.annexe.includes("pdf");
88
+ if (!this.chosenPlanIsPdf) {
89
+ setTimeout(() => {
90
+ this.configureCanvas().then(() => {
91
+ this.panzoom = panzoom(this.canvas, {
92
+ bounds: true,
93
+ boundsPadding: 0,
94
+ maxZoom: 3.5,
95
+ minZoom: 0.1,
96
+ initialZoom: 0.5,
97
+ });
98
+ });
99
+ }, 500);
100
+ }
101
+ }
102
+ async configureCanvas() {
103
+ this.uploadingPlan = true;
104
+ const canvas = document.querySelector("#canvas");
105
+ const image = await getMetaForImage(this.getChoosenPlan().filepath);
106
+ canvas.width = image.width;
107
+ canvas.height = image.height;
108
+ this.canvas = canvas;
109
+ this.drawImage(this.getChoosenPlan().filepath);
110
+ this.uploadingPlan = false;
111
+ }
112
+ drawImage(url, x = 0, y = 0) {
113
+ const image = new Image();
114
+ const context = this.canvas.getContext("2d");
115
+ const imageWidth = this.canvas.width;
116
+ const imageHeight = this.canvas.height;
117
+ image.addEventListener("load", () => {
118
+ context.drawImage(image, 0, 0, image.width, image.height, x, y, imageWidth, imageHeight);
119
+ });
120
+ image.src = url;
121
+ // image.crossOrigin = "*"; //need to download as png,
122
+ // BUT: https://stackoverflow.com/questions/49503171/the-image-tag-with-crossorigin-anonymous-cant-load-success-from-s3
123
+ }
124
+ async getPlans() {
125
+ this.loading = true;
126
+ this.currentSpace = await this.spaceService.getSpace(this.spaceID);
127
+ this.setupMenuItems();
128
+ this.zones = this.currentSpace.zones.items;
129
+ this.plans = await this.planService.getSingedPlansForSpace(this.spaceID);
130
+ this.loading = false;
131
+ if (this.plans.length === 1) {
132
+ this.onPlanClick(this.plans[0]);
133
+ }
134
+ }
135
+ getChoosenPlan() {
136
+ return this.planService.getChosenPlan();
137
+ }
138
+ removeImage() {
139
+ const context = this.canvas.getContext("2d");
140
+ context.clearRect(0, 0, 4096, 4096);
141
+ }
142
+ /**
143
+ *
144
+ */
145
+ onCalibrateClick() {
146
+ if (this.getChoosenPlan()) {
147
+ this.router.navigate(["/dashboard/localisation", this.spaceID, "plan-calibration"], { queryParams: { spaceID: this.spaceID } });
148
+ }
149
+ }
150
+ /**
151
+ *
152
+ */
153
+ onEditClick() {
154
+ if (this.getChoosenPlan()) {
155
+ this.router.navigate(["/dashboard/localisation", this.spaceID, "plan-edit"], { queryParams: { spaceID: this.spaceID } });
156
+ }
157
+ }
158
+ onUploadClick() {
159
+ const inputFile = document.querySelector("#upload-file");
160
+ inputFile.click();
161
+ }
162
+ addPlan(target) {
163
+ this.fileToUpload = target.files[0];
164
+ this.planForm = this.fb.group({
165
+ name: [this.fileToUpload.name, [Validators.required]],
166
+ zoneID: [null, [Validators.required]],
167
+ spaceID: this.spaceID,
168
+ isModified: false,
169
+ calibration: "",
170
+ });
171
+ }
172
+ addPlanFromCache(file, plan) {
173
+ this.fileToUpload = file;
174
+ this.planForm = this.fb.group({
175
+ name: [this.fileToUpload.name, [Validators.required]],
176
+ zoneID: [plan ? plan.zoneID : null, [Validators.required]],
177
+ spaceID: this.spaceID,
178
+ isModified: !!plan,
179
+ calibration: plan && plan.isModified && plan.calibration
180
+ ? plan.calibration
181
+ : "",
182
+ });
183
+ }
184
+ async onSavePlan() {
185
+ const formValue = this.planForm.value;
186
+ formValue.isCurrentForZone = this.isCurrentPlanForZone;
187
+ const createdPlan = await this.planService.createPlanWithAnnexe(formValue, this.fileToUpload);
188
+ const filepath = await getSignedFile(createdPlan.annexe);
189
+ if (filepath) {
190
+ createdPlan.filepath = filepath;
191
+ }
192
+ if (formValue.isCurrentForZone) {
193
+ // set all other plans to not current
194
+ this.planService.setAllPlansForZoneNotCurrent(createdPlan.zoneID, createdPlan.id);
195
+ }
196
+ this.plans.push(createdPlan);
197
+ this.planForm = null;
198
+ this.fileToUpload = null;
199
+ }
200
+ onCancelUpload() {
201
+ this.fileToUpload = null;
202
+ this.planForm = null;
203
+ }
204
+ async onCurrentPlanClick() {
205
+ await this.planService.updatePlan({
206
+ id: this.getChoosenPlan().id,
207
+ isCurrentForZone: this.getChoosenPlan().isCurrentForZone,
208
+ });
209
+ if (this.getChoosenPlan().isCurrentForZone) {
210
+ this.planService.setAllPlansForZoneNotCurrent(this.getChoosenPlan().zoneID, this.getChoosenPlan().id);
211
+ }
212
+ }
213
+ async onDownloadClick() {
214
+ const signedFile = await downloadFileAsObject(this.getChoosenPlan().annexe);
215
+ if (signedFile) {
216
+ // @ts-ignore
217
+ downloadBlob(signedFile.Body, this.getChoosenPlan().name);
218
+ }
219
+ }
220
+ async onDownloadAsPng() {
221
+ const canvas = document.querySelector("#canvas");
222
+ canvas.toBlob(function (blob) {
223
+ downloadBlob(blob, "plan-as-png.png");
224
+ });
225
+ }
226
+ async onRemoveClick() {
227
+ const message = this.translate.instant("confirm.deletePlan");
228
+ if (window.confirm(message)) {
229
+ await this.planService.deletePlan(this.getChoosenPlan());
230
+ this.removeImage();
231
+ this.planService.setChosenPlan(null);
232
+ this.getPlans();
233
+ }
234
+ }
235
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlansComponent, deps: [{ token: i1.ActivatedRoute }, { token: i1.Router }, { token: i2.SpaceService }, { token: i2.PlanService }, { token: i3.UntypedFormBuilder }, { token: i4.TranslateService }, { token: i2.NavigatorService }], target: i0.ɵɵFactoryTarget.Component });
236
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: PlansComponent, selector: "lib-plans", ngImport: i0, template: "<div class=\"container-fluid\" *ngIf=\"currentSpace\" class=\"dashboard-tab\">\r\n <div class=\"m-3\">\r\n <lib-tab-navigation [menuItems]='menuItems' (onGoBack)=\"onGoBack()\"></lib-tab-navigation>\r\n </div>\r\n <div class=\"d-flex justify-content-center\" *ngIf=\"loading\">\r\n <div class=\"spinner-border\" role=\"status\">\r\n <span class=\"visually-hidden\">Loading...</span>\r\n </div>\r\n </div>\r\n <div class=\"mt-3\" *ngIf=\"!plans && !loading\">\r\n <h4 style=\"font-weight: bold;\">{{'No imported plans' | translate }}</h4>\r\n <p>{{'For import from 3D visit: go Virtual Visits => Import Images' | translate}}</p>\r\n </div>\r\n <div class=\"row ms-1\">\r\n <div ngbDropdown class=\"d-inline-block me-3\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownBasic1\" ngbDropdownToggle>{{getChoosenPlan() ?\r\n getChoosenPlan().name: ('Choose Plan' | translate) }}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownBasic1\">\r\n <button ngbDropdownItem *ngFor=\"let plan of plans\" (click)=\"onPlanClick(plan)\">{{plan.name }}\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"d-inline-block\" ngbDropdown #myDrop=\"ngbDropdown\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownManual\" ngbDropdownToggle>{{'Choose action' |\r\n translate}}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownManual\">\r\n <button (click)=\"onCalibrateClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Calibrate' |\r\n translate}}</button>\r\n <button (click)=\"onEditClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Edit plan' |\r\n translate}}\r\n </button>\r\n <button (click)=\"onUploadClick()\" ngbDropdownItem>{{'Upload new plan' | translate}}</button>\r\n <button (click)=\"onDownloadClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Download plan' |\r\n translate}}</button>\r\n <button (click)=\"onRemoveClick()\" ngbDropdownItem\r\n [disabled]=\"!getChoosenPlan() || getChoosenPlan().isImportedMatterport\">{{'Delete plan' |\r\n translate}}</button>\r\n <!-- <button (click)=\"onDownloadAsPng()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">\r\n {{'Download plan as PNG' | translate}}</button> -->\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"row mt-3 ms-0\">\r\n <h4 *ngIf=\"fileToUpload\">{{'New plan' | translate }}</h4>\r\n <input class=\"hidden\" type=\"file\" id=\"upload-file\" name=\"upload-file\" accept=\"image/png, image/jpeg, .pdf, .svg\"\r\n ngf-max-size=\"6MB\" (change)=\"addPlan($event.target)\">\r\n </div>\r\n <div class=\"col-md-6 mt-3\" *ngIf=\"planForm\">\r\n <form (ngSubmit)=\"onSavePlan()\" [formGroup]=\"planForm\">\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Name' | translate}} </label>\r\n <div class=\"col-sm-9\">\r\n <input type=\"text\" class=\"form-control\" formControlName=\"name\">\r\n </div>\r\n </div>\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Zone' | translate}} </label>\r\n <div class=\"col-sm-9\">\r\n <select class=\"form-control\" formControlName=\"zoneID\">\r\n <option *ngFor=\"let zone of zones\" [ngValue]=\"zone.id\">\r\n {{ zone.name }}\r\n </option>\r\n </select>\r\n </div>\r\n </div>\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Set as current plan for zone' | translate}}</label>\r\n <div class=\"col-sm-3\">\r\n <input type=\"checkbox\" [(ngModel)]=\"isCurrentPlanForZone\" [ngModelOptions]=\"{standalone: true}\">\r\n </div>\r\n </div>\r\n <button [disabled]=\"planForm.invalid\" type='submit' class=\"btn btn-label-file rounded-pill\">{{'Save' |\r\n translate}}</button>\r\n <button class=\"btn btn-label-file rounded-pill ms-3\" type=\"button\" (click)=\"onCancelUpload()\">{{'Cancel' |\r\n translate}}</button>\r\n </form>\r\n </div>\r\n <ul class=\"col-md-6 list-group list-group-flush\" *ngIf=\"getChoosenPlan()\">\r\n <li class=\"list-group-item bg-transparent\">{{'Name' | translate }} : {{getChoosenPlan().name}} </li>\r\n <li class=\"list-group-item bg-transparent\"> {{'Plan is ' | translate }} :\r\n {{getChoosenPlan().calibration ? ('Calibrated' | translate) : ('Not calibrated' | translate)}}</li>\r\n <li class=\"list-group-item bg-transparent\">{{'Attributed to zone ' | translate }} :\r\n {{getChoosenPlan().zone ? getChoosenPlan().zone.name : 'None'}}</li>\r\n <li class=\"list-group-item bg-transparent\">{{'Is current plan for zone ' | translate }} :\r\n <input type=\"checkbox\" [(ngModel)]=\"getChoosenPlan().isCurrentForZone\" (change)=\"onCurrentPlanClick()\">\r\n </li>\r\n\r\n </ul>\r\n\r\n <div class=\"row mt-4\">\r\n <div class=\"col-md-10\">\r\n <embed *ngIf=\"getChoosenPlan() && chosenPlanIsPdf\" [src]=\"getChoosenPlan().filepath | safeUrl\"\r\n type=\"application/pdf\" frameBorder=\"0\" scrolling=\"auto\" height=\"650px;\" width=\"100%\" />\r\n <div *ngIf=\"!chosenPlanIsPdf\" class=\"row\" style=\"height: 500px; overflow: hidden;\" id=\"canvasDiv\">\r\n <canvas id=\"canvas\" width=\"4096px\" height=\"4096px\">\r\n <!-- <img *ngIf=\"chosenPlan\" id=\"plan-image\" [src]=\"chosenPlan.filepath\" style=\"width: 100%;\"> -->\r\n </canvas>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".button-visit{display:none;height:30px;width:30px;position:absolute;background:url(https://api.iconify.design/mdi:map-marker-check.svg?color=red&height=30) no-repeat scroll 0 0 transparent;border:none}#button-visit-left{left:350px;top:550px}#button-visit-right{left:500px;top:600px}.hidden{visibility:hidden;width:1px;height:1px}\n"], dependencies: [{ kind: "directive", type: i5.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "popperOptions", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { kind: "directive", type: i5.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { kind: "directive", type: i5.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { kind: "directive", type: i5.NgbDropdownItem, selector: "[ngbDropdownItem]", inputs: ["disabled"] }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i7.TabNavigationComponent, selector: "lib-tab-navigation", inputs: ["menuItems"], outputs: ["onGoBack"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }, { kind: "pipe", type: i2.SafeUrlPipe, name: "safeUrl" }] });
237
+ }
238
+ export { PlansComponent };
239
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlansComponent, decorators: [{
240
+ type: Component,
241
+ args: [{ selector: 'lib-plans', template: "<div class=\"container-fluid\" *ngIf=\"currentSpace\" class=\"dashboard-tab\">\r\n <div class=\"m-3\">\r\n <lib-tab-navigation [menuItems]='menuItems' (onGoBack)=\"onGoBack()\"></lib-tab-navigation>\r\n </div>\r\n <div class=\"d-flex justify-content-center\" *ngIf=\"loading\">\r\n <div class=\"spinner-border\" role=\"status\">\r\n <span class=\"visually-hidden\">Loading...</span>\r\n </div>\r\n </div>\r\n <div class=\"mt-3\" *ngIf=\"!plans && !loading\">\r\n <h4 style=\"font-weight: bold;\">{{'No imported plans' | translate }}</h4>\r\n <p>{{'For import from 3D visit: go Virtual Visits => Import Images' | translate}}</p>\r\n </div>\r\n <div class=\"row ms-1\">\r\n <div ngbDropdown class=\"d-inline-block me-3\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownBasic1\" ngbDropdownToggle>{{getChoosenPlan() ?\r\n getChoosenPlan().name: ('Choose Plan' | translate) }}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownBasic1\">\r\n <button ngbDropdownItem *ngFor=\"let plan of plans\" (click)=\"onPlanClick(plan)\">{{plan.name }}\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"d-inline-block\" ngbDropdown #myDrop=\"ngbDropdown\">\r\n <button class=\"btn btn-label-file rounded-pill\" id=\"dropdownManual\" ngbDropdownToggle>{{'Choose action' |\r\n translate}}</button>\r\n <div ngbDropdownMenu aria-labelledby=\"dropdownManual\">\r\n <button (click)=\"onCalibrateClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Calibrate' |\r\n translate}}</button>\r\n <button (click)=\"onEditClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Edit plan' |\r\n translate}}\r\n </button>\r\n <button (click)=\"onUploadClick()\" ngbDropdownItem>{{'Upload new plan' | translate}}</button>\r\n <button (click)=\"onDownloadClick()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">{{'Download plan' |\r\n translate}}</button>\r\n <button (click)=\"onRemoveClick()\" ngbDropdownItem\r\n [disabled]=\"!getChoosenPlan() || getChoosenPlan().isImportedMatterport\">{{'Delete plan' |\r\n translate}}</button>\r\n <!-- <button (click)=\"onDownloadAsPng()\" ngbDropdownItem [disabled]=\"!getChoosenPlan()\">\r\n {{'Download plan as PNG' | translate}}</button> -->\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"row mt-3 ms-0\">\r\n <h4 *ngIf=\"fileToUpload\">{{'New plan' | translate }}</h4>\r\n <input class=\"hidden\" type=\"file\" id=\"upload-file\" name=\"upload-file\" accept=\"image/png, image/jpeg, .pdf, .svg\"\r\n ngf-max-size=\"6MB\" (change)=\"addPlan($event.target)\">\r\n </div>\r\n <div class=\"col-md-6 mt-3\" *ngIf=\"planForm\">\r\n <form (ngSubmit)=\"onSavePlan()\" [formGroup]=\"planForm\">\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Name' | translate}} </label>\r\n <div class=\"col-sm-9\">\r\n <input type=\"text\" class=\"form-control\" formControlName=\"name\">\r\n </div>\r\n </div>\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Zone' | translate}} </label>\r\n <div class=\"col-sm-9\">\r\n <select class=\"form-control\" formControlName=\"zoneID\">\r\n <option *ngFor=\"let zone of zones\" [ngValue]=\"zone.id\">\r\n {{ zone.name }}\r\n </option>\r\n </select>\r\n </div>\r\n </div>\r\n <div class=\"mb-3 row\">\r\n <label class=\"col-sm-3\">{{'Set as current plan for zone' | translate}}</label>\r\n <div class=\"col-sm-3\">\r\n <input type=\"checkbox\" [(ngModel)]=\"isCurrentPlanForZone\" [ngModelOptions]=\"{standalone: true}\">\r\n </div>\r\n </div>\r\n <button [disabled]=\"planForm.invalid\" type='submit' class=\"btn btn-label-file rounded-pill\">{{'Save' |\r\n translate}}</button>\r\n <button class=\"btn btn-label-file rounded-pill ms-3\" type=\"button\" (click)=\"onCancelUpload()\">{{'Cancel' |\r\n translate}}</button>\r\n </form>\r\n </div>\r\n <ul class=\"col-md-6 list-group list-group-flush\" *ngIf=\"getChoosenPlan()\">\r\n <li class=\"list-group-item bg-transparent\">{{'Name' | translate }} : {{getChoosenPlan().name}} </li>\r\n <li class=\"list-group-item bg-transparent\"> {{'Plan is ' | translate }} :\r\n {{getChoosenPlan().calibration ? ('Calibrated' | translate) : ('Not calibrated' | translate)}}</li>\r\n <li class=\"list-group-item bg-transparent\">{{'Attributed to zone ' | translate }} :\r\n {{getChoosenPlan().zone ? getChoosenPlan().zone.name : 'None'}}</li>\r\n <li class=\"list-group-item bg-transparent\">{{'Is current plan for zone ' | translate }} :\r\n <input type=\"checkbox\" [(ngModel)]=\"getChoosenPlan().isCurrentForZone\" (change)=\"onCurrentPlanClick()\">\r\n </li>\r\n\r\n </ul>\r\n\r\n <div class=\"row mt-4\">\r\n <div class=\"col-md-10\">\r\n <embed *ngIf=\"getChoosenPlan() && chosenPlanIsPdf\" [src]=\"getChoosenPlan().filepath | safeUrl\"\r\n type=\"application/pdf\" frameBorder=\"0\" scrolling=\"auto\" height=\"650px;\" width=\"100%\" />\r\n <div *ngIf=\"!chosenPlanIsPdf\" class=\"row\" style=\"height: 500px; overflow: hidden;\" id=\"canvasDiv\">\r\n <canvas id=\"canvas\" width=\"4096px\" height=\"4096px\">\r\n <!-- <img *ngIf=\"chosenPlan\" id=\"plan-image\" [src]=\"chosenPlan.filepath\" style=\"width: 100%;\"> -->\r\n </canvas>\r\n\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".button-visit{display:none;height:30px;width:30px;position:absolute;background:url(https://api.iconify.design/mdi:map-marker-check.svg?color=red&height=30) no-repeat scroll 0 0 transparent;border:none}#button-visit-left{left:350px;top:550px}#button-visit-right{left:500px;top:600px}.hidden{visibility:hidden;width:1px;height:1px}\n"] }]
242
+ }], ctorParameters: function () { return [{ type: i1.ActivatedRoute }, { type: i1.Router }, { type: i2.SpaceService }, { type: i2.PlanService }, { type: i3.UntypedFormBuilder }, { type: i4.TranslateService }, { type: i2.NavigatorService }]; } });
243
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxhbnMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvcGxhbnMvcGxhbnMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNtYXJ0ZXJwbGFuLWxvY2F0aW9ucy9zcmMvbGliL2NvbXBvbmVudHMvcGxhbnMvcGxhbnMuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBVSxNQUFNLGVBQWUsQ0FBQztBQUNsRCxPQUFPLEVBQXdDLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBR2xGLE9BQU8sRUFBMEQsZUFBZSxFQUFFLGFBQWEsRUFBRSxvQkFBb0IsRUFBRSxZQUFZLEVBQW9CLE1BQU0sbUNBQW1DLENBQUM7QUFDak0sT0FBTyxPQUFPLE1BQU0sU0FBUyxDQUFDO0FBQzlCLE9BQU8sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDOzs7Ozs7Ozs7QUFFMUMsTUFLYSxjQUFjO0lBdUNYO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBM0NaLE9BQU8sQ0FBUztJQUVoQixZQUFZLENBQVE7SUFFcEIsS0FBSyxDQUFTO0lBRWQsb0JBQW9CO0lBRXBCLFlBQVksR0FBRyxDQUFDLENBQUMsQ0FBQztJQUVsQixPQUFPLEdBQUcsS0FBSyxDQUFDO0lBRWhCLGFBQWEsR0FBRyxLQUFLLENBQUM7SUFFdEIsUUFBUSxDQUFtQjtJQUUzQixvQkFBb0IsR0FBRyxLQUFLLENBQUM7SUFFN0IsTUFBTSxDQUFDO0lBRVAsS0FBSyxDQUFTO0lBRWQsT0FBTyxDQUFNO0lBRWIsV0FBVyxDQUFPO0lBRWxCLFlBQVksQ0FBTztJQUVuQixlQUFlLEdBQUcsS0FBSyxDQUFDO0lBRXhCLEtBQUssQ0FB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Y0FBYyxFQUFFLENBQUMsTUFBTSxDQUMvQixDQUFDO1FBQ0YsSUFBSSxVQUFVLEVBQUU7WUFDWixhQUFhO1lBQ2IsWUFBWSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQzdEO0lBQ0wsQ0FBQztJQUVELEtBQUssQ0FBQyxlQUFlO1FBQ2pCLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFzQixDQUFDO1FBQ3RFLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxJQUFJO1lBQ3hCLFlBQVksQ0FBQyxJQUFJLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztRQUMxQyxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxLQUFLLENBQUMsYUFBYTtRQUNmLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDN0QsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ3pCLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUM7WUFDekQsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3JDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztTQUNuQjtJQUNMLENBQUM7d0dBbFNRLGNBQWM7NEZBQWQsY0FBYyxpRENiM0IseWxNQXNHQTs7U0R6RmEsY0FBYzs0RkFBZCxjQUFjO2tCQUwxQixTQUFTOytCQUNJLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBVbnR5cGVkRm9ybUdyb3VwLCBVbnR5cGVkRm9ybUJ1aWxkZXIsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xyXG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XHJcbmltcG9ydCB7IFpvbmUsIFNwYWNlLCBQbGFuLCBNZW51SXRlbSwgU3BhY2VTZXJ2aWNlLCBQbGFuU2VydmljZSwgZ2V0TWV0YUZvckltYWdlLCBnZXRTaWduZWRGaWxlLCBkb3dubG9hZEZpbGVBc09iamVjdCwgZG93bmxvYWRCbG9iLCBOYXZpZ2F0b3JTZXJ2aWNlIH0gZnJvbSAnQHNtYXJ0ZXJwbGFuL25neC1zbWFydGVycGxhbi1jb3JlJztcclxuaW1wb3J0IHBhbnpvb20gZnJvbSAncGFuem9vbSc7XHJcbmltcG9ydCB7IFN1YmplY3QsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgICBzZWxlY3RvcjogJ2xpYi1wbGFucycsXHJcbiAgICB0ZW1wbGF0ZVVybDogJy4vcGxhbnMuY29tcG9uZW50Lmh0bWwnLFxyXG4gICAgc3R5bGVVcmxzOiBbJy4vcGxhbnMuY29tcG9uZW50LnNjc3MnXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgUGxhbnNDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xyXG5cclxuICAgIHNwYWNlSUQ6IHN0cmluZztcclxuXHJcbiAgICBjdXJyZW50U3BhY2U6IFNwYWNlO1xyXG5cclxuICAgIHBsYW5zOiBQbGFuW107XHJcblxyXG4gICAgLy8gY2hvc2VuUGxhbjogUGxhbjtcclxuXHJcbiAgICBpbmRleERldGFpbHMgPSAtMTtcclxuXHJcbiAgICBsb2FkaW5nID0gZmFsc2U7XHJcblxyXG4gICAgdXBsb2FkaW5nUGxhbiA9IGZhbHNlO1xyXG5cclxuICAgIHBsYW5Gb3JtOiBVbnR5cGVkRm9ybUdyb3VwO1xyXG5cclxuICAgIGlzQ3VycmVudFBsYW5Gb3Jab25lID0gZmFsc2U7XHJcblxyXG4gICAgY2FudmFzO1xyXG5cclxuICAgIHNjYWxlOiBudW1iZXI7XHJcblxyXG4gICAgcGFuem9vbTogYW55O1xyXG5cclxuICAgIGN1cnJlbnRab25lOiBab25lO1xyXG5cclxuICAgIGZpbGVUb1VwbG9hZDogRmlsZTtcclxuXHJcbiAgICBjaG9zZW5QbGFuSXNQZGYgPSBmYWxzZTtcclxuXHJcbiAgICB6b25lczogWm9uZVtdO1xyXG5cclxuICAgIG1lbnVJdGVtczogTWVudUl0ZW1bXSA9IFtdO1xyXG5cclxuICAgIGRlc3Ryb3kkID0gbmV3IFN1YmplY3QoKTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwcml2YXRlIHJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSxcclxuICAgICAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxyXG4gICAgICAgIHByaXZhdGUgc3BhY2VTZXJ2aWNlOiBTcGFjZVNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSBwbGFuU2VydmljZTogUGxhblNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSBmYjogVW50eXBlZEZvcm1CdWlsZGVyLFxyXG4gICAgICAgIHByaXZhdGUgdHJhbnNsYXRlOiBUcmFuc2xhdGVTZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgbmF2aWdhdG9yU2VydmljZTogTmF2aWdhdG9yU2VydmljZVxyXG4gICAgKSB7XHJcbiAgICAgICAgdGhpcy5uYXZpZ2F0b3JTZXJ2aWNlLmxvY2F0aW9uSURDaGFuZ2VcclxuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxyXG4gICAgICAgICAgICAuc3Vic2NyaWJlKChzcGFjZUlEKSA9PiB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbXCJkYXNoYm9hcmQvbG9jYWxpc2F0aW9uXCIsIHNwYWNlSUQsIFwicGxhbnNcIl0pO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgdGhpcy5yb3V0ZS5wYXJhbXMuc3Vic2NyaWJlKChwYXJhbXMpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5zcGFjZUlEID0gcGFyYW1zLmlkO1xyXG4gICAgICAgICAgICB0aGlzLmdldFBsYW5zKCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgICB0aGlzLnBsYW5TZXJ2aWNlLmdldFBsYW5GaWxlQ2FjaGUoKSAmJlxyXG4gICAgICAgICAgICB0aGlzLnBsYW5TZXJ2aWNlLmdldENob3NlblBsYW4oKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgICB0aGlzLmFkZFBsYW5Gcm9tQ2FjaGUoXHJcbiAgICAgICAgICAgICAgICB0aGlzLnBsYW5TZXJ2aWNlLmdldFBsYW5GaWxlQ2FjaGUoKSxcclxuICAgICAgICAgICAgICAgIHRoaXMucGxhblNlcnZpY2UuZ2V0Q2hvc2VuUGxhbigpLFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB0aGlzLnBsYW5TZXJ2aWNlLnNldFBsYW5GaWxlQ2FjaGUobnVsbCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMucGxhblNlcnZpY2Uuc2V0Q2hvc2VuUGxhbihudWxsKTtcclxuICAgIH1cclxuXHJcbiAgICBuZ09uRGVzdHJveSgpIHtcclxuICAgICAgICB0aGlzLmRlc3Ryb3kkLm5leHQodHJ1ZSk7XHJcbiAgICAgICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHNldHVwTWVudUl0ZW1zKCkge1xyXG4gICAgICAgIHRoaXMubWVudUl0ZW1zID0gW1xyXG4gICAgICAgICAgICB7IGxhYmVsOiBcIkxvY2F0aW9uc1wiLCB1cmw6IFwiL2xvY2FsaXNhdGlvblwiIH0sXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIGxhYmVsOiB0aGlzLmN1cnJlbnRTcGFjZS5uYW1lLFxyXG4gICAgICAgICAgICAgICAgdXJsOiBgL2xvY2FsaXNhdGlvbi8ke3RoaXMuY3VycmVudFNwYWNlLmlkfWAsXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIGxhYmVsOiBcIlBsYW5zXCIsXHJcbiAgICAgICAgICAgICAgICB1cmw6IGAvbG9jYWxpc2F0aW9uLyR7dGhpcy5jdXJyZW50U3BhY2UuaWR9L3BsYW5zYCxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIG9uR29CYWNrKCkgeyB9XHJcblxyXG4gICAgYXN5bmMgb25QbGFuQ2xpY2socGxhbj86IFBsYW4pIHtcclxuICAgICAgICBpZiAocGxhbikgdGhpcy5wbGFuU2VydmljZS5zZXRDaG9zZW5QbGFuKHBsYW4pO1xyXG4gICAgICAgIHRoaXMuY2hvc2VuUGxhbklzUGRmID0gcGxhbi5hbm5leGUuaW5jbHVkZXMoXCJwZGZcIik7XHJcbiAgICAgICAgaWYgKCF0aGlzLmNob3NlblBsYW5Jc1BkZikge1xyXG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlndXJlQ2FudmFzKCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wYW56b29tID0gcGFuem9vbSh0aGlzLmNhbnZhcywge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBib3VuZHM6IHRydWUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kc1BhZGRpbmc6IDAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heFpvb206IDMuNSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWluWm9vbTogMC4xLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsWm9vbTogMC41LFxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0sIDUwMCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIGNvbmZpZ3VyZUNhbnZhcygpIHtcclxuICAgICAgICB0aGlzLnVwbG9hZGluZ1BsYW4gPSB0cnVlO1xyXG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXCIjY2FudmFzXCIpIGFzIEhUTUxDYW52YXNFbGVtZW50O1xyXG4gICAgICAgIGNvbnN0IGltYWdlID0gYXdhaXQgZ2V0TWV0YUZvckltYWdlKHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5maWxlcGF0aCk7XHJcbiAgICAgICAgY2FudmFzLndpZHRoID0gaW1hZ2Uud2lkdGg7XHJcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IGltYWdlLmhlaWdodDtcclxuICAgICAgICB0aGlzLmNhbnZhcyA9IGNhbnZhcztcclxuICAgICAgICB0aGlzLmRyYXdJbWFnZSh0aGlzLmdldENob29zZW5QbGFuKCkuZmlsZXBhdGgpO1xyXG4gICAgICAgIHRoaXMudXBsb2FkaW5nUGxhbiA9IGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIGRyYXdJbWFnZSh1cmw6IHN0cmluZywgeCA9IDAsIHkgPSAwKSB7XHJcbiAgICAgICAgY29uc3QgaW1hZ2UgPSBuZXcgSW1hZ2UoKTtcclxuICAgICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xyXG4gICAgICAgIGNvbnN0IGltYWdlV2lkdGggPSB0aGlzLmNhbnZhcy53aWR0aDtcclxuICAgICAgICBjb25zdCBpbWFnZUhlaWdodCA9IHRoaXMuY2FudmFzLmhlaWdodDtcclxuICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKFwibG9hZFwiLCAoKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnRleHQuZHJhd0ltYWdlKFxyXG4gICAgICAgICAgICAgICAgaW1hZ2UsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIGltYWdlLndpZHRoLFxyXG4gICAgICAgICAgICAgICAgaW1hZ2UuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgICAgeCxcclxuICAgICAgICAgICAgICAgIHksXHJcbiAgICAgICAgICAgICAgICBpbWFnZVdpZHRoLFxyXG4gICAgICAgICAgICAgICAgaW1hZ2VIZWlnaHQsXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaW1hZ2Uuc3JjID0gdXJsO1xyXG4gICAgICAgIC8vIGltYWdlLmNyb3NzT3JpZ2luID0gXCIqXCI7IC8vbmVlZCB0byBkb3dubG9hZCBhcyBwbmcsXHJcbiAgICAgICAgLy8gQlVUOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80OTUwMzE3MS90aGUtaW1hZ2UtdGFnLXdpdGgtY3Jvc3NvcmlnaW4tYW5vbnltb3VzLWNhbnQtbG9hZC1zdWNjZXNzLWZyb20tczNcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBnZXRQbGFucygpIHtcclxuICAgICAgICB0aGlzLmxvYWRpbmcgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMuY3VycmVudFNwYWNlID0gYXdhaXQgdGhpcy5zcGFjZVNlcnZpY2UuZ2V0U3BhY2UodGhpcy5zcGFjZUlEKTtcclxuICAgICAgICB0aGlzLnNldHVwTWVudUl0ZW1zKCk7XHJcblxyXG4gICAgICAgIHRoaXMuem9uZXMgPSB0aGlzLmN1cnJlbnRTcGFjZS56b25lcy5pdGVtcztcclxuICAgICAgICB0aGlzLnBsYW5zID0gYXdhaXQgdGhpcy5wbGFuU2VydmljZS5nZXRTaW5nZWRQbGFuc0ZvclNwYWNlKHRoaXMuc3BhY2VJRCk7XHJcbiAgICAgICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XHJcbiAgICAgICAgaWYgKHRoaXMucGxhbnMubGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIHRoaXMub25QbGFuQ2xpY2sodGhpcy5wbGFuc1swXSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGdldENob29zZW5QbGFuKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnBsYW5TZXJ2aWNlLmdldENob3NlblBsYW4oKTtcclxuICAgIH1cclxuXHJcbiAgICByZW1vdmVJbWFnZSgpIHtcclxuICAgICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xyXG4gICAgICAgIGNvbnRleHQuY2xlYXJSZWN0KDAsIDAsIDQwOTYsIDQwOTYpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICpcclxuICAgICAqL1xyXG4gICAgb25DYWxpYnJhdGVDbGljaygpIHtcclxuICAgICAgICBpZiAodGhpcy5nZXRDaG9vc2VuUGxhbigpKSB7XHJcbiAgICAgICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFxyXG4gICAgICAgICAgICAgICAgW1wiL2Rhc2hib2FyZC9sb2NhbGlzYXRpb25cIiwgdGhpcy5zcGFjZUlELCBcInBsYW4tY2FsaWJyYXRpb25cIl0sXHJcbiAgICAgICAgICAgICAgICB7IHF1ZXJ5UGFyYW1zOiB7IHNwYWNlSUQ6IHRoaXMuc3BhY2VJRCB9IH0sXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICpcclxuICAgICAqL1xyXG4gICAgb25FZGl0Q2xpY2soKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZ2V0Q2hvb3NlblBsYW4oKSkge1xyXG4gICAgICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShcclxuICAgICAgICAgICAgICAgIFtcIi9kYXNoYm9hcmQvbG9jYWxpc2F0aW9uXCIsIHRoaXMuc3BhY2VJRCwgXCJwbGFuLWVkaXRcIl0sXHJcbiAgICAgICAgICAgICAgICB7IHF1ZXJ5UGFyYW1zOiB7IHNwYWNlSUQ6IHRoaXMuc3BhY2VJRCB9IH0sXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIG9uVXBsb2FkQ2xpY2soKSB7XHJcbiAgICAgICAgY29uc3QgaW5wdXRGaWxlID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcclxuICAgICAgICAgICAgXCIjdXBsb2FkLWZpbGVcIixcclxuICAgICAgICApIGFzIEhUTUxJbnB1dEVsZW1lbnQ7XHJcbiAgICAgICAgaW5wdXRGaWxlLmNsaWNrKCk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkUGxhbih0YXJnZXQ6IEV2ZW50VGFyZ2V0KSB7XHJcbiAgICAgICAgdGhpcy5maWxlVG9VcGxvYWQgPSAodGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQpLmZpbGVzWzBdO1xyXG4gICAgICAgIHRoaXMucGxhbkZvcm0gPSB0aGlzLmZiLmdyb3VwKHtcclxuICAgICAgICAgICAgbmFtZTogW3RoaXMuZmlsZVRvVXBsb2FkLm5hbWUsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXV0sXHJcbiAgICAgICAgICAgIHpvbmVJRDogW251bGwsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXV0sXHJcbiAgICAgICAgICAgIHNwYWNlSUQ6IHRoaXMuc3BhY2VJRCxcclxuICAgICAgICAgICAgaXNNb2RpZmllZDogZmFsc2UsXHJcbiAgICAgICAgICAgIGNhbGlicmF0aW9uOiBcIlwiLFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZFBsYW5Gcm9tQ2FjaGUoZmlsZTogRmlsZSwgcGxhbjogUGxhbikge1xyXG4gICAgICAgIHRoaXMuZmlsZVRvVXBsb2FkID0gZmlsZTtcclxuICAgICAgICB0aGlzLnBsYW5Gb3JtID0gdGhpcy5mYi5ncm91cCh7XHJcbiAgICAgICAgICAgIG5hbWU6IFt0aGlzLmZpbGVUb1VwbG9hZC5uYW1lLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF1dLFxyXG4gICAgICAgICAgICB6b25lSUQ6IFtwbGFuID8gcGxhbi56b25lSUQgOiBudWxsLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF1dLFxyXG4gICAgICAgICAgICBzcGFjZUlEOiB0aGlzLnNwYWNlSUQsXHJcbiAgICAgICAgICAgIGlzTW9kaWZpZWQ6ICEhcGxhbixcclxuICAgICAgICAgICAgY2FsaWJyYXRpb246XHJcbiAgICAgICAgICAgICAgICBwbGFuICYmIHBsYW4uaXNNb2RpZmllZCAmJiBwbGFuLmNhbGlicmF0aW9uXHJcbiAgICAgICAgICAgICAgICAgICAgPyBwbGFuLmNhbGlicmF0aW9uXHJcbiAgICAgICAgICAgICAgICAgICAgOiBcIlwiLFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uU2F2ZVBsYW4oKSB7XHJcbiAgICAgICAgY29uc3QgZm9ybVZhbHVlID0gdGhpcy5wbGFuRm9ybS52YWx1ZSBhcyBQbGFuO1xyXG4gICAgICAgIGZvcm1WYWx1ZS5pc0N1cnJlbnRGb3Jab25lID0gdGhpcy5pc0N1cnJlbnRQbGFuRm9yWm9uZTtcclxuICAgICAgICBjb25zdCBjcmVhdGVkUGxhbiA9IGF3YWl0IHRoaXMucGxhblNlcnZpY2UuY3JlYXRlUGxhbldpdGhBbm5leGUoXHJcbiAgICAgICAgICAgIGZvcm1WYWx1ZSxcclxuICAgICAgICAgICAgdGhpcy5maWxlVG9VcGxvYWQsXHJcbiAgICAgICAgKTtcclxuICAgICAgICBjb25zdCBmaWxlcGF0aCA9IGF3YWl0IGdldFNpZ25lZEZpbGUoY3JlYXRlZFBsYW4uYW5uZXhlKTtcclxuICAgICAgICBpZiAoZmlsZXBhdGgpIHtcclxuICAgICAgICAgICAgY3JlYXRlZFBsYW4uZmlsZXBhdGggPSBmaWxlcGF0aDtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGZvcm1WYWx1ZS5pc0N1cnJlbnRGb3Jab25lKSB7XHJcbiAgICAgICAgICAgIC8vIHNldCBhbGwgb3RoZXIgcGxhbnMgdG8gbm90IGN1cnJlbnRcclxuICAgICAgICAgICAgdGhpcy5wbGFuU2VydmljZS5zZXRBbGxQbGFuc0ZvclpvbmVOb3RDdXJyZW50KFxyXG4gICAgICAgICAgICAgICAgY3JlYXRlZFBsYW4uem9uZUlELFxyXG4gICAgICAgICAgICAgICAgY3JlYXRlZFBsYW4uaWQsXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMucGxhbnMucHVzaChjcmVhdGVkUGxhbik7XHJcbiAgICAgICAgdGhpcy5wbGFuRm9ybSA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5maWxlVG9VcGxvYWQgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIG9uQ2FuY2VsVXBsb2FkKCkge1xyXG4gICAgICAgIHRoaXMuZmlsZVRvVXBsb2FkID0gbnVsbDtcclxuICAgICAgICB0aGlzLnBsYW5Gb3JtID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvbkN1cnJlbnRQbGFuQ2xpY2soKSB7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5wbGFuU2VydmljZS51cGRhdGVQbGFuKHtcclxuICAgICAgICAgICAgaWQ6IHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5pZCxcclxuICAgICAgICAgICAgaXNDdXJyZW50Rm9yWm9uZTogdGhpcy5nZXRDaG9vc2VuUGxhbigpLmlzQ3VycmVudEZvclpvbmUsXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaWYgKHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5pc0N1cnJlbnRGb3Jab25lKSB7XHJcbiAgICAgICAgICAgIHRoaXMucGxhblNlcnZpY2Uuc2V0QWxsUGxhbnNGb3Jab25lTm90Q3VycmVudChcclxuICAgICAgICAgICAgICAgIHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS56b25lSUQsXHJcbiAgICAgICAgICAgICAgICB0aGlzLmdldENob29zZW5QbGFuKCkuaWQsXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uRG93bmxvYWRDbGljaygpIHtcclxuICAgICAgICBjb25zdCBzaWduZWRGaWxlID0gYXdhaXQgZG93bmxvYWRGaWxlQXNPYmplY3QoXHJcbiAgICAgICAgICAgIHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5hbm5leGUsXHJcbiAgICAgICAgKTtcclxuICAgICAgICBpZiAoc2lnbmVkRmlsZSkge1xyXG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgICAgICAgIGRvd25sb2FkQmxvYihzaWduZWRGaWxlLkJvZHksIHRoaXMuZ2V0Q2hvb3NlblBsYW4oKS5uYW1lKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgb25Eb3dubG9hZEFzUG5nKCkge1xyXG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXCIjY2FudmFzXCIpIGFzIEhUTUxDYW52YXNFbGVtZW50O1xyXG4gICAgICAgIGNhbnZhcy50b0Jsb2IoZnVuY3Rpb24gKGJsb2IpIHtcclxuICAgICAgICAgICAgZG93bmxvYWRCbG9iKGJsb2IsIFwicGxhbi1hcy1wbmcucG5nXCIpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uUmVtb3ZlQ2xpY2soKSB7XHJcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IHRoaXMudHJhbnNsYXRlLmluc3RhbnQoXCJjb25maXJtLmRlbGV0ZVBsYW5cIik7XHJcbiAgICAgICAgaWYgKHdpbmRvdy5jb25maXJtKG1lc3NhZ2UpKSB7XHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGxhblNlcnZpY2UuZGVsZXRlUGxhbih0aGlzLmdldENob29zZW5QbGFuKCkpO1xyXG4gICAgICAgICAgICB0aGlzLnJlbW92ZUltYWdlKCk7XHJcbiAgICAgICAgICAgIHRoaXMucGxhblNlcnZpY2Uuc2V0Q2hvc2VuUGxhbihudWxsKTtcclxuICAgICAgICAgICAgdGhpcy5nZXRQbGFucygpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCI8ZGl2IGNsYXNzPVwiY29udGFpbmVyLWZsdWlkXCIgKm5nSWY9XCJjdXJyZW50U3BhY2VcIiBjbGFzcz1cImRhc2hib2FyZC10YWJcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJtLTNcIj5cclxuICAgICAgICA8bGliLXRhYi1uYXZpZ2F0aW9uIFttZW51SXRlbXNdPSdtZW51SXRlbXMnIChvbkdvQmFjayk9XCJvbkdvQmFjaygpXCI+PC9saWItdGFiLW5hdmlnYXRpb24+XHJcbiAgICA8L2Rpdj5cclxuICAgIDxkaXYgY2xhc3M9XCJkLWZsZXgganVzdGlmeS1jb250ZW50LWNlbnRlclwiICpuZ0lmPVwibG9hZGluZ1wiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJzcGlubmVyLWJvcmRlclwiIHJvbGU9XCJzdGF0dXNcIj5cclxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ2aXN1YWxseS1oaWRkZW5cIj5Mb2FkaW5nLi4uPC9zcGFuPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbiAgICA8ZGl2IGNsYXNzPVwibXQtM1wiICpuZ0lmPVwiIXBsYW5zICYmICFsb2FkaW5nXCI+XHJcbiAgICAgICAgPGg0IHN0eWxlPVwiZm9udC13ZWlnaHQ6IGJvbGQ7XCI+e3snTm8gaW1wb3J0ZWQgcGxhbnMnIHwgdHJhbnNsYXRlIH19PC9oND5cclxuICAgICAgICA8cD57eydGb3IgaW1wb3J0IGZyb20gM0QgdmlzaXQ6IGdvIFZpcnR1YWwgVmlzaXRzID0+IEltcG9ydCBJbWFnZXMnIHwgdHJhbnNsYXRlfX08L3A+XHJcbiAgICA8L2Rpdj5cclxuICAgIDxkaXYgY2xhc3M9XCJyb3cgbXMtMVwiPlxyXG4gICAgICAgIDxkaXYgbmdiRHJvcGRvd24gY2xhc3M9XCJkLWlubGluZS1ibG9jayBtZS0zXCI+XHJcbiAgICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJidG4gYnRuLWxhYmVsLWZpbGUgcm91bmRlZC1waWxsXCIgaWQ9XCJkcm9wZG93bkJhc2ljMVwiIG5nYkRyb3Bkb3duVG9nZ2xlPnt7Z2V0Q2hvb3NlblBsYW4oKSA/XHJcbiAgICAgICAgICAgICAgICBnZXRDaG9vc2VuUGxhbigpLm5hbWU6ICgnQ2hvb3NlIFBsYW4nIHwgdHJhbnNsYXRlKSB9fTwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8ZGl2IG5nYkRyb3Bkb3duTWVudSBhcmlhLWxhYmVsbGVkYnk9XCJkcm9wZG93bkJhc2ljMVwiPlxyXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiBuZ2JEcm9wZG93bkl0ZW0gKm5nRm9yPVwibGV0IHBsYW4gb2YgcGxhbnNcIiAoY2xpY2spPVwib25QbGFuQ2xpY2socGxhbilcIj57e3BsYW4ubmFtZSB9fVxyXG4gICAgICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJkLWlubGluZS1ibG9ja1wiIG5nYkRyb3Bkb3duICNteURyb3A9XCJuZ2JEcm9wZG93blwiPlxyXG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1sYWJlbC1maWxlIHJvdW5kZWQtcGlsbFwiIGlkPVwiZHJvcGRvd25NYW51YWxcIiBuZ2JEcm9wZG93blRvZ2dsZT57eydDaG9vc2UgYWN0aW9uJyB8XHJcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8ZGl2IG5nYkRyb3Bkb3duTWVudSBhcmlhLWxhYmVsbGVkYnk9XCJkcm9wZG93bk1hbnVhbFwiPlxyXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiAoY2xpY2spPVwib25DYWxpYnJhdGVDbGljaygpXCIgbmdiRHJvcGRvd25JdGVtIFtkaXNhYmxlZF09XCIhZ2V0Q2hvb3NlblBsYW4oKVwiPnt7J0NhbGlicmF0ZScgfFxyXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19PC9idXR0b24+XHJcbiAgICAgICAgICAgICAgICA8YnV0dG9uIChjbGljayk9XCJvbkVkaXRDbGljaygpXCIgbmdiRHJvcGRvd25JdGVtIFtkaXNhYmxlZF09XCIhZ2V0Q2hvb3NlblBsYW4oKVwiPnt7J0VkaXQgcGxhbicgfFxyXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19XHJcbiAgICAgICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cIm9uVXBsb2FkQ2xpY2soKVwiIG5nYkRyb3Bkb3duSXRlbT57eydVcGxvYWQgbmV3IHBsYW4nIHwgdHJhbnNsYXRlfX08L2J1dHRvbj5cclxuICAgICAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cIm9uRG93bmxvYWRDbGljaygpXCIgbmdiRHJvcGRvd25JdGVtIFtkaXNhYmxlZF09XCIhZ2V0Q2hvb3NlblBsYW4oKVwiPnt7J0Rvd25sb2FkIHBsYW4nIHxcclxuICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiAoY2xpY2spPVwib25SZW1vdmVDbGljaygpXCIgbmdiRHJvcGRvd25JdGVtXHJcbiAgICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFnZXRDaG9vc2VuUGxhbigpIHx8IGdldENob29zZW5QbGFuKCkuaXNJbXBvcnRlZE1hdHRlcnBvcnRcIj57eydEZWxldGUgcGxhbicgfFxyXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZX19PC9idXR0b24+XHJcbiAgICAgICAgICAgICAgICA8IS0tIDxidXR0b24gKGNsaWNrKT1cIm9uRG93bmxvYWRBc1BuZygpXCIgbmdiRHJvcGRvd25JdGVtIFtkaXNhYmxlZF09XCIhZ2V0Q2hvb3NlblBsYW4oKVwiPlxyXG4gICAgICAgICAgICAgICAgICAgIHt7J0Rvd25sb2FkIHBsYW4gYXMgUE5HJyB8IHRyYW5zbGF0ZX19PC9idXR0b24+IC0tPlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgIDwvZGl2PlxyXG4gICAgPGRpdiBjbGFzcz1cInJvdyBtdC0zIG1zLTBcIj5cclxuICAgICAgICA8aDQgKm5nSWY9XCJmaWxlVG9VcGxvYWRcIj57eydOZXcgcGxhbicgfCB0cmFuc2xhdGUgfX08L2g0PlxyXG4gICAgICAgIDxpbnB1dCBjbGFzcz1cImhpZGRlblwiIHR5cGU9XCJmaWxlXCIgaWQ9XCJ1cGxvYWQtZmlsZVwiIG5hbWU9XCJ1cGxvYWQtZmlsZVwiIGFjY2VwdD1cImltYWdlL3BuZywgaW1hZ2UvanBlZywgLnBkZiwgLnN2Z1wiXHJcbiAgICAgICAgICAgIG5nZi1tYXgtc2l6ZT1cIjZNQlwiIChjaGFuZ2UpPVwiYWRkUGxhbigkZXZlbnQudGFyZ2V0KVwiPlxyXG4gICAgPC9kaXY+XHJcbiAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTYgbXQtM1wiICpuZ0lmPVwicGxhbkZvcm1cIj5cclxuICAgICAgICA8Zm9ybSAobmdTdWJtaXQpPVwib25TYXZlUGxhbigpXCIgW2Zvcm1Hcm91cF09XCJwbGFuRm9ybVwiPlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibWItMyByb3dcIj5cclxuICAgICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNvbC1zbS0zXCI+e3snTmFtZScgfCB0cmFuc2xhdGV9fSA8L2xhYmVsPlxyXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1zbS05XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBmb3JtQ29udHJvbE5hbWU9XCJuYW1lXCI+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtYi0zIHJvd1wiPlxyXG4gICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY29sLXNtLTNcIj57eydab25lJyB8IHRyYW5zbGF0ZX19IDwvbGFiZWw+XHJcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLXNtLTlcIj5cclxuICAgICAgICAgICAgICAgICAgICA8c2VsZWN0IGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZm9ybUNvbnRyb2xOYW1lPVwiem9uZUlEXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gKm5nRm9yPVwibGV0IHpvbmUgb2Ygem9uZXNcIiBbbmdWYWx1ZV09XCJ6b25lLmlkXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7eyB6b25lLm5hbWUgfX1cclxuICAgICAgICAgICAgICAgICAgICAgICAgPC9vcHRpb24+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9zZWxlY3Q+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtYi0zIHJvd1wiPlxyXG4gICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY29sLXNtLTNcIj57eydTZXQgYXMgY3VycmVudCBwbGFuIGZvciB6b25lJyB8IHRyYW5zbGF0ZX19PC9sYWJlbD5cclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtc20tM1wiPlxyXG4gICAgICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBbKG5nTW9kZWwpXT1cImlzQ3VycmVudFBsYW5Gb3Jab25lXCIgW25nTW9kZWxPcHRpb25zXT1cIntzdGFuZGFsb25lOiB0cnVlfVwiPlxyXG4gICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8YnV0dG9uIFtkaXNhYmxlZF09XCJwbGFuRm9ybS5pbnZhbGlkXCIgdHlwZT0nc3VibWl0JyBjbGFzcz1cImJ0biBidG4tbGFiZWwtZmlsZSByb3VuZGVkLXBpbGxcIj57eydTYXZlJyB8XHJcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1sYWJlbC1maWxlIHJvdW5kZWQtcGlsbCBtcy0zXCIgdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJvbkNhbmNlbFVwbG9hZCgpXCI+e3snQ2FuY2VsJyB8XHJcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGV9fTwvYnV0dG9uPlxyXG4gICAgICAgIDwvZm9ybT5cclxuICAgIDwvZGl2PlxyXG4gICAgPHVsIGNsYXNzPVwiY29sLW1kLTYgbGlzdC1ncm91cCBsaXN0LWdyb3VwLWZsdXNoXCIgKm5nSWY9XCJnZXRDaG9vc2VuUGxhbigpXCI+XHJcbiAgICAgICAgPGxpIGNsYXNzPVwibGlzdC1ncm91cC1pdGVtIGJnLXRyYW5zcGFyZW50XCI+e3snTmFtZScgfCB0cmFuc2xhdGUgfX0gOiB7e2dldENob29zZW5QbGFuKCkubmFtZX19IDwvbGk+XHJcbiAgICAgICAgPGxpIGNsYXNzPVwibGlzdC1ncm91cC1pdGVtIGJnLXRyYW5zcGFyZW50XCI+IHt7J1BsYW4gaXMgJyB8IHRyYW5zbGF0ZSB9fSA6XHJcbiAgICAgICAgICAgIHt7Z2V0Q2hvb3NlblBsYW4oKS5jYWxpYnJhdGlvbiA/ICgnQ2FsaWJyYXRlZCcgfCB0cmFuc2xhdGUpIDogKCdOb3QgY2FsaWJyYXRlZCcgfCB0cmFuc2xhdGUpfX08L2xpPlxyXG4gICAgICAgIDxsaSBjbGFzcz1cImxpc3QtZ3JvdXAtaXRlbSBiZy10cmFuc3BhcmVudFwiPnt7J0F0dHJpYnV0ZWQgdG8gem9uZSAnIHwgdHJhbnNsYXRlIH19IDpcclxuICAgICAgICAgICAge3tnZXRDaG9vc2VuUGxhbigpLnpvbmUgPyBnZXRDaG9vc2VuUGxhbigpLnpvbmUubmFtZSA6ICdOb25lJ319PC9saT5cclxuICAgICAgICA8bGkgY2xhc3M9XCJsaXN0LWdyb3VwLWl0ZW0gYmctdHJhbnNwYXJlbnRcIj57eydJcyBjdXJyZW50IHBsYW4gZm9yIHpvbmUgJyB8IHRyYW5zbGF0ZSB9fSA6XHJcbiAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBbKG5nTW9kZWwpXT1cImdldENob29zZW5QbGFuKCkuaXNDdXJyZW50Rm9yWm9uZVwiIChjaGFuZ2UpPVwib25DdXJyZW50UGxhbkNsaWNrKClcIj5cclxuICAgICAgICA8L2xpPlxyXG5cclxuICAgIDwvdWw+XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cInJvdyBtdC00XCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1tZC0xMFwiPlxyXG4gICAgICAgICAgICA8ZW1iZWQgKm5nSWY9XCJnZXRDaG9vc2VuUGxhbigpICYmIGNob3NlblBsYW5Jc1BkZlwiIFtzcmNdPVwiZ2V0Q2hvb3NlblBsYW4oKS5maWxlcGF0aCB8IHNhZmVVcmxcIlxyXG4gICAgICAgICAgICAgICAgdHlwZT1cImFwcGxpY2F0aW9uL3BkZlwiIGZyYW1lQm9yZGVyPVwiMFwiIHNjcm9sbGluZz1cImF1dG9cIiBoZWlnaHQ9XCI2NTBweDtcIiB3aWR0aD1cIjEwMCVcIiAvPlxyXG4gICAgICAgICAgICA8ZGl2ICpuZ0lmPVwiIWNob3NlblBsYW5Jc1BkZlwiIGNsYXNzPVwicm93XCIgc3R5bGU9XCJoZWlnaHQ6IDUwMHB4OyBvdmVyZmxvdzogaGlkZGVuO1wiIGlkPVwiY2FudmFzRGl2XCI+XHJcbiAgICAgICAgICAgICAgICA8Y2FudmFzIGlkPVwiY2FudmFzXCIgd2lkdGg9XCI0MDk2cHhcIiBoZWlnaHQ9XCI0MDk2cHhcIj5cclxuICAgICAgICAgICAgICAgICAgICA8IS0tIDxpbWcgKm5nSWY9XCJjaG9zZW5QbGFuXCIgaWQ9XCJwbGFuLWltYWdlXCIgW3NyY109XCJjaG9zZW5QbGFuLmZpbGVwYXRoXCIgc3R5bGU9XCJ3aWR0aDogMTAwJTtcIj4gLS0+XHJcbiAgICAgICAgICAgICAgICA8L2NhbnZhcz5cclxuXHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbjwvZGl2PlxyXG4iXX0=