@sumaris-net/ngx-components 18.17.2 → 18.17.4

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 (36) hide show
  1. package/doc/changelog.md +3 -0
  2. package/esm2022/public_api.mjs +3 -1
  3. package/esm2022/src/app/admin/users/person.filter.mjs +79 -2
  4. package/esm2022/src/app/admin/users/person.service.mjs +2 -2
  5. package/esm2022/src/app/admin/users/users-select.modal.mjs +167 -0
  6. package/esm2022/src/app/admin/users/users.mjs +163 -52
  7. package/esm2022/src/app/admin/users/users.module.mjs +7 -4
  8. package/esm2022/src/app/admin/users/users.utils.mjs +29 -0
  9. package/esm2022/src/app/core/table/async-table.class.mjs +6 -3
  10. package/esm2022/src/app/core/table/table.class.mjs +7 -3
  11. package/esm2022/src/app/shared/toolbar/toolbar.mjs +12 -7
  12. package/esm2022/src/app/social/feed/feed.service.mjs +22 -10
  13. package/esm2022/src/app/social/message/message.form.mjs +7 -3
  14. package/esm2022/src/app/social/message/message.modal.mjs +4 -4
  15. package/esm2022/src/app/social/message/message.model.mjs +5 -1
  16. package/esm2022/src/app/social/message/message.module.mjs +7 -5
  17. package/esm2022/src/app/social/message/message.service.mjs +3 -1
  18. package/esm2022/src/environments/environment.mjs +2 -1
  19. package/fesm2022/sumaris-net.ngx-components.mjs +470 -65
  20. package/fesm2022/sumaris-net.ngx-components.mjs.map +1 -1
  21. package/package.json +1 -1
  22. package/public_api.d.ts +2 -0
  23. package/src/app/admin/users/person.filter.d.ts +11 -0
  24. package/src/app/admin/users/users-select.modal.d.ts +73 -0
  25. package/src/app/admin/users/users.d.ts +31 -4
  26. package/src/app/admin/users/users.module.d.ts +9 -8
  27. package/src/app/admin/users/users.utils.d.ts +6 -0
  28. package/src/app/shared/inputs.d.ts +1 -1
  29. package/src/app/shared/toolbar/toolbar.d.ts +3 -3
  30. package/src/app/social/feed/feed.service.d.ts +4 -2
  31. package/src/app/social/message/message.model.d.ts +2 -0
  32. package/src/app/social/message/message.module.d.ts +2 -1
  33. package/src/assets/i18n/en-US.json +6 -0
  34. package/src/assets/i18n/en.json +6 -0
  35. package/src/assets/i18n/fr.json +6 -0
  36. package/src/assets/manifest.json +1 -1
@@ -0,0 +1,167 @@
1
+ import { booleanAttribute, ChangeDetectionStrategy, Component, Input, ViewChild } from '@angular/core';
2
+ import { Person } from '../../core/services/model/person.model';
3
+ import { toBoolean } from '../../shared/functions';
4
+ import { RxState } from '@rx-angular/state';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "../../core/services/local-settings.service";
7
+ import * as i2 from "@ionic/angular";
8
+ import * as i3 from "@rx-angular/state";
9
+ import * as i4 from "@ngx-translate/core";
10
+ import * as i5 from "@angular/common";
11
+ import * as i6 from "./users";
12
+ export class AppSelectUsersModal {
13
+ settings;
14
+ viewCtrl;
15
+ cd;
16
+ state;
17
+ debug = false;
18
+ title = 'USER.SELECT.TITLE';
19
+ settingsId = 'users-select-modal';
20
+ showEmailColumn = false;
21
+ showPubkeyColumn = false;
22
+ showUpdateDateColumn = false;
23
+ showCreationDateColumn = false;
24
+ usersTable;
25
+ constructor(settings, viewCtrl, cd, state) {
26
+ this.settings = settings;
27
+ this.viewCtrl = viewCtrl;
28
+ this.cd = cd;
29
+ this.state = state;
30
+ // Initialize state with default values
31
+ this.state.set({
32
+ showFilter: true,
33
+ canEdit: false,
34
+ showMessageButton: false,
35
+ mobile: this.settings.mobile,
36
+ multiple: true,
37
+ selectedUsers: [],
38
+ });
39
+ }
40
+ // Input getters and setters using RxState
41
+ get showFilter() {
42
+ return this.state.get('showFilter');
43
+ }
44
+ set showFilter(value) {
45
+ this.state.set('showFilter', () => toBoolean(value, true));
46
+ }
47
+ get canEdit() {
48
+ return this.state.get('canEdit');
49
+ }
50
+ set canEdit(value) {
51
+ this.state.set('canEdit', () => toBoolean(value, false));
52
+ }
53
+ get showMessageButton() {
54
+ return this.state.get('showMessageButton');
55
+ }
56
+ set showMessageButton(value) {
57
+ this.state.set('showMessageButton', () => toBoolean(value, false));
58
+ }
59
+ get mobile() {
60
+ return this.state.get('mobile');
61
+ }
62
+ set mobile(value) {
63
+ this.state.set('mobile', () => toBoolean(value, this.settings.mobile));
64
+ }
65
+ get multiple() {
66
+ return this.state.get('multiple');
67
+ }
68
+ set multiple(value) {
69
+ this.state.set('multiple', () => toBoolean(value, true));
70
+ }
71
+ get selectedUsers() {
72
+ return this.state.get('selectedUsers');
73
+ }
74
+ set selectedUsers(value) {
75
+ this.state.set('selectedUsers', () => value || []);
76
+ }
77
+ get hasSelection() {
78
+ return this.selectedUsers && this.selectedUsers.length > 0;
79
+ }
80
+ ngOnInit() {
81
+ // Additional initialization if needed
82
+ }
83
+ ngAfterViewInit() {
84
+ setTimeout(() => {
85
+ if (this.usersTable) {
86
+ // Note: canEdit and canSendMessage are readonly properties set in constructor
87
+ // They will be configured via Input properties in the template
88
+ // Set initial selection if provided
89
+ if (this.selectedUsers && this.selectedUsers.length > 0) {
90
+ // TODO: Set initial selection in the table
91
+ }
92
+ this.markForCheck();
93
+ }
94
+ });
95
+ }
96
+ cancel() {
97
+ this.viewCtrl.dismiss();
98
+ }
99
+ async validate() {
100
+ if (!this.usersTable)
101
+ return;
102
+ const selectedRows = this.usersTable.selection.selected || [];
103
+ const selectedUsers = selectedRows.map((row) => row.currentData).map(Person.fromObject);
104
+ return this.viewCtrl.dismiss(selectedUsers);
105
+ }
106
+ markForCheck() {
107
+ this.cd.markForCheck();
108
+ }
109
+ clickRow(row) {
110
+ // DEBUG
111
+ //console.debug('[users-select-modal] clickRow', row);
112
+ if (this.multiple) {
113
+ this.usersTable.selection.toggle(row);
114
+ }
115
+ else {
116
+ this.usersTable.selection.select(row);
117
+ }
118
+ this.onSelectionChange();
119
+ }
120
+ onSelectionChange() {
121
+ const selectedRows = this.usersTable?.selection.selected || [];
122
+ const selectedUsers = selectedRows.map((row) => row.currentData).map(Person.fromObject);
123
+ this.state.set('selectedUsers', () => selectedUsers);
124
+ this.markForCheck();
125
+ }
126
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppSelectUsersModal, deps: [{ token: i1.LocalSettingsService }, { token: i2.ModalController }, { token: i0.ChangeDetectorRef }, { token: i3.RxState }], target: i0.ɵɵFactoryTarget.Component });
127
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: AppSelectUsersModal, selector: "app-select-users-modal", inputs: { debug: "debug", title: "title", settingsId: "settingsId", showEmailColumn: "showEmailColumn", showPubkeyColumn: "showPubkeyColumn", showUpdateDateColumn: "showUpdateDateColumn", showCreationDateColumn: "showCreationDateColumn", showFilter: ["showFilter", "showFilter", booleanAttribute], canEdit: ["canEdit", "canEdit", booleanAttribute], showMessageButton: ["showMessageButton", "showMessageButton", booleanAttribute], mobile: ["mobile", "mobile", booleanAttribute], multiple: ["multiple", "multiple", booleanAttribute], selectedUsers: "selectedUsers" }, providers: [RxState], viewQueries: [{ propertyName: "usersTable", first: true, predicate: ["usersTable"], descendants: true, static: true }], ngImport: i0, template: "<ion-content scroll-y=\"false\">\n <!-- Reuse UsersPage component -->\n <app-users-table\n #usersTable\n [inModal]=\"true\"\n [title]=\"title\"\n [settingsId]=\"settingsId\"\n [usePageSettings]=\"false\"\n [sticky]=\"false\"\n [stickyEnd]=\"false\"\n [canSendMessage]=\"false\"\n [canDownload]=\"false\"\n [showFooter]=\"false\"\n [showEmailColumn]=\"showEmailColumn\"\n [showPubkeyColumn]=\"showPubkeyColumn\"\n [showUpdateDateColumn]=\"showUpdateDateColumn\"\n [showCreationDateColumn]=\"showCreationDateColumn\"\n [showUsernameColumn]=\"false\"\n [showUsernameExtranetColumn]=\"false\"\n [canEdit]=\"false\"\n [debug]=\"debug\"\n (onClickRow)=\"clickRow($event)\"\n >\n </app-users-table>\n</ion-content>\n\n<ion-footer *ngIf=\"!mobile\" hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\">\n <!-- Selection info -->\n <ion-col >\n <ion-item lines=\"none\" color=\"transparent\">\n <ion-label color=\"medium\">\n @if(hasSelection) {\n {{ 'USER.SELECT.SELECTED_COUNT' | translate: { count: selectedUsers.length } }}\n }\n </ion-label>\n </ion-item>\n </ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button\n [fill]=\"!hasSelection && !multiple ? 'clear' : 'solid'\"\n [disabled]=\"!hasSelection\"\n (keyup.enter)=\"validate()\"\n (click)=\"validate()\"\n color=\"tertiary\"\n >\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n", styles: [":host{--table-offset: calc(var(--ion-toolbar-height, 56px) + var(--app-paginator-height, 34px))}\n"], dependencies: [{ kind: "directive", type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i6.UsersPage, selector: "app-users-table", inputs: ["showUsernameColumn", "showUsernameExtranetColumn", "showEmailColumn", "showPubkeyColumn", "showCreationDateColumn", "showUpdateDateColumn", "title", "canSendMessage", "canEdit", "compact", "usePageSettings", "sticky", "stickyEnd", "canDownload", "inModal", "showFooter", "showToolbar", "showPaginator"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
128
+ }
129
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppSelectUsersModal, decorators: [{
130
+ type: Component,
131
+ args: [{ selector: 'app-select-users-modal', providers: [RxState], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-content scroll-y=\"false\">\n <!-- Reuse UsersPage component -->\n <app-users-table\n #usersTable\n [inModal]=\"true\"\n [title]=\"title\"\n [settingsId]=\"settingsId\"\n [usePageSettings]=\"false\"\n [sticky]=\"false\"\n [stickyEnd]=\"false\"\n [canSendMessage]=\"false\"\n [canDownload]=\"false\"\n [showFooter]=\"false\"\n [showEmailColumn]=\"showEmailColumn\"\n [showPubkeyColumn]=\"showPubkeyColumn\"\n [showUpdateDateColumn]=\"showUpdateDateColumn\"\n [showCreationDateColumn]=\"showCreationDateColumn\"\n [showUsernameColumn]=\"false\"\n [showUsernameExtranetColumn]=\"false\"\n [canEdit]=\"false\"\n [debug]=\"debug\"\n (onClickRow)=\"clickRow($event)\"\n >\n </app-users-table>\n</ion-content>\n\n<ion-footer *ngIf=\"!mobile\" hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\">\n <!-- Selection info -->\n <ion-col >\n <ion-item lines=\"none\" color=\"transparent\">\n <ion-label color=\"medium\">\n @if(hasSelection) {\n {{ 'USER.SELECT.SELECTED_COUNT' | translate: { count: selectedUsers.length } }}\n }\n </ion-label>\n </ion-item>\n </ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button\n [fill]=\"!hasSelection && !multiple ? 'clear' : 'solid'\"\n [disabled]=\"!hasSelection\"\n (keyup.enter)=\"validate()\"\n (click)=\"validate()\"\n color=\"tertiary\"\n >\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n", styles: [":host{--table-offset: calc(var(--ion-toolbar-height, 56px) + var(--app-paginator-height, 34px))}\n"] }]
132
+ }], ctorParameters: () => [{ type: i1.LocalSettingsService }, { type: i2.ModalController }, { type: i0.ChangeDetectorRef }, { type: i3.RxState }], propDecorators: { debug: [{
133
+ type: Input
134
+ }], title: [{
135
+ type: Input
136
+ }], settingsId: [{
137
+ type: Input
138
+ }], showEmailColumn: [{
139
+ type: Input
140
+ }], showPubkeyColumn: [{
141
+ type: Input
142
+ }], showUpdateDateColumn: [{
143
+ type: Input
144
+ }], showCreationDateColumn: [{
145
+ type: Input
146
+ }], usersTable: [{
147
+ type: ViewChild,
148
+ args: ['usersTable', { static: true }]
149
+ }], showFilter: [{
150
+ type: Input,
151
+ args: [{ transform: booleanAttribute }]
152
+ }], canEdit: [{
153
+ type: Input,
154
+ args: [{ transform: booleanAttribute }]
155
+ }], showMessageButton: [{
156
+ type: Input,
157
+ args: [{ transform: booleanAttribute }]
158
+ }], mobile: [{
159
+ type: Input,
160
+ args: [{ transform: booleanAttribute }]
161
+ }], multiple: [{
162
+ type: Input,
163
+ args: [{ transform: booleanAttribute }]
164
+ }], selectedUsers: [{
165
+ type: Input
166
+ }] } });
167
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlcnMtc2VsZWN0Lm1vZGFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9hZG1pbi91c2Vycy91c2Vycy1zZWxlY3QubW9kYWwudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL2FkbWluL3VzZXJzL3VzZXJzLXNlbGVjdC5tb2RhbC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBaUIsZ0JBQWdCLEVBQUUsdUJBQXVCLEVBQXFCLFNBQVMsRUFBRSxLQUFLLEVBQVUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRWpKLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUVoRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFbkQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLG1CQUFtQixDQUFDOzs7Ozs7OztBQW1DNUMsTUFBTSxPQUFPLG1CQUFtQjtJQVlsQjtJQUNBO0lBQ0E7SUFDQTtJQWRILEtBQUssR0FBRyxLQUFLLENBQUM7SUFDZCxLQUFLLEdBQUcsbUJBQW1CLENBQUM7SUFDNUIsVUFBVSxHQUFHLG9CQUFvQixDQUFDO0lBQ2xDLGVBQWUsR0FBRyxLQUFLLENBQUM7SUFDeEIsZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0lBQ3pCLG9CQUFvQixHQUFHLEtBQUssQ0FBQztJQUM3QixzQkFBc0IsR0FBRyxLQUFLLENBQUM7SUFFVyxVQUFVLENBQVk7SUFFekUsWUFDWSxRQUE4QixFQUM5QixRQUF5QixFQUN6QixFQUFxQixFQUNyQixLQUF3QztRQUh4QyxhQUFRLEdBQVIsUUFBUSxDQUFzQjtRQUM5QixhQUFRLEdBQVIsUUFBUSxDQUFpQjtRQUN6QixPQUFFLEdBQUYsRUFBRSxDQUFtQjtRQUNyQixVQUFLLEdBQUwsS0FBSyxDQUFtQztRQUVsRCx1Q0FBdUM7UUFDdkMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENB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QUU7Z0JBT00sTUFBTTtzQkFBakQsS0FBSzt1QkFBQyxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRTtnQkFPTSxRQUFRO3NCQUFuRCxLQUFLO3VCQUFDLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFO2dCQU96QixhQUFhO3NCQUF6QixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQWZ0ZXJWaWV3SW5pdCwgYm9vbGVhbkF0dHJpYnV0ZSwgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENoYW5nZURldGVjdG9yUmVmLCBDb21wb25lbnQsIElucHV0LCBPbkluaXQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTW9kYWxDb250cm9sbGVyIH0gZnJvbSAnQGlvbmljL2FuZ3VsYXInO1xuaW1wb3J0IHsgUGVyc29uIH0gZnJvbSAnLi4vLi4vY29yZS9zZXJ2aWNlcy9tb2RlbC9wZXJzb24ubW9kZWwnO1xuaW1wb3J0IHsgTG9jYWxTZXR0aW5nc1NlcnZpY2UgfSBmcm9tICcuLi8uLi9jb3JlL3NlcnZpY2VzL2xvY2FsLXNldHRpbmdzLnNlcnZpY2UnO1xuaW1wb3J0IHsgdG9Cb29sZWFuIH0gZnJvbSAnLi4vLi4vc2hhcmVkL2Z1bmN0aW9ucyc7XG5pbXBvcnQgeyBVc2Vyc1BhZ2UgfSBmcm9tICcuL3VzZXJzJztcbmltcG9ydCB7IFJ4U3RhdGUgfSBmcm9tICdAcngtYW5ndWxhci9zdGF0ZSc7XG5pbXBvcnQgeyBUYWJsZUVsZW1lbnQgfSBmcm9tICdAZS1pcy9uZ3gtbWF0ZXJpYWwtdGFibGUnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEFwcFNlbGVjdFVzZXJzTW9kYWxPcHRpb25zIHtcbiAgZGVidWc/OiBib29sZWFuO1xuICB0aXRsZT86IHN0cmluZztcbiAgc2hvd0ZpbHRlcj86IGJvb2xlYW47XG4gIGNhbkVkaXQ/OiBib29sZWFuO1xuICBoaWRlRm9vdGVyPzogYm9vbGVhbjtcbiAgc2hvd01lc3NhZ2VCdXR0b24/OiBib29sZWFuO1xuICBtb2JpbGU/OiBib29sZWFuO1xuICBtdWx0aXBsZT86IGJvb2xlYW47XG4gIHNlbGVjdGVkVXNlcnM/OiBQZXJzb25bXTtcbn1cblxuaW50ZXJmYWNlIEFwcFNlbGVjdFVzZXJzTW9kYWxTdGF0ZSB7XG4gIHNob3dGaWx0ZXI6IGJvb2xlYW47XG4gIGNhbkVkaXQ6IGJvb2xlYW47XG4gIHNob3dNZXNzYWdlQnV0dG9uOiBib29sZWFuO1xuICBtb2JpbGU6IGJvb2xlYW47XG4gIG11bHRpcGxlOiBib29sZWFuO1xuICBzZWxlY3RlZFVzZXJzOiBQZXJzb25bXTtcbiAgc2hvd0VtYWlsQ29sdW1uOiBib29sZWFuO1xuICBzaG93UHVia2V5Q29sdW1uOiBib29sZWFuO1xuICBzaG93VXBkYXRlRGF0ZUNvbHVtbjogYm9vbGVhbjtcbiAgc2hvd0NyZWF0aW9uRGF0ZUNvbHVtbjogYm9vbGVhbjtcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYXBwLXNlbGVjdC11c2Vycy1tb2RhbCcsXG4gIHRlbXBsYXRlVXJsOiAnLi91c2Vycy1zZWxlY3QubW9kYWwuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3VzZXJzLXNlbGVjdC5tb2RhbC5zY3NzJ10sXG4gIHByb3ZpZGVyczogW1J4U3RhdGVdLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgQXBwU2VsZWN0VXNlcnNNb2RhbCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgQXBwU2VsZWN0VXNlcnNNb2RhbE9wdGlvbnMge1xuICBASW5wdXQoKSBkZWJ1ZyA9IGZhbHNlO1xuICBASW5wdXQoKSB0aXRsZSA9ICdVU0VSLlNFTEVDVC5USVRMRSc7XG4gIEBJbnB1dCgpIHNldHRpbmdzSWQgPSAndXNlcnMtc2VsZWN0LW1vZGFsJztcbiAgQElucHV0KCkgc2hvd0VtYWlsQ29sdW1uID0gZmFsc2U7XG4gIEBJbnB1dCgpIHNob3dQdWJrZXlDb2x1bW4gPSBmYWxzZTtcbiAgQElucHV0KCkgc2hvd1VwZGF0ZURhdGVDb2x1bW4gPSBmYWxzZTtcbiAgQElucHV0KCkgc2hvd0NyZWF0aW9uRGF0ZUNvbHVtbiA9IGZhbHNlO1xuXG4gIEBWaWV3Q2hpbGQoJ3VzZXJzVGFibGUnLCB7IHN0YXRpYzogdHJ1ZSB9KSBwcml2YXRlIHVzZXJzVGFibGU6IFVzZXJzUGFnZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcm90ZWN0ZWQgc2V0dGluZ3M6IExvY2FsU2V0dGluZ3NTZXJ2aWNlLFxuICAgIHByb3RlY3RlZCB2aWV3Q3RybDogTW9kYWxDb250cm9sbGVyLFxuICAgIHByb3RlY3RlZCBjZDogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJvdGVjdGVkIHN0YXRlOiBSeFN0YXRlPEFwcFNlbGVjdFVzZXJzTW9kYWxTdGF0ZT5cbiAgKSB7XG4gICAgLy8gSW5pdGlhbGl6ZSBzdGF0ZSB3aXRoIGRlZmF1bHQgdmFsdWVzXG4gICAgdGhpcy5zdGF0ZS5zZXQoe1xuICAgICAgc2hvd0ZpbHRlcjogdHJ1ZSxcbiAgICAgIGNhbkVkaXQ6IGZhbHNlLFxuICAgICAgc2hvd01lc3NhZ2VCdXR0b246IGZhbHNlLFxuICAgICAgbW9iaWxlOiB0aGlzLnNldHRpbmdzLm1vYmlsZSxcbiAgICAgIG11bHRpcGxlOiB0cnVlLFxuICAgICAgc2VsZWN0ZWRVc2VyczogW10sXG4gICAgfSk7XG4gIH1cblxuICAvLyBJbnB1dCBnZXR0ZXJzIGFuZCBzZXR0ZXJzIHVzaW5nIFJ4U3RhdGVcbiAgZ2V0IHNob3dGaWx0ZXIoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuZ2V0KCdzaG93RmlsdGVyJyk7XG4gIH1cbiAgQElucHV0KHsgdHJhbnNmb3JtOiBib29sZWFuQXR0cmlidXRlIH0pIHNldCBzaG93RmlsdGVyKHZhbHVlOiBib29sZWFuKSB7XG4gICAgdGhpcy5zdGF0ZS5zZXQoJ3Nob3dGaWx0ZXInLCAoKSA9PiB0b0Jvb2xlYW4odmFsdWUsIHRydWUpKTtcbiAgfVxuXG4gIGdldCBjYW5FZGl0KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLmdldCgnY2FuRWRpdCcpO1xuICB9XG4gIEBJbnB1dCh7IHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KSBzZXQgY2FuRWRpdCh2YWx1ZTogYm9vbGVhbikge1xuICAgIHRoaXMuc3RhdGUuc2V0KCdjYW5FZGl0JywgKCkgPT4gdG9Cb29sZWFuKHZhbHVlLCBmYWxzZSkpO1xuICB9XG5cbiAgZ2V0IHNob3dNZXNzYWdlQnV0dG9uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLmdldCgnc2hvd01lc3NhZ2VCdXR0b24nKTtcbiAgfVxuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgc2V0IHNob3dNZXNzYWdlQnV0dG9uKHZhbHVlOiBib29sZWFuKSB7XG4gICAgdGhpcy5zdGF0ZS5zZXQoJ3Nob3dNZXNzYWdlQnV0dG9uJywgKCkgPT4gdG9Cb29sZWFuKHZhbHVlLCBmYWxzZSkpO1xuICB9XG5cbiAgZ2V0IG1vYmlsZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5nZXQoJ21vYmlsZScpO1xuICB9XG4gIEBJbnB1dCh7IHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KSBzZXQgbW9iaWxlKHZhbHVlOiBib29sZWFuKSB7XG4gICAgdGhpcy5zdGF0ZS5zZXQoJ21vYmlsZScsICgpID0+IHRvQm9vbGVhbih2YWx1ZSwgdGhpcy5zZXR0aW5ncy5tb2JpbGUpKTtcbiAgfVxuXG4gIGdldCBtdWx0aXBsZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5nZXQoJ211bHRpcGxlJyk7XG4gIH1cbiAgQElucHV0KHsgdHJhbnNmb3JtOiBib29sZWFuQXR0cmlidXRlIH0pIHNldCBtdWx0aXBsZSh2YWx1ZTogYm9vbGVhbikge1xuICAgIHRoaXMuc3RhdGUuc2V0KCdtdWx0aXBsZScsICgpID0+IHRvQm9vbGVhbih2YWx1ZSwgdHJ1ZSkpO1xuICB9XG5cbiAgZ2V0IHNlbGVjdGVkVXNlcnMoKTogUGVyc29uW10ge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLmdldCgnc2VsZWN0ZWRVc2VycycpO1xuICB9XG4gIEBJbnB1dCgpIHNldCBzZWxlY3RlZFVzZXJzKHZhbHVlOiBQZXJzb25bXSkge1xuICAgIHRoaXMuc3RhdGUuc2V0KCdzZWxlY3RlZFVzZXJzJywgKCkgPT4gdmFsdWUgfHwgW10pO1xuICB9XG5cbiAgZ2V0IGhhc1NlbGVjdGlvbigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zZWxlY3RlZFVzZXJzICYmIHRoaXMuc2VsZWN0ZWRVc2Vycy5sZW5ndGggPiAwO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgLy8gQWRkaXRpb25hbCBpbml0aWFsaXphdGlvbiBpZiBuZWVkZWRcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGlmICh0aGlzLnVzZXJzVGFibGUpIHtcbiAgICAgICAgLy8gTm90ZTogY2FuRWRpdCBhbmQgY2FuU2VuZE1lc3NhZ2UgYXJlIHJlYWRvbmx5IHByb3BlcnRpZXMgc2V0IGluIGNvbnN0cnVjdG9yXG4gICAgICAgIC8vIFRoZXkgd2lsbCBiZSBjb25maWd1cmVkIHZpYSBJbnB1dCBwcm9wZXJ0aWVzIGluIHRoZSB0ZW1wbGF0ZVxuXG4gICAgICAgIC8vIFNldCBpbml0aWFsIHNlbGVjdGlvbiBpZiBwcm92aWRlZFxuICAgICAgICBpZiAodGhpcy5zZWxlY3RlZFVzZXJzICYmIHRoaXMuc2VsZWN0ZWRVc2Vycy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgLy8gVE9ETzogU2V0IGluaXRpYWwgc2VsZWN0aW9uIGluIHRoZSB0YWJsZVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tYXJrRm9yQ2hlY2soKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGNhbmNlbCgpIHtcbiAgICB0aGlzLnZpZXdDdHJsLmRpc21pc3MoKTtcbiAgfVxuXG4gIGFzeW5jIHZhbGlkYXRlKCk6IFByb21pc2U8YW55PiB7XG4gICAgaWYgKCF0aGlzLnVzZXJzVGFibGUpIHJldHVybjtcblxuICAgIGNvbnN0IHNlbGVjdGVkUm93cyA9IHRoaXMudXNlcnNUYWJsZS5zZWxlY3Rpb24uc2VsZWN0ZWQgfHwgW107XG4gICAgY29uc3Qgc2VsZWN0ZWRVc2VycyA9IHNlbGVjdGVkUm93cy5tYXAoKHJvdykgPT4gcm93LmN1cnJlbnREYXRhKS5tYXAoUGVyc29uLmZyb21PYmplY3QpO1xuXG4gICAgcmV0dXJuIHRoaXMudmlld0N0cmwuZGlzbWlzcyhzZWxlY3RlZFVzZXJzKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBtYXJrRm9yQ2hlY2soKSB7XG4gICAgdGhpcy5jZC5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBjbGlja1Jvdyhyb3c6IFRhYmxlRWxlbWVudDxQZXJzb24+KSB7XG4gICAgLy8gREVCVUdcbiAgICAvL2NvbnNvbGUuZGVidWcoJ1t1c2Vycy1zZWxlY3QtbW9kYWxdIGNsaWNrUm93Jywgcm93KTtcblxuICAgIGlmICh0aGlzLm11bHRpcGxlKSB7XG4gICAgICB0aGlzLnVzZXJzVGFibGUuc2VsZWN0aW9uLnRvZ2dsZShyb3cpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnVzZXJzVGFibGUuc2VsZWN0aW9uLnNlbGVjdChyb3cpO1xuICAgIH1cblxuICAgIHRoaXMub25TZWxlY3Rpb25DaGFuZ2UoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvblNlbGVjdGlvbkNoYW5nZSgpIHtcbiAgICBjb25zdCBzZWxlY3RlZFJvd3MgPSB0aGlzLnVzZXJzVGFibGU/LnNlbGVjdGlvbi5zZWxlY3RlZCB8fCBbXTtcbiAgICBjb25zdCBzZWxlY3RlZFVzZXJzID0gc2VsZWN0ZWRSb3dzLm1hcCgocm93KSA9PiByb3cuY3VycmVudERhdGEpLm1hcChQZXJzb24uZnJvbU9iamVjdCk7XG5cbiAgICB0aGlzLnN0YXRlLnNldCgnc2VsZWN0ZWRVc2VycycsICgpID0+IHNlbGVjdGVkVXNlcnMpO1xuICAgIHRoaXMubWFya0ZvckNoZWNrKCk7XG4gIH1cbn1cbiIsIjxpb24tY29udGVudCBzY3JvbGwteT1cImZhbHNlXCI+XG4gIDwhLS0gUmV1c2UgVXNlcnNQYWdlIGNvbXBvbmVudCAtLT5cbiAgPGFwcC11c2Vycy10YWJsZVxuICAgICN1c2Vyc1RhYmxlXG4gICAgW2luTW9kYWxdPVwidHJ1ZVwiXG4gICAgW3RpdGxlXT1cInRpdGxlXCJcbiAgICBbc2V0dGluZ3NJZF09XCJzZXR0aW5nc0lkXCJcbiAgICBbdXNlUGFnZVNldHRpbmdzXT1cImZhbHNlXCJcbiAgICBbc3RpY2t5XT1cImZhbHNlXCJcbiAgICBbc3RpY2t5RW5kXT1cImZhbHNlXCJcbiAgICBbY2FuU2VuZE1lc3NhZ2VdPVwiZmFsc2VcIlxuICAgIFtjYW5Eb3dubG9hZF09XCJmYWxzZVwiXG4gICAgW3Nob3dGb290ZXJdPVwiZmFsc2VcIlxuICAgIFtzaG93RW1haWxDb2x1bW5dPVwic2hvd0VtYWlsQ29sdW1uXCJcbiAgICBbc2hvd1B1YmtleUNvbHVtbl09XCJzaG93UHVia2V5Q29sdW1uXCJcbiAgICBbc2hvd1VwZGF0ZURhdGVDb2x1bW5dPVwic2hvd1VwZGF0ZURhdGVDb2x1bW5cIlxuICAgIFtzaG93Q3JlYXRpb25EYXRlQ29sdW1uXT1cInNob3dDcmVhdGlvbkRhdGVDb2x1bW5cIlxuICAgIFtzaG93VXNlcm5hbWVDb2x1bW5dPVwiZmFsc2VcIlxuICAgIFtzaG93VXNlcm5hbWVFeHRyYW5ldENvbHVtbl09XCJmYWxzZVwiXG4gICAgW2NhbkVkaXRdPVwiZmFsc2VcIlxuICAgIFtkZWJ1Z109XCJkZWJ1Z1wiXG4gICAgKG9uQ2xpY2tSb3cpPVwiY2xpY2tSb3coJGV2ZW50KVwiXG4gID5cbiAgPC9hcHAtdXNlcnMtdGFibGU+XG48L2lvbi1jb250ZW50PlxuXG48aW9uLWZvb3RlciAqbmdJZj1cIiFtb2JpbGVcIiBoaWRkZW4teHMgaGlkZGVuLXNtIGhpZGRlbi1tb2JpbGU+XG4gIDxpb24tdG9vbGJhcj5cbiAgICA8aW9uLXJvdyBjbGFzcz1cImlvbi1uby1wYWRkaW5nXCI+XG4gICAgICA8IS0tIFNlbGVjdGlvbiBpbmZvIC0tPlxuICAgICAgPGlvbi1jb2wgID5cbiAgICAgICAgPGlvbi1pdGVtIGxpbmVzPVwibm9uZVwiIGNvbG9yPVwidHJhbnNwYXJlbnRcIj5cbiAgICAgICAgICA8aW9uLWxhYmVsIGNvbG9yPVwibWVkaXVtXCI+XG4gICAgICAgICAgICBAaWYoaGFzU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgIHt7ICdVU0VSLlNFTEVDVC5TRUxFQ1RFRF9DT1VOVCcgfCB0cmFuc2xhdGU6IHsgY291bnQ6IHNlbGVjdGVkVXNlcnMubGVuZ3RoIH0gfX1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L2lvbi1sYWJlbD5cbiAgICAgICAgPC9pb24taXRlbT5cbiAgICAgIDwvaW9uLWNvbD5cblxuICAgICAgPCEtLSBidXR0b25zIC0tPlxuICAgICAgPGlvbi1jb2wgc2l6ZT1cImF1dG9cIj5cbiAgICAgICAgPGlvbi1idXR0b24gZmlsbD1cImNsZWFyXCIgY29sb3I9XCJkYXJrXCIgKGNsaWNrKT1cImNhbmNlbCgpXCI+XG4gICAgICAgICAgPGlvbi1sYWJlbCB0cmFuc2xhdGU+Q09NTU9OLkJUTl9DQU5DRUw8L2lvbi1sYWJlbD5cbiAgICAgICAgPC9pb24tYnV0dG9uPlxuXG4gICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgW2ZpbGxdPVwiIWhhc1NlbGVjdGlvbiAmJiAhbXVsdGlwbGUgPyAnY2xlYXInIDogJ3NvbGlkJ1wiXG4gICAgICAgICAgW2Rpc2FibGVkXT1cIiFoYXNTZWxlY3Rpb25cIlxuICAgICAgICAgIChrZXl1cC5lbnRlcik9XCJ2YWxpZGF0ZSgpXCJcbiAgICAgICAgICAoY2xpY2spPVwidmFsaWRhdGUoKVwiXG4gICAgICAgICAgY29sb3I9XCJ0ZXJ0aWFyeVwiXG4gICAgICAgID5cbiAgICAgICAgICA8aW9uLWxhYmVsIHRyYW5zbGF0ZT5DT01NT04uQlROX1ZBTElEQVRFPC9pb24tbGFiZWw+XG4gICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgIDwvaW9uLWNvbD5cbiAgICA8L2lvbi1yb3c+XG4gIDwvaW9uLXRvb2xiYXI+XG48L2lvbi1mb290ZXI+XG4iXX0=