tango-app-ui-store-builder 1.2.10 → 1.2.12

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 (50) hide show
  1. package/esm2022/lib/components/chips-input/chips-input.component.mjs +101 -0
  2. package/esm2022/lib/components/collection-update-ai/find-replace-layout/prepare-template/prepare-template.component.mjs +2 -2
  3. package/esm2022/lib/components/create-fixture/create-fixture.component.mjs +66 -25
  4. package/esm2022/lib/components/create-vm/create-vm.component.mjs +2 -2
  5. package/esm2022/lib/components/fixture-template/template-basic-details/template-basic-details.component.mjs +1 -1
  6. package/esm2022/lib/components/fixture-template/template-products/template-products.component.mjs +15 -5
  7. package/esm2022/lib/components/fixture-template/template-vms/template-vms.component.mjs +31 -12
  8. package/esm2022/lib/components/fixture-template-table/popups/create-fixture-template/create-fixture-template.component.mjs +1 -1
  9. package/esm2022/lib/components/look-plano-collection/look-plano-collection.component.mjs +156 -0
  10. package/esm2022/lib/components/look-plano-collection-form/look-plano-collection-form.component.mjs +1204 -0
  11. package/esm2022/lib/components/manage-store-plano/manage-store-plano.component.mjs +1 -1
  12. package/esm2022/lib/components/manage-store-plano/plano-rollout/plano-rollout.component.mjs +1 -1
  13. package/esm2022/lib/components/manage-store-plano/template-basic-details/template-basic-details.component.mjs +1 -1
  14. package/esm2022/lib/components/manage-store-plano/template-products/template-products.component.mjs +2 -2
  15. package/esm2022/lib/components/manage-store-plano/template-vms/template-vms.component.mjs +2 -2
  16. package/esm2022/lib/components/manage-store-plano/verification-feedback/zone-editable-fixture/zone-editable-fixture.component.mjs +1 -1
  17. package/esm2022/lib/components/multiselect-chip-dropdown/multiselect-chip-dropdown.component.mjs +27 -4
  18. package/esm2022/lib/components/onboard-store-plano/create-planogram/create-planogram.component.mjs +2 -2
  19. package/esm2022/lib/components/onboard-store-plano/onboard-store-plano.component.mjs +1 -1
  20. package/esm2022/lib/components/plano-library/fixture-library/popups/create-fixture-modal/create-fixture-modal.component.mjs +1 -1
  21. package/esm2022/lib/components/plano-tools/delete-floor/delete-floor.component.mjs +3 -3
  22. package/esm2022/lib/components/plano-tools/move-bucket/move-bucket.component.mjs +1 -1
  23. package/esm2022/lib/components/plano-tools/swap-template/swap-template.component.mjs +1 -1
  24. package/esm2022/lib/components/planogram/plano-details-parent/plano-details-parent.component.mjs +1 -1
  25. package/esm2022/lib/components/planogram/plano-overview/plano-overview.component.mjs +1 -1
  26. package/esm2022/lib/components/popups/publish-plano-modal/publish-plano-modal.component.mjs +1 -1
  27. package/esm2022/lib/components/reactive-select/reactive-select.component.mjs +22 -3
  28. package/esm2022/lib/components/searchable-select/searchable-select.component.mjs +265 -0
  29. package/esm2022/lib/components/store-plano/store-plano.component.mjs +1 -1
  30. package/esm2022/lib/interfaces/fixture-library.interface.mjs +1 -1
  31. package/esm2022/lib/services/store-builder.service.mjs +28 -3
  32. package/esm2022/lib/tango-store-builder-routing.module.mjs +11 -1
  33. package/esm2022/lib/tango-store-builder.module.mjs +23 -4
  34. package/fesm2022/tango-app-ui-store-builder.mjs +1914 -69
  35. package/fesm2022/tango-app-ui-store-builder.mjs.map +1 -1
  36. package/lib/components/chips-input/chips-input.component.d.ts +35 -0
  37. package/lib/components/create-fixture/create-fixture.component.d.ts +3 -0
  38. package/lib/components/fixture-template/template-products/template-products.component.d.ts +9 -1
  39. package/lib/components/fixture-template/template-vms/template-vms.component.d.ts +9 -1
  40. package/lib/components/look-plano-collection/look-plano-collection.component.d.ts +53 -0
  41. package/lib/components/look-plano-collection-form/look-plano-collection-form.component.d.ts +237 -0
  42. package/lib/components/manage-plano/rollout-table/rollout-table.component.d.ts +4 -4
  43. package/lib/components/manage-plano/verification-table/verification-table.component.d.ts +5 -5
  44. package/lib/components/multiselect-chip-dropdown/multiselect-chip-dropdown.component.d.ts +12 -1
  45. package/lib/components/reactive-select/reactive-select.component.d.ts +12 -1
  46. package/lib/components/searchable-select/searchable-select.component.d.ts +56 -0
  47. package/lib/interfaces/fixture-library.interface.d.ts +1 -0
  48. package/lib/services/store-builder.service.d.ts +7 -1
  49. package/lib/tango-store-builder.module.d.ts +39 -34
  50. package/package.json +1 -1
@@ -63,7 +63,7 @@ export class CreateFixtureTemplateComponent {
63
63
  this.activeModal.dismiss();
64
64
  }
65
65
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CreateFixtureTemplateComponent, deps: [{ token: i1.NgbActiveModal }, { token: i2.StoreBuilderService }, { token: i3.ToastService }], target: i0.ɵɵFactoryTarget.Component });
66
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CreateFixtureTemplateComponent, selector: "app-create-fixture-template", inputs: { clientId: "clientId" }, ngImport: i0, template: "<div class=\"modal-wrapper\">\r\n <h3 class=\"mb-4\">Create fixture template</h3>\r\n <lib-reactive-select\r\n [(ngModel)]=\"selectedFixtureType\"\r\n [idField]=\"'value'\"\r\n [nameField]=\"'label'\"\r\n [data]=\"fixtureTypesList\"\r\n [label]=\"'Select fixture Type'\"\r\n class=\"mb-4\"\r\n [search]=\"true\"\r\n >\r\n </lib-reactive-select>\r\n\r\n <div class=\"modal-actions mt-5\">\r\n <button type=\"button\" class=\"btn btn-outline\" (click)=\"onCancel()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary px-4\" [disabled]=\"!selectedFixtureType\" (click)=\"onCreate()\">Create</button>\r\n </div>\r\n</div>\r\n", styles: [".modal-wrapper{padding:24px}.type-container{display:flex;justify-content:stretch;gap:16px;margin-bottom:24px}.type-item{width:100%;padding:30px;background:#fff;border:2px solid #d0d5dd;border-radius:6px;display:flex;flex-direction:column;justify-content:center;align-items:center;transition:all ease .2s;box-shadow:0 8px 8px -4px #fff0;box-shadow:0 20px 24px -4px #fff0}.type-item:hover{cursor:pointer}.type-item.active{border:2px solid #00a3ff;box-shadow:0 8px 8px -4px #10182808;box-shadow:0 20px 24px -4px #10182814}.modal-actions{display:flex;justify-content:end;gap:12px}::ng-deep .modal-content{border-radius:12px!important}\n"], dependencies: [{ kind: "component", type: i4.ReactiveSelectComponent, selector: "lib-reactive-select", inputs: ["idField", "nameField", "subTextField", "searchField", "label", "data", "action", "search", "prefix", "actionLabel"], outputs: ["actionClick"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
66
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CreateFixtureTemplateComponent, selector: "app-create-fixture-template", inputs: { clientId: "clientId" }, ngImport: i0, template: "<div class=\"modal-wrapper\">\r\n <h3 class=\"mb-4\">Create fixture template</h3>\r\n <lib-reactive-select\r\n [(ngModel)]=\"selectedFixtureType\"\r\n [idField]=\"'value'\"\r\n [nameField]=\"'label'\"\r\n [data]=\"fixtureTypesList\"\r\n [label]=\"'Select fixture Type'\"\r\n class=\"mb-4\"\r\n [search]=\"true\"\r\n >\r\n </lib-reactive-select>\r\n\r\n <div class=\"modal-actions mt-5\">\r\n <button type=\"button\" class=\"btn btn-outline\" (click)=\"onCancel()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary px-4\" [disabled]=\"!selectedFixtureType\" (click)=\"onCreate()\">Create</button>\r\n </div>\r\n</div>\r\n", styles: [".modal-wrapper{padding:24px}.type-container{display:flex;justify-content:stretch;gap:16px;margin-bottom:24px}.type-item{width:100%;padding:30px;background:#fff;border:2px solid #d0d5dd;border-radius:6px;display:flex;flex-direction:column;justify-content:center;align-items:center;transition:all ease .2s;box-shadow:0 8px 8px -4px #fff0;box-shadow:0 20px 24px -4px #fff0}.type-item:hover{cursor:pointer}.type-item.active{border:2px solid #00a3ff;box-shadow:0 8px 8px -4px #10182808;box-shadow:0 20px 24px -4px #10182814}.modal-actions{display:flex;justify-content:end;gap:12px}::ng-deep .modal-content{border-radius:12px!important}\n"], dependencies: [{ kind: "component", type: i4.ReactiveSelectComponent, selector: "lib-reactive-select", inputs: ["idField", "nameField", "subTextField", "searchField", "label", "data", "action", "search", "prefix", "actionLabel", "disabled"], outputs: ["actionClick"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
67
67
  }
68
68
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CreateFixtureTemplateComponent, decorators: [{
69
69
  type: Component,
@@ -0,0 +1,156 @@
1
+ import { Component } from '@angular/core';
2
+ import { NavigationEnd } from '@angular/router';
3
+ import { filter, lastValueFrom, Subject, takeUntil } from 'rxjs';
4
+ import { DeleteConfirmationComponent } from '../popups/delete-confirmation/delete-confirmation.component';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "@angular/router";
7
+ import * as i2 from "@ng-bootstrap/ng-bootstrap";
8
+ import * as i3 from "tango-app-ui-global";
9
+ import * as i4 from "../../services/store-builder.service";
10
+ import * as i5 from "tango-app-ui-shared";
11
+ import * as i6 from "@angular/common";
12
+ import * as i7 from "@angular/forms";
13
+ export class LookPlanoCollectionComponent {
14
+ router;
15
+ modal;
16
+ gs;
17
+ builderService;
18
+ toast;
19
+ pageInfo;
20
+ clientId = '';
21
+ loading = false;
22
+ items = [];
23
+ totalItems = 0;
24
+ searchTerm = '';
25
+ limit = 10;
26
+ offset = 1;
27
+ paginationSizes = [10, 20, 30];
28
+ sortedColumn = 'createdAt';
29
+ sortOrder = -1;
30
+ destroy$ = new Subject();
31
+ constructor(router, modal, gs, builderService, toast, pageInfo) {
32
+ this.router = router;
33
+ this.modal = modal;
34
+ this.gs = gs;
35
+ this.builderService = builderService;
36
+ this.toast = toast;
37
+ this.pageInfo = pageInfo;
38
+ }
39
+ ngOnInit() {
40
+ this.setPageData();
41
+ this.gs.dataRangeValue.pipe(takeUntil(this.destroy$)).subscribe((data) => {
42
+ const headerFilters = JSON.parse(localStorage.getItem('header-filters') || '{}');
43
+ this.clientId = data?.client || headerFilters?.client;
44
+ console.log('[Looks list] clientId resolved =', this.clientId);
45
+ if (this.clientId)
46
+ this.loadList();
47
+ });
48
+ // Defensive: reload when this URL is navigated to (covers route reuse / back-button)
49
+ this.router.events
50
+ .pipe(filter((e) => e instanceof NavigationEnd), takeUntil(this.destroy$))
51
+ .subscribe((e) => {
52
+ if (e.urlAfterRedirects.endsWith('/manage/planogram/looks') && this.clientId) {
53
+ this.loadList();
54
+ }
55
+ });
56
+ }
57
+ setPageData() {
58
+ this.pageInfo.setTitle('Looks');
59
+ this.pageInfo.setBreadcrumbs([
60
+ {
61
+ title: 'Planogram',
62
+ path: '/manage/planogram/manage-planograms',
63
+ isActive: false,
64
+ isSeparator: false,
65
+ },
66
+ { title: '', path: '', isActive: false, isSeparator: true },
67
+ { title: 'Looks', path: '/manage/planogram/looks', isActive: true, isSeparator: false },
68
+ ]);
69
+ }
70
+ async loadList() {
71
+ this.loading = true;
72
+ try {
73
+ const payload = {
74
+ clientId: this.clientId,
75
+ limit: this.limit,
76
+ offset: this.offset,
77
+ searchValue: this.searchTerm || '',
78
+ sortColumnName: this.sortedColumn,
79
+ sortBy: this.sortOrder,
80
+ };
81
+ console.log('[Looks list] POST /lookPlanoCollection/getCollectionList payload:', payload);
82
+ const res = await lastValueFrom(this.builderService.getLookPlanoCollectionList(payload));
83
+ console.log('[Looks list] response:', res);
84
+ this.items = res?.data?.items || [];
85
+ this.totalItems = res?.data?.total || 0;
86
+ console.log('[Looks list] items.length =', this.items.length, 'total =', this.totalItems);
87
+ }
88
+ catch (err) {
89
+ console.log('@@ ~ loadList [ERR]:', err);
90
+ this.toast.getErrorToast?.('Failed to load Looks');
91
+ }
92
+ finally {
93
+ this.loading = false;
94
+ }
95
+ }
96
+ onSearch() {
97
+ this.offset = 1;
98
+ this.loadList();
99
+ }
100
+ onPageChange(page) {
101
+ this.offset = page;
102
+ this.loadList();
103
+ }
104
+ onPageSizeChange(size) {
105
+ this.limit = size;
106
+ this.offset = 1;
107
+ this.loadList();
108
+ }
109
+ createNew() {
110
+ this.router.navigate(['/manage/planogram/looks/new']);
111
+ }
112
+ edit(item) {
113
+ this.router.navigate(['/manage/planogram/looks', item._id]);
114
+ }
115
+ async duplicate(item) {
116
+ try {
117
+ await lastValueFrom(this.builderService.duplicateLookPlanoCollection(item._id));
118
+ this.toast.getSuccessToast?.('Look collection duplicated');
119
+ this.loadList();
120
+ }
121
+ catch (err) {
122
+ console.log('@@ ~ duplicate [ERR]:', err);
123
+ this.toast.getErrorToast?.('Failed to duplicate');
124
+ }
125
+ }
126
+ async confirmDelete(item) {
127
+ const ref = this.modal.open(DeleteConfirmationComponent, { centered: true, backdrop: 'static' });
128
+ ref.componentInstance.title = 'Delete Look Collection';
129
+ ref.componentInstance.description = `Are you sure you want to delete "${item.name}"?`;
130
+ try {
131
+ const result = await ref.result;
132
+ if (result === 'ok') {
133
+ await lastValueFrom(this.builderService.deleteLookPlanoCollection(item._id));
134
+ this.toast.getSuccessToast?.('Look collection deleted');
135
+ this.loadList();
136
+ }
137
+ }
138
+ catch (_) {
139
+ // user dismissed
140
+ }
141
+ }
142
+ trackById(_, item) {
143
+ return item._id;
144
+ }
145
+ ngOnDestroy() {
146
+ this.destroy$.next();
147
+ this.destroy$.complete();
148
+ }
149
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookPlanoCollectionComponent, deps: [{ token: i1.Router }, { token: i2.NgbModal }, { token: i3.GlobalStateService }, { token: i4.StoreBuilderService }, { token: i5.ToastService }, { token: i3.PageInfoService }], target: i0.ɵɵFactoryTarget.Component });
150
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LookPlanoCollectionComponent, selector: "lib-look-plano-collection", ngImport: i0, template: "<section class=\"looks-wrapper\">\r\n <div class=\"row mx-0 my-5\">\r\n <div class=\"card p-5 col-md-12\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-5\">\r\n <div>\r\n <h4>Looks</h4>\r\n <span>{{ totalItems }} - Total Look Collections</span>\r\n </div>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <div style=\"position: relative\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"searchTerm\"\r\n (change)=\"onSearch()\"\r\n style=\"padding-left: 3rem; padding-right: 3rem\"\r\n class=\"form-control\"\r\n name=\"search\"\r\n autocomplete=\"off\"\r\n placeholder=\"Search by name\"\r\n />\r\n <span class=\"search-icon\">\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <circle cx=\"8\" cy=\"8\" r=\"6\" stroke=\"currentColor\" stroke-width=\"2\" />\r\n <line x1=\"13\" y1=\"13\" x2=\"16\" y2=\"16\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n </span>\r\n <button *ngIf=\"searchTerm\" type=\"button\" aria-label=\"Clear\" (click)=\"searchTerm = ''; onSearch()\" class=\"clear-search\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M9 9L15 15\" stroke=\"#667085\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\r\n <path d=\"M15 9L9 15\" stroke=\"#667085\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"9\" stroke=\"#667085\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></circle>\r\n </svg>\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"btn btn-primary text-nowrap\" (click)=\"createNew()\">+ New Look Collection</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Loading -->\r\n <div *ngIf=\"loading\" class=\"text-center text-muted py-10\">Loading\u2026</div>\r\n\r\n <!-- Empty state -->\r\n <div *ngIf=\"!loading && items.length === 0\" class=\"text-center text-muted py-10\">\r\n <div class=\"mb-3\">No Look collections yet.</div>\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"createNew()\">Create your first Look collection</button>\r\n </div>\r\n\r\n <!-- Table -->\r\n <div class=\"table-responsive\" *ngIf=\"!loading && items.length > 0\">\r\n <table class=\"table table-row-dashed align-middle gs-0 gy-3\">\r\n <thead>\r\n <tr class=\"fw-bolder text-muted text-uppercase fs-7\">\r\n <th>Name</th>\r\n <th>Description</th>\r\n <th class=\"text-end\">Looks</th>\r\n <th>Created By</th>\r\n <th>Created At</th>\r\n <th class=\"text-end\">Action</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let item of items; trackBy: trackById\">\r\n <td>\r\n <a class=\"text-dark fw-bold text-hover-primary cursor-pointer\" (click)=\"edit(item)\">{{ item.name }}</a>\r\n </td>\r\n <td>{{ item.description || '\u2014' }}</td>\r\n <td class=\"text-end\">{{ item.looksCount || 0 }}</td>\r\n <td>{{ item.createdByName || '\u2014' }}</td>\r\n <td>{{ item.createdAt | date: 'mediumDate' }}</td>\r\n <td class=\"text-end\">\r\n <button class=\"btn btn-sm btn-light me-2\" (click)=\"edit(item)\">Edit</button>\r\n <button class=\"btn btn-sm btn-light me-2\" (click)=\"duplicate(item)\">Duplicate</button>\r\n <button class=\"btn btn-sm btn-light-danger\" (click)=\"confirmDelete(item)\">Delete</button>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n </div>\r\n</section>\r\n", styles: [".looks-wrapper .search-icon{position:absolute;top:50%;left:1rem;transform:translateY(-50%);color:#667085;pointer-events:none}.looks-wrapper .clear-search{position:absolute;top:50%;right:.75rem;transform:translateY(-50%);background:transparent;border:0;padding:0;line-height:0}.looks-wrapper .cursor-pointer{cursor:pointer}\n"], dependencies: [{ 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: i7.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: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i6.DatePipe, name: "date" }] });
151
+ }
152
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookPlanoCollectionComponent, decorators: [{
153
+ type: Component,
154
+ args: [{ selector: 'lib-look-plano-collection', template: "<section class=\"looks-wrapper\">\r\n <div class=\"row mx-0 my-5\">\r\n <div class=\"card p-5 col-md-12\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-5\">\r\n <div>\r\n <h4>Looks</h4>\r\n <span>{{ totalItems }} - Total Look Collections</span>\r\n </div>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <div style=\"position: relative\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"searchTerm\"\r\n (change)=\"onSearch()\"\r\n style=\"padding-left: 3rem; padding-right: 3rem\"\r\n class=\"form-control\"\r\n name=\"search\"\r\n autocomplete=\"off\"\r\n placeholder=\"Search by name\"\r\n />\r\n <span class=\"search-icon\">\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <circle cx=\"8\" cy=\"8\" r=\"6\" stroke=\"currentColor\" stroke-width=\"2\" />\r\n <line x1=\"13\" y1=\"13\" x2=\"16\" y2=\"16\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n </span>\r\n <button *ngIf=\"searchTerm\" type=\"button\" aria-label=\"Clear\" (click)=\"searchTerm = ''; onSearch()\" class=\"clear-search\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M9 9L15 15\" stroke=\"#667085\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\r\n <path d=\"M15 9L9 15\" stroke=\"#667085\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"9\" stroke=\"#667085\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></circle>\r\n </svg>\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"btn btn-primary text-nowrap\" (click)=\"createNew()\">+ New Look Collection</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Loading -->\r\n <div *ngIf=\"loading\" class=\"text-center text-muted py-10\">Loading\u2026</div>\r\n\r\n <!-- Empty state -->\r\n <div *ngIf=\"!loading && items.length === 0\" class=\"text-center text-muted py-10\">\r\n <div class=\"mb-3\">No Look collections yet.</div>\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"createNew()\">Create your first Look collection</button>\r\n </div>\r\n\r\n <!-- Table -->\r\n <div class=\"table-responsive\" *ngIf=\"!loading && items.length > 0\">\r\n <table class=\"table table-row-dashed align-middle gs-0 gy-3\">\r\n <thead>\r\n <tr class=\"fw-bolder text-muted text-uppercase fs-7\">\r\n <th>Name</th>\r\n <th>Description</th>\r\n <th class=\"text-end\">Looks</th>\r\n <th>Created By</th>\r\n <th>Created At</th>\r\n <th class=\"text-end\">Action</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let item of items; trackBy: trackById\">\r\n <td>\r\n <a class=\"text-dark fw-bold text-hover-primary cursor-pointer\" (click)=\"edit(item)\">{{ item.name }}</a>\r\n </td>\r\n <td>{{ item.description || '\u2014' }}</td>\r\n <td class=\"text-end\">{{ item.looksCount || 0 }}</td>\r\n <td>{{ item.createdByName || '\u2014' }}</td>\r\n <td>{{ item.createdAt | date: 'mediumDate' }}</td>\r\n <td class=\"text-end\">\r\n <button class=\"btn btn-sm btn-light me-2\" (click)=\"edit(item)\">Edit</button>\r\n <button class=\"btn btn-sm btn-light me-2\" (click)=\"duplicate(item)\">Duplicate</button>\r\n <button class=\"btn btn-sm btn-light-danger\" (click)=\"confirmDelete(item)\">Delete</button>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n </div>\r\n</section>\r\n", styles: [".looks-wrapper .search-icon{position:absolute;top:50%;left:1rem;transform:translateY(-50%);color:#667085;pointer-events:none}.looks-wrapper .clear-search{position:absolute;top:50%;right:.75rem;transform:translateY(-50%);background:transparent;border:0;padding:0;line-height:0}.looks-wrapper .cursor-pointer{cursor:pointer}\n"] }]
155
+ }], ctorParameters: () => [{ type: i1.Router }, { type: i2.NgbModal }, { type: i3.GlobalStateService }, { type: i4.StoreBuilderService }, { type: i5.ToastService }, { type: i3.PageInfoService }] });
156
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9vay1wbGFuby1jb2xsZWN0aW9uLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3RhbmdvLXN0b3JlLWJ1aWxkZXIvc3JjL2xpYi9jb21wb25lbnRzL2xvb2stcGxhbm8tY29sbGVjdGlvbi9sb29rLXBsYW5vLWNvbGxlY3Rpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdGFuZ28tc3RvcmUtYnVpbGRlci9zcmMvbGliL2NvbXBvbmVudHMvbG9vay1wbGFuby1jb2xsZWN0aW9uL2xvb2stcGxhbm8tY29sbGVjdGlvbi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUM3RCxPQUFPLEVBQUUsYUFBYSxFQUFVLE1BQU0saUJBQWlCLENBQUM7QUFFeEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUlqRSxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSw2REFBNkQsQ0FBQzs7Ozs7Ozs7O0FBbUIxRyxNQUFNLE9BQU8sNEJBQTRCO0lBaUI3QjtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFyQlYsUUFBUSxHQUFXLEVBQUUsQ0FBQztJQUN0QixPQUFPLEdBQUcsS0FBSyxDQUFDO0lBQ2hCLEtBQUssR0FBa0MsRUFBRSxDQUFDO0lBQzFDLFVBQVUsR0FBRyxDQUFDLENBQUM7SUFFZixVQUFVLEdBQUcsRUFBRSxDQUFDO0lBQ2hCLEtBQUssR0FBRyxFQUFFLENBQUM7SUFDWCxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ1gsZUFBZSxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUUvQixZQUFZLEdBQUcsV0FBVyxDQUFDO0lBQzNCLFNBQVMsR0FB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RyxNQUFNLEdBQUcsQ0FBQyxNQUFNLENBQUM7WUFDaEMsSUFBSSxNQUFNLEtBQUssSUFBSSxFQUFFO2dCQUNuQixNQUFNLGFBQWEsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLHlCQUF5QixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUM3RSxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDLHlCQUF5QixDQUFDLENBQUM7Z0JBQ3hELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQzthQUNqQjtTQUNGO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDVixpQkFBaUI7U0FDbEI7SUFDSCxDQUFDO0lBRUQsU0FBUyxDQUFDLENBQVMsRUFBRSxJQUFpQztRQUNwRCxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDbEIsQ0FBQztJQUVELFdBQVc7UUFDVCxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDM0IsQ0FBQzt3R0FoSlUsNEJBQTRCOzRGQUE1Qiw0QkFBNEIsaUVDMUJ6QyxpbElBaUZBOzs0RkR2RGEsNEJBQTRCO2tCQUx4QyxTQUFTOytCQUNFLDJCQUEyQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25EZXN0cm95LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgTmF2aWdhdGlvbkVuZCwgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcclxuaW1wb3J0IHsgTmdiTW9kYWwgfSBmcm9tICdAbmctYm9vdHN0cmFwL25nLWJvb3RzdHJhcCc7XHJcbmltcG9ydCB7IGZpbHRlciwgbGFzdFZhbHVlRnJvbSwgU3ViamVjdCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IEdsb2JhbFN0YXRlU2VydmljZSwgUGFnZUluZm9TZXJ2aWNlIH0gZnJvbSAndGFuZ28tYXBwLXVpLWdsb2JhbCc7XHJcbmltcG9ydCB7IFRvYXN0U2VydmljZSB9IGZyb20gJ3RhbmdvLWFwcC11aS1zaGFyZWQnO1xyXG5pbXBvcnQgeyBTdG9yZUJ1aWxkZXJTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvc3RvcmUtYnVpbGRlci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgRGVsZXRlQ29uZmlybWF0aW9uQ29tcG9uZW50IH0gZnJvbSAnLi4vcG9wdXBzL2RlbGV0ZS1jb25maXJtYXRpb24vZGVsZXRlLWNvbmZpcm1hdGlvbi5jb21wb25lbnQnO1xyXG5cclxuaW50ZXJmYWNlIExvb2tQbGFub0NvbGxlY3Rpb25MaXN0SXRlbSB7XHJcbiAgX2lkOiBzdHJpbmc7XHJcbiAgbmFtZTogc3RyaW5nO1xyXG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xyXG4gIGlzQWN0aXZlPzogYm9vbGVhbjtcclxuICBsb29rc0NvdW50PzogbnVtYmVyO1xyXG4gIGNyZWF0ZWRBdD86IHN0cmluZztcclxuICB1cGRhdGVkQXQ/OiBzdHJpbmc7XHJcbiAgY3JlYXRlZEJ5TmFtZT86IHN0cmluZztcclxuICB1cGRhdGVkQnlOYW1lPzogc3RyaW5nO1xyXG59XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2xpYi1sb29rLXBsYW5vLWNvbGxlY3Rpb24nLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9sb29rLXBsYW5vLWNvbGxlY3Rpb24uY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsOiAnLi9sb29rLXBsYW5vLWNvbGxlY3Rpb24uY29tcG9uZW50LnNjc3MnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTG9va1BsYW5vQ29sbGVjdGlvbkNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcclxuICBjbGllbnRJZDogc3RyaW5nID0gJyc7XHJcbiAgbG9hZGluZyA9IGZhbHNlO1xyXG4gIGl0ZW1zOiBMb29rUGxhbm9Db2xsZWN0aW9uTGlzdEl0ZW1bXSA9IFtdO1xyXG4gIHRvdGFsSXRlbXMgPSAwO1xyXG5cclxuICBzZWFyY2hUZXJtID0gJyc7XHJcbiAgbGltaXQgPSAxMDtcclxuICBvZmZzZXQgPSAxO1xyXG4gIHBhZ2luYXRpb25TaXplcyA9IFsxMCwgMjAsIDMwXTtcclxuXHJcbiAgc29ydGVkQ29sdW1uID0gJ2NyZWF0ZWRBdCc7XHJcbiAgc29ydE9yZGVyOiBudW1iZXIgPSAtMTtcclxuXHJcbiAgcHJpdmF0ZSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcixcclxuICAgIHByaXZhdGUgbW9kYWw6IE5nYk1vZGFsLFxyXG4gICAgcHJpdmF0ZSBnczogR2xvYmFsU3RhdGVTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBidWlsZGVyU2VydmljZTogU3RvcmVCdWlsZGVyU2VydmljZSxcclxuICAgIHByaXZhdGUgdG9hc3Q6IFRvYXN0U2VydmljZSxcclxuICAgIHByaXZhdGUgcGFnZUluZm86IFBhZ2VJbmZvU2VydmljZSxcclxuICApIHt9XHJcblxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5zZXRQYWdlRGF0YSgpO1xyXG4gICAgdGhpcy5ncy5kYXRhUmFuZ2VWYWx1ZS5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSkuc3Vic2NyaWJlKChkYXRhKSA9PiB7XHJcbiAgICAgIGNvbnN0IGhlYWRlckZpbHRlcnMgPSBKU09OLnBhcnNlKGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdoZWFkZXItZmlsdGVycycpIHx8ICd7fScpO1xyXG4gICAgICB0aGlzLmNsaWVudElkID0gZGF0YT8uY2xpZW50IHx8IGhlYWRlckZpbHRlcnM/LmNsaWVudDtcclxuICAgICAgY29uc29sZS5sb2coJ1tMb29rcyBsaXN0XSBjbGllbnRJZCByZXNvbHZlZCA9JywgdGhpcy5jbGllbnRJZCk7XHJcbiAgICAgIGlmICh0aGlzLmNsaWVudElkKSB0aGlzLmxvYWRMaXN0KCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBEZWZlbnNpdmU6IHJlbG9hZCB3aGVuIHRoaXMgVVJMIGlzIG5hdmlnYXRlZCB0byAoY292ZXJzIHJvdXRlIHJldXNlIC8gYmFjay1idXR0b24pXHJcbiAgICB0aGlzLnJvdXRlci5ldmVudHNcclxuICAgICAgLnBpcGUoXHJcbiAgICAgICAgZmlsdGVyKChlKTogZSBpcyBOYXZpZ2F0aW9uRW5kID0+IGUgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uRW5kKSxcclxuICAgICAgICB0YWtlVW50aWwodGhpcy5kZXN0cm95JCksXHJcbiAgICAgIClcclxuICAgICAgLnN1YnNjcmliZSgoZSkgPT4ge1xyXG4gICAgICAgIGlmIChlLnVybEFmdGVyUmVkaXJlY3RzLmVuZHNXaXRoKCcvbWFuYWdlL3BsYW5vZ3JhbS9sb29rcycpICYmIHRoaXMuY2xpZW50SWQpIHtcclxuICAgICAgICAgIHRoaXMubG9hZExpc3QoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgc2V0UGFnZURhdGEoKSB7XHJcbiAgICB0aGlzLnBhZ2VJbmZvLnNldFRpdGxlKCdMb29rcycpO1xyXG4gICAgdGhpcy5wYWdlSW5mby5zZXRCcmVhZGNydW1icyhbXHJcbiAgICAgIHtcclxuICAgICAgICB0aXRsZTogJ1BsYW5vZ3JhbScsXHJcbiAgICAgICAgcGF0aDogJy9tYW5hZ2UvcGxhbm9ncmFtL21hbmFnZS1wbGFub2dyYW1zJyxcclxuICAgICAgICBpc0FjdGl2ZTogZmFsc2UsXHJcbiAgICAgICAgaXNTZXBhcmF0b3I6IGZhbHNlLFxyXG4gICAgICB9LFxyXG4gICAgICB7IHRpdGxlOiAnJywgcGF0aDogJycsIGlzQWN0aXZlOiBmYWxzZSwgaXNTZXBhcmF0b3I6IHRydWUgfSxcclxuICAgICAgeyB0aXRsZTogJ0xvb2tzJywgcGF0aDogJy9tYW5hZ2UvcGxhbm9ncmFtL2xvb2tzJywgaXNBY3RpdmU6IHRydWUsIGlzU2VwYXJhdG9yOiBmYWxzZSB9LFxyXG4gICAgXSk7XHJcbiAgfVxyXG5cclxuICBhc3luYyBsb2FkTGlzdCgpIHtcclxuICAgIHRoaXMubG9hZGluZyA9IHRydWU7XHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCBwYXlsb2FkID0ge1xyXG4gICAgICAgIGNsaWVudElkOiB0aGlzLmNsaWVudElkLFxyXG4gICAgICAgIGxpbWl0OiB0aGlzLmxpbWl0LFxyXG4gICAgICAgIG9mZnNldDogdGhpcy5vZmZzZXQsXHJcbiAgICAgICAgc2VhcmNoVmFsdWU6IHRoaXMuc2VhcmNoVGVybSB8fCAnJyxcclxuICAgICAgICBzb3J0Q29sdW1uTmFtZTogdGhpcy5zb3J0ZWRDb2x1bW4sXHJcbiAgICAgICAgc29ydEJ5OiB0aGlzLnNvcnRPcmRlcixcclxuICAgICAgfTtcclxuICAgICAgY29uc29sZS5sb2coJ1tMb29rcyBsaXN0XSBQT1NUIC9sb29rUGxhbm9Db2xsZWN0aW9uL2dldENvbGxlY3Rpb25MaXN0IHBheWxvYWQ6JywgcGF5bG9hZCk7XHJcbiAgICAgIGNvbnN0IHJlczogYW55ID0gYXdhaXQgbGFzdFZhbHVlRnJvbSh0aGlzLmJ1aWxkZXJTZXJ2aWNlLmdldExvb2tQbGFub0NvbGxlY3Rpb25MaXN0KHBheWxvYWQpKTtcclxuICAgICAgY29uc29sZS5sb2coJ1tMb29rcyBsaXN0XSByZXNwb25zZTonLCByZXMpO1xyXG4gICAgICB0aGlzLml0ZW1zID0gcmVzPy5kYXRhPy5pdGVtcyB8fCBbXTtcclxuICAgICAgdGhpcy50b3RhbEl0ZW1zID0gcmVzPy5kYXRhPy50b3RhbCB8fCAwO1xyXG4gICAgICBjb25zb2xlLmxvZygnW0xvb2tzIGxpc3RdIGl0ZW1zLmxlbmd0aCA9JywgdGhpcy5pdGVtcy5sZW5ndGgsICd0b3RhbCA9JywgdGhpcy50b3RhbEl0ZW1zKTtcclxuICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICBjb25zb2xlLmxvZygnQEAgfiBsb2FkTGlzdCBbRVJSXTonLCBlcnIpO1xyXG4gICAgICB0aGlzLnRvYXN0LmdldEVycm9yVG9hc3Q/LignRmFpbGVkIHRvIGxvYWQgTG9va3MnKTtcclxuICAgIH0gZmluYWxseSB7XHJcbiAgICAgIHRoaXMubG9hZGluZyA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgb25TZWFyY2goKSB7XHJcbiAgICB0aGlzLm9mZnNldCA9IDE7XHJcbiAgICB0aGlzLmxvYWRMaXN0KCk7XHJcbiAgfVxyXG5cclxuICBvblBhZ2VDaGFuZ2UocGFnZTogbnVtYmVyKSB7XHJcbiAgICB0aGlzLm9mZnNldCA9IHBhZ2U7XHJcbiAgICB0aGlzLmxvYWRMaXN0KCk7XHJcbiAgfVxyXG5cclxuICBvblBhZ2VTaXplQ2hhbmdlKHNpemU6IG51bWJlcikge1xyXG4gICAgdGhpcy5saW1pdCA9IHNpemU7XHJcbiAgICB0aGlzLm9mZnNldCA9IDE7XHJcbiAgICB0aGlzLmxvYWRMaXN0KCk7XHJcbiAgfVxyXG5cclxuICBjcmVhdGVOZXcoKSB7XHJcbiAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbJy9tYW5hZ2UvcGxhbm9ncmFtL2xvb2tzL25ldyddKTtcclxuICB9XHJcblxyXG4gIGVkaXQoaXRlbTogTG9va1BsYW5vQ29sbGVjdGlvbkxpc3RJdGVtKSB7XHJcbiAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbJy9tYW5hZ2UvcGxhbm9ncmFtL2xvb2tzJywgaXRlbS5faWRdKTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGR1cGxpY2F0ZShpdGVtOiBMb29rUGxhbm9Db2xsZWN0aW9uTGlzdEl0ZW0pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IGxhc3RWYWx1ZUZyb20odGhpcy5idWlsZGVyU2VydmljZS5kdXBsaWNhdGVMb29rUGxhbm9Db2xsZWN0aW9uKGl0ZW0uX2lkKSk7XHJcbiAgICAgIHRoaXMudG9hc3QuZ2V0U3VjY2Vzc1RvYXN0Py4oJ0xvb2sgY29sbGVjdGlvbiBkdXBsaWNhdGVkJyk7XHJcbiAgICAgIHRoaXMubG9hZExpc3QoKTtcclxuICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICBjb25zb2xlLmxvZygnQEAgfiBkdXBsaWNhdGUgW0VSUl06JywgZXJyKTtcclxuICAgICAgdGhpcy50b2FzdC5nZXRFcnJvclRvYXN0Py4oJ0ZhaWxlZCB0byBkdXBsaWNhdGUnKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGNvbmZpcm1EZWxldGUoaXRlbTogTG9va1BsYW5vQ29sbGVjdGlvbkxpc3RJdGVtKSB7XHJcbiAgICBjb25zdCByZWYgPSB0aGlzLm1vZGFsLm9wZW4oRGVsZXRlQ29uZmlybWF0aW9uQ29tcG9uZW50LCB7IGNlbnRlcmVkOiB0cnVlLCBiYWNrZHJvcDogJ3N0YXRpYycgfSk7XHJcbiAgICByZWYuY29tcG9uZW50SW5zdGFuY2UudGl0bGUgPSAnRGVsZXRlIExvb2sgQ29sbGVjdGlvbic7XHJcbiAgICByZWYuY29tcG9uZW50SW5zdGFuY2UuZGVzY3JpcHRpb24gPSBgQXJlIHlvdSBzdXJlIHlvdSB3YW50IHRvIGRlbGV0ZSBcIiR7aXRlbS5uYW1lfVwiP2A7XHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCByZWYucmVzdWx0O1xyXG4gICAgICBpZiAocmVzdWx0ID09PSAnb2snKSB7XHJcbiAgICAgICAgYXdhaXQgbGFzdFZhbHVlRnJvbSh0aGlzLmJ1aWxkZXJTZXJ2aWNlLmRlbGV0ZUxvb2tQbGFub0NvbGxlY3Rpb24oaXRlbS5faWQpKTtcclxuICAgICAgICB0aGlzLnRvYXN0LmdldFN1Y2Nlc3NUb2FzdD8uKCdMb29rIGNvbGxlY3Rpb24gZGVsZXRlZCcpO1xyXG4gICAgICAgIHRoaXMubG9hZExpc3QoKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoXykge1xyXG4gICAgICAvLyB1c2VyIGRpc21pc3NlZFxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdHJhY2tCeUlkKF86IG51bWJlciwgaXRlbTogTG9va1BsYW5vQ29sbGVjdGlvbkxpc3RJdGVtKSB7XHJcbiAgICByZXR1cm4gaXRlbS5faWQ7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xyXG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xyXG4gIH1cclxufVxyXG4iLCI8c2VjdGlvbiBjbGFzcz1cImxvb2tzLXdyYXBwZXJcIj5cclxuICA8ZGl2IGNsYXNzPVwicm93IG14LTAgbXktNVwiPlxyXG4gICAgPGRpdiBjbGFzcz1cImNhcmQgcC01IGNvbC1tZC0xMlwiPlxyXG4gICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGp1c3RpZnktY29udGVudC1iZXR3ZWVuIGFsaWduLWl0ZW1zLWNlbnRlciBtYi01XCI+XHJcbiAgICAgICAgPGRpdj5cclxuICAgICAgICAgIDxoND5Mb29rczwvaDQ+XHJcbiAgICAgICAgICA8c3Bhbj57eyB0b3RhbEl0ZW1zIH19IC0gVG90YWwgTG9vayBDb2xsZWN0aW9uczwvc3Bhbj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGFsaWduLWl0ZW1zLWNlbnRlciBnYXAtMlwiPlxyXG4gICAgICAgICAgPGRpdiBzdHlsZT1cInBvc2l0aW9uOiByZWxhdGl2ZVwiPlxyXG4gICAgICAgICAgICA8aW5wdXRcclxuICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXHJcbiAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJzZWFyY2hUZXJtXCJcclxuICAgICAgICAgICAgICAoY2hhbmdlKT1cIm9uU2VhcmNoKClcIlxyXG4gICAgICAgICAgICAgIHN0eWxlPVwicGFkZGluZy1sZWZ0OiAzcmVtOyBwYWRkaW5nLXJpZ2h0OiAzcmVtXCJcclxuICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXHJcbiAgICAgICAgICAgICAgbmFtZT1cInNlYXJjaFwiXHJcbiAgICAgICAgICAgICAgYXV0b2NvbXBsZXRlPVwib2ZmXCJcclxuICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cIlNlYXJjaCBieSBuYW1lXCJcclxuICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzZWFyY2gtaWNvblwiPlxyXG4gICAgICAgICAgICAgIDxzdmcgd2lkdGg9XCIxOFwiIGhlaWdodD1cIjE4XCIgdmlld0JveD1cIjAgMCAxOCAxOFwiIGZpbGw9XCJub25lXCI+XHJcbiAgICAgICAgICAgICAgICA8Y2lyY2xlIGN4PVwiOFwiIGN5PVwiOFwiIHI9XCI2XCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIC8+XHJcbiAgICAgICAgICAgICAgICA8bGluZSB4MT1cIjEzXCIgeTE9XCIxM1wiIHgyPVwiMTZcIiB5Mj1cIjE2XCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiAvPlxyXG4gICAgICAgICAgICAgIDwvc3ZnPlxyXG4gICAgICAgICAgICA8L3NwYW4+XHJcbiAgICAgICAgICAgIDxidXR0b24gKm5nSWY9XCJzZWFyY2hUZXJtXCIgdHlwZT1cImJ1dHRvblwiIGFyaWEtbGFiZWw9XCJDbGVhclwiIChjbGljayk9XCJzZWFyY2hUZXJtID0gJyc7IG9uU2VhcmNoKClcIiBjbGFzcz1cImNsZWFyLXNlYXJjaFwiPlxyXG4gICAgICAgICAgICAgIDxzdmcgd2lkdGg9XCIyMFwiIGhlaWdodD1cIjIwXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCI+XHJcbiAgICAgICAgICAgICAgICA8cGF0aCBkPVwiTTkgOUwxNSAxNVwiIHN0cm9rZT1cIiM2NjcwODVcIiBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCI+PC9wYXRoPlxyXG4gICAgICAgICAgICAgICAgPHBhdGggZD1cIk0xNSA5TDkgMTVcIiBzdHJva2U9XCIjNjY3MDg1XCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiPjwvcGF0aD5cclxuICAgICAgICAgICAgICAgIDxjaXJjbGUgY3g9XCIxMlwiIGN5PVwiMTJcIiByPVwiOVwiIHN0cm9rZT1cIiM2NjcwODVcIiBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCI+PC9jaXJjbGU+XHJcbiAgICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0biBidG4tcHJpbWFyeSB0ZXh0LW5vd3JhcFwiIChjbGljayk9XCJjcmVhdGVOZXcoKVwiPisgTmV3IExvb2sgQ29sbGVjdGlvbjwvYnV0dG9uPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICA8L2Rpdj5cclxuXHJcbiAgICAgIDwhLS0gTG9hZGluZyAtLT5cclxuICAgICAgPGRpdiAqbmdJZj1cImxvYWRpbmdcIiBjbGFzcz1cInRleHQtY2VudGVyIHRleHQtbXV0ZWQgcHktMTBcIj5Mb2FkaW5n4oCmPC9kaXY+XHJcblxyXG4gICAgICA8IS0tIEVtcHR5IHN0YXRlIC0tPlxyXG4gICAgICA8ZGl2ICpuZ0lmPVwiIWxvYWRpbmcgJiYgaXRlbXMubGVuZ3RoID09PSAwXCIgY2xhc3M9XCJ0ZXh0LWNlbnRlciB0ZXh0LW11dGVkIHB5LTEwXCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cIm1iLTNcIj5ObyBMb29rIGNvbGxlY3Rpb25zIHlldC48L2Rpdj5cclxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0biBidG4tcHJpbWFyeVwiIChjbGljayk9XCJjcmVhdGVOZXcoKVwiPkNyZWF0ZSB5b3VyIGZpcnN0IExvb2sgY29sbGVjdGlvbjwvYnV0dG9uPlxyXG4gICAgICA8L2Rpdj5cclxuXHJcbiAgICAgIDwhLS0gVGFibGUgLS0+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJ0YWJsZS1yZXNwb25zaXZlXCIgKm5nSWY9XCIhbG9hZGluZyAmJiBpdGVtcy5sZW5ndGggPiAwXCI+XHJcbiAgICAgICAgPHRhYmxlIGNsYXNzPVwidGFibGUgdGFibGUtcm93LWRhc2hlZCBhbGlnbi1taWRkbGUgZ3MtMCBneS0zXCI+XHJcbiAgICAgICAgICA8dGhlYWQ+XHJcbiAgICAgICAgICAgIDx0ciBjbGFzcz1cImZ3LWJvbGRlciB0ZXh0LW11dGVkIHRleHQtdXBwZXJjYXNlIGZzLTdcIj5cclxuICAgICAgICAgICAgICA8dGg+TmFtZTwvdGg+XHJcbiAgICAgICAgICAgICAgPHRoPkRlc2NyaXB0aW9uPC90aD5cclxuICAgICAgICAgICAgICA8dGggY2xhc3M9XCJ0ZXh0LWVuZFwiPkxvb2tzPC90aD5cclxuICAgICAgICAgICAgICA8dGg+Q3JlYXRlZCBCeTwvdGg+XHJcbiAgICAgICAgICAgICAgPHRoPkNyZWF0ZWQgQXQ8L3RoPlxyXG4gICAgICAgICAgICAgIDx0aCBjbGFzcz1cInRleHQtZW5kXCI+QWN0aW9uPC90aD5cclxuICAgICAgICAgICAgPC90cj5cclxuICAgICAgICAgIDwvdGhlYWQ+XHJcbiAgICAgICAgICA8dGJvZHk+XHJcbiAgICAgICAgICAgIDx0ciAqbmdGb3I9XCJsZXQgaXRlbSBvZiBpdGVtczsgdHJhY2tCeTogdHJhY2tCeUlkXCI+XHJcbiAgICAgICAgICAgICAgPHRkPlxyXG4gICAgICAgICAgICAgICAgPGEgY2xhc3M9XCJ0ZXh0LWRhcmsgZnctYm9sZCB0ZXh0LWhvdmVyLXByaW1hcnkgY3Vyc29yLXBvaW50ZXJcIiAoY2xpY2spPVwiZWRpdChpdGVtKVwiPnt7IGl0ZW0ubmFtZSB9fTwvYT5cclxuICAgICAgICAgICAgICA8L3RkPlxyXG4gICAgICAgICAgICAgIDx0ZD57eyBpdGVtLmRlc2NyaXB0aW9uIHx8ICfigJQnIH19PC90ZD5cclxuICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJ0ZXh0LWVuZFwiPnt7IGl0ZW0ubG9va3NDb3VudCB8fCAwIH19PC90ZD5cclxuICAgICAgICAgICAgICA8dGQ+e3sgaXRlbS5jcmVhdGVkQnlOYW1lIHx8ICfigJQnIH19PC90ZD5cclxuICAgICAgICAgICAgICA8dGQ+e3sgaXRlbS5jcmVhdGVkQXQgfCBkYXRlOiAnbWVkaXVtRGF0ZScgfX08L3RkPlxyXG4gICAgICAgICAgICAgIDx0ZCBjbGFzcz1cInRleHQtZW5kXCI+XHJcbiAgICAgICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1zbSBidG4tbGlnaHQgbWUtMlwiIChjbGljayk9XCJlZGl0KGl0ZW0pXCI+RWRpdDwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tc20gYnRuLWxpZ2h0IG1lLTJcIiAoY2xpY2spPVwiZHVwbGljYXRlKGl0ZW0pXCI+RHVwbGljYXRlPC9idXR0b24+XHJcbiAgICAgICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1zbSBidG4tbGlnaHQtZGFuZ2VyXCIgKGNsaWNrKT1cImNvbmZpcm1EZWxldGUoaXRlbSlcIj5EZWxldGU8L2J1dHRvbj5cclxuICAgICAgICAgICAgICA8L3RkPlxyXG4gICAgICAgICAgICA8L3RyPlxyXG4gICAgICAgICAgPC90Ym9keT5cclxuICAgICAgICA8L3RhYmxlPlxyXG4gICAgICA8L2Rpdj5cclxuICAgIDwvZGl2PlxyXG4gIDwvZGl2PlxyXG48L3NlY3Rpb24+XHJcbiJdfQ==