tango-app-ui-ticket-user 3.5.0 → 3.5.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.
- package/README.md +28 -28
- package/esm2022/lib/components/audit-management/audit-management.component.mjs +1 -1
- package/esm2022/lib/components/contact-details/contact-details.component.mjs +3 -3
- package/esm2022/lib/components/dropdown/dropdown.component.mjs +3 -3
- package/esm2022/lib/components/edge-cameraview/edge-cameraview.component.mjs +3 -3
- package/esm2022/lib/components/edgeapp-log/edgeapp-log.component.mjs +3 -3
- package/esm2022/lib/components/edit-details/edit-details.component.mjs +3 -3
- package/esm2022/lib/components/infratickets/infratickets.component.mjs +8 -3
- package/esm2022/lib/components/installation/installation.component.mjs +30 -3
- package/esm2022/lib/components/preinstallation-info/preinstallation-info.component.mjs +178 -0
- package/esm2022/lib/components/store-activity/store-activity.component.mjs +3 -3
- package/esm2022/lib/components/store-info/store-info.component.mjs +3 -3
- package/esm2022/lib/components/takeremote/takeremote.component.mjs +3 -3
- package/esm2022/lib/components/tango-ticket-users/tango-ticket-users.component.mjs +3 -3
- package/esm2022/lib/components/tickets/tickets.component.mjs +3 -3
- package/esm2022/lib/components/viewhistory/viewhistory.component.mjs +3 -3
- package/esm2022/lib/route-wrappers/edge-wrapper.module.mjs +2 -1
- package/esm2022/lib/services/data.service.mjs +1 -1
- package/esm2022/lib/services/excel.service.mjs +1 -1
- package/esm2022/lib/services/ticket-infra.service.mjs +13 -1
- package/esm2022/lib/tango-ticket-users-routing.module.mjs +6 -1
- package/esm2022/lib/tango-ticket-users.module.mjs +4 -3
- package/esm2022/public-api.mjs +1 -1
- package/fesm2022/tango-app-ui-ticket-user-edge-wrapper.module-CFDk0tvS.mjs.map +1 -1
- package/fesm2022/tango-app-ui-ticket-user.mjs +277 -59
- package/fesm2022/tango-app-ui-ticket-user.mjs.map +1 -1
- package/lib/components/installation/installation.component.d.ts +3 -0
- package/lib/components/preinstallation-info/preinstallation-info.component.d.ts +56 -0
- package/lib/services/ticket-infra.service.d.ts +5 -0
- package/lib/tango-ticket-users.module.d.ts +8 -7
- package/package.json +1 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { Subject, takeUntil } from 'rxjs';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "@angular/router";
|
|
5
|
+
import * as i2 from "../../services/ticket-infra.service";
|
|
6
|
+
import * as i3 from "tango-app-ui-shared";
|
|
7
|
+
import * as i4 from "@angular/common";
|
|
8
|
+
import * as i5 from "@ng-bootstrap/ng-bootstrap";
|
|
9
|
+
/**
|
|
10
|
+
* Pre-Installation ticket detail page (workspace entry for TE_PRE tickets).
|
|
11
|
+
* Same role as InstallationComponent for TE_INS tickets: the ticket header +
|
|
12
|
+
* activity trail come from the tickets API, the LIVE camera-placement state
|
|
13
|
+
* comes from the store-builder CCTV row, and the page gates the next step:
|
|
14
|
+
* autoPlacement -> "Auto placement in progress", editor locked
|
|
15
|
+
* failed -> failure reason + Retry
|
|
16
|
+
* open -> "Open DXF editor" (assignee gated server-side)
|
|
17
|
+
* approvalPending-> waiting for approval, drawing viewable
|
|
18
|
+
* approved -> done (ticket closes via the approve hook)
|
|
19
|
+
* Loading the CCTV detail also triggers the server-side OS reconcile, so this
|
|
20
|
+
* page keeps the row fresh, the job the CCTV table used to do.
|
|
21
|
+
*/
|
|
22
|
+
export class PreinstallationInfoComponent {
|
|
23
|
+
route;
|
|
24
|
+
router;
|
|
25
|
+
service;
|
|
26
|
+
toastService;
|
|
27
|
+
ticketId;
|
|
28
|
+
storeId;
|
|
29
|
+
ticketInfo;
|
|
30
|
+
cctvRow;
|
|
31
|
+
cctvFloor;
|
|
32
|
+
/** live placement state straight off the status index */
|
|
33
|
+
placement = null;
|
|
34
|
+
fileUrls = {};
|
|
35
|
+
loading = true;
|
|
36
|
+
cctvLoading = false;
|
|
37
|
+
cctvError = '';
|
|
38
|
+
retrying = false;
|
|
39
|
+
destroy$ = new Subject();
|
|
40
|
+
constructor(route, router, service, toastService) {
|
|
41
|
+
this.route = route;
|
|
42
|
+
this.router = router;
|
|
43
|
+
this.service = service;
|
|
44
|
+
this.toastService = toastService;
|
|
45
|
+
this.ticketId = this.route.snapshot.paramMap.get('ticketId');
|
|
46
|
+
this.storeId = this.route.snapshot.paramMap.get('storeId');
|
|
47
|
+
}
|
|
48
|
+
ngOnInit() {
|
|
49
|
+
this.viewTicket();
|
|
50
|
+
}
|
|
51
|
+
ngOnDestroy() {
|
|
52
|
+
this.destroy$.next(true);
|
|
53
|
+
this.destroy$.complete();
|
|
54
|
+
}
|
|
55
|
+
get floorId() {
|
|
56
|
+
return this.ticketInfo?.preInstallation?.floorId || '';
|
|
57
|
+
}
|
|
58
|
+
get floorNumber() {
|
|
59
|
+
return this.ticketInfo?.preInstallation?.floorNumber || '-';
|
|
60
|
+
}
|
|
61
|
+
/** Presigned link to the imported drawing (v1), from the detail call's url map. */
|
|
62
|
+
get sourceDxfUrl() {
|
|
63
|
+
const key = this.cctvRow?.sourceKey;
|
|
64
|
+
return key ? this.fileUrls?.[key] || null : null;
|
|
65
|
+
}
|
|
66
|
+
get sourceDxfName() {
|
|
67
|
+
const key = this.cctvRow?.sourceKey || '';
|
|
68
|
+
return key.split('/').pop() || 'source.dxf';
|
|
69
|
+
}
|
|
70
|
+
// The page's single state switch, derived from ticket + live CCTV row.
|
|
71
|
+
get placementState() {
|
|
72
|
+
if (this.ticketInfo?.status === 'closed')
|
|
73
|
+
return 'approved';
|
|
74
|
+
if (!this.floorId)
|
|
75
|
+
return 'waitingLayout';
|
|
76
|
+
if (!this.cctvRow)
|
|
77
|
+
return this.cctvError ? 'unavailable' : 'loading';
|
|
78
|
+
// The status index owns the placement half: queued and running both read
|
|
79
|
+
// as "in progress", and a failure carries its reason. Once the placement
|
|
80
|
+
// is done the workflow row takes over (open | approvalPending | approved).
|
|
81
|
+
const jobStatus = this.placement?.status;
|
|
82
|
+
if (jobStatus === 'pending' || jobStatus === 'processing')
|
|
83
|
+
return 'processing';
|
|
84
|
+
if (jobStatus === 'failed')
|
|
85
|
+
return 'failed';
|
|
86
|
+
if (this.cctvRow.status === 'autoPlacement')
|
|
87
|
+
return 'processing';
|
|
88
|
+
return this.cctvRow.status;
|
|
89
|
+
}
|
|
90
|
+
get versions() {
|
|
91
|
+
const files = Array.isArray(this.cctvRow?.files) ? [...this.cctvRow.files] : [];
|
|
92
|
+
return files.sort((a, b) => (b?.version ?? 0) - (a?.version ?? 0));
|
|
93
|
+
}
|
|
94
|
+
get activity() {
|
|
95
|
+
const list = Array.isArray(this.ticketInfo?.ticketActivity) ? [...this.ticketInfo.ticketActivity] : [];
|
|
96
|
+
return list.reverse();
|
|
97
|
+
}
|
|
98
|
+
viewTicket() {
|
|
99
|
+
this.service.viewTicket({ ticketId: this.ticketId })
|
|
100
|
+
.pipe(takeUntil(this.destroy$))
|
|
101
|
+
.subscribe({
|
|
102
|
+
next: (res) => {
|
|
103
|
+
this.loading = false;
|
|
104
|
+
if (res && res.code == 200) {
|
|
105
|
+
this.ticketInfo = res.data;
|
|
106
|
+
if (this.floorId) {
|
|
107
|
+
this.loadCctvDetail();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
error: () => {
|
|
112
|
+
this.loading = false;
|
|
113
|
+
this.toastService.getErrorToast('Unable to load the ticket.');
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
loadCctvDetail() {
|
|
118
|
+
if (!this.floorId)
|
|
119
|
+
return;
|
|
120
|
+
this.cctvLoading = true;
|
|
121
|
+
this.cctvError = '';
|
|
122
|
+
this.service.getCctvDetail(this.floorId)
|
|
123
|
+
.pipe(takeUntil(this.destroy$))
|
|
124
|
+
.subscribe({
|
|
125
|
+
next: (res) => {
|
|
126
|
+
this.cctvLoading = false;
|
|
127
|
+
this.cctvRow = res?.data?.row || null;
|
|
128
|
+
this.cctvFloor = res?.data?.floor || null;
|
|
129
|
+
this.fileUrls = res?.data?.urls || {};
|
|
130
|
+
this.placement = res?.data?.placement || null;
|
|
131
|
+
},
|
|
132
|
+
error: () => {
|
|
133
|
+
this.cctvLoading = false;
|
|
134
|
+
this.cctvError = 'Unable to load the camera placement status.';
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
refresh() {
|
|
139
|
+
this.viewTicket();
|
|
140
|
+
}
|
|
141
|
+
retryPlacement() {
|
|
142
|
+
if (!this.floorId || this.retrying)
|
|
143
|
+
return;
|
|
144
|
+
this.retrying = true;
|
|
145
|
+
this.service.cctvRetry({ floorId: this.floorId })
|
|
146
|
+
.pipe(takeUntil(this.destroy$))
|
|
147
|
+
.subscribe({
|
|
148
|
+
next: (res) => {
|
|
149
|
+
this.retrying = false;
|
|
150
|
+
this.toastService.getSuccessToast(res?.data?.startedNow ?
|
|
151
|
+
'Auto placement is running again.' :
|
|
152
|
+
'Queued for auto placement. It will start on the next run.');
|
|
153
|
+
this.loadCctvDetail();
|
|
154
|
+
},
|
|
155
|
+
error: () => {
|
|
156
|
+
this.retrying = false;
|
|
157
|
+
this.toastService.getErrorToast('Unable to retry. Please try again.');
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
openEditor() {
|
|
162
|
+
if (!this.floorId)
|
|
163
|
+
return;
|
|
164
|
+
this.router.navigate(['/manage/planogram/cctv-editor'], {
|
|
165
|
+
queryParams: { floorId: this.floorId, mode: 'edit' },
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
back() {
|
|
169
|
+
this.router.navigate(['/tickets/users'], { queryParams: { type: 'installation' } });
|
|
170
|
+
}
|
|
171
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PreinstallationInfoComponent, deps: [{ token: i1.ActivatedRoute }, { token: i1.Router }, { token: i2.TicketsService }, { token: i3.ToastService }], target: i0.ɵɵFactoryTarget.Component });
|
|
172
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: PreinstallationInfoComponent, selector: "lib-preinstallation-info", ngImport: i0, template: "<div class=\"container-fluid p-5 preinstall-page\">\n\n <!-- Header -->\n <div class=\"card mb-5\">\n <div class=\"card-body d-flex flex-wrap align-items-center justify-content-between gap-4 py-4\">\n <div class=\"d-flex align-items-center gap-4\">\n <button type=\"button\" class=\"btn btn-sm btn-light back-btn\" (click)=\"back()\" aria-label=\"Back to workspace\">\n <i class=\"bi bi-arrow-left\"></i>\n </button>\n <div>\n <div class=\"d-flex align-items-center gap-3\">\n <h4 class=\"mb-0\">{{ ticketInfo?.ticketId || ticketId }}</h4>\n <span class=\"badge state-badge\" [ngClass]=\"'state-' + placementState\">\n {{\n placementState === 'waitingLayout' ? 'Waiting for layout' :\n placementState === 'processing' ? 'Auto placement in progress' :\n placementState === 'failed' ? 'Placement failed' :\n placementState === 'open' ? 'Ready for placement review' :\n placementState === 'approvalPending' ? 'Waiting for approval' :\n placementState === 'approved' ? 'Approved' :\n placementState === 'unavailable' ? 'Status unavailable' : 'Loading'\n }}\n </span>\n </div>\n <div class=\"text-muted fs-7 mt-1\">\n Pre-Installation, camera placement\n <span *ngIf=\"ticketInfo?.basicDetails?.storeName\">, {{ ticketInfo?.basicDetails?.storeName }}</span>\n <span>, Floor {{ floorNumber }}</span>\n </div>\n </div>\n </div>\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\" class=\"btn btn-sm btn-light row-btn\" (click)=\"refresh()\">\n <i class=\"bi bi-arrow-clockwise me-1\"></i>Refresh\n </button>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"loading\" class=\"text-center py-10 text-muted\">Loading ticket...</div>\n\n <div *ngIf=\"!loading && ticketInfo\" class=\"row g-5\">\n\n <!-- Placement state / action panel -->\n <div class=\"col-12 col-lg-7\">\n <div class=\"card h-100\">\n <div class=\"card-body\">\n <div class=\"card-head mb-4\">\n <h5 class=\"mb-0\">Camera placement</h5>\n <!-- The imported drawing itself, for the internal team to inspect in\n CAD when the engine cannot handle it or before editing. -->\n <a *ngIf=\"sourceDxfUrl\" [href]=\"sourceDxfUrl\" target=\"_blank\" rel=\"noopener\"\n class=\"btn btn-sm btn-light row-btn\" [ngbTooltip]=\"sourceDxfName\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12 3v12m0 0 4-4m-4 4-4-4M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\"\n stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <span class=\"ms-1\">Download source DXF</span>\n </a>\n </div>\n\n <div [ngSwitch]=\"placementState\" class=\"state-panel\">\n\n <div *ngSwitchCase=\"'waitingLayout'\" class=\"state-box\">\n <p class=\"mb-1 fw-semibold\">Waiting for the CAD layout.</p>\n <p class=\"text-muted mb-0\">The store's floor drawing has not been imported yet. Auto placement starts right after the CAD import.</p>\n </div>\n\n <div *ngSwitchCase=\"'processing'\" class=\"state-box\">\n <div class=\"d-flex align-items-center gap-3 mb-1\">\n <span class=\"spinner-border spinner-border-sm text-primary\" role=\"status\" aria-hidden=\"true\"></span>\n <p class=\"mb-0 fw-semibold\">Auto camera placement is running.</p>\n </div>\n <p class=\"text-muted mb-0\">The DXF editor unlocks when placement completes. Use Refresh to check again.</p>\n </div>\n\n <div *ngSwitchCase=\"'failed'\" class=\"state-box state-box-danger\">\n <p class=\"mb-1 fw-semibold\">Auto placement failed.</p>\n <p class=\"text-muted mb-3\">{{ placement?.errorMsg || cctvRow?.errorMsg || 'The placement engine reported a failure.' }}</p>\n <!-- Retry hidden until the autoPlace Lambda exists (LAMBDAURL.autoPlace is empty).\n Re-enable by removing this comment; retryPlacement() is still wired in the component.\n <button type=\"button\" class=\"btn btn-sm btn-primary row-btn\" [disabled]=\"retrying\" (click)=\"retryPlacement()\">\n <span *ngIf=\"retrying\" class=\"spinner-border spinner-border-sm me-2\" role=\"status\" aria-hidden=\"true\"></span>\n {{ retrying ? 'Retrying...' : 'Retry auto placement' }}\n </button>\n -->\n </div>\n\n <div *ngSwitchCase=\"'open'\" class=\"state-box\">\n <p class=\"mb-1 fw-semibold\">The drawing is ready for camera review.</p>\n <p class=\"text-muted mb-3\">\n Adjust the auto-placed cameras in the DXF editor, then submit for approval.\n <span *ngIf=\"cctvRow?.isRework\" class=\"text-warning fw-semibold\">This floor was sent back for rework.</span>\n </p>\n <button type=\"button\" class=\"btn btn-sm btn-primary row-btn\" (click)=\"openEditor()\">\n <i class=\"bi bi-pencil-square me-1\"></i>Open DXF editor\n </button>\n </div>\n\n <div *ngSwitchCase=\"'approvalPending'\" class=\"state-box\">\n <p class=\"mb-1 fw-semibold\">Submitted, waiting for approval.</p>\n <p class=\"text-muted mb-3\">The approval team reviews it from the onboard table. You can still view the drawing.</p>\n <button type=\"button\" class=\"btn btn-sm btn-light row-btn\" (click)=\"openEditor()\">\n <i class=\"bi bi-eye me-1\"></i>View drawing\n </button>\n </div>\n\n <div *ngSwitchCase=\"'approved'\" class=\"state-box state-box-success\">\n <p class=\"mb-1 fw-semibold\">Camera placement approved.</p>\n <p class=\"text-muted mb-0\">This ticket is closed. The installation ticket takes over once every floor of the store is approved.</p>\n </div>\n\n <div *ngSwitchCase=\"'unavailable'\" class=\"state-box state-box-danger\">\n <p class=\"mb-1 fw-semibold\">Placement status unavailable.</p>\n <p class=\"text-muted mb-3\">{{ cctvError }}</p>\n <button type=\"button\" class=\"btn btn-sm btn-light row-btn\" (click)=\"loadCctvDetail()\">Try again</button>\n </div>\n\n <div *ngSwitchDefault class=\"state-box\">\n <p class=\"text-muted mb-0\">Loading placement status...</p>\n </div>\n </div>\n\n <!-- Version timeline -->\n <div *ngIf=\"versions.length\" class=\"mt-6\">\n <h6 class=\"text-muted mb-3\">Drawing versions</h6>\n <div class=\"version-list\">\n <div class=\"version-row d-flex align-items-center justify-content-between\" *ngFor=\"let file of versions\">\n <div>\n <span class=\"fw-semibold\">v{{ file.version }}</span>\n <span class=\"text-muted ms-2 fs-7\">{{ file.kind === 'auto' ? 'Auto placement' : file.kind === 'approver' ? 'Approver edit' : 'Internal edit' }}</span>\n <span class=\"text-muted ms-2 fs-7\" *ngIf=\"file.cameraCount != null\">{{ file.cameraCount }} cameras</span>\n </div>\n <div class=\"d-flex align-items-center gap-3\">\n <span class=\"text-muted fs-7\">{{ file.uploadedAt | date: 'dd MMM, y HH:mm' }}</span>\n <a *ngIf=\"fileUrls[file.key]\" [href]=\"fileUrls[file.key]\" target=\"_blank\" rel=\"noopener\" class=\"btn btn-sm btn-light row-btn\">\n <i class=\"bi bi-download\"></i>\n </a>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Ticket info + activity -->\n <div class=\"col-12 col-lg-5\">\n <div class=\"card mb-5\">\n <div class=\"card-body\">\n <h5 class=\"mb-4\">Ticket details</h5>\n <div class=\"detail-grid\">\n <div class=\"detail-row\"><span class=\"text-muted\">Store</span><span>{{ ticketInfo?.basicDetails?.storeName || '-' }} ({{ ticketInfo?.basicDetails?.storeId || storeId }})</span></div>\n <div class=\"detail-row\"><span class=\"text-muted\">Brand</span><span>{{ ticketInfo?.basicDetails?.clientName || '-' }}</span></div>\n <div class=\"detail-row\"><span class=\"text-muted\">Floor</span><span>Floor {{ floorNumber }}</span></div>\n <div class=\"detail-row\"><span class=\"text-muted\">Ticket status</span><span class=\"text-capitalize\">{{ ticketInfo?.status || '-' }}</span></div>\n <div class=\"detail-row\"><span class=\"text-muted\">Created</span><span>{{ ticketInfo?.createdAt | date: 'dd MMM, y HH:mm' }}</span></div>\n <div class=\"detail-row\" *ngIf=\"cctvRow?.assigneeName\"><span class=\"text-muted\">Assignee</span><span>{{ cctvRow?.assigneeName }}</span></div>\n <div class=\"detail-row\" *ngIf=\"cctvRow?.reworkCount\"><span class=\"text-muted\">Rework count</span><span>{{ cctvRow?.reworkCount }}</span></div>\n </div>\n </div>\n </div>\n\n <div class=\"card\">\n <div class=\"card-body\">\n <h5 class=\"mb-4\">Activity</h5>\n <div *ngIf=\"!activity.length\" class=\"text-muted fs-7\">No activity yet.</div>\n <div class=\"activity-list\">\n <div class=\"activity-row\" *ngFor=\"let entry of activity\">\n <div class=\"activity-dot\" aria-hidden=\"true\"></div>\n <div class=\"flex-grow-1\">\n <div class=\"d-flex justify-content-between gap-3\">\n <span class=\"fw-semibold fs-7\">{{ entry.description || entry.actionType }}</span>\n <span class=\"text-muted fs-8 text-nowrap\">{{ entry.timeStamp | date: 'dd MMM, HH:mm' }}</span>\n </div>\n <div class=\"text-muted fs-8\" *ngIf=\"entry.comment\">{{ entry.comment }}</div>\n <div class=\"text-muted fs-8\" *ngIf=\"entry.IdentifiedBy && entry.IdentifiedBy !== 'Tango'\">by {{ entry.IdentifiedBy }}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".preinstall-page .back-btn,.preinstall-page .card-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.preinstall-page .back-btn .row-btn,.preinstall-page .card-head .row-btn{display:inline-flex;align-items:center;white-space:nowrap}.preinstall-page .row-btn{height:40px;display:inline-flex;align-items:center}.preinstall-page .state-badge{padding:6px 12px;font-weight:600;border-radius:999px}.preinstall-page .state-badge.state-waitingLayout,.preinstall-page .state-badge.state-loading,.preinstall-page .state-badge.state-unavailable{background:#f1f3f5;color:#5e6278}.preinstall-page .state-badge.state-processing{background:#eef6ff;color:#1b84ff}.preinstall-page .state-badge.state-failed{background:#fff5f8;color:#f1416c}.preinstall-page .state-badge.state-open{background:#e8fff3;color:#17c653}.preinstall-page .state-badge.state-approvalPending{background:#fff8dd;color:#f6c000}.preinstall-page .state-badge.state-approved{background:#e8fff3;color:#17c653}.preinstall-page .state-panel .state-box{border:1px solid #e9ecef;border-radius:8px;padding:16px 20px;opacity:0;transform:translateY(4px);animation:preinstallFade .25s ease forwards}.preinstall-page .state-panel .state-box.state-box-danger{border-color:#ffd6e1;background:#fff9fb}.preinstall-page .state-panel .state-box.state-box-success{border-color:#c8f2d8;background:#f6fffa}.preinstall-page .version-list .version-row{padding:10px 0;border-bottom:1px dashed #e9ecef}.preinstall-page .version-list .version-row:last-child{border-bottom:none}.preinstall-page .detail-grid .detail-row{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-bottom:1px dashed #f1f3f5;font-size:13px}.preinstall-page .detail-grid .detail-row:last-child{border-bottom:none}.preinstall-page .activity-list{max-height:420px;overflow-y:auto}.preinstall-page .activity-list .activity-row{display:flex;gap:10px;padding:8px 0}.preinstall-page .activity-list .activity-row .activity-dot{width:8px;height:8px;border-radius:50%;background:#1b84ff;margin-top:6px;flex-shrink:0}@keyframes preinstallFade{to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion: reduce){.preinstall-page .state-panel .state-box{animation:none;opacity:1;transform:none}}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i4.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i5.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "pipe", type: i4.DatePipe, name: "date" }] });
|
|
173
|
+
}
|
|
174
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PreinstallationInfoComponent, decorators: [{
|
|
175
|
+
type: Component,
|
|
176
|
+
args: [{ selector: 'lib-preinstallation-info', template: "<div class=\"container-fluid p-5 preinstall-page\">\n\n <!-- Header -->\n <div class=\"card mb-5\">\n <div class=\"card-body d-flex flex-wrap align-items-center justify-content-between gap-4 py-4\">\n <div class=\"d-flex align-items-center gap-4\">\n <button type=\"button\" class=\"btn btn-sm btn-light back-btn\" (click)=\"back()\" aria-label=\"Back to workspace\">\n <i class=\"bi bi-arrow-left\"></i>\n </button>\n <div>\n <div class=\"d-flex align-items-center gap-3\">\n <h4 class=\"mb-0\">{{ ticketInfo?.ticketId || ticketId }}</h4>\n <span class=\"badge state-badge\" [ngClass]=\"'state-' + placementState\">\n {{\n placementState === 'waitingLayout' ? 'Waiting for layout' :\n placementState === 'processing' ? 'Auto placement in progress' :\n placementState === 'failed' ? 'Placement failed' :\n placementState === 'open' ? 'Ready for placement review' :\n placementState === 'approvalPending' ? 'Waiting for approval' :\n placementState === 'approved' ? 'Approved' :\n placementState === 'unavailable' ? 'Status unavailable' : 'Loading'\n }}\n </span>\n </div>\n <div class=\"text-muted fs-7 mt-1\">\n Pre-Installation, camera placement\n <span *ngIf=\"ticketInfo?.basicDetails?.storeName\">, {{ ticketInfo?.basicDetails?.storeName }}</span>\n <span>, Floor {{ floorNumber }}</span>\n </div>\n </div>\n </div>\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\" class=\"btn btn-sm btn-light row-btn\" (click)=\"refresh()\">\n <i class=\"bi bi-arrow-clockwise me-1\"></i>Refresh\n </button>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"loading\" class=\"text-center py-10 text-muted\">Loading ticket...</div>\n\n <div *ngIf=\"!loading && ticketInfo\" class=\"row g-5\">\n\n <!-- Placement state / action panel -->\n <div class=\"col-12 col-lg-7\">\n <div class=\"card h-100\">\n <div class=\"card-body\">\n <div class=\"card-head mb-4\">\n <h5 class=\"mb-0\">Camera placement</h5>\n <!-- The imported drawing itself, for the internal team to inspect in\n CAD when the engine cannot handle it or before editing. -->\n <a *ngIf=\"sourceDxfUrl\" [href]=\"sourceDxfUrl\" target=\"_blank\" rel=\"noopener\"\n class=\"btn btn-sm btn-light row-btn\" [ngbTooltip]=\"sourceDxfName\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12 3v12m0 0 4-4m-4 4-4-4M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\"\n stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <span class=\"ms-1\">Download source DXF</span>\n </a>\n </div>\n\n <div [ngSwitch]=\"placementState\" class=\"state-panel\">\n\n <div *ngSwitchCase=\"'waitingLayout'\" class=\"state-box\">\n <p class=\"mb-1 fw-semibold\">Waiting for the CAD layout.</p>\n <p class=\"text-muted mb-0\">The store's floor drawing has not been imported yet. Auto placement starts right after the CAD import.</p>\n </div>\n\n <div *ngSwitchCase=\"'processing'\" class=\"state-box\">\n <div class=\"d-flex align-items-center gap-3 mb-1\">\n <span class=\"spinner-border spinner-border-sm text-primary\" role=\"status\" aria-hidden=\"true\"></span>\n <p class=\"mb-0 fw-semibold\">Auto camera placement is running.</p>\n </div>\n <p class=\"text-muted mb-0\">The DXF editor unlocks when placement completes. Use Refresh to check again.</p>\n </div>\n\n <div *ngSwitchCase=\"'failed'\" class=\"state-box state-box-danger\">\n <p class=\"mb-1 fw-semibold\">Auto placement failed.</p>\n <p class=\"text-muted mb-3\">{{ placement?.errorMsg || cctvRow?.errorMsg || 'The placement engine reported a failure.' }}</p>\n <!-- Retry hidden until the autoPlace Lambda exists (LAMBDAURL.autoPlace is empty).\n Re-enable by removing this comment; retryPlacement() is still wired in the component.\n <button type=\"button\" class=\"btn btn-sm btn-primary row-btn\" [disabled]=\"retrying\" (click)=\"retryPlacement()\">\n <span *ngIf=\"retrying\" class=\"spinner-border spinner-border-sm me-2\" role=\"status\" aria-hidden=\"true\"></span>\n {{ retrying ? 'Retrying...' : 'Retry auto placement' }}\n </button>\n -->\n </div>\n\n <div *ngSwitchCase=\"'open'\" class=\"state-box\">\n <p class=\"mb-1 fw-semibold\">The drawing is ready for camera review.</p>\n <p class=\"text-muted mb-3\">\n Adjust the auto-placed cameras in the DXF editor, then submit for approval.\n <span *ngIf=\"cctvRow?.isRework\" class=\"text-warning fw-semibold\">This floor was sent back for rework.</span>\n </p>\n <button type=\"button\" class=\"btn btn-sm btn-primary row-btn\" (click)=\"openEditor()\">\n <i class=\"bi bi-pencil-square me-1\"></i>Open DXF editor\n </button>\n </div>\n\n <div *ngSwitchCase=\"'approvalPending'\" class=\"state-box\">\n <p class=\"mb-1 fw-semibold\">Submitted, waiting for approval.</p>\n <p class=\"text-muted mb-3\">The approval team reviews it from the onboard table. You can still view the drawing.</p>\n <button type=\"button\" class=\"btn btn-sm btn-light row-btn\" (click)=\"openEditor()\">\n <i class=\"bi bi-eye me-1\"></i>View drawing\n </button>\n </div>\n\n <div *ngSwitchCase=\"'approved'\" class=\"state-box state-box-success\">\n <p class=\"mb-1 fw-semibold\">Camera placement approved.</p>\n <p class=\"text-muted mb-0\">This ticket is closed. The installation ticket takes over once every floor of the store is approved.</p>\n </div>\n\n <div *ngSwitchCase=\"'unavailable'\" class=\"state-box state-box-danger\">\n <p class=\"mb-1 fw-semibold\">Placement status unavailable.</p>\n <p class=\"text-muted mb-3\">{{ cctvError }}</p>\n <button type=\"button\" class=\"btn btn-sm btn-light row-btn\" (click)=\"loadCctvDetail()\">Try again</button>\n </div>\n\n <div *ngSwitchDefault class=\"state-box\">\n <p class=\"text-muted mb-0\">Loading placement status...</p>\n </div>\n </div>\n\n <!-- Version timeline -->\n <div *ngIf=\"versions.length\" class=\"mt-6\">\n <h6 class=\"text-muted mb-3\">Drawing versions</h6>\n <div class=\"version-list\">\n <div class=\"version-row d-flex align-items-center justify-content-between\" *ngFor=\"let file of versions\">\n <div>\n <span class=\"fw-semibold\">v{{ file.version }}</span>\n <span class=\"text-muted ms-2 fs-7\">{{ file.kind === 'auto' ? 'Auto placement' : file.kind === 'approver' ? 'Approver edit' : 'Internal edit' }}</span>\n <span class=\"text-muted ms-2 fs-7\" *ngIf=\"file.cameraCount != null\">{{ file.cameraCount }} cameras</span>\n </div>\n <div class=\"d-flex align-items-center gap-3\">\n <span class=\"text-muted fs-7\">{{ file.uploadedAt | date: 'dd MMM, y HH:mm' }}</span>\n <a *ngIf=\"fileUrls[file.key]\" [href]=\"fileUrls[file.key]\" target=\"_blank\" rel=\"noopener\" class=\"btn btn-sm btn-light row-btn\">\n <i class=\"bi bi-download\"></i>\n </a>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Ticket info + activity -->\n <div class=\"col-12 col-lg-5\">\n <div class=\"card mb-5\">\n <div class=\"card-body\">\n <h5 class=\"mb-4\">Ticket details</h5>\n <div class=\"detail-grid\">\n <div class=\"detail-row\"><span class=\"text-muted\">Store</span><span>{{ ticketInfo?.basicDetails?.storeName || '-' }} ({{ ticketInfo?.basicDetails?.storeId || storeId }})</span></div>\n <div class=\"detail-row\"><span class=\"text-muted\">Brand</span><span>{{ ticketInfo?.basicDetails?.clientName || '-' }}</span></div>\n <div class=\"detail-row\"><span class=\"text-muted\">Floor</span><span>Floor {{ floorNumber }}</span></div>\n <div class=\"detail-row\"><span class=\"text-muted\">Ticket status</span><span class=\"text-capitalize\">{{ ticketInfo?.status || '-' }}</span></div>\n <div class=\"detail-row\"><span class=\"text-muted\">Created</span><span>{{ ticketInfo?.createdAt | date: 'dd MMM, y HH:mm' }}</span></div>\n <div class=\"detail-row\" *ngIf=\"cctvRow?.assigneeName\"><span class=\"text-muted\">Assignee</span><span>{{ cctvRow?.assigneeName }}</span></div>\n <div class=\"detail-row\" *ngIf=\"cctvRow?.reworkCount\"><span class=\"text-muted\">Rework count</span><span>{{ cctvRow?.reworkCount }}</span></div>\n </div>\n </div>\n </div>\n\n <div class=\"card\">\n <div class=\"card-body\">\n <h5 class=\"mb-4\">Activity</h5>\n <div *ngIf=\"!activity.length\" class=\"text-muted fs-7\">No activity yet.</div>\n <div class=\"activity-list\">\n <div class=\"activity-row\" *ngFor=\"let entry of activity\">\n <div class=\"activity-dot\" aria-hidden=\"true\"></div>\n <div class=\"flex-grow-1\">\n <div class=\"d-flex justify-content-between gap-3\">\n <span class=\"fw-semibold fs-7\">{{ entry.description || entry.actionType }}</span>\n <span class=\"text-muted fs-8 text-nowrap\">{{ entry.timeStamp | date: 'dd MMM, HH:mm' }}</span>\n </div>\n <div class=\"text-muted fs-8\" *ngIf=\"entry.comment\">{{ entry.comment }}</div>\n <div class=\"text-muted fs-8\" *ngIf=\"entry.IdentifiedBy && entry.IdentifiedBy !== 'Tango'\">by {{ entry.IdentifiedBy }}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".preinstall-page .back-btn,.preinstall-page .card-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.preinstall-page .back-btn .row-btn,.preinstall-page .card-head .row-btn{display:inline-flex;align-items:center;white-space:nowrap}.preinstall-page .row-btn{height:40px;display:inline-flex;align-items:center}.preinstall-page .state-badge{padding:6px 12px;font-weight:600;border-radius:999px}.preinstall-page .state-badge.state-waitingLayout,.preinstall-page .state-badge.state-loading,.preinstall-page .state-badge.state-unavailable{background:#f1f3f5;color:#5e6278}.preinstall-page .state-badge.state-processing{background:#eef6ff;color:#1b84ff}.preinstall-page .state-badge.state-failed{background:#fff5f8;color:#f1416c}.preinstall-page .state-badge.state-open{background:#e8fff3;color:#17c653}.preinstall-page .state-badge.state-approvalPending{background:#fff8dd;color:#f6c000}.preinstall-page .state-badge.state-approved{background:#e8fff3;color:#17c653}.preinstall-page .state-panel .state-box{border:1px solid #e9ecef;border-radius:8px;padding:16px 20px;opacity:0;transform:translateY(4px);animation:preinstallFade .25s ease forwards}.preinstall-page .state-panel .state-box.state-box-danger{border-color:#ffd6e1;background:#fff9fb}.preinstall-page .state-panel .state-box.state-box-success{border-color:#c8f2d8;background:#f6fffa}.preinstall-page .version-list .version-row{padding:10px 0;border-bottom:1px dashed #e9ecef}.preinstall-page .version-list .version-row:last-child{border-bottom:none}.preinstall-page .detail-grid .detail-row{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-bottom:1px dashed #f1f3f5;font-size:13px}.preinstall-page .detail-grid .detail-row:last-child{border-bottom:none}.preinstall-page .activity-list{max-height:420px;overflow-y:auto}.preinstall-page .activity-list .activity-row{display:flex;gap:10px;padding:8px 0}.preinstall-page .activity-list .activity-row .activity-dot{width:8px;height:8px;border-radius:50%;background:#1b84ff;margin-top:6px;flex-shrink:0}@keyframes preinstallFade{to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion: reduce){.preinstall-page .state-panel .state-box{animation:none;opacity:1;transform:none}}\n"] }]
|
|
177
|
+
}], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: i1.Router }, { type: i2.TicketsService }, { type: i3.ToastService }] });
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJlaW5zdGFsbGF0aW9uLWluZm8uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdGFuZ28tdGlja2V0LXVzZXIvc3JjL2xpYi9jb21wb25lbnRzL3ByZWluc3RhbGxhdGlvbi1pbmZvL3ByZWluc3RhbGxhdGlvbi1pbmZvLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3RhbmdvLXRpY2tldC11c2VyL3NyYy9saWIvY29tcG9uZW50cy9wcmVpbnN0YWxsYXRpb24taW5mby9wcmVpbnN0YWxsYXRpb24taW5mby5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUU3RCxPQUFPLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQzs7Ozs7OztBQUkxQzs7Ozs7Ozs7Ozs7O0dBWUc7QUFNSCxNQUFNLE9BQU8sNEJBQTRCO0lBaUI3QjtJQUNBO0lBQ0E7SUFDQTtJQW5CVixRQUFRLENBQWdCO0lBQ3hCLE9BQU8sQ0FBZ0I7SUFDdkIsVUFBVSxDQUFNO0lBQ2hCLE9BQU8sQ0FBTTtJQUNiLFNBQVMsQ0FBTTtJQUNmLHlEQUF5RDtJQUN6RCxTQUFTLEdBQVEsSUFBSSxDQUFDO0lBQ3RCLFFBQVEsR0FBUSxFQUFFLENBQUM7SUFDbkIsT0FBTyxHQUFZLElBQUksQ0FBQztJQUN4QixXQUFXLEdBQVksS0FBSyxDQUFDO0lBQzdCLFNBQVMsR0FBVyxFQUFFLENBQUM7SUFDdkIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUVULFFBQVEsR0FBRyxJQUFJLE9BQU8sRUFBRSxDQUFDO0lBRTFDLFlBQ1UsS0FBcUIsRUFDckIsTUFBYyxFQUNkLE9BQXVCLEVBQ3ZCLFlBQTBCO1FBSDFCLFVBQUssR0FBTCxLQUFLLENBQWdCO1FBQ3JCLFdBQU0sR0FBTixNQUFNLENB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b20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBTdWJqZWN0LCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IFRvYXN0U2VydmljZSB9IGZyb20gJ3RhbmdvLWFwcC11aS1zaGFyZWQnO1xuaW1wb3J0IHsgVGlja2V0c1NlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy90aWNrZXQtaW5mcmEuc2VydmljZSc7XG5cbi8qKlxuICogUHJlLUluc3RhbGxhdGlvbiB0aWNrZXQgZGV0YWlsIHBhZ2UgKHdvcmtzcGFjZSBlbnRyeSBmb3IgVEVfUFJFIHRpY2tldHMpLlxuICogU2FtZSByb2xlIGFzIEluc3RhbGxhdGlvbkNvbXBvbmVudCBmb3IgVEVfSU5TIHRpY2tldHM6IHRoZSB0aWNrZXQgaGVhZGVyICtcbiAqIGFjdGl2aXR5IHRyYWlsIGNvbWUgZnJvbSB0aGUgdGlja2V0cyBBUEksIHRoZSBMSVZFIGNhbWVyYS1wbGFjZW1lbnQgc3RhdGVcbiAqIGNvbWVzIGZyb20gdGhlIHN0b3JlLWJ1aWxkZXIgQ0NUViByb3csIGFuZCB0aGUgcGFnZSBnYXRlcyB0aGUgbmV4dCBzdGVwOlxuICogICBhdXRvUGxhY2VtZW50ICAtPiBcIkF1dG8gcGxhY2VtZW50IGluIHByb2dyZXNzXCIsIGVkaXRvciBsb2NrZWRcbiAqICAgZmFpbGVkICAgICAgICAgLT4gZmFpbHVyZSByZWFzb24gKyBSZXRyeVxuICogICBvcGVuICAgICAgICAgICAtPiBcIk9wZW4gRFhGIGVkaXRvclwiIChhc3NpZ25lZSBnYXRlZCBzZXJ2ZXItc2lkZSlcbiAqICAgYXBwcm92YWxQZW5kaW5nLT4gd2FpdGluZyBmb3IgYXBwcm92YWwsIGRyYXdpbmcgdmlld2FibGVcbiAqICAgYXBwcm92ZWQgICAgICAgLT4gZG9uZSAodGlja2V0IGNsb3NlcyB2aWEgdGhlIGFwcHJvdmUgaG9vaylcbiAqIExvYWRpbmcgdGhlIENDVFYgZGV0YWlsIGFsc28gdHJpZ2dlcnMgdGhlIHNlcnZlci1zaWRlIE9TIHJlY29uY2lsZSwgc28gdGhpc1xuICogcGFnZSBrZWVwcyB0aGUgcm93IGZyZXNoLCB0aGUgam9iIHRoZSBDQ1RWIHRhYmxlIHVzZWQgdG8gZG8uXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1wcmVpbnN0YWxsYXRpb24taW5mbycsXG4gIHRlbXBsYXRlVXJsOiAnLi9wcmVpbnN0YWxsYXRpb24taW5mby5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsOiAnLi9wcmVpbnN0YWxsYXRpb24taW5mby5jb21wb25lbnQuc2NzcycsXG59KVxuZXhwb3J0IGNsYXNzIFByZWluc3RhbGxhdGlvbkluZm9Db21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIHRpY2tldElkOiBzdHJpbmcgfCBudWxsO1xuICBzdG9yZUlkOiBzdHJpbmcgfCBudWxsO1xuICB0aWNrZXRJbmZvOiBhbnk7XG4gIGNjdHZSb3c6IGFueTtcbiAgY2N0dkZsb29yOiBhbnk7XG4gIC8qKiBsaXZlIHBsYWNlbWVudCBzdGF0ZSBzdHJhaWdodCBvZmYgdGhlIHN0YXR1cyBpbmRleCAqL1xuICBwbGFjZW1lbnQ6IGFueSA9IG51bGw7XG4gIGZpbGVVcmxzOiBhbnkgPSB7fTtcbiAgbG9hZGluZzogYm9vbGVhbiA9IHRydWU7XG4gIGNjdHZMb2FkaW5nOiBib29sZWFuID0gZmFsc2U7XG4gIGNjdHZFcnJvcjogc3RyaW5nID0gJyc7XG4gIHJldHJ5aW5nOiBib29sZWFuID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByb3V0ZTogQWN0aXZhdGVkUm91dGUsXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcixcbiAgICBwcml2YXRlIHNlcnZpY2U6IFRpY2tldHNTZXJ2aWNlLFxuICAgIHByaXZhdGUgdG9hc3RTZXJ2aWNlOiBUb2FzdFNlcnZpY2UsXG4gICkge1xuICAgIHRoaXMudGlja2V0SWQgPSB0aGlzLnJvdXRlLnNuYXBzaG90LnBhcmFtTWFwLmdldCgndGlja2V0SWQnKTtcbiAgICB0aGlzLnN0b3JlSWQgPSB0aGlzLnJvdXRlLnNuYXBzaG90LnBhcmFtTWFwLmdldCgnc3RvcmVJZCcpO1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy52aWV3VGlja2V0KCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3kkLm5leHQodHJ1ZSk7XG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgZ2V0IGZsb29ySWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50aWNrZXRJbmZvPy5wcmVJbnN0YWxsYXRpb24/LmZsb29ySWQgfHwgJyc7XG4gIH1cblxuICBnZXQgZmxvb3JOdW1iZXIoKTogYW55IHtcbiAgICByZXR1cm4gdGhpcy50aWNrZXRJbmZvPy5wcmVJbnN0YWxsYXRpb24/LmZsb29yTnVtYmVyIHx8ICctJztcbiAgfVxuXG4gIC8qKiBQcmVzaWduZWQgbGluayB0byB0aGUgaW1wb3J0ZWQgZHJhd2luZyAodjEpLCBmcm9tIHRoZSBkZXRhaWwgY2FsbCdzIHVybCBtYXAuICovXG4gIGdldCBzb3VyY2VEeGZVcmwoKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3Qga2V5ID0gdGhpcy5jY3R2Um93Py5zb3VyY2VLZXk7XG4gICAgcmV0dXJuIGtleSA/IHRoaXMuZmlsZVVybHM/LltrZXldIHx8IG51bGwgOiBudWxsO1xuICB9XG5cbiAgZ2V0IHNvdXJjZUR4Zk5hbWUoKTogc3RyaW5nIHtcbiAgICBjb25zdCBrZXk6IHN0cmluZyA9IHRoaXMuY2N0dlJvdz8uc291cmNlS2V5IHx8ICcnO1xuICAgIHJldHVybiBrZXkuc3BsaXQoJy8nKS5wb3AoKSB8fCAnc291cmNlLmR4Zic7XG4gIH1cblxuICAvLyBUaGUgcGFnZSdzIHNpbmdsZSBzdGF0ZSBzd2l0Y2gsIGRlcml2ZWQgZnJvbSB0aWNrZXQgKyBsaXZlIENDVFYgcm93LlxuICBnZXQgcGxhY2VtZW50U3RhdGUoKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy50aWNrZXRJbmZvPy5zdGF0dXMgPT09ICdjbG9zZWQnKSByZXR1cm4gJ2FwcHJvdmVkJztcbiAgICBpZiAoIXRoaXMuZmxvb3JJZCkgcmV0dXJuICd3YWl0aW5nTGF5b3V0JztcbiAgICBpZiAoIXRoaXMuY2N0dlJvdykgcmV0dXJuIHRoaXMuY2N0dkVycm9yID8gJ3VuYXZhaWxhYmxlJyA6ICdsb2FkaW5nJztcblxuICAgIC8vIFRoZSBzdGF0dXMgaW5kZXggb3ducyB0aGUgcGxhY2VtZW50IGhhbGY6IHF1ZXVlZCBhbmQgcnVubmluZyBib3RoIHJlYWRcbiAgICAvLyBhcyBcImluIHByb2dyZXNzXCIsIGFuZCBhIGZhaWx1cmUgY2FycmllcyBpdHMgcmVhc29uLiBPbmNlIHRoZSBwbGFjZW1lbnRcbiAgICAvLyBpcyBkb25lIHRoZSB3b3JrZmxvdyByb3cgdGFrZXMgb3ZlciAob3BlbiB8IGFwcHJvdmFsUGVuZGluZyB8IGFwcHJvdmVkKS5cbiAgICBjb25zdCBqb2JTdGF0dXMgPSB0aGlzLnBsYWNlbWVudD8uc3RhdHVzO1xuICAgIGlmIChqb2JTdGF0dXMgPT09ICdwZW5kaW5nJyB8fCBqb2JTdGF0dXMgPT09ICdwcm9jZXNzaW5nJykgcmV0dXJuICdwcm9jZXNzaW5nJztcbiAgICBpZiAoam9iU3RhdHVzID09PSAnZmFpbGVkJykgcmV0dXJuICdmYWlsZWQnO1xuICAgIGlmICh0aGlzLmNjdHZSb3cuc3RhdHVzID09PSAnYXV0b1BsYWNlbWVudCcpIHJldHVybiAncHJvY2Vzc2luZyc7XG4gICAgcmV0dXJuIHRoaXMuY2N0dlJvdy5zdGF0dXM7XG4gIH1cblxuICBnZXQgdmVyc2lvbnMoKTogYW55W10ge1xuICAgIGNvbnN0IGZpbGVzID0gQXJyYXkuaXNBcnJheSh0aGlzLmNjdHZSb3c/LmZpbGVzKSA/IFsuLi50aGlzLmNjdHZSb3cuZmlsZXNdIDogW107XG4gICAgcmV0dXJuIGZpbGVzLnNvcnQoKGEsIGIpID0+IChiPy52ZXJzaW9uID8/IDApIC0gKGE/LnZlcnNpb24gPz8gMCkpO1xuICB9XG5cbiAgZ2V0IGFjdGl2aXR5KCk6IGFueVtdIHtcbiAgICBjb25zdCBsaXN0ID0gQXJyYXkuaXNBcnJheSh0aGlzLnRpY2tldEluZm8/LnRpY2tldEFjdGl2aXR5KSA/IFsuLi50aGlzLnRpY2tldEluZm8udGlja2V0QWN0aXZpdHldIDogW107XG4gICAgcmV0dXJuIGxpc3QucmV2ZXJzZSgpO1xuICB9XG5cbiAgdmlld1RpY2tldCgpOiB2b2lkIHtcbiAgICB0aGlzLnNlcnZpY2Uudmlld1RpY2tldCh7IHRpY2tldElkOiB0aGlzLnRpY2tldElkIH0pXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXG4gICAgICAuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKHJlczogYW55KSA9PiB7XG4gICAgICAgICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XG4gICAgICAgICAgaWYgKHJlcyAmJiByZXMuY29kZSA9PSAyMDApIHtcbiAgICAgICAgICAgIHRoaXMudGlja2V0SW5mbyA9IHJlcy5kYXRhO1xuICAgICAgICAgICAgaWYgKHRoaXMuZmxvb3JJZCkge1xuICAgICAgICAgICAgICB0aGlzLmxvYWRDY3R2RGV0YWlsKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBlcnJvcjogKCkgPT4ge1xuICAgICAgICAgIHRoaXMubG9hZGluZyA9IGZhbHNlO1xuICAgICAgICAgIHRoaXMudG9hc3RTZXJ2aWNlLmdldEVycm9yVG9hc3QoJ1VuYWJsZSB0byBsb2FkIHRoZSB0aWNrZXQuJyk7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgfVxuXG4gIGxvYWRDY3R2RGV0YWlsKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5mbG9vcklkKSByZXR1cm47XG4gICAgdGhpcy5jY3R2TG9hZGluZyA9IHRydWU7XG4gICAgdGhpcy5jY3R2RXJyb3IgPSAnJztcbiAgICB0aGlzLnNlcnZpY2UuZ2V0Q2N0dkRldGFpbCh0aGlzLmZsb29ySWQpXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXG4gICAgICAuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKHJlczogYW55KSA9PiB7XG4gICAgICAgICAgdGhpcy5jY3R2TG9hZGluZyA9IGZhbHNlO1xuICAgICAgICAgIHRoaXMuY2N0dlJvdyA9IHJlcz8uZGF0YT8ucm93IHx8IG51bGw7XG4gICAgICAgICAgdGhpcy5jY3R2Rmxvb3IgPSByZXM/LmRhdGE/LmZsb29yIHx8IG51bGw7XG4gICAgICAgICAgdGhpcy5maWxlVXJscyA9IHJlcz8uZGF0YT8udXJscyB8fCB7fTtcbiAgICAgICAgICB0aGlzLnBsYWNlbWVudCA9IHJlcz8uZGF0YT8ucGxhY2VtZW50IHx8IG51bGw7XG4gICAgICAgIH0sXG4gICAgICAgIGVycm9yOiAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5jY3R2TG9hZGluZyA9IGZhbHNlO1xuICAgICAgICAgIHRoaXMuY2N0dkVycm9yID0gJ1VuYWJsZSB0byBsb2FkIHRoZSBjYW1lcmEgcGxhY2VtZW50IHN0YXR1cy4nO1xuICAgICAgICB9LFxuICAgICAgfSk7XG4gIH1cblxuICByZWZyZXNoKCk6IHZvaWQge1xuICAgIHRoaXMudmlld1RpY2tldCgpO1xuICB9XG5cbiAgcmV0cnlQbGFjZW1lbnQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmZsb29ySWQgfHwgdGhpcy5yZXRyeWluZykgcmV0dXJuO1xuICAgIHRoaXMucmV0cnlpbmcgPSB0cnVlO1xuICAgIHRoaXMuc2VydmljZS5jY3R2UmV0cnkoeyBmbG9vcklkOiB0aGlzLmZsb29ySWQgfSlcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcbiAgICAgIC5zdWJzY3JpYmUoe1xuICAgICAgICBuZXh0OiAocmVzOiBhbnkpID0+IHtcbiAgICAgICAgICB0aGlzLnJldHJ5aW5nID0gZmFsc2U7XG4gICAgICAgICAgdGhpcy50b2FzdFNlcnZpY2UuZ2V0U3VjY2Vzc1RvYXN0KFxuICAgICAgICAgICAgcmVzPy5kYXRhPy5zdGFydGVkTm93ID9cbiAgICAgICAgICAgICAgJ0F1dG8gcGxhY2VtZW50IGlzIHJ1bm5pbmcgYWdhaW4uJyA6XG4gICAgICAgICAgICAgICdRdWV1ZWQgZm9yIGF1dG8gcGxhY2VtZW50LiBJdCB3aWxsIHN0YXJ0IG9uIHRoZSBuZXh0IHJ1bi4nLFxuICAgICAgICAgICk7XG4gICAgICAgICAgdGhpcy5sb2FkQ2N0dkRldGFpbCgpO1xuICAgICAgICB9LFxuICAgICAgICBlcnJvcjogKCkgPT4ge1xuICAgICAgICAgIHRoaXMucmV0cnlpbmcgPSBmYWxzZTtcbiAgICAgICAgICB0aGlzLnRvYXN0U2VydmljZS5nZXRFcnJvclRvYXN0KCdVbmFibGUgdG8gcmV0cnkuIFBsZWFzZSB0cnkgYWdhaW4uJyk7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgfVxuXG4gIG9wZW5FZGl0b3IoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmZsb29ySWQpIHJldHVybjtcbiAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbJy9tYW5hZ2UvcGxhbm9ncmFtL2NjdHYtZWRpdG9yJ10sIHtcbiAgICAgIHF1ZXJ5UGFyYW1zOiB7IGZsb29ySWQ6IHRoaXMuZmxvb3JJZCwgbW9kZTogJ2VkaXQnIH0sXG4gICAgfSk7XG4gIH1cblxuICBiYWNrKCk6IHZvaWQge1xuICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFsnL3RpY2tldHMvdXNlcnMnXSwgeyBxdWVyeVBhcmFtczogeyB0eXBlOiAnaW5zdGFsbGF0aW9uJyB9IH0pO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiY29udGFpbmVyLWZsdWlkIHAtNSBwcmVpbnN0YWxsLXBhZ2VcIj5cblxuICA8IS0tIEhlYWRlciAtLT5cbiAgPGRpdiBjbGFzcz1cImNhcmQgbWItNVwiPlxuICAgIDxkaXYgY2xhc3M9XCJjYXJkLWJvZHkgZC1mbGV4IGZsZXgtd3JhcCBhbGlnbi1pdGVtcy1jZW50ZXIganVzdGlmeS1jb250ZW50LWJldHdlZW4gZ2FwLTQgcHktNFwiPlxuICAgICAgPGRpdiBjbGFzcz1cImQtZmxleCBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTRcIj5cbiAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLXNtIGJ0bi1saWdodCBiYWNrLWJ0blwiIChjbGljayk9XCJiYWNrKClcIiBhcmlhLWxhYmVsPVwiQmFjayB0byB3b3Jrc3BhY2VcIj5cbiAgICAgICAgICA8aSBjbGFzcz1cImJpIGJpLWFycm93LWxlZnRcIj48L2k+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8ZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXggYWxpZ24taXRlbXMtY2VudGVyIGdhcC0zXCI+XG4gICAgICAgICAgICA8aDQgY2xhc3M9XCJtYi0wXCI+e3sgdGlja2V0SW5mbz8udGlja2V0SWQgfHwgdGlja2V0SWQgfX08L2g0PlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJiYWRnZSBzdGF0ZS1iYWRnZVwiIFtuZ0NsYXNzXT1cIidzdGF0ZS0nICsgcGxhY2VtZW50U3RhdGVcIj5cbiAgICAgICAgICAgICAge3tcbiAgICAgICAgICAgICAgICBwbGFjZW1lbnRTdGF0ZSA9PT0gJ3dhaXRpbmdMYXlvdXQnID8gJ1dhaXRpbmcgZm9yIGxheW91dCcgOlxuICAgICAgICAgICAgICAgIHBsYWNlbWVudFN0YXRlID09PSAncHJvY2Vzc2luZycgPyAnQXV0byBwbGFjZW1lbnQgaW4gcHJvZ3Jlc3MnIDpcbiAgICAgICAgICAgICAgICBwbGFjZW1lbnRTdGF0ZSA9PT0gJ2ZhaWxlZCcgPyAnUGxhY2VtZW50IGZhaWxlZCcgOlxuICAgICAgICAgICAgICAgIHBsYWNlbWVudFN0YXRlID09PSAnb3BlbicgPyAnUmVhZHkgZm9yIHBsYWNlbWVudCByZXZpZXcnIDpcbiAgICAgICAgICAgICAgICBwbGFjZW1lbnRTdGF0ZSA9PT0gJ2FwcHJvdmFsUGVuZGluZycgPyAnV2FpdGluZyBmb3IgYXBwcm92YWwnIDpcbiAgICAgICAgICAgICAgICBwbGFjZW1lbnRTdGF0ZSA9PT0gJ2FwcHJvdmVkJyA/ICdBcHByb3ZlZCcgOlxuICAgICAgICAgICAgICAgIHBsYWNlbWVudFN0YXRlID09PSAndW5hdmFpbGFibGUnID8gJ1N0YXR1cyB1bmF2YWlsYWJsZScgOiAnTG9hZGluZydcbiAgICAgICAgICAgICAgfX1cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwidGV4dC1tdXRlZCBmcy03IG10LTFcIj5cbiAgICAgICAgICAgIFByZS1JbnN0YWxsYXRpb24sIGNhbWVyYSBwbGFjZW1lbnRcbiAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwidGlja2V0SW5mbz8uYmFzaWNEZXRhaWxzPy5zdG9yZU5hbWVcIj4sIHt7IHRpY2tldEluZm8/LmJhc2ljRGV0YWlscz8uc3RvcmVOYW1lIH19PC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4+LCBGbG9vciB7eyBmbG9vck51bWJlciB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXggYWxpZ24taXRlbXMtY2VudGVyIGdhcC0zXCI+XG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1zbSBidG4tbGlnaHQgcm93LWJ0blwiIChjbGljayk9XCJyZWZyZXNoKClcIj5cbiAgICAgICAgICA8aSBjbGFzcz1cImJpIGJpLWFycm93LWNsb2Nrd2lzZSBtZS0xXCI+PC9pPlJlZnJlc2hcbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPGRpdiAqbmdJZj1cImxvYWRpbmdcIiBjbGFzcz1cInRleHQtY2VudGVyIHB5LTEwIHRleHQtbXV0ZWRcIj5Mb2FkaW5nIHRpY2tldC4uLjwvZGl2PlxuXG4gIDxkaXYgKm5nSWY9XCIhbG9hZGluZyAmJiB0aWNrZXRJbmZvXCIgY2xhc3M9XCJyb3cgZy01XCI+XG5cbiAgICA8IS0tIFBsYWNlbWVudCBzdGF0ZSAvIGFjdGlvbiBwYW5lbCAtLT5cbiAgICA8ZGl2IGNsYXNzPVwiY29sLTEyIGNvbC1sZy03XCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY2FyZCBoLTEwMFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1ib2R5XCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQtaGVhZCBtYi00XCI+XG4gICAgICAgICAgICA8aDUgY2xhc3M9XCJtYi0wXCI+Q2FtZXJhIHBsYWNlbWVudDwvaDU+XG4gICAgICAgICAgICA8IS0tIFRoZSBpbXBvcnRlZCBkcmF3aW5nIGl0c2VsZiwgZm9yIHRoZSBpbnRlcm5hbCB0ZWFtIHRvIGluc3BlY3QgaW5cbiAgICAgICAgICAgICAgICAgQ0FEIHdoZW4gdGhlIGVuZ2luZSBjYW5ub3QgaGFuZGxlIGl0IG9yIGJlZm9yZSBlZGl0aW5nLiAtLT5cbiAgICAgICAgICAgIDxhICpuZ0lmPVwic291cmNlRHhmVXJsXCIgW2hyZWZdPVwic291cmNlRHhmVXJsXCIgdGFyZ2V0PVwiX2JsYW5rXCIgcmVsPVwibm9vcGVuZXJcIlxuICAgICAgICAgICAgICBjbGFzcz1cImJ0biBidG4tc20gYnRuLWxpZ2h0IHJvdy1idG5cIiBbbmdiVG9vbHRpcF09XCJzb3VyY2VEeGZOYW1lXCI+XG4gICAgICAgICAgICAgIDxzdmcgd2lkdGg9XCIxNlwiIGhlaWdodD1cIjE2XCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPlxuICAgICAgICAgICAgICAgIDxwYXRoIGQ9XCJNMTIgM3YxMm0wIDAgNC00bS00IDQtNC00TTQgMTd2MmEyIDIgMCAwIDAgMiAyaDEyYTIgMiAwIDAgMCAyLTJ2LTJcIlxuICAgICAgICAgICAgICAgICAgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMS44XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cbiAgICAgICAgICAgICAgPC9zdmc+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibXMtMVwiPkRvd25sb2FkIHNvdXJjZSBEWEY8L3NwYW4+XG4gICAgICAgICAgICA8L2E+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8ZGl2IFtuZ1N3aXRjaF09XCJwbGFjZW1lbnRTdGF0ZVwiIGNsYXNzPVwic3RhdGUtcGFuZWxcIj5cblxuICAgICAgICAgICAgPGRpdiAqbmdTd2l0Y2hDYXNlPVwiJ3dhaXRpbmdMYXlvdXQnXCIgY2xhc3M9XCJzdGF0ZS1ib3hcIj5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJtYi0xIGZ3LXNlbWlib2xkXCI+V2FpdGluZyBmb3IgdGhlIENBRCBsYXlvdXQuPC9wPlxuICAgICAgICAgICAgICA8cCBjbGFzcz1cInRleHQtbXV0ZWQgbWItMFwiPlRoZSBzdG9yZSdzIGZsb29yIGRyYXdpbmcgaGFzIG5vdCBiZWVuIGltcG9ydGVkIHlldC4gQXV0byBwbGFjZW1lbnQgc3RhcnRzIHJpZ2h0IGFmdGVyIHRoZSBDQUQgaW1wb3J0LjwvcD5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2ICpuZ1N3aXRjaENhc2U9XCIncHJvY2Vzc2luZydcIiBjbGFzcz1cInN0YXRlLWJveFwiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGFsaWduLWl0ZW1zLWNlbnRlciBnYXAtMyBtYi0xXCI+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzcGlubmVyLWJvcmRlciBzcGlubmVyLWJvcmRlci1zbSB0ZXh0LXByaW1hcnlcIiByb2xlPVwic3RhdHVzXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9zcGFuPlxuICAgICAgICAgICAgICAgIDxwIGNsYXNzPVwibWItMCBmdy1zZW1pYm9sZFwiPkF1dG8gY2FtZXJhIHBsYWNlbWVudCBpcyBydW5uaW5nLjwvcD5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDxwIGNsYXNzPVwidGV4dC1tdXRlZCBtYi0wXCI+VGhlIERYRiBlZGl0b3IgdW5sb2NrcyB3aGVuIHBsYWNlbWVudCBjb21wbGV0ZXMuIFVzZSBSZWZyZXNoIHRvIGNoZWNrIGFnYWluLjwvcD5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2ICpuZ1N3aXRjaENhc2U9XCInZmFpbGVkJ1wiIGNsYXNzPVwic3RhdGUtYm94IHN0YXRlLWJveC1kYW5nZXJcIj5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJtYi0xIGZ3LXNlbWlib2xkXCI+QXV0byBwbGFjZW1lbnQgZmFpbGVkLjwvcD5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJ0ZXh0LW11dGVkIG1iLTNcIj57eyBwbGFjZW1lbnQ/LmVycm9yTXNnIHx8IGNjdHZSb3c/LmVycm9yTXNnIHx8ICdUaGUgcGxhY2VtZW50IGVuZ2luZSByZXBvcnRlZCBhIGZhaWx1cmUuJyB9fTwvcD5cbiAgICAgICAgICAgICAgPCEtLSBSZXRyeSBoaWRkZW4gdW50aWwgdGhlIGF1dG9QbGFjZSBMYW1iZGEgZXhpc3RzIChMQU1CREFVUkwuYXV0b1BsYWNlIGlzIGVtcHR5KS5cbiAgICAgICAgICAgICAgICAgICBSZS1lbmFibGUgYnkgcmVtb3ZpbmcgdGhpcyBjb21tZW50OyByZXRyeVBsYWNlbWVudCgpIGlzIHN0aWxsIHdpcmVkIGluIHRoZSBjb21wb25lbnQuXG4gICAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1zbSBidG4tcHJpbWFyeSByb3ctYnRuXCIgW2Rpc2FibGVkXT1cInJldHJ5aW5nXCIgKGNsaWNrKT1cInJldHJ5UGxhY2VtZW50KClcIj5cbiAgICAgICAgICAgICAgICA8c3BhbiAqbmdJZj1cInJldHJ5aW5nXCIgY2xhc3M9XCJzcGlubmVyLWJvcmRlciBzcGlubmVyLWJvcmRlci1zbSBtZS0yXCIgcm9sZT1cInN0YXR1c1wiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPjwvc3Bhbj5cbiAgICAgICAgICAgICAgICB7eyByZXRyeWluZyA/ICdSZXRyeWluZy4uLicgOiAnUmV0cnkgYXV0byBwbGFjZW1lbnQnIH19XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAtLT5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2ICpuZ1N3aXRjaENhc2U9XCInb3BlbidcIiBjbGFzcz1cInN0YXRlLWJveFwiPlxuICAgICAgICAgICAgICA8cCBjbGFzcz1cIm1iLTEgZnctc2VtaWJvbGRcIj5UaGUgZHJhd2luZyBpcyByZWFkeSBmb3IgY2FtZXJhIHJldmlldy48L3A+XG4gICAgICAgICAgICAgIDxwIGNsYXNzPVwidGV4dC1tdXRlZCBtYi0zXCI+XG4gICAgICAgICAgICAgICAgQWRqdXN0IHRoZSBhdXRvLXBsYWNlZCBjYW1lcmFzIGluIHRoZSBEWEYgZWRpdG9yLCB0aGVuIHN1Ym1pdCBmb3IgYXBwcm92YWwuXG4gICAgICAgICAgICAgICAgPHNwYW4gKm5nSWY9XCJjY3R2Um93Py5pc1Jld29ya1wiIGNsYXNzPVwidGV4dC13YXJuaW5nIGZ3LXNlbWlib2xkXCI+VGhpcyBmbG9vciB3YXMgc2VudCBiYWNrIGZvciByZXdvcmsuPC9zcGFuPlxuICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1zbSBidG4tcHJpbWFyeSByb3ctYnRuXCIgKGNsaWNrKT1cIm9wZW5FZGl0b3IoKVwiPlxuICAgICAgICAgICAgICAgIDxpIGNsYXNzPVwiYmkgYmktcGVuY2lsLXNxdWFyZSBtZS0xXCI+PC9pPk9wZW4gRFhGIGVkaXRvclxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2ICpuZ1N3aXRjaENhc2U9XCInYXBwcm92YWxQZW5kaW5nJ1wiIGNsYXNzPVwic3RhdGUtYm94XCI+XG4gICAgICAgICAgICAgIDxwIGNsYXNzPVwibWItMSBmdy1zZW1pYm9sZFwiPlN1Ym1pdHRlZCwgd2FpdGluZyBmb3IgYXBwcm92YWwuPC9wPlxuICAgICAgICAgICAgICA8cCBjbGFzcz1cInRleHQtbXV0ZWQgbWItM1wiPlRoZSBhcHByb3ZhbCB0ZWFtIHJldmlld3MgaXQgZnJvbSB0aGUgb25ib2FyZCB0YWJsZS4gWW91IGNhbiBzdGlsbCB2aWV3IHRoZSBkcmF3aW5nLjwvcD5cbiAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLXNtIGJ0bi1saWdodCByb3ctYnRuXCIgKGNsaWNrKT1cIm9wZW5FZGl0b3IoKVwiPlxuICAgICAgICAgICAgICAgIDxpIGNsYXNzPVwiYmkgYmktZXllIG1lLTFcIj48L2k+VmlldyBkcmF3aW5nXG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDxkaXYgKm5nU3dpdGNoQ2FzZT1cIidhcHByb3ZlZCdcIiBjbGFzcz1cInN0YXRlLWJveCBzdGF0ZS1ib3gtc3VjY2Vzc1wiPlxuICAgICAgICAgICAgICA8cCBjbGFzcz1cIm1iLTEgZnctc2VtaWJvbGRcIj5DYW1lcmEgcGxhY2VtZW50IGFwcHJvdmVkLjwvcD5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJ0ZXh0LW11dGVkIG1iLTBcIj5UaGlzIHRpY2tldCBpcyBjbG9zZWQuIFRoZSBpbnN0YWxsYXRpb24gdGlja2V0IHRha2VzIG92ZXIgb25jZSBldmVyeSBmbG9vciBvZiB0aGUgc3RvcmUgaXMgYXBwcm92ZWQuPC9wPlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDxkaXYgKm5nU3dpdGNoQ2FzZT1cIid1bmF2YWlsYWJsZSdcIiBjbGFzcz1cInN0YXRlLWJveCBzdGF0ZS1ib3gtZGFuZ2VyXCI+XG4gICAgICAgICAgICAgIDxwIGNsYXNzPVwibWItMSBmdy1zZW1pYm9sZFwiPlBsYWNlbWVudCBzdGF0dXMgdW5hdmFpbGFibGUuPC9wPlxuICAgICAgICAgICAgICA8cCBjbGFzcz1cInRleHQtbXV0ZWQgbWItM1wiPnt7IGNjdHZFcnJvciB9fTwvcD5cbiAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLXNtIGJ0bi1saWdodCByb3ctYnRuXCIgKGNsaWNrKT1cImxvYWRDY3R2RGV0YWlsKClcIj5UcnkgYWdhaW48L2J1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2ICpuZ1N3aXRjaERlZmF1bHQgY2xhc3M9XCJzdGF0ZS1ib3hcIj5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJ0ZXh0LW11dGVkIG1iLTBcIj5Mb2FkaW5nIHBsYWNlbWVudCBzdGF0dXMuLi48L3A+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDwhLS0gVmVyc2lvbiB0aW1lbGluZSAtLT5cbiAgICAgICAgICA8ZGl2ICpuZ0lmPVwidmVyc2lvbnMubGVuZ3RoXCIgY2xhc3M9XCJtdC02XCI+XG4gICAgICAgICAgICA8aDYgY2xhc3M9XCJ0ZXh0LW11dGVkIG1iLTNcIj5EcmF3aW5nIHZlcnNpb25zPC9oNj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ2ZXJzaW9uLWxpc3RcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInZlcnNpb24tcm93IGQtZmxleCBhbGlnbi1pdGVtcy1jZW50ZXIganVzdGlmeS1jb250ZW50LWJldHdlZW5cIiAqbmdGb3I9XCJsZXQgZmlsZSBvZiB2ZXJzaW9uc1wiPlxuICAgICAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImZ3LXNlbWlib2xkXCI+dnt7IGZpbGUudmVyc2lvbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1tdXRlZCBtcy0yIGZzLTdcIj57eyBmaWxlLmtpbmQgPT09ICdhdXRvJyA/ICdBdXRvIHBsYWNlbWVudCcgOiBmaWxlLmtpbmQgPT09ICdhcHByb3ZlcicgPyAnQXBwcm92ZXIgZWRpdCcgOiAnSW50ZXJuYWwgZWRpdCcgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtbXV0ZWQgbXMtMiBmcy03XCIgKm5nSWY9XCJmaWxlLmNhbWVyYUNvdW50ICE9IG51bGxcIj57eyBmaWxlLmNhbWVyYUNvdW50IH19IGNhbWVyYXM8L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImQtZmxleCBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTNcIj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1tdXRlZCBmcy03XCI+e3sgZmlsZS51cGxvYWRlZEF0IHwgZGF0ZTogJ2RkIE1NTSwgeSBISDptbScgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8YSAqbmdJZj1cImZpbGVVcmxzW2ZpbGUua2V5XVwiIFtocmVmXT1cImZpbGVVcmxzW2ZpbGUua2V5XVwiIHRhcmdldD1cIl9ibGFua1wiIHJlbD1cIm5vb3BlbmVyXCIgY2xhc3M9XCJidG4gYnRuLXNtIGJ0bi1saWdodCByb3ctYnRuXCI+XG4gICAgICAgICAgICAgICAgICAgIDxpIGNsYXNzPVwiYmkgYmktZG93bmxvYWRcIj48L2k+XG4gICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIFRpY2tldCBpbmZvICsgYWN0aXZpdHkgLS0+XG4gICAgPGRpdiBjbGFzcz1cImNvbC0xMiBjb2wtbGctNVwiPlxuICAgICAgPGRpdiBjbGFzcz1cImNhcmQgbWItNVwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1ib2R5XCI+XG4gICAgICAgICAgPGg1IGNsYXNzPVwibWItNFwiPlRpY2tldCBkZXRhaWxzPC9oNT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZGV0YWlsLWdyaWRcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkZXRhaWwtcm93XCI+PHNwYW4gY2xhc3M9XCJ0ZXh0LW11dGVkXCI+U3RvcmU8L3NwYW4+PHNwYW4+e3sgdGlja2V0SW5mbz8uYmFzaWNEZXRhaWxzPy5zdG9yZU5hbWUgfHwgJy0nIH19ICh7eyB0aWNrZXRJbmZvPy5iYXNpY0RldGFpbHM/LnN0b3JlSWQgfHwgc3RvcmVJZCB9fSk8L3NwYW4+PC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZGV0YWlsLXJvd1wiPjxzcGFuIGNsYXNzPVwidGV4dC1tdXRlZFwiPkJyYW5kPC9zcGFuPjxzcGFuPnt7IHRpY2tldEluZm8/LmJhc2ljRGV0YWlscz8uY2xpZW50TmFtZSB8fCAnLScgfX08L3NwYW4+PC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZGV0YWlsLXJvd1wiPjxzcGFuIGNsYXNzPVwidGV4dC1tdXRlZFwiPkZsb29yPC9zcGFuPjxzcGFuPkZsb29yIHt7IGZsb29yTnVtYmVyIH19PC9zcGFuPjwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImRldGFpbC1yb3dcIj48c3BhbiBjbGFzcz1cInRleHQtbXV0ZWRcIj5UaWNrZXQgc3RhdHVzPC9zcGFuPjxzcGFuIGNsYXNzPVwidGV4dC1jYXBpdGFsaXplXCI+e3sgdGlja2V0SW5mbz8uc3RhdHVzIHx8ICctJyB9fTwvc3Bhbj48L2Rpdj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkZXRhaWwtcm93XCI+PHNwYW4gY2xhc3M9XCJ0ZXh0LW11dGVkXCI+Q3JlYXRlZDwvc3Bhbj48c3Bhbj57eyB0aWNrZXRJbmZvPy5jcmVhdGVkQXQgfCBkYXRlOiAnZGQgTU1NLCB5IEhIOm1tJyB9fTwvc3Bhbj48L2Rpdj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkZXRhaWwtcm93XCIgKm5nSWY9XCJjY3R2Um93Py5hc3NpZ25lZU5hbWVcIj48c3BhbiBjbGFzcz1cInRleHQtbXV0ZWRcIj5Bc3NpZ25lZTwvc3Bhbj48c3Bhbj57eyBjY3R2Um93Py5hc3NpZ25lZU5hbWUgfX08L3NwYW4+PC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZGV0YWlsLXJvd1wiICpuZ0lmPVwiY2N0dlJvdz8ucmV3b3JrQ291bnRcIj48c3BhbiBjbGFzcz1cInRleHQtbXV0ZWRcIj5SZXdvcmsgY291bnQ8L3NwYW4+PHNwYW4+e3sgY2N0dlJvdz8ucmV3b3JrQ291bnQgfX08L3NwYW4+PC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJjYXJkXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWJvZHlcIj5cbiAgICAgICAgICA8aDUgY2xhc3M9XCJtYi00XCI+QWN0aXZpdHk8L2g1PlxuICAgICAgICAgIDxkaXYgKm5nSWY9XCIhYWN0aXZpdHkubGVuZ3RoXCIgY2xhc3M9XCJ0ZXh0LW11dGVkIGZzLTdcIj5ObyBhY3Rpdml0eSB5ZXQuPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImFjdGl2aXR5LWxpc3RcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJhY3Rpdml0eS1yb3dcIiAqbmdGb3I9XCJsZXQgZW50cnkgb2YgYWN0aXZpdHlcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImFjdGl2aXR5LWRvdFwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPjwvZGl2PlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleC1ncm93LTFcIj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGp1c3RpZnktY29udGVudC1iZXR3ZWVuIGdhcC0zXCI+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImZ3LXNlbWlib2xkIGZzLTdcIj57eyBlbnRyeS5kZXNjcmlwdGlvbiB8fCBlbnRyeS5hY3Rpb25UeXBlIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LW11dGVkIGZzLTggdGV4dC1ub3dyYXBcIj57eyBlbnRyeS50aW1lU3RhbXAgfCBkYXRlOiAnZGQgTU1NLCBISDptbScgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInRleHQtbXV0ZWQgZnMtOFwiICpuZ0lmPVwiZW50cnkuY29tbWVudFwiPnt7IGVudHJ5LmNvbW1lbnQgfX08L2Rpdj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwidGV4dC1tdXRlZCBmcy04XCIgKm5nSWY9XCJlbnRyeS5JZGVudGlmaWVkQnkgJiYgZW50cnkuSWRlbnRpZmllZEJ5ICE9PSAnVGFuZ28nXCI+Ynkge3sgZW50cnkuSWRlbnRpZmllZEJ5IH19PC9kaXY+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=
|