@gnggln/ng-ui-system 1.0.0-alpha.0

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 (141) hide show
  1. package/esm2022/gnggln-ng-ui-system.mjs +5 -0
  2. package/esm2022/lib/components/accordion/accordion.component.mjs +353 -0
  3. package/esm2022/lib/components/accordion/accordion.types.mjs +6 -0
  4. package/esm2022/lib/components/accordion/index.mjs +2 -0
  5. package/esm2022/lib/components/base-layout/base-layout.component.mjs +218 -0
  6. package/esm2022/lib/components/base-layout/base-layout.types.mjs +6 -0
  7. package/esm2022/lib/components/base-layout/index.mjs +14 -0
  8. package/esm2022/lib/components/button/button-area.component.mjs +196 -0
  9. package/esm2022/lib/components/button/button.component.mjs +164 -0
  10. package/esm2022/lib/components/button/button.types.mjs +6 -0
  11. package/esm2022/lib/components/button/index.mjs +16 -0
  12. package/esm2022/lib/components/crud-table/crud-table.component.mjs +789 -0
  13. package/esm2022/lib/components/crud-table/crud-table.types.mjs +6 -0
  14. package/esm2022/lib/components/crud-table/index.mjs +16 -0
  15. package/esm2022/lib/components/form-builder/adapters/it-date-adapter.mjs +82 -0
  16. package/esm2022/lib/components/form-builder/directives/currency-input.directive.mjs +184 -0
  17. package/esm2022/lib/components/form-builder/form-builder.component.mjs +824 -0
  18. package/esm2022/lib/components/form-builder/form-wizard.component.mjs +510 -0
  19. package/esm2022/lib/components/form-builder/index.mjs +19 -0
  20. package/esm2022/lib/components/form-builder/services/form-condition.service.mjs +132 -0
  21. package/esm2022/lib/components/form-builder/services/form-validation.service.mjs +381 -0
  22. package/esm2022/lib/components/form-builder/services/location.service.mjs +140 -0
  23. package/esm2022/lib/components/form-builder/services/wizard-sync.service.mjs +84 -0
  24. package/esm2022/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.mjs +161 -0
  25. package/esm2022/lib/components/form-builder/sub-components/file-input/file-input.component.mjs +310 -0
  26. package/esm2022/lib/components/form-builder/sub-components/specifica-territoriale/specifica-territoriale.component.mjs +648 -0
  27. package/esm2022/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.mjs +432 -0
  28. package/esm2022/lib/components/form-builder/types/condition.types.mjs +6 -0
  29. package/esm2022/lib/components/form-builder/types/field.types.mjs +6 -0
  30. package/esm2022/lib/components/form-builder/types/index.mjs +2 -0
  31. package/esm2022/lib/components/form-builder/types/schema.types.mjs +6 -0
  32. package/esm2022/lib/components/form-builder/types/territoriale.types.mjs +6 -0
  33. package/esm2022/lib/components/form-builder/types/validation.types.mjs +6 -0
  34. package/esm2022/lib/components/form-builder-editor/form-builder-editor.component.mjs +730 -0
  35. package/esm2022/lib/components/form-builder-editor/form-builder-editor.service.mjs +56 -0
  36. package/esm2022/lib/components/form-builder-editor/index.mjs +21 -0
  37. package/esm2022/lib/components/form-builder-editor/services/editor-persistence.service.mjs +190 -0
  38. package/esm2022/lib/components/form-builder-editor/services/editor-state.service.mjs +324 -0
  39. package/esm2022/lib/components/form-builder-editor/services/field-factory.service.mjs +188 -0
  40. package/esm2022/lib/components/form-builder-editor/sub-components/condition-editor/condition-editor.component.mjs +667 -0
  41. package/esm2022/lib/components/form-builder-editor/sub-components/editor-toolbar/editor-toolbar.component.mjs +317 -0
  42. package/esm2022/lib/components/form-builder-editor/sub-components/field-config-panel/field-config-panel.component.mjs +611 -0
  43. package/esm2022/lib/components/form-builder-editor/sub-components/field-palette/field-palette.component.mjs +267 -0
  44. package/esm2022/lib/components/form-builder-editor/sub-components/form-values-panel/form-values-panel.component.mjs +276 -0
  45. package/esm2022/lib/components/form-builder-editor/sub-components/options-editor/options-editor.component.mjs +323 -0
  46. package/esm2022/lib/components/form-builder-editor/sub-components/preview-container/preview-container.component.mjs +238 -0
  47. package/esm2022/lib/components/form-builder-editor/sub-components/section-editor/section-editor.component.mjs +472 -0
  48. package/esm2022/lib/components/form-builder-editor/sub-components/validation-editor/validation-editor.component.mjs +473 -0
  49. package/esm2022/lib/components/form-builder-editor/types/editor.types.mjs +6 -0
  50. package/esm2022/lib/components/layout-builder/index.mjs +18 -0
  51. package/esm2022/lib/components/layout-builder/layout-builder.component.mjs +1730 -0
  52. package/esm2022/lib/components/layout-builder/layout-builder.types.mjs +9 -0
  53. package/esm2022/lib/components/layout-builder/layout.service.mjs +239 -0
  54. package/esm2022/lib/components/modal/confirm-dialog.component.mjs +151 -0
  55. package/esm2022/lib/components/modal/index.mjs +4 -0
  56. package/esm2022/lib/components/modal/modal.component.mjs +139 -0
  57. package/esm2022/lib/components/modal/modal.service.mjs +194 -0
  58. package/esm2022/lib/components/modal/modal.types.mjs +6 -0
  59. package/esm2022/lib/components/page-header/breadcrumb.service.mjs +242 -0
  60. package/esm2022/lib/components/page-header/index.mjs +20 -0
  61. package/esm2022/lib/components/page-header/page-header.component.mjs +243 -0
  62. package/esm2022/lib/components/page-header/page-header.types.mjs +21 -0
  63. package/esm2022/lib/components/table/index.mjs +2 -0
  64. package/esm2022/lib/components/table/paginated-table.component.mjs +407 -0
  65. package/esm2022/lib/components/table/table.types.mjs +6 -0
  66. package/esm2022/lib/core/types/index.mjs +6 -0
  67. package/esm2022/lib/core/utils/index.mjs +53 -0
  68. package/esm2022/lib/sources/location-data.opt.json +8942 -0
  69. package/esm2022/lib/sources/nazioni.opt.json +215 -0
  70. package/esm2022/public-api.mjs +34 -0
  71. package/fesm2022/gnggln-ng-ui-system.mjs +55752 -0
  72. package/fesm2022/gnggln-ng-ui-system.mjs.map +1 -0
  73. package/index.d.ts +5 -0
  74. package/lib/components/accordion/accordion.component.d.ts +118 -0
  75. package/lib/components/accordion/accordion.types.d.ts +62 -0
  76. package/lib/components/accordion/index.d.ts +2 -0
  77. package/lib/components/base-layout/base-layout.component.d.ts +83 -0
  78. package/lib/components/base-layout/base-layout.types.d.ts +26 -0
  79. package/lib/components/base-layout/index.d.ts +13 -0
  80. package/lib/components/button/button-area.component.d.ts +88 -0
  81. package/lib/components/button/button.component.d.ts +55 -0
  82. package/lib/components/button/button.types.d.ts +70 -0
  83. package/lib/components/button/index.d.ts +15 -0
  84. package/lib/components/crud-table/crud-table.component.d.ts +143 -0
  85. package/lib/components/crud-table/crud-table.types.d.ts +207 -0
  86. package/lib/components/crud-table/index.d.ts +15 -0
  87. package/lib/components/form-builder/adapters/it-date-adapter.d.ts +32 -0
  88. package/lib/components/form-builder/directives/currency-input.directive.d.ts +48 -0
  89. package/lib/components/form-builder/form-builder.component.d.ts +183 -0
  90. package/lib/components/form-builder/form-wizard.component.d.ts +87 -0
  91. package/lib/components/form-builder/index.d.ts +13 -0
  92. package/lib/components/form-builder/services/form-condition.service.d.ts +46 -0
  93. package/lib/components/form-builder/services/form-validation.service.d.ts +63 -0
  94. package/lib/components/form-builder/services/location.service.d.ts +83 -0
  95. package/lib/components/form-builder/services/wizard-sync.service.d.ts +63 -0
  96. package/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.d.ts +28 -0
  97. package/lib/components/form-builder/sub-components/file-input/file-input.component.d.ts +41 -0
  98. package/lib/components/form-builder/sub-components/specifica-territoriale/specifica-territoriale.component.d.ts +145 -0
  99. package/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.d.ts +108 -0
  100. package/lib/components/form-builder/types/condition.types.d.ts +51 -0
  101. package/lib/components/form-builder/types/field.types.d.ts +288 -0
  102. package/lib/components/form-builder/types/index.d.ts +5 -0
  103. package/lib/components/form-builder/types/schema.types.d.ts +227 -0
  104. package/lib/components/form-builder/types/territoriale.types.d.ts +170 -0
  105. package/lib/components/form-builder/types/validation.types.d.ts +174 -0
  106. package/lib/components/form-builder-editor/form-builder-editor.component.d.ts +117 -0
  107. package/lib/components/form-builder-editor/form-builder-editor.service.d.ts +38 -0
  108. package/lib/components/form-builder-editor/index.d.ts +15 -0
  109. package/lib/components/form-builder-editor/services/editor-persistence.service.d.ts +42 -0
  110. package/lib/components/form-builder-editor/services/editor-state.service.d.ts +66 -0
  111. package/lib/components/form-builder-editor/services/field-factory.service.d.ts +28 -0
  112. package/lib/components/form-builder-editor/sub-components/condition-editor/condition-editor.component.d.ts +139 -0
  113. package/lib/components/form-builder-editor/sub-components/editor-toolbar/editor-toolbar.component.d.ts +43 -0
  114. package/lib/components/form-builder-editor/sub-components/field-config-panel/field-config-panel.component.d.ts +83 -0
  115. package/lib/components/form-builder-editor/sub-components/field-palette/field-palette.component.d.ts +40 -0
  116. package/lib/components/form-builder-editor/sub-components/form-values-panel/form-values-panel.component.d.ts +51 -0
  117. package/lib/components/form-builder-editor/sub-components/options-editor/options-editor.component.d.ts +63 -0
  118. package/lib/components/form-builder-editor/sub-components/preview-container/preview-container.component.d.ts +68 -0
  119. package/lib/components/form-builder-editor/sub-components/section-editor/section-editor.component.d.ts +82 -0
  120. package/lib/components/form-builder-editor/sub-components/validation-editor/validation-editor.component.d.ts +112 -0
  121. package/lib/components/form-builder-editor/types/editor.types.d.ts +124 -0
  122. package/lib/components/layout-builder/index.d.ts +16 -0
  123. package/lib/components/layout-builder/layout-builder.component.d.ts +85 -0
  124. package/lib/components/layout-builder/layout-builder.types.d.ts +436 -0
  125. package/lib/components/layout-builder/layout.service.d.ts +100 -0
  126. package/lib/components/modal/confirm-dialog.component.d.ts +46 -0
  127. package/lib/components/modal/index.d.ts +4 -0
  128. package/lib/components/modal/modal.component.d.ts +44 -0
  129. package/lib/components/modal/modal.service.d.ts +93 -0
  130. package/lib/components/modal/modal.types.d.ts +110 -0
  131. package/lib/components/page-header/breadcrumb.service.d.ts +96 -0
  132. package/lib/components/page-header/index.d.ts +16 -0
  133. package/lib/components/page-header/page-header.component.d.ts +59 -0
  134. package/lib/components/page-header/page-header.types.d.ts +96 -0
  135. package/lib/components/table/index.d.ts +2 -0
  136. package/lib/components/table/paginated-table.component.d.ts +85 -0
  137. package/lib/components/table/table.types.d.ts +81 -0
  138. package/lib/core/types/index.d.ts +57 -0
  139. package/lib/core/utils/index.d.ts +29 -0
  140. package/package.json +44 -0
  141. package/public-api.d.ts +22 -0
@@ -0,0 +1,218 @@
1
+ import { Component, DestroyRef, inject, Input, ChangeDetectionStrategy, ViewEncapsulation, } from '@angular/core';
2
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
+ import { Location } from '@angular/common';
4
+ import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
5
+ import { filter, debounceTime } from 'rxjs/operators';
6
+ import { UiPageHeaderComponent } from '../page-header/page-header.component';
7
+ import { UiBreadcrumbService } from '../page-header/breadcrumb.service';
8
+ import { UiButtonAreaComponent } from '../button/button-area.component';
9
+ import * as i0 from "@angular/core";
10
+ /**
11
+ * Full-page layout component that combines a page header (breadcrumbs + title),
12
+ * a main content area via `<ng-content>`, and a sticky footer action bar
13
+ * powered by `UiButtonAreaComponent`.
14
+ *
15
+ * Optionally renders an automatic "back" button in the footer, derived from
16
+ * the breadcrumb trail (navigates to the parent breadcrumb).
17
+ *
18
+ * @selector ui-base-layout
19
+ *
20
+ * @example
21
+ * ```html
22
+ * <ui-base-layout [actions]="pageActions" footerAlign="end">
23
+ * <p>Your page content here</p>
24
+ * </ui-base-layout>
25
+ * ```
26
+ *
27
+ * @example
28
+ * ```html
29
+ * <!-- With back button and custom title -->
30
+ * <ui-base-layout
31
+ * title="Dettaglio utente"
32
+ * [showBackButton]="true"
33
+ * [actions]="[
34
+ * { id: 'save', label: 'Salva', variant: 'primary', icon: 'save', action: save },
35
+ * ]"
36
+ * >
37
+ * <app-user-detail />
38
+ * </ui-base-layout>
39
+ * ```
40
+ */
41
+ export class UiBaseLayoutComponent {
42
+ constructor() {
43
+ /** Whether to display the page header (breadcrumbs + title). */
44
+ this.showHeader = true;
45
+ /** Override the auto-detected page title. Passed through to `ui-page-header`. */
46
+ this.title = '';
47
+ /** Route path for the Home breadcrumb link. */
48
+ this.homeRoute = '/';
49
+ /** Whether to display the Home link in the breadcrumb trail. */
50
+ this.showHome = true;
51
+ /** When `true`, updates `document.title` on navigation. */
52
+ this.updateDocumentTitle = false;
53
+ /** Suffix appended to `document.title`. */
54
+ this.titleSuffix = '';
55
+ /** Whether to show an automatic "back" button based on breadcrumbs. */
56
+ this.showBackButton = true;
57
+ /** Configuration overrides for the automatic back button. */
58
+ this.backButtonConfig = {};
59
+ /** Array of button descriptors for the footer action area. */
60
+ this.actions = [];
61
+ /** Horizontal alignment of the footer button area. */
62
+ this.footerAlign = 'start';
63
+ /** Gap size between footer buttons. */
64
+ this.footerGap = 'sm';
65
+ this.router = inject(Router);
66
+ this.location = inject(Location);
67
+ this.activatedRoute = inject(ActivatedRoute);
68
+ this.breadcrumbService = inject(UiBreadcrumbService);
69
+ this.destroyRef = inject(DestroyRef);
70
+ /** @internal Current breadcrumbs, updated on each navigation. */
71
+ this.breadcrumbs = [];
72
+ }
73
+ /**
74
+ * Merged action list (back button + consumer actions).
75
+ * Computed on every change-detection check so it stays in sync
76
+ * with both navigation state (breadcrumbs) and input changes.
77
+ */
78
+ get mergedActions() {
79
+ const result = [];
80
+ if (this.showBackButton) {
81
+ const backTarget = this.getBackTarget();
82
+ result.push({
83
+ id: '__ui-back',
84
+ label: this.backButtonConfig.label ?? 'Indietro',
85
+ icon: this.backButtonConfig.icon ?? 'arrow-left',
86
+ iconPosition: 'leading',
87
+ variant: this.backButtonConfig.variant ?? 'outline',
88
+ hidden: !backTarget,
89
+ action: () => this.navigateBack(),
90
+ });
91
+ }
92
+ result.push(...this.actions);
93
+ return result;
94
+ }
95
+ /** Whether the footer should render (at least one non-hidden action exists). */
96
+ get hasVisibleActions() {
97
+ return this.mergedActions.some((a) => !a.hidden);
98
+ }
99
+ ngOnInit() {
100
+ this.refreshBreadcrumbs();
101
+ this.router.events
102
+ .pipe(filter((event) => event instanceof NavigationEnd), debounceTime(50), takeUntilDestroyed(this.destroyRef))
103
+ .subscribe(() => this.refreshBreadcrumbs());
104
+ }
105
+ /** @internal Refreshes breadcrumb state from the current route. */
106
+ refreshBreadcrumbs() {
107
+ this.breadcrumbs = this.breadcrumbService.getBreadcrumbsForRoute(this.activatedRoute);
108
+ }
109
+ /** @internal Determines the back navigation target from breadcrumbs. */
110
+ getBackTarget() {
111
+ if (this.breadcrumbs.length < 2)
112
+ return null;
113
+ return this.breadcrumbs[this.breadcrumbs.length - 2];
114
+ }
115
+ /** @internal Navigates to the parent breadcrumb or falls back to browser history. */
116
+ navigateBack() {
117
+ const target = this.getBackTarget();
118
+ if (target?.url) {
119
+ this.router.navigateByUrl(target.url);
120
+ }
121
+ else {
122
+ this.location.back();
123
+ }
124
+ }
125
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBaseLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
126
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: UiBaseLayoutComponent, isStandalone: true, selector: "ui-base-layout", inputs: { showHeader: "showHeader", title: "title", homeRoute: "homeRoute", showHome: "showHome", updateDocumentTitle: "updateDocumentTitle", titleSuffix: "titleSuffix", showBackButton: "showBackButton", backButtonConfig: "backButtonConfig", actions: "actions", footerAlign: "footerAlign", footerGap: "footerGap" }, host: { classAttribute: "ui-base-layout-host" }, ngImport: i0, template: `
127
+ <div class="ui-base-layout">
128
+ @if (showHeader) {
129
+ <ui-page-header
130
+ [title]="title"
131
+ [homeRoute]="homeRoute"
132
+ [showHome]="showHome"
133
+ [updateDocumentTitle]="updateDocumentTitle"
134
+ [titleSuffix]="titleSuffix"
135
+ />
136
+ }
137
+
138
+ <main class="ui-base-layout__content">
139
+ <ng-content />
140
+ </main>
141
+
142
+ @if (hasVisibleActions) {
143
+ <aside
144
+ class="ui-base-layout__footer"
145
+ aria-label="Page actions"
146
+ >
147
+ <ui-button-area
148
+ [buttons]="mergedActions"
149
+ [align]="footerAlign"
150
+ [gap]="footerGap"
151
+ [stackOnMobile]="true"
152
+ ariaLabel="Page actions"
153
+ />
154
+ </aside>
155
+ }
156
+ </div>
157
+ `, isInline: true, styles: [".ui-base-layout-host{display:block;min-height:100%}.ui-base-layout{display:flex;flex-direction:column;min-height:100%;font-family:var(--ui-font-family);padding:var(--ui-spacing-6)}.ui-base-layout__content{flex:1 1 auto}.ui-base-layout__footer{position:sticky;bottom:0;z-index:var(--ui-z-sticky, 100);padding:var(--ui-spacing-4) 0;margin-top:var(--ui-spacing-6);background:var(--ui-color-surface);border-top:1px solid var(--ui-color-border)}@media (min-width: 640px){.ui-base-layout__footer{padding:var(--ui-spacing-3) 0}}\n"], dependencies: [{ kind: "component", type: UiPageHeaderComponent, selector: "ui-page-header", inputs: ["title", "homeRoute", "showHome", "updateDocumentTitle", "titleSuffix"] }, { kind: "component", type: UiButtonAreaComponent, selector: "ui-button-area", inputs: ["buttons", "align", "ariaLabel", "gap", "stackOnMobile", "disableWhileLoading", "loadingIds"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
158
+ }
159
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBaseLayoutComponent, decorators: [{
160
+ type: Component,
161
+ args: [{ selector: 'ui-base-layout', standalone: true, imports: [UiPageHeaderComponent, UiButtonAreaComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
162
+ class: 'ui-base-layout-host',
163
+ }, template: `
164
+ <div class="ui-base-layout">
165
+ @if (showHeader) {
166
+ <ui-page-header
167
+ [title]="title"
168
+ [homeRoute]="homeRoute"
169
+ [showHome]="showHome"
170
+ [updateDocumentTitle]="updateDocumentTitle"
171
+ [titleSuffix]="titleSuffix"
172
+ />
173
+ }
174
+
175
+ <main class="ui-base-layout__content">
176
+ <ng-content />
177
+ </main>
178
+
179
+ @if (hasVisibleActions) {
180
+ <aside
181
+ class="ui-base-layout__footer"
182
+ aria-label="Page actions"
183
+ >
184
+ <ui-button-area
185
+ [buttons]="mergedActions"
186
+ [align]="footerAlign"
187
+ [gap]="footerGap"
188
+ [stackOnMobile]="true"
189
+ ariaLabel="Page actions"
190
+ />
191
+ </aside>
192
+ }
193
+ </div>
194
+ `, styles: [".ui-base-layout-host{display:block;min-height:100%}.ui-base-layout{display:flex;flex-direction:column;min-height:100%;font-family:var(--ui-font-family);padding:var(--ui-spacing-6)}.ui-base-layout__content{flex:1 1 auto}.ui-base-layout__footer{position:sticky;bottom:0;z-index:var(--ui-z-sticky, 100);padding:var(--ui-spacing-4) 0;margin-top:var(--ui-spacing-6);background:var(--ui-color-surface);border-top:1px solid var(--ui-color-border)}@media (min-width: 640px){.ui-base-layout__footer{padding:var(--ui-spacing-3) 0}}\n"] }]
195
+ }], propDecorators: { showHeader: [{
196
+ type: Input
197
+ }], title: [{
198
+ type: Input
199
+ }], homeRoute: [{
200
+ type: Input
201
+ }], showHome: [{
202
+ type: Input
203
+ }], updateDocumentTitle: [{
204
+ type: Input
205
+ }], titleSuffix: [{
206
+ type: Input
207
+ }], showBackButton: [{
208
+ type: Input
209
+ }], backButtonConfig: [{
210
+ type: Input
211
+ }], actions: [{
212
+ type: Input
213
+ }], footerAlign: [{
214
+ type: Input
215
+ }], footerGap: [{
216
+ type: Input
217
+ }] } });
218
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1sYXlvdXQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvbmctdWktc3lzdGVtL3NyYy9saWIvY29tcG9uZW50cy9iYXNlLWxheW91dC9iYXNlLWxheW91dC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsTUFBTSxFQUNOLEtBQUssRUFFTCx1QkFBdUIsRUFDdkIsaUJBQWlCLEdBQ2xCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLGFBQWEsRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN4RSxPQUFPLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQzdFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBRXhFLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDOztBQUl4RTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBOEJHO0FBNENILE1BQU0sT0FBTyxxQkFBcUI7SUEzQ2xDO1FBNENFLGdFQUFnRTtRQUN2RCxlQUFVLEdBQUcsSUFBSSxDQUFDO1FBRTNCLGlGQUFpRjtRQUN4RSxVQUFLLEdBQUcsRUFBRSxDQUFDO1FBRXBCLCtDQUErQztRQUN0QyxjQUFTLEdBQUcsR0FBRyxDQUFDO1FBRXpCLGdFQUFnRTtRQUN2RCxhQUFRLEdBQUcsSUFBSSxDQUFDO1FBRXpCLDJEQUEyRDtRQUNsRCx3QkFBbUIsR0FBRyxLQUFLLENBQUM7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N0UsWUFBWTtRQUNsQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDcEMsSUFBSSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUM7WUFDaEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hDLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN2QixDQUFDO0lBQ0gsQ0FBQzsrR0F4R1UscUJBQXFCO21HQUFyQixxQkFBcUIsdWJBbEN0Qjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQStCVCxxbEJBckNTLHFCQUFxQiw2SUFBRSxxQkFBcUI7OzRGQXdDM0MscUJBQXFCO2tCQTNDakMsU0FBUzsrQkFDRSxnQkFBZ0IsY0FDZCxJQUFJLFdBQ1AsQ0FBQyxxQkFBcUIsRUFBRSxxQkFBcUIsQ0FBQyxtQkFDdEMsdUJBQXVCLENBQUMsTUFBTSxpQkFDaEMsaUJBQWlCLENBQUMsSUFBSSxRQUMvQjt3QkFDSixLQUFLLEVBQUUscUJBQXFCO3FCQUM3QixZQUNTOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBK0JUOzhCQUtRLFVBQVU7c0JBQWxCLEtBQUs7Z0JBR0csS0FBSztzQkFBYixLQUFLO2dCQUdHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBR0csUUFBUTtzQkFBaEIsS0FBSztnQkFHRyxtQkFBbUI7c0JBQTNCLEtBQUs7Z0JBR0csV0FBVztzQkFBbkIsS0FBSztnQkFHRyxjQUFjO3NCQUF0QixLQUFLO2dCQUdHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFHRyxPQUFPO3NCQUFmLEtBQUs7Z0JBR0csV0FBVztzQkFBbkIsS0FBSztnQkFHRyxTQUFTO3NCQUFqQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgRGVzdHJveVJlZixcclxuICBpbmplY3QsXHJcbiAgSW5wdXQsXHJcbiAgT25Jbml0LFxyXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxyXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XHJcbmltcG9ydCB7IExvY2F0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIE5hdmlnYXRpb25FbmQsIFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XHJcbmltcG9ydCB7IGZpbHRlciwgZGVib3VuY2VUaW1lIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBVaVBhZ2VIZWFkZXJDb21wb25lbnQgfSBmcm9tICcuLi9wYWdlLWhlYWRlci9wYWdlLWhlYWRlci5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBVaUJyZWFkY3J1bWJTZXJ2aWNlIH0gZnJvbSAnLi4vcGFnZS1oZWFkZXIvYnJlYWRjcnVtYi5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVWlCcmVhZGNydW1iSXRlbSB9IGZyb20gJy4uL3BhZ2UtaGVhZGVyL3BhZ2UtaGVhZGVyLnR5cGVzJztcclxuaW1wb3J0IHsgVWlCdXR0b25BcmVhQ29tcG9uZW50IH0gZnJvbSAnLi4vYnV0dG9uL2J1dHRvbi1hcmVhLmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFVpQnV0dG9uRGVzY3JpcHRvciwgVWlCdXR0b25BcmVhQWxpZ24gfSBmcm9tICcuLi9idXR0b24vYnV0dG9uLnR5cGVzJztcclxuaW1wb3J0IHsgVWlCYWNrQnV0dG9uQ29uZmlnIH0gZnJvbSAnLi9iYXNlLWxheW91dC50eXBlcyc7XHJcblxyXG4vKipcclxuICogRnVsbC1wYWdlIGxheW91dCBjb21wb25lbnQgdGhhdCBjb21iaW5lcyBhIHBhZ2UgaGVhZGVyIChicmVhZGNydW1icyArIHRpdGxlKSxcclxuICogYSBtYWluIGNvbnRlbnQgYXJlYSB2aWEgYDxuZy1jb250ZW50PmAsIGFuZCBhIHN0aWNreSBmb290ZXIgYWN0aW9uIGJhclxyXG4gKiBwb3dlcmVkIGJ5IGBVaUJ1dHRvbkFyZWFDb21wb25lbnRgLlxyXG4gKlxyXG4gKiBPcHRpb25hbGx5IHJlbmRlcnMgYW4gYXV0b21hdGljIFwiYmFja1wiIGJ1dHRvbiBpbiB0aGUgZm9vdGVyLCBkZXJpdmVkIGZyb21cclxuICogdGhlIGJyZWFkY3J1bWIgdHJhaWwgKG5hdmlnYXRlcyB0byB0aGUgcGFyZW50IGJyZWFkY3J1bWIpLlxyXG4gKlxyXG4gKiBAc2VsZWN0b3IgdWktYmFzZS1sYXlvdXRcclxuICpcclxuICogQGV4YW1wbGVcclxuICogYGBgaHRtbFxyXG4gKiA8dWktYmFzZS1sYXlvdXQgW2FjdGlvbnNdPVwicGFnZUFjdGlvbnNcIiBmb290ZXJBbGlnbj1cImVuZFwiPlxyXG4gKiAgIDxwPllvdXIgcGFnZSBjb250ZW50IGhlcmU8L3A+XHJcbiAqIDwvdWktYmFzZS1sYXlvdXQ+XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKiBgYGBodG1sXHJcbiAqIDwhLS0gV2l0aCBiYWNrIGJ1dHRvbiBhbmQgY3VzdG9tIHRpdGxlIC0tPlxyXG4gKiA8dWktYmFzZS1sYXlvdXRcclxuICogICB0aXRsZT1cIkRldHRhZ2xpbyB1dGVudGVcIlxyXG4gKiAgIFtzaG93QmFja0J1dHRvbl09XCJ0cnVlXCJcclxuICogICBbYWN0aW9uc109XCJbXHJcbiAqICAgICB7IGlkOiAnc2F2ZScsIGxhYmVsOiAnU2FsdmEnLCB2YXJpYW50OiAncHJpbWFyeScsIGljb246ICdzYXZlJywgYWN0aW9uOiBzYXZlIH0sXHJcbiAqICAgXVwiXHJcbiAqID5cclxuICogICA8YXBwLXVzZXItZGV0YWlsIC8+XHJcbiAqIDwvdWktYmFzZS1sYXlvdXQ+XHJcbiAqIGBgYFxyXG4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICd1aS1iYXNlLWxheW91dCcsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbVWlQYWdlSGVhZGVyQ29tcG9uZW50LCBVaUJ1dHRvbkFyZWFDb21wb25lbnRdLFxyXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxyXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXHJcbiAgaG9zdDoge1xyXG4gICAgY2xhc3M6ICd1aS1iYXNlLWxheW91dC1ob3N0JyxcclxuICB9LFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2IGNsYXNzPVwidWktYmFzZS1sYXlvdXRcIj5cclxuICAgICAgQGlmIChzaG93SGVhZGVyKSB7XHJcbiAgICAgICAgPHVpLXBhZ2UtaGVhZGVyXHJcbiAgICAgICAgICBbdGl0bGVdPVwidGl0bGVcIlxyXG4gICAgICAgICAgW2hvbWVSb3V0ZV09XCJob21lUm91dGVcIlxyXG4gICAgICAgICAgW3Nob3dIb21lXT1cInNob3dIb21lXCJcclxuICAgICAgICAgIFt1cGRhdGVEb2N1bWVudFRpdGxlXT1cInVwZGF0ZURvY3VtZW50VGl0bGVcIlxyXG4gICAgICAgICAgW3RpdGxlU3VmZml4XT1cInRpdGxlU3VmZml4XCJcclxuICAgICAgICAvPlxyXG4gICAgICB9XHJcblxyXG4gICAgICA8bWFpbiBjbGFzcz1cInVpLWJhc2UtbGF5b3V0X19jb250ZW50XCI+XHJcbiAgICAgICAgPG5nLWNvbnRlbnQgLz5cclxuICAgICAgPC9tYWluPlxyXG5cclxuICAgICAgQGlmIChoYXNWaXNpYmxlQWN0aW9ucykge1xyXG4gICAgICAgIDxhc2lkZVxyXG4gICAgICAgICAgY2xhc3M9XCJ1aS1iYXNlLWxheW91dF9fZm9vdGVyXCJcclxuICAgICAgICAgIGFyaWEtbGFiZWw9XCJQYWdlIGFjdGlvbnNcIlxyXG4gICAgICAgID5cclxuICAgICAgICAgIDx1aS1idXR0b24tYXJlYVxyXG4gICAgICAgICAgICBbYnV0dG9uc109XCJtZXJnZWRBY3Rpb25zXCJcclxuICAgICAgICAgICAgW2FsaWduXT1cImZvb3RlckFsaWduXCJcclxuICAgICAgICAgICAgW2dhcF09XCJmb290ZXJHYXBcIlxyXG4gICAgICAgICAgICBbc3RhY2tPbk1vYmlsZV09XCJ0cnVlXCJcclxuICAgICAgICAgICAgYXJpYUxhYmVsPVwiUGFnZSBhY3Rpb25zXCJcclxuICAgICAgICAgIC8+XHJcbiAgICAgICAgPC9hc2lkZT5cclxuICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxuICBzdHlsZVVybDogJy4vYmFzZS1sYXlvdXQuY29tcG9uZW50LnNjc3MnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgVWlCYXNlTGF5b3V0Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcclxuICAvKiogV2hldGhlciB0byBkaXNwbGF5IHRoZSBwYWdlIGhlYWRlciAoYnJlYWRjcnVtYnMgKyB0aXRsZSkuICovXHJcbiAgQElucHV0KCkgc2hvd0hlYWRlciA9IHRydWU7XHJcblxyXG4gIC8qKiBPdmVycmlkZSB0aGUgYXV0by1kZXRlY3RlZCBwYWdlIHRpdGxlLiBQYXNzZWQgdGhyb3VnaCB0byBgdWktcGFnZS1oZWFkZXJgLiAqL1xyXG4gIEBJbnB1dCgpIHRpdGxlID0gJyc7XHJcblxyXG4gIC8qKiBSb3V0ZSBwYXRoIGZvciB0aGUgSG9tZSBicmVhZGNydW1iIGxpbmsuICovXHJcbiAgQElucHV0KCkgaG9tZVJvdXRlID0gJy8nO1xyXG5cclxuICAvKiogV2hldGhlciB0byBkaXNwbGF5IHRoZSBIb21lIGxpbmsgaW4gdGhlIGJyZWFkY3J1bWIgdHJhaWwuICovXHJcbiAgQElucHV0KCkgc2hvd0hvbWUgPSB0cnVlO1xyXG5cclxuICAvKiogV2hlbiBgdHJ1ZWAsIHVwZGF0ZXMgYGRvY3VtZW50LnRpdGxlYCBvbiBuYXZpZ2F0aW9uLiAqL1xyXG4gIEBJbnB1dCgpIHVwZGF0ZURvY3VtZW50VGl0bGUgPSBmYWxzZTtcclxuXHJcbiAgLyoqIFN1ZmZpeCBhcHBlbmRlZCB0byBgZG9jdW1lbnQudGl0bGVgLiAqL1xyXG4gIEBJbnB1dCgpIHRpdGxlU3VmZml4ID0gJyc7XHJcblxyXG4gIC8qKiBXaGV0aGVyIHRvIHNob3cgYW4gYXV0b21hdGljIFwiYmFja1wiIGJ1dHRvbiBiYXNlZCBvbiBicmVhZGNydW1icy4gKi9cclxuICBASW5wdXQoKSBzaG93QmFja0J1dHRvbiA9IHRydWU7XHJcblxyXG4gIC8qKiBDb25maWd1cmF0aW9uIG92ZXJyaWRlcyBmb3IgdGhlIGF1dG9tYXRpYyBiYWNrIGJ1dHRvbi4gKi9cclxuICBASW5wdXQoKSBiYWNrQnV0dG9uQ29uZmlnOiBVaUJhY2tCdXR0b25Db25maWcgPSB7fTtcclxuXHJcbiAgLyoqIEFycmF5IG9mIGJ1dHRvbiBkZXNjcmlwdG9ycyBmb3IgdGhlIGZvb3RlciBhY3Rpb24gYXJlYS4gKi9cclxuICBASW5wdXQoKSBhY3Rpb25zOiBVaUJ1dHRvbkRlc2NyaXB0b3JbXSA9IFtdO1xyXG5cclxuICAvKiogSG9yaXpvbnRhbCBhbGlnbm1lbnQgb2YgdGhlIGZvb3RlciBidXR0b24gYXJlYS4gKi9cclxuICBASW5wdXQoKSBmb290ZXJBbGlnbjogVWlCdXR0b25BcmVhQWxpZ24gPSAnc3RhcnQnO1xyXG5cclxuICAvKiogR2FwIHNpemUgYmV0d2VlbiBmb290ZXIgYnV0dG9ucy4gKi9cclxuICBASW5wdXQoKSBmb290ZXJHYXA6ICd4cycgfCAnc20nIHwgJ21kJyB8ICdsZycgfCAneGwnID0gJ3NtJztcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSByb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGxvY2F0aW9uID0gaW5qZWN0KExvY2F0aW9uKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGFjdGl2YXRlZFJvdXRlID0gaW5qZWN0KEFjdGl2YXRlZFJvdXRlKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGJyZWFkY3J1bWJTZXJ2aWNlID0gaW5qZWN0KFVpQnJlYWRjcnVtYlNlcnZpY2UpO1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgZGVzdHJveVJlZiA9IGluamVjdChEZXN0cm95UmVmKTtcclxuXHJcbiAgLyoqIEBpbnRlcm5hbCBDdXJyZW50IGJyZWFkY3J1bWJzLCB1cGRhdGVkIG9uIGVhY2ggbmF2aWdhdGlvbi4gKi9cclxuICBwcml2YXRlIGJyZWFkY3J1bWJzOiBVaUJyZWFkY3J1bWJJdGVtW10gPSBbXTtcclxuXHJcbiAgLyoqXHJcbiAgICogTWVyZ2VkIGFjdGlvbiBsaXN0IChiYWNrIGJ1dHRvbiArIGNvbnN1bWVyIGFjdGlvbnMpLlxyXG4gICAqIENvbXB1dGVkIG9uIGV2ZXJ5IGNoYW5nZS1kZXRlY3Rpb24gY2hlY2sgc28gaXQgc3RheXMgaW4gc3luY1xyXG4gICAqIHdpdGggYm90aCBuYXZpZ2F0aW9uIHN0YXRlIChicmVhZGNydW1icykgYW5kIGlucHV0IGNoYW5nZXMuXHJcbiAgICovXHJcbiAgZ2V0IG1lcmdlZEFjdGlvbnMoKTogVWlCdXR0b25EZXNjcmlwdG9yW10ge1xyXG4gICAgY29uc3QgcmVzdWx0OiBVaUJ1dHRvbkRlc2NyaXB0b3JbXSA9IFtdO1xyXG5cclxuICAgIGlmICh0aGlzLnNob3dCYWNrQnV0dG9uKSB7XHJcbiAgICAgIGNvbnN0IGJhY2tUYXJnZXQgPSB0aGlzLmdldEJhY2tUYXJnZXQoKTtcclxuICAgICAgcmVzdWx0LnB1c2goe1xyXG4gICAgICAgIGlkOiAnX191aS1iYWNrJyxcclxuICAgICAgICBsYWJlbDogdGhpcy5iYWNrQnV0dG9uQ29uZmlnLmxhYmVsID8/ICdJbmRpZXRybycsXHJcbiAgICAgICAgaWNvbjogKHRoaXMuYmFja0J1dHRvbkNvbmZpZy5pY29uIGFzIGFueSkgPz8gJ2Fycm93LWxlZnQnLFxyXG4gICAgICAgIGljb25Qb3NpdGlvbjogJ2xlYWRpbmcnLFxyXG4gICAgICAgIHZhcmlhbnQ6ICh0aGlzLmJhY2tCdXR0b25Db25maWcudmFyaWFudCBhcyBhbnkpID8/ICdvdXRsaW5lJyxcclxuICAgICAgICBoaWRkZW46ICFiYWNrVGFyZ2V0LFxyXG4gICAgICAgIGFjdGlvbjogKCkgPT4gdGhpcy5uYXZpZ2F0ZUJhY2soKSxcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmVzdWx0LnB1c2goLi4udGhpcy5hY3Rpb25zKTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfVxyXG5cclxuICAvKiogV2hldGhlciB0aGUgZm9vdGVyIHNob3VsZCByZW5kZXIgKGF0IGxlYXN0IG9uZSBub24taGlkZGVuIGFjdGlvbiBleGlzdHMpLiAqL1xyXG4gIGdldCBoYXNWaXNpYmxlQWN0aW9ucygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLm1lcmdlZEFjdGlvbnMuc29tZSgoYSkgPT4gIWEuaGlkZGVuKTtcclxuICB9XHJcblxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5yZWZyZXNoQnJlYWRjcnVtYnMoKTtcclxuXHJcbiAgICB0aGlzLnJvdXRlci5ldmVudHNcclxuICAgICAgLnBpcGUoXHJcbiAgICAgICAgZmlsdGVyKChldmVudCkgPT4gZXZlbnQgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uRW5kKSxcclxuICAgICAgICBkZWJvdW5jZVRpbWUoNTApLFxyXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpLFxyXG4gICAgICApXHJcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5yZWZyZXNoQnJlYWRjcnVtYnMoKSk7XHJcbiAgfVxyXG5cclxuICAvKiogQGludGVybmFsIFJlZnJlc2hlcyBicmVhZGNydW1iIHN0YXRlIGZyb20gdGhlIGN1cnJlbnQgcm91dGUuICovXHJcbiAgcHJpdmF0ZSByZWZyZXNoQnJlYWRjcnVtYnMoKTogdm9pZCB7XHJcbiAgICB0aGlzLmJyZWFkY3J1bWJzID0gdGhpcy5icmVhZGNydW1iU2VydmljZS5nZXRCcmVhZGNydW1ic0ZvclJvdXRlKHRoaXMuYWN0aXZhdGVkUm91dGUpO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBpbnRlcm5hbCBEZXRlcm1pbmVzIHRoZSBiYWNrIG5hdmlnYXRpb24gdGFyZ2V0IGZyb20gYnJlYWRjcnVtYnMuICovXHJcbiAgcHJpdmF0ZSBnZXRCYWNrVGFyZ2V0KCk6IFVpQnJlYWRjcnVtYkl0ZW0gfCBudWxsIHtcclxuICAgIGlmICh0aGlzLmJyZWFkY3J1bWJzLmxlbmd0aCA8IDIpIHJldHVybiBudWxsO1xyXG4gICAgcmV0dXJuIHRoaXMuYnJlYWRjcnVtYnNbdGhpcy5icmVhZGNydW1icy5sZW5ndGggLSAyXTtcclxuICB9XHJcblxyXG4gIC8qKiBAaW50ZXJuYWwgTmF2aWdhdGVzIHRvIHRoZSBwYXJlbnQgYnJlYWRjcnVtYiBvciBmYWxscyBiYWNrIHRvIGJyb3dzZXIgaGlzdG9yeS4gKi9cclxuICBwcml2YXRlIG5hdmlnYXRlQmFjaygpOiB2b2lkIHtcclxuICAgIGNvbnN0IHRhcmdldCA9IHRoaXMuZ2V0QmFja1RhcmdldCgpO1xyXG4gICAgaWYgKHRhcmdldD8udXJsKSB7XHJcbiAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlQnlVcmwodGFyZ2V0LnVybCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLmxvY2F0aW9uLmJhY2soKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @module ng-ui-system/base-layout
3
+ * Types and interfaces for UiBaseLayout component.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1sYXlvdXQudHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9uZy11aS1zeXN0ZW0vc3JjL2xpYi9jb21wb25lbnRzL2Jhc2UtbGF5b3V0L2Jhc2UtbGF5b3V0LnR5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxyXG4gKiBAbW9kdWxlIG5nLXVpLXN5c3RlbS9iYXNlLWxheW91dFxyXG4gKiBUeXBlcyBhbmQgaW50ZXJmYWNlcyBmb3IgVWlCYXNlTGF5b3V0IGNvbXBvbmVudC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBVaUJ1dHRvbkRlc2NyaXB0b3IsIFVpQnV0dG9uQXJlYUFsaWduIH0gZnJvbSAnLi4vYnV0dG9uL2J1dHRvbi50eXBlcyc7XHJcblxyXG4vLyBSZS1leHBvcnQgZm9yIGNvbnN1bWVyIGNvbnZlbmllbmNlXHJcbmV4cG9ydCB7IFVpQnV0dG9uRGVzY3JpcHRvciwgVWlCdXR0b25BcmVhQWxpZ24gfTtcclxuXHJcbi8qKlxyXG4gKiBDb25maWd1cmF0aW9uIGZvciB0aGUgYXV0b21hdGljIFwiYmFja1wiIGJ1dHRvbiByZW5kZXJlZCBpbiB0aGUgZm9vdGVyIGFjdGlvbiBhcmVhLlxyXG4gKlxyXG4gKiBAdXNhZ2VOb3Rlc1xyXG4gKiBgYGB0eXBlc2NyaXB0XHJcbiAqIGNvbnN0IGJhY2tDb25maWc6IFVpQmFja0J1dHRvbkNvbmZpZyA9IHtcclxuICogICBsYWJlbDogJ0luZGlldHJvJyxcclxuICogICBpY29uOiAnYXJyb3ctbGVmdCcsXHJcbiAqICAgdmFyaWFudDogJ291dGxpbmUnLFxyXG4gKiB9O1xyXG4gKiBgYGBcclxuICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgVWlCYWNrQnV0dG9uQ29uZmlnIHtcclxuICAvKiogTGFiZWwgdGV4dCBmb3IgdGhlIGJhY2sgYnV0dG9uLiBAZGVmYXVsdCAnSW5kaWV0cm8nICovXHJcbiAgbGFiZWw/OiBzdHJpbmc7XHJcbiAgLyoqIEx1Y2lkZSBpY29uIG5hbWUuIEBkZWZhdWx0ICdhcnJvdy1sZWZ0JyAqL1xyXG4gIGljb24/OiBzdHJpbmc7XHJcbiAgLyoqIFZpc3VhbCB2YXJpYW50LiBAZGVmYXVsdCAnb3V0bGluZScgKi9cclxuICB2YXJpYW50Pzogc3RyaW5nO1xyXG59XHJcbiJdfQ==
@@ -0,0 +1,14 @@
1
+ /**
2
+ * ng-ui-system — Base Layout entry point.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import {
7
+ * UiBaseLayoutComponent,
8
+ * UiBackButtonConfig,
9
+ * } from 'ng-ui-system';
10
+ * ```
11
+ */
12
+ // Components
13
+ export { UiBaseLayoutComponent } from './base-layout.component';
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9uZy11aS1zeXN0ZW0vc3JjL2xpYi9jb21wb25lbnRzL2Jhc2UtbGF5b3V0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxhQUFhO0FBQ2IsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0seUJBQXlCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcclxuICogbmctdWktc3lzdGVtIOKAlCBCYXNlIExheW91dCBlbnRyeSBwb2ludC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICogYGBgdHlwZXNjcmlwdFxyXG4gKiBpbXBvcnQge1xyXG4gKiAgIFVpQmFzZUxheW91dENvbXBvbmVudCxcclxuICogICBVaUJhY2tCdXR0b25Db25maWcsXHJcbiAqIH0gZnJvbSAnbmctdWktc3lzdGVtJztcclxuICogYGBgXHJcbiAqL1xyXG5cclxuLy8gQ29tcG9uZW50c1xyXG5leHBvcnQgeyBVaUJhc2VMYXlvdXRDb21wb25lbnQgfSBmcm9tICcuL2Jhc2UtbGF5b3V0LmNvbXBvbmVudCc7XHJcblxyXG4vLyBUeXBlc1xyXG5leHBvcnQgeyBVaUJhY2tCdXR0b25Db25maWcgfSBmcm9tICcuL2Jhc2UtbGF5b3V0LnR5cGVzJztcclxuIl19
@@ -0,0 +1,196 @@
1
+ import { Component, Input, ChangeDetectionStrategy, ViewEncapsulation, inject } from '@angular/core';
2
+ import { Router } from '@angular/router';
3
+ import { UiButtonComponent } from './button.component';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * Standalone button-group component driven by a `UiButtonDescriptor[]` configuration.
7
+ *
8
+ * Renders a group of `UiButton` instances from declarative descriptors.
9
+ * Supports per-button loading/disabled states, dynamic visibility,
10
+ * alignment control, and optional navigation via Angular Router.
11
+ *
12
+ * @selector ui-button-area
13
+ *
14
+ * @example
15
+ * ```html
16
+ * <ui-button-area
17
+ * [buttons]="actions"
18
+ * align="end"
19
+ * gap="sm"
20
+ * [loadingIds]="currentlyLoading"
21
+ * />
22
+ * ```
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Dynamic configuration
27
+ * actions: UiButtonDescriptor[] = [
28
+ * { id: 'export', label: 'Export Excel', icon: 'file-spreadsheet', variant: 'primary',
29
+ * action: () => this.exportExcel() },
30
+ * { id: 'delete', label: 'Delete', icon: 'trash-2', variant: 'warn',
31
+ * action: () => this.deleteSelected(), hidden: !this.hasSelection },
32
+ * ];
33
+ *
34
+ * // Set loading state from outside:
35
+ * currentlyLoading: string | string[] | null = 'export';
36
+ * ```
37
+ */
38
+ export class UiButtonAreaComponent {
39
+ constructor() {
40
+ /**
41
+ * Array of button descriptors to render.
42
+ * Buttons with `hidden: true` are filtered out.
43
+ */
44
+ this.buttons = [];
45
+ /** Horizontal alignment of the button group. */
46
+ this.align = 'end';
47
+ /** Accessible group label for screen readers. */
48
+ this.ariaLabel = 'Actions';
49
+ /** Gap between buttons (maps to design token spacing). */
50
+ this.gap = 'sm';
51
+ /** Stack buttons vertically on mobile viewports (<600px). */
52
+ this.stackOnMobile = true;
53
+ /**
54
+ * When `true`, all buttons are disabled while any button is in a loading state.
55
+ * Useful to prevent double-actions during async operations.
56
+ */
57
+ this.disableWhileLoading = false;
58
+ /** @internal */
59
+ this._loadingIds = new Set();
60
+ /** @internal Optional router for href navigation. */
61
+ this.router = inject(Router, { optional: true });
62
+ }
63
+ /**
64
+ * Set one or more buttons to a loading state by their `id`.
65
+ * Accepts a single string, an array of strings, or `null` to clear.
66
+ *
67
+ * @example
68
+ * ```html
69
+ * <!-- Single -->
70
+ * <ui-button-area [loadingIds]="'save'" />
71
+ *
72
+ * <!-- Multiple -->
73
+ * <ui-button-area [loadingIds]="['save', 'export']" />
74
+ * ```
75
+ */
76
+ set loadingIds(value) {
77
+ if (value === null || value === undefined) {
78
+ this._loadingIds = new Set();
79
+ }
80
+ else if (Array.isArray(value)) {
81
+ this._loadingIds = new Set(value);
82
+ }
83
+ else {
84
+ this._loadingIds = new Set([value]);
85
+ }
86
+ }
87
+ /** Buttons filtered to visible (non-hidden) entries. */
88
+ get visibleButtons() {
89
+ return this.buttons.filter((b) => !b.hidden);
90
+ }
91
+ /** Assembled CSS class string for the button area container. */
92
+ get areaClasses() {
93
+ return [
94
+ 'ui-button-area',
95
+ `ui-button-area--align-${this.align}`,
96
+ `ui-button-area--gap-${this.gap}`,
97
+ this.stackOnMobile ? 'ui-button-area--stack-mobile' : '',
98
+ ]
99
+ .filter(Boolean)
100
+ .join(' ');
101
+ }
102
+ /** @internal Track function for @for loop. */
103
+ trackButton(index, button) {
104
+ return button.id ?? `idx-${index}`;
105
+ }
106
+ /** Whether a specific button is in a loading state. */
107
+ isButtonLoading(button) {
108
+ return !!button.loading || (!!button.id && this._loadingIds.has(button.id));
109
+ }
110
+ /** Whether a specific button is disabled (includes loading logic). */
111
+ isButtonDisabled(button) {
112
+ if (button.disabled)
113
+ return true;
114
+ if (this.isButtonLoading(button))
115
+ return true;
116
+ if (this.disableWhileLoading && this._loadingIds.size > 0)
117
+ return true;
118
+ return false;
119
+ }
120
+ /** @internal Handles button click: calls action callback and/or navigates. */
121
+ handleButtonClick(button, event) {
122
+ if (button.action) {
123
+ button.action(event);
124
+ }
125
+ if (button.href && this.router) {
126
+ this.router.navigateByUrl(button.href);
127
+ }
128
+ }
129
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiButtonAreaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
130
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: UiButtonAreaComponent, isStandalone: true, selector: "ui-button-area", inputs: { buttons: "buttons", align: "align", ariaLabel: "ariaLabel", gap: "gap", stackOnMobile: "stackOnMobile", disableWhileLoading: "disableWhileLoading", loadingIds: "loadingIds" }, host: { classAttribute: "ui-button-area-host" }, ngImport: i0, template: `
131
+ <div
132
+ [class]="areaClasses"
133
+ role="group"
134
+ [attr.aria-label]="ariaLabel"
135
+ >
136
+ @for (button of visibleButtons; track trackButton($index, button)) {
137
+ <ui-button
138
+ [attr.data-button-id]="button.id || null"
139
+ [label]="button.label"
140
+ [tooltip]="button.tooltip ?? ''"
141
+ [icon]="button.icon"
142
+ [iconPosition]="button.iconPosition ?? 'trailing'"
143
+ [variant]="button.variant ?? 'primary'"
144
+ [size]="button.size ?? 'md'"
145
+ [loading]="isButtonLoading(button)"
146
+ [disabled]="isButtonDisabled(button)"
147
+ [customClass]="button.customClass"
148
+ (click)="handleButtonClick(button, $event)"
149
+ />
150
+ }
151
+ </div>
152
+ `, isInline: true, styles: [".ui-button-area-host{display:block}@media (max-width: 767.98px){.ui-button-area-host{width:100%}}.ui-button-area{display:flex;flex-wrap:wrap;align-items:center}.ui-button-area--gap-xs{gap:var(--ui-spacing-1)}.ui-button-area--gap-sm{gap:var(--ui-spacing-2)}.ui-button-area--gap-md{gap:var(--ui-spacing-3)}.ui-button-area--gap-lg{gap:var(--ui-spacing-4)}.ui-button-area--gap-xl{gap:var(--ui-spacing-5)}.ui-button-area--align-start{justify-content:flex-start}.ui-button-area--align-center{justify-content:center}.ui-button-area--align-end{justify-content:flex-end}.ui-button-area--align-between{justify-content:space-between}@media (max-width: 767.98px){.ui-button-area--stack-mobile{flex-direction:column;width:100%}.ui-button-area--stack-mobile .ui-button-host{display:flex;width:100%}.ui-button-area--stack-mobile .ui-button{width:100%}}\n"], dependencies: [{ kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["label", "tooltip", "variant", "size", "icon", "iconPosition", "loading", "disabled", "fullWidth", "type", "ariaLabel", "customClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
153
+ }
154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiButtonAreaComponent, decorators: [{
155
+ type: Component,
156
+ args: [{ selector: 'ui-button-area', standalone: true, imports: [UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
157
+ class: 'ui-button-area-host',
158
+ }, template: `
159
+ <div
160
+ [class]="areaClasses"
161
+ role="group"
162
+ [attr.aria-label]="ariaLabel"
163
+ >
164
+ @for (button of visibleButtons; track trackButton($index, button)) {
165
+ <ui-button
166
+ [attr.data-button-id]="button.id || null"
167
+ [label]="button.label"
168
+ [tooltip]="button.tooltip ?? ''"
169
+ [icon]="button.icon"
170
+ [iconPosition]="button.iconPosition ?? 'trailing'"
171
+ [variant]="button.variant ?? 'primary'"
172
+ [size]="button.size ?? 'md'"
173
+ [loading]="isButtonLoading(button)"
174
+ [disabled]="isButtonDisabled(button)"
175
+ [customClass]="button.customClass"
176
+ (click)="handleButtonClick(button, $event)"
177
+ />
178
+ }
179
+ </div>
180
+ `, styles: [".ui-button-area-host{display:block}@media (max-width: 767.98px){.ui-button-area-host{width:100%}}.ui-button-area{display:flex;flex-wrap:wrap;align-items:center}.ui-button-area--gap-xs{gap:var(--ui-spacing-1)}.ui-button-area--gap-sm{gap:var(--ui-spacing-2)}.ui-button-area--gap-md{gap:var(--ui-spacing-3)}.ui-button-area--gap-lg{gap:var(--ui-spacing-4)}.ui-button-area--gap-xl{gap:var(--ui-spacing-5)}.ui-button-area--align-start{justify-content:flex-start}.ui-button-area--align-center{justify-content:center}.ui-button-area--align-end{justify-content:flex-end}.ui-button-area--align-between{justify-content:space-between}@media (max-width: 767.98px){.ui-button-area--stack-mobile{flex-direction:column;width:100%}.ui-button-area--stack-mobile .ui-button-host{display:flex;width:100%}.ui-button-area--stack-mobile .ui-button{width:100%}}\n"] }]
181
+ }], propDecorators: { buttons: [{
182
+ type: Input
183
+ }], align: [{
184
+ type: Input
185
+ }], ariaLabel: [{
186
+ type: Input
187
+ }], gap: [{
188
+ type: Input
189
+ }], stackOnMobile: [{
190
+ type: Input
191
+ }], disableWhileLoading: [{
192
+ type: Input
193
+ }], loadingIds: [{
194
+ type: Input
195
+ }] } });
196
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnV0dG9uLWFyZWEuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvbmctdWktc3lzdGVtL3NyYy9saWIvY29tcG9uZW50cy9idXR0b24vYnV0dG9uLWFyZWEuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLHVCQUF1QixFQUFFLGlCQUFpQixFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNyRyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFekMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7O0FBR3ZEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdDRztBQW1DSCxNQUFNLE9BQU8scUJBQXFCO0lBbENsQztRQW1DRTs7O1dBR0c7UUFDTSxZQUFPLEdBQXlCLEVBQUUsQ0FBQztRQUU1QyxnREFBZ0Q7UUFDdkMsVUFBSyxHQUFzQixLQUFLLENBQUM7UUFFMUMsaURBQWlEO1FBQ3hDLGNBQVMsR0FBRyxTQUFTLENBQUM7UUFFL0IsMERBQTBEO1FBQ2pELFFBQUcsR0FBVyxJQUFJLENBQUM7UUFFNUIsNkRBQTZEO1FBQ3BELGtCQUFhLEdBQUcsSUFBSSxDQUFDO1FBRTlCOzs7V0FHRztRQUNNLHdCQUFtQixHQUFHLEtBQUssQ0FBQztRQTBCckMsZ0JBQWdCO1FBQ1IsZ0JBQVcsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBRXhDLHFEQUFxRDtRQUM3QyxXQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0tBOENyRDtJQTFFQzs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxJQUNJLFVBQVUsQ0FBQyxLQUEyQztRQUN4RCxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxL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LEtBQUs7Z0JBR0csU0FBUztzQkFBakIsS0FBSztnQkFHRyxHQUFHO3NCQUFYLEtBQUs7Z0JBR0csYUFBYTtzQkFBckIsS0FBSztnQkFNRyxtQkFBbUI7c0JBQTNCLEtBQUs7Z0JBZ0JGLFVBQVU7c0JBRGIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBWaWV3RW5jYXBzdWxhdGlvbiwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XHJcbmltcG9ydCB7IFVpU2l6ZSB9IGZyb20gJy4uLy4uL2NvcmUvdHlwZXMnO1xyXG5pbXBvcnQgeyBVaUJ1dHRvbkNvbXBvbmVudCB9IGZyb20gJy4vYnV0dG9uLmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFVpQnV0dG9uRGVzY3JpcHRvciwgVWlCdXR0b25BcmVhQWxpZ24gfSBmcm9tICcuL2J1dHRvbi50eXBlcyc7XHJcblxyXG4vKipcclxuICogU3RhbmRhbG9uZSBidXR0b24tZ3JvdXAgY29tcG9uZW50IGRyaXZlbiBieSBhIGBVaUJ1dHRvbkRlc2NyaXB0b3JbXWAgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogUmVuZGVycyBhIGdyb3VwIG9mIGBVaUJ1dHRvbmAgaW5zdGFuY2VzIGZyb20gZGVjbGFyYXRpdmUgZGVzY3JpcHRvcnMuXHJcbiAqIFN1cHBvcnRzIHBlci1idXR0b24gbG9hZGluZy9kaXNhYmxlZCBzdGF0ZXMsIGR5bmFtaWMgdmlzaWJpbGl0eSxcclxuICogYWxpZ25tZW50IGNvbnRyb2wsIGFuZCBvcHRpb25hbCBuYXZpZ2F0aW9uIHZpYSBBbmd1bGFyIFJvdXRlci5cclxuICpcclxuICogQHNlbGVjdG9yIHVpLWJ1dHRvbi1hcmVhXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIGBgYGh0bWxcclxuICogPHVpLWJ1dHRvbi1hcmVhXHJcbiAqICAgW2J1dHRvbnNdPVwiYWN0aW9uc1wiXHJcbiAqICAgYWxpZ249XCJlbmRcIlxyXG4gKiAgIGdhcD1cInNtXCJcclxuICogICBbbG9hZGluZ0lkc109XCJjdXJyZW50bHlMb2FkaW5nXCJcclxuICogLz5cclxuICogYGBgXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIGBgYHR5cGVzY3JpcHRcclxuICogLy8gRHluYW1pYyBjb25maWd1cmF0aW9uXHJcbiAqIGFjdGlvbnM6IFVpQnV0dG9uRGVzY3JpcHRvcltdID0gW1xyXG4gKiAgIHsgaWQ6ICdleHBvcnQnLCBsYWJlbDogJ0V4cG9ydCBFeGNlbCcsIGljb246ICdmaWxlLXNwcmVhZHNoZWV0JywgdmFyaWFudDogJ3ByaW1hcnknLFxyXG4gKiAgICAgYWN0aW9uOiAoKSA9PiB0aGlzLmV4cG9ydEV4Y2VsKCkgfSxcclxuICogICB7IGlkOiAnZGVsZXRlJywgbGFiZWw6ICdEZWxldGUnLCBpY29uOiAndHJhc2gtMicsIHZhcmlhbnQ6ICd3YXJuJyxcclxuICogICAgIGFjdGlvbjogKCkgPT4gdGhpcy5kZWxldGVTZWxlY3RlZCgpLCBoaWRkZW46ICF0aGlzLmhhc1NlbGVjdGlvbiB9LFxyXG4gKiBdO1xyXG4gKlxyXG4gKiAvLyBTZXQgbG9hZGluZyBzdGF0ZSBmcm9tIG91dHNpZGU6XHJcbiAqIGN1cnJlbnRseUxvYWRpbmc6IHN0cmluZyB8IHN0cmluZ1tdIHwgbnVsbCA9ICdleHBvcnQnO1xyXG4gKiBgYGBcclxuICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAndWktYnV0dG9uLWFyZWEnLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW1VpQnV0dG9uQ29tcG9uZW50XSxcclxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcclxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxyXG4gIGhvc3Q6IHtcclxuICAgIGNsYXNzOiAndWktYnV0dG9uLWFyZWEtaG9zdCcsXHJcbiAgfSxcclxuICB0ZW1wbGF0ZTogYFxyXG4gICAgPGRpdlxyXG4gICAgICBbY2xhc3NdPVwiYXJlYUNsYXNzZXNcIlxyXG4gICAgICByb2xlPVwiZ3JvdXBcIlxyXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImFyaWFMYWJlbFwiXHJcbiAgICA+XHJcbiAgICAgIEBmb3IgKGJ1dHRvbiBvZiB2aXNpYmxlQnV0dG9uczsgdHJhY2sgdHJhY2tCdXR0b24oJGluZGV4LCBidXR0b24pKSB7XHJcbiAgICAgICAgPHVpLWJ1dHRvblxyXG4gICAgICAgICAgW2F0dHIuZGF0YS1idXR0b24taWRdPVwiYnV0dG9uLmlkIHx8IG51bGxcIlxyXG4gICAgICAgICAgW2xhYmVsXT1cImJ1dHRvbi5sYWJlbFwiXHJcbiAgICAgICAgICBbdG9vbHRpcF09XCJidXR0b24udG9vbHRpcCA/PyAnJ1wiXHJcbiAgICAgICAgICBbaWNvbl09XCJidXR0b24uaWNvblwiXHJcbiAgICAgICAgICBbaWNvblBvc2l0aW9uXT1cImJ1dHRvbi5pY29uUG9zaXRpb24gPz8gJ3RyYWlsaW5nJ1wiXHJcbiAgICAgICAgICBbdmFyaWFudF09XCJidXR0b24udmFyaWFudCA/PyAncHJpbWFyeSdcIlxyXG4gICAgICAgICAgW3NpemVdPVwiYnV0dG9uLnNpemUgPz8gJ21kJ1wiXHJcbiAgICAgICAgICBbbG9hZGluZ109XCJpc0J1dHRvbkxvYWRpbmcoYnV0dG9uKVwiXHJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwiaXNCdXR0b25EaXNhYmxlZChidXR0b24pXCJcclxuICAgICAgICAgIFtjdXN0b21DbGFzc109XCJidXR0b24uY3VzdG9tQ2xhc3NcIlxyXG4gICAgICAgICAgKGNsaWNrKT1cImhhbmRsZUJ1dHRvbkNsaWNrKGJ1dHRvbiwgJGV2ZW50KVwiXHJcbiAgICAgICAgLz5cclxuICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxuICBzdHlsZVVybDogJy4vYnV0dG9uLWFyZWEuY29tcG9uZW50LnNjc3MnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgVWlCdXR0b25BcmVhQ29tcG9uZW50IHtcclxuICAvKipcclxuICAgKiBBcnJheSBvZiBidXR0b24gZGVzY3JpcHRvcnMgdG8gcmVuZGVyLlxyXG4gICAqIEJ1dHRvbnMgd2l0aCBgaGlkZGVuOiB0cnVlYCBhcmUgZmlsdGVyZWQgb3V0LlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIGJ1dHRvbnM6IFVpQnV0dG9uRGVzY3JpcHRvcltdID0gW107XHJcblxyXG4gIC8qKiBIb3Jpem9udGFsIGFsaWdubWVudCBvZiB0aGUgYnV0dG9uIGdyb3VwLiAqL1xyXG4gIEBJbnB1dCgpIGFsaWduOiBVaUJ1dHRvbkFyZWFBbGlnbiA9ICdlbmQnO1xyXG5cclxuICAvKiogQWNjZXNzaWJsZSBncm91cCBsYWJlbCBmb3Igc2NyZWVuIHJlYWRlcnMuICovXHJcbiAgQElucHV0KCkgYXJpYUxhYmVsID0gJ0FjdGlvbnMnO1xyXG5cclxuICAvKiogR2FwIGJldHdlZW4gYnV0dG9ucyAobWFwcyB0byBkZXNpZ24gdG9rZW4gc3BhY2luZykuICovXHJcbiAgQElucHV0KCkgZ2FwOiBVaVNpemUgPSAnc20nO1xyXG5cclxuICAvKiogU3RhY2sgYnV0dG9ucyB2ZXJ0aWNhbGx5IG9uIG1vYmlsZSB2aWV3cG9ydHMgKDw2MDBweCkuICovXHJcbiAgQElucHV0KCkgc3RhY2tPbk1vYmlsZSA9IHRydWU7XHJcblxyXG4gIC8qKlxyXG4gICAqIFdoZW4gYHRydWVgLCBhbGwgYnV0dG9ucyBhcmUgZGlzYWJsZWQgd2hpbGUgYW55IGJ1dHRvbiBpcyBpbiBhIGxvYWRpbmcgc3RhdGUuXHJcbiAgICogVXNlZnVsIHRvIHByZXZlbnQgZG91YmxlLWFjdGlvbnMgZHVyaW5nIGFzeW5jIG9wZXJhdGlvbnMuXHJcbiAgICovXHJcbiAgQElucHV0KCkgZGlzYWJsZVdoaWxlTG9hZGluZyA9IGZhbHNlO1xyXG5cclxuICAvKipcclxuICAgKiBTZXQgb25lIG9yIG1vcmUgYnV0dG9ucyB0byBhIGxvYWRpbmcgc3RhdGUgYnkgdGhlaXIgYGlkYC5cclxuICAgKiBBY2NlcHRzIGEgc2luZ2xlIHN0cmluZywgYW4gYXJyYXkgb2Ygc3RyaW5ncywgb3IgYG51bGxgIHRvIGNsZWFyLlxyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBgYGBodG1sXHJcbiAgICogPCEtLSBTaW5nbGUgLS0+XHJcbiAgICogPHVpLWJ1dHRvbi1hcmVhIFtsb2FkaW5nSWRzXT1cIidzYXZlJ1wiIC8+XHJcbiAgICpcclxuICAgKiA8IS0tIE11bHRpcGxlIC0tPlxyXG4gICAqIDx1aS1idXR0b24tYXJlYSBbbG9hZGluZ0lkc109XCJbJ3NhdmUnLCAnZXhwb3J0J11cIiAvPlxyXG4gICAqIGBgYFxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgc2V0IGxvYWRpbmdJZHModmFsdWU6IHN0cmluZyB8IHN0cmluZ1tdIHwgbnVsbCB8IHVuZGVmaW5lZCkge1xyXG4gICAgaWYgKHZhbHVlID09PSBudWxsIHx8IHZhbHVlID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgdGhpcy5fbG9hZGluZ0lkcyA9IG5ldyBTZXQoKTtcclxuICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcclxuICAgICAgdGhpcy5fbG9hZGluZ0lkcyA9IG5ldyBTZXQodmFsdWUpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5fbG9hZGluZ0lkcyA9IG5ldyBTZXQoW3ZhbHVlXSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogQGludGVybmFsICovXHJcbiAgcHJpdmF0ZSBfbG9hZGluZ0lkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xyXG5cclxuICAvKiogQGludGVybmFsIE9wdGlvbmFsIHJvdXRlciBmb3IgaHJlZiBuYXZpZ2F0aW9uLiAqL1xyXG4gIHByaXZhdGUgcm91dGVyID0gaW5qZWN0KFJvdXRlciwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcclxuXHJcbiAgLyoqIEJ1dHRvbnMgZmlsdGVyZWQgdG8gdmlzaWJsZSAobm9uLWhpZGRlbikgZW50cmllcy4gKi9cclxuICBnZXQgdmlzaWJsZUJ1dHRvbnMoKTogVWlCdXR0b25EZXNjcmlwdG9yW10ge1xyXG4gICAgcmV0dXJuIHRoaXMuYnV0dG9ucy5maWx0ZXIoKGIpID0+ICFiLmhpZGRlbik7XHJcbiAgfVxyXG5cclxuICAvKiogQXNzZW1ibGVkIENTUyBjbGFzcyBzdHJpbmcgZm9yIHRoZSBidXR0b24gYXJlYSBjb250YWluZXIuICovXHJcbiAgZ2V0IGFyZWFDbGFzc2VzKCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gW1xyXG4gICAgICAndWktYnV0dG9uLWFyZWEnLFxyXG4gICAgICBgdWktYnV0dG9uLWFyZWEtLWFsaWduLSR7dGhpcy5hbGlnbn1gLFxyXG4gICAgICBgdWktYnV0dG9uLWFyZWEtLWdhcC0ke3RoaXMuZ2FwfWAsXHJcbiAgICAgIHRoaXMuc3RhY2tPbk1vYmlsZSA/ICd1aS1idXR0b24tYXJlYS0tc3RhY2stbW9iaWxlJyA6ICcnLFxyXG4gICAgXVxyXG4gICAgICAuZmlsdGVyKEJvb2xlYW4pXHJcbiAgICAgIC5qb2luKCcgJyk7XHJcbiAgfVxyXG5cclxuICAvKiogQGludGVybmFsIFRyYWNrIGZ1bmN0aW9uIGZvciBAZm9yIGxvb3AuICovXHJcbiAgdHJhY2tCdXR0b24oaW5kZXg6IG51bWJlciwgYnV0dG9uOiBVaUJ1dHRvbkRlc2NyaXB0b3IpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIGJ1dHRvbi5pZCA/PyBgaWR4LSR7aW5kZXh9YDtcclxuICB9XHJcblxyXG4gIC8qKiBXaGV0aGVyIGEgc3BlY2lmaWMgYnV0dG9uIGlzIGluIGEgbG9hZGluZyBzdGF0ZS4gKi9cclxuICBpc0J1dHRvbkxvYWRpbmcoYnV0dG9uOiBVaUJ1dHRvbkRlc2NyaXB0b3IpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAhIWJ1dHRvbi5sb2FkaW5nIHx8ICghIWJ1dHRvbi5pZCAmJiB0aGlzLl9sb2FkaW5nSWRzLmhhcyhidXR0b24uaWQpKTtcclxuICB9XHJcblxyXG4gIC8qKiBXaGV0aGVyIGEgc3BlY2lmaWMgYnV0dG9uIGlzIGRpc2FibGVkIChpbmNsdWRlcyBsb2FkaW5nIGxvZ2ljKS4gKi9cclxuICBpc0J1dHRvbkRpc2FibGVkKGJ1dHRvbjogVWlCdXR0b25EZXNjcmlwdG9yKTogYm9vbGVhbiB7XHJcbiAgICBpZiAoYnV0dG9uLmRpc2FibGVkKSByZXR1cm4gdHJ1ZTtcclxuICAgIGlmICh0aGlzLmlzQnV0dG9uTG9hZGluZyhidXR0b24pKSByZXR1cm4gdHJ1ZTtcclxuICAgIGlmICh0aGlzLmRpc2FibGVXaGlsZUxvYWRpbmcgJiYgdGhpcy5fbG9hZGluZ0lkcy5zaXplID4gMCkgcmV0dXJuIHRydWU7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvKiogQGludGVybmFsIEhhbmRsZXMgYnV0dG9uIGNsaWNrOiBjYWxscyBhY3Rpb24gY2FsbGJhY2sgYW5kL29yIG5hdmlnYXRlcy4gKi9cclxuICBoYW5kbGVCdXR0b25DbGljayhidXR0b246IFVpQnV0dG9uRGVzY3JpcHRvciwgZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcclxuICAgIGlmIChidXR0b24uYWN0aW9uKSB7XHJcbiAgICAgIGJ1dHRvbi5hY3Rpb24oZXZlbnQpO1xyXG4gICAgfVxyXG4gICAgaWYgKGJ1dHRvbi5ocmVmICYmIHRoaXMucm91dGVyKSB7XHJcbiAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlQnlVcmwoYnV0dG9uLmhyZWYpO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0=