@decaf-ts/for-angular 0.0.24 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decaf-ts/for-angular",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "author": "Tiago Venceslau",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "repository": {
@@ -1,291 +0,0 @@
1
- import { __decorate, __metadata } from "tslib";
2
- import { Component, Input, Output, EventEmitter } from '@angular/core';
3
- import { ReactiveFormsModule } from '@angular/forms';
4
- import { IonButton, IonIcon, IonSkeletonText, IonText } from '@ionic/angular/standalone';
5
- import { arrowForwardOutline, arrowBackOutline } from 'ionicons/icons';
6
- import { addIcons } from 'ionicons';
7
- import { OperationKeys } from '@decaf-ts/db-decorators';
8
- import { Dynamic, EventConstants, NgxFormService } from '../../engine';
9
- import { ComponentRendererComponent } from '../component-renderer/component-renderer.component';
10
- import { ModelRendererComponent } from '../model-renderer/model-renderer.component';
11
- import { timer } from 'rxjs';
12
- import * as i0 from "@angular/core";
13
- import * as i1 from "@angular/forms";
14
- let StepedFormComponent = class StepedFormComponent {
15
- /**
16
- * @description Creates an instance of StepedFormComponent.
17
- * @summary Initializes a new StepedFormComponent instance and registers the required
18
- * Ionic icons for navigation buttons (forward and back arrows).
19
- *
20
- * @memberOf StepedFormComponent
21
- */
22
- constructor() {
23
- /**
24
- * @description Number of pages in the stepped form.
25
- * @summary Represents the total number of steps/pages in the multi-step form.
26
- * This value is automatically calculated based on the page properties of the children
27
- * or can be explicitly set. Each page represents a logical group of form fields.
28
- *
29
- * @type {number}
30
- * @default 1
31
- * @memberOf StepedFormComponent
32
- */
33
- this.pages = 1;
34
- /**
35
- * @description The CRUD operation type for this form.
36
- * @summary Defines the type of operation being performed (CREATE, READ, UPDATE, DELETE).
37
- * This affects form behavior, validation rules, and field accessibility. For example,
38
- * READ operations might disable form fields, while CREATE operations enable all fields.
39
- *
40
- * @type {CrudOperations}
41
- * @default OperationKeys.CREATE
42
- * @memberOf StepedFormComponent
43
- */
44
- this.operation = OperationKeys.CREATE;
45
- /**
46
- * @description The initial page to display when the form loads.
47
- * @summary Specifies which page of the multi-step form should be shown first.
48
- * This allows starting the form at any step, useful for scenarios like editing
49
- * existing data where you might want to jump to a specific section.
50
- *
51
- * @type {number}
52
- * @default 1
53
- * @memberOf StepedFormComponent
54
- */
55
- this.startPage = 1;
56
- /**
57
- * @description Array of UI model metadata for the currently active page.
58
- * @summary Contains only the UI model metadata for fields that should be displayed
59
- * on the currently active page. This is a filtered subset of the children array,
60
- * updated whenever the user navigates between pages.
61
- *
62
- * @type {UIModelMetadata[] | undefined}
63
- * @memberOf StepedFormComponent
64
- */
65
- this.activeChildren = undefined;
66
- /**
67
- * @description FormGroup for the currently active page.
68
- * @summary The FormGroup instance that manages form controls and validation
69
- * for the current page only. This is extracted from the main formGroup
70
- * when using FormArray structure.
71
- *
72
- * @type {FormGroup | undefined}
73
- * @memberOf StepedFormComponent
74
- */
75
- this.activeFormGroup = undefined;
76
- /**
77
- * @description The currently active page number.
78
- * @summary Tracks which page of the multi-step form is currently being displayed.
79
- * This property is updated as users navigate through the form steps using
80
- * the next/back buttons or programmatic navigation.
81
- *
82
- * @type {number}
83
- * @memberOf StepedFormComponent
84
- */
85
- this.activePage = 1;
86
- /**
87
- * @description Array representing the structure of pages.
88
- * @summary Contains metadata about each page, including page numbers and indices.
89
- * This array is built during initialization to organize the form fields into
90
- * logical pages and provide navigation structure.
91
- *
92
- * @type {UIModelMetadata[]}
93
- * @memberOf StepedFormComponent
94
- */
95
- this.pagesArray = [];
96
- /**
97
- * @description Event emitter for form submission.
98
- * @summary Emits events when the form is submitted, typically on the last page
99
- * when all validation passes. The emitted event contains the form data and
100
- * event type information for parent components to handle.
101
- *
102
- * @type {EventEmitter<BaseCustomEvent>}
103
- * @memberOf StepedFormComponent
104
- */
105
- this.submitEvent = new EventEmitter();
106
- addIcons({ arrowForwardOutline, arrowBackOutline });
107
- }
108
- /**
109
- * @description Initializes the component after Angular first displays the data-bound properties.
110
- * @summary Sets up the stepped form by organizing children into pages, calculating the total
111
- * number of pages, and initializing the active page. This method processes the UI model metadata
112
- * to create a logical page structure and ensures proper page assignments for all form fields.
113
- *
114
- * @mermaid
115
- * sequenceDiagram
116
- * participant A as Angular Lifecycle
117
- * participant S as StepedFormComponent
118
- * participant F as Form Service
119
- *
120
- * A->>S: ngOnInit()
121
- * S->>S: Set activePage = startPage
122
- * S->>S: Process children into pagesArray
123
- * S->>S: Calculate total pages
124
- * S->>S: Assign page props to children
125
- * S->>S: getCurrentFormGroup(activePage)
126
- * S->>F: Extract FormGroup for active page
127
- * F-->>S: Return activeFormGroup
128
- *
129
- * @memberOf StepedFormComponent
130
- */
131
- ngOnInit() {
132
- this.activePage = this.startPage;
133
- this.pagesArray = this.children.reduce((acc, curr, index) => {
134
- const page = curr.props?.['page'] || index + 1;
135
- if (!acc[page])
136
- acc[page] = [];
137
- acc[page].push({ index: page });
138
- return acc;
139
- }, []).filter(Boolean);
140
- this.pages = this.pagesArray.length;
141
- this.children = [...this.children.map((c) => {
142
- if (!c.props)
143
- c.props = {};
144
- const page = c.props['page'] || 1;
145
- // prevent page overflow
146
- c.props['page'] = page > this.pages ? this.pages : page;
147
- return c;
148
- })];
149
- this.getCurrentFormGroup(this.activePage);
150
- }
151
- /**
152
- * @description Cleanup method called when the component is destroyed.
153
- * @summary Unsubscribes from any active timer subscriptions to prevent memory leaks.
154
- * This is part of Angular's component lifecycle and ensures proper resource cleanup.
155
- *
156
- * @memberOf StepedFormComponent
157
- */
158
- ngOnDestroy() {
159
- if (this.timerSubscription)
160
- this.timerSubscription.unsubscribe();
161
- }
162
- /**
163
- * @description Handles navigation to the next page or form submission.
164
- * @summary Validates the current page's form fields and either navigates to the next page
165
- * or submits the entire form if on the last page. Form validation must pass before
166
- * proceeding. On successful submission, emits a submit event with form data.
167
- *
168
- * @param {boolean} lastPage - Whether this is the last page of the form
169
- * @return {void}
170
- *
171
- * @mermaid
172
- * sequenceDiagram
173
- * participant U as User
174
- * participant S as StepedFormComponent
175
- * participant F as Form Service
176
- * participant P as Parent Component
177
- *
178
- * U->>S: Click Next/Submit
179
- * S->>F: validateFields(activeFormGroup)
180
- * F-->>S: Return validation result
181
- * alt Not last page and valid
182
- * S->>S: activePage++
183
- * S->>S: getCurrentFormGroup(activePage)
184
- * else Last page and valid
185
- * S->>F: getFormData(formGroup)
186
- * F-->>S: Return form data
187
- * S->>P: submitEvent.emit({data, name: SUBMIT})
188
- * end
189
- *
190
- * @memberOf StepedFormComponent
191
- */
192
- handleNext(lastPage = false) {
193
- const isValid = NgxFormService.validateFields(this.activeFormGroup);
194
- if (!lastPage) {
195
- if (isValid) {
196
- this.activePage = this.activePage + 1;
197
- this.getCurrentFormGroup(this.activePage);
198
- }
199
- }
200
- else {
201
- if (isValid) {
202
- const data = Object.assign({}, ...Object.values(NgxFormService.getFormData(this.formGroup)));
203
- this.submitEvent.emit({
204
- data,
205
- name: EventConstants.SUBMIT,
206
- });
207
- }
208
- }
209
- }
210
- /**
211
- * @description Handles navigation to the previous page.
212
- * @summary Moves the user back to the previous page in the stepped form.
213
- * This method decrements the active page number and updates the form
214
- * group and children to display the previous page's content.
215
- *
216
- * @return {void}
217
- *
218
- * @mermaid
219
- * sequenceDiagram
220
- * participant U as User
221
- * participant S as StepedFormComponent
222
- *
223
- * U->>S: Click Back
224
- * S->>S: activePage--
225
- * S->>S: getCurrentFormGroup(activePage)
226
- * Note over S: Update active form and children
227
- *
228
- * @memberOf StepedFormComponent
229
- */
230
- handleBack() {
231
- this.activePage = this.activePage - 1;
232
- this.getCurrentFormGroup(this.activePage);
233
- }
234
- /**
235
- * @description Updates the active form group and children for the specified page.
236
- * @summary Extracts the FormGroup for the given page from the FormArray and filters
237
- * the children to show only fields belonging to that page. Uses a timer to ensure
238
- * proper Angular change detection when updating the activeChildren.
239
- *
240
- * @param {number} page - The page number to activate
241
- * @return {void}
242
- *
243
- * @private
244
- * @mermaid
245
- * sequenceDiagram
246
- * participant S as StepedFormComponent
247
- * participant F as FormArray
248
- * participant T as Timer
249
- *
250
- * S->>F: Extract FormGroup at index (page - 1)
251
- * F-->>S: Return page FormGroup
252
- * S->>S: Set activeChildren = undefined
253
- * S->>T: timer(10).subscribe()
254
- * T-->>S: Filter children for active page
255
- * S->>S: Set activeChildren
256
- *
257
- * @memberOf StepedFormComponent
258
- */
259
- getCurrentFormGroup(page) {
260
- this.activeFormGroup = this.formGroup.at(page - 1);
261
- this.activeChildren = undefined;
262
- this.timerSubscription = timer(10).subscribe(() => {
263
- this.activeChildren = this.children.filter(c => c.props?.['page'] === page);
264
- console.log(this.activeChildren);
265
- });
266
- }
267
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StepedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
268
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: StepedFormComponent, isStandalone: true, selector: "ngx-decaf-steped-form", inputs: { pages: "pages", operation: "operation", startPage: "startPage", children: "children", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, ngImport: i0, template: " <!-- @for(child of children; track trackItemFn($index, child)) {\n {{child.tag }}\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{props: child.props}'>\n </ngx-decaf-component-renderer>\n } -->\n <form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div>\n @for(page of pagesArray; track $index;) {\n <div [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n }\n </div>\n </div>\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"clear\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon>\n Previous\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button [fill]=\"activePage === pages ? 'solid' : 'outline'\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n Submit\n } @else {\n Next\n <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon>\n }\n </ion-button>\n </div>\n </div>\n </form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;margin-bottom:2rem}.dcf-page-steps>div{justify-content:center;min-width:200px;max-width:200px;column-gap:.25em;display:flex}.dcf-page-steps>div>div{width:30px;text-align:center;border-bottom:solid var(--dcf-color-gray-3);box-sizing:border-box;border-width:3px;font-size:0px;font-weight:600}.dcf-page-steps>div>div.dcf-active{border-width:5px;font-size:1rem;color:var(--ion-color-gray-7);border-color:var(--ion-color-primary);line-height:1rem}.dcf-page-steps>div>div.dcf-passed{border-width:4px;font-size:.5rem;line-height:1.2rem;border-color:var(--dcf-color-gray-5);color:var(--ion-color-primary)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: 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: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
269
- };
270
- StepedFormComponent = __decorate([
271
- Dynamic(),
272
- __metadata("design:paramtypes", [])
273
- ], StepedFormComponent);
274
- export { StepedFormComponent };
275
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StepedFormComponent, decorators: [{
276
- type: Component,
277
- args: [{ selector: 'ngx-decaf-steped-form', imports: [ReactiveFormsModule, IonSkeletonText, IonText, IonButton, IonIcon, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: " <!-- @for(child of children; track trackItemFn($index, child)) {\n {{child.tag }}\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{props: child.props}'>\n </ngx-decaf-component-renderer>\n } -->\n <form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div>\n @for(page of pagesArray; track $index;) {\n <div [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n }\n </div>\n </div>\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"clear\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon>\n Previous\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button [fill]=\"activePage === pages ? 'solid' : 'outline'\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n Submit\n } @else {\n Next\n <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon>\n }\n </ion-button>\n </div>\n </div>\n </form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;margin-bottom:2rem}.dcf-page-steps>div{justify-content:center;min-width:200px;max-width:200px;column-gap:.25em;display:flex}.dcf-page-steps>div>div{width:30px;text-align:center;border-bottom:solid var(--dcf-color-gray-3);box-sizing:border-box;border-width:3px;font-size:0px;font-weight:600}.dcf-page-steps>div>div.dcf-active{border-width:5px;font-size:1rem;color:var(--ion-color-gray-7);border-color:var(--ion-color-primary);line-height:1rem}.dcf-page-steps>div>div.dcf-passed{border-width:4px;font-size:.5rem;line-height:1.2rem;border-color:var(--dcf-color-gray-5);color:var(--ion-color-primary)}\n"] }]
278
- }], ctorParameters: () => [], propDecorators: { pages: [{
279
- type: Input
280
- }], operation: [{
281
- type: Input
282
- }], startPage: [{
283
- type: Input
284
- }], children: [{
285
- type: Input
286
- }], formGroup: [{
287
- type: Input
288
- }], submitEvent: [{
289
- type: Output
290
- }] } });
291
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcGVkLWZvcm0uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL3N0ZXBlZC1mb3JtL3N0ZXBlZC1mb3JtLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9zdGVwZWQtZm9ybS9zdGVwZWQtZm9ybS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQXFCLE1BQU0sRUFBRSxZQUFZLEVBQUcsTUFBTSxlQUFlLENBQUM7QUFDM0YsT0FBTyxFQUF3QixtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNFLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN6RixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2RSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRXBDLE9BQU8sRUFBa0IsYUFBYSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDeEUsT0FBTyxFQUFtQixPQUFPLEVBQUUsY0FBYyxFQUFZLGNBQWMsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNsRyxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxvREFBb0QsQ0FBQztBQUNoRyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUNwRixPQUFPLEVBQWdCLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQzs7O0FBV3BDLElBQU0sbUJBQW1CLEdBQXpCLE1BQU0sbUJBQW1CO0lBc0k5Qjs7Ozs7O09BTUc7SUFDSDtRQTNJQTs7Ozs7Ozs7O1dBU0c7UUFFSCxVQUFLLEdBQVcsQ0FBQyxDQUFDO1FBRWxCOzs7Ozs7Ozs7V0FTRztRQUVI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bkMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDOytHQXBUVSxtQkFBbUI7bUdBQW5CLG1CQUFtQixvUENyQmhDLG9yRUFxREEscWlDRG5DWSxtQkFBbUIsb1NBQUUsZUFBZSxvRkFBRSxPQUFPLGdGQUFFLFNBQVMsb1BBQUUsT0FBTywySkFBMEIsMEJBQTBCOztBQUdwSCxtQkFBbUI7SUFSL0IsT0FBTyxFQUFFOztHQVFHLG1CQUFtQixDQXNUL0I7OzRGQXRUWSxtQkFBbUI7a0JBUC9CLFNBQVM7K0JBQ0UsdUJBQXVCLFdBR3hCLENBQUMsbUJBQW1CLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLDBCQUEwQixDQUFDLGNBQ3BILElBQUk7d0RBZWhCLEtBQUs7c0JBREosS0FBSztnQkFjTixTQUFTO3NCQURSLEtBQUs7Z0JBY04sU0FBUztzQkFEUixLQUFLO2dCQWNOLFFBQVE7c0JBRFAsS0FBSztnQkFhTixTQUFTO3NCQURSLEtBQUs7Z0JBcUVOLFdBQVc7c0JBRFYsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE9uSW5pdCwgT25EZXN0cm95LCBPdXRwdXQsIEV2ZW50RW1pdHRlciAgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1BcnJheSwgRm9ybUdyb3VwLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgSW9uQnV0dG9uLCBJb25JY29uLCBJb25Ta2VsZXRvblRleHQsIElvblRleHQgfSBmcm9tICdAaW9uaWMvYW5ndWxhci9zdGFuZGFsb25lJztcbmltcG9ydCB7IGFycm93Rm9yd2FyZE91dGxpbmUsIGFycm93QmFja091dGxpbmUgfSBmcm9tICdpb25pY29ucy9pY29ucyc7XG5pbXBvcnQgeyBhZGRJY29ucyB9IGZyb20gJ2lvbmljb25zJztcbmltcG9ydCB7IFVJTW9kZWxNZXRhZGF0YX0gZnJvbSAnQGRlY2FmLXRzL3VpLWRlY29yYXRvcnMnO1xuaW1wb3J0IHsgQ3J1ZE9wZXJhdGlvbnMsIE9wZXJhdGlvbktleXMgfSBmcm9tICdAZGVjYWYtdHMvZGItZGVjb3JhdG9ycyc7XG5pbXBvcnQgeyBCYXNlQ3VzdG9tRXZlbnQsIER5bmFtaWMsIEV2ZW50Q29uc3RhbnRzLCBLZXlWYWx1ZSwgTmd4Rm9ybVNlcnZpY2UgfSBmcm9tICcuLi8uLi9lbmdpbmUnO1xuaW1wb3J0IHsgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnQgfSBmcm9tICcuLi9jb21wb25lbnQtcmVuZGVyZXIvY29tcG9uZW50LXJlbmRlcmVyLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBNb2RlbFJlbmRlcmVyQ29tcG9uZW50IH0gZnJvbSAnLi4vbW9kZWwtcmVuZGVyZXIvbW9kZWwtcmVuZGVyZXIuY29tcG9uZW50JztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiwgdGltZXIgfSBmcm9tICdyeGpzJztcblxuXG5ARHluYW1pYygpXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtZGVjYWYtc3RlcGVkLWZvcm0nLFxuICB0ZW1wbGF0ZVVybDogJy4vc3RlcGVkLWZvcm0uY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9zdGVwZWQtZm9ybS5jb21wb25lbnQuc2NzcyddLFxuICBpbXBvcnRzOiBbUmVhY3RpdmVGb3Jtc01vZHVsZSwgSW9uU2tlbGV0b25UZXh0LCBJb25UZXh0LCBJb25CdXR0b24sIElvbkljb24sIE1vZGVsUmVuZGVyZXJDb21wb25lbnQsIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XSxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbn0pXG5leHBvcnQgY2xhc3MgU3RlcGVkRm9ybUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIE51bWJlciBvZiBwYWdlcyBpbiB0aGUgc3RlcHBlZCBmb3JtLlxuICAgKiBAc3VtbWFyeSBSZXByZXNlbnRzIHRoZSB0b3RhbCBudW1iZXIgb2Ygc3RlcHMvcGFnZXMgaW4gdGhlIG11bHRpLXN0ZXAgZm9ybS5cbiAgICogVGhpcyB2YWx1ZSBpcyBhdXRvbWF0aWNhbGx5IGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlIHBhZ2UgcHJvcGVydGllcyBvZiB0aGUgY2hpbGRyZW5cbiAgICogb3IgY2FuIGJlIGV4cGxpY2l0bHkgc2V0LiBFYWNoIHBhZ2UgcmVwcmVzZW50cyBhIGxvZ2ljYWwgZ3JvdXAgb2YgZm9ybSBmaWVsZHMuXG4gICAqXG4gICAqIEB0eXBlIHtudW1iZXJ9XG4gICAqIEBkZWZhdWx0IDFcbiAgICogQG1lbWJlck9mIFN0ZXBlZEZvcm1Db21wb25lbnRcbiAgICovXG4gIEBJbnB1dCgpXG4gIHBhZ2VzOiBudW1iZXIgPSAxO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGhlIENSVUQgb3BlcmF0aW9uIHR5cGUgZm9yIHRoaXMgZm9ybS5cbiAgICogQHN1bW1hcnkgRGVmaW5lcyB0aGUgdHlwZSBvZiBvcGVyYXRpb24gYmVpbmcgcGVyZm9ybWVkIChDUkVBVEUsIFJFQUQsIFVQREFURSwgREVMRVRFKS5cbiAgICogVGhpcyBhZmZlY3RzIGZvcm0gYmVoYXZpb3IsIHZhbGlkYXRpb24gcnVsZXMsIGFuZCBmaWVsZCBhY2Nlc3NpYmlsaXR5LiBGb3IgZXhhbXBsZSxcbiAgICogUkVBRCBvcGVyYXRpb25zIG1pZ2h0IGRpc2FibGUgZm9ybSBmaWVsZHMsIHdoaWxlIENSRUFURSBvcGVyYXRpb25zIGVuYWJsZSBhbGwgZmllbGRzLlxuICAgKlxuICAgKiBAdHlwZSB7Q3J1ZE9wZXJhdGlvbnN9XG4gICAqIEBkZWZhdWx0IE9wZXJhdGlvbktleXMuQ1JFQVRFXG4gICAqIEBtZW1iZXJPZiBTdGVwZWRGb3JtQ29tcG9uZW50XG4gICAqL1xuICBASW5wdXQoKVxuICBvcGVyYXRpb246IENydWRPcGVyYXRpb25zID0gT3BlcmF0aW9uS2V5cy5DUkVBVEU7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgaW5pdGlhbCBwYWdlIHRvIGRpc3BsYXkgd2hlbiB0aGUgZm9ybSBsb2Fkcy5cbiAgICogQHN1bW1hcnkgU3BlY2lmaWVzIHdoaWNoIHBhZ2Ugb2YgdGhlIG11bHRpLXN0ZXAgZm9ybSBzaG91bGQgYmUgc2hvd24gZmlyc3QuXG4gICAqIFRoaXMgYWxsb3dzIHN0YXJ0aW5nIHRoZSBmb3JtIGF0IGFueSBzdGVwLCB1c2VmdWwgZm9yIHNjZW5hcmlvcyBsaWtlIGVkaXRpbmdcbiAgICogZXhpc3RpbmcgZGF0YSB3aGVyZSB5b3UgbWlnaHQgd2FudCB0byBqdW1wIHRvIGEgc3BlY2lmaWMgc2VjdGlvbi5cbiAgICpcbiAgICogQHR5cGUge251bWJlcn1cbiAgICogQGRlZmF1bHQgMVxuICAgKiBAbWVtYmVyT2YgU3RlcGVkRm9ybUNvbXBvbmVudFxuICAgKi9cbiAgQElucHV0KClcbiAgc3RhcnRQYWdlOiBudW1iZXIgPSAxO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQXJyYXkgb2YgVUkgbW9kZWwgbWV0YWRhdGEgZm9yIGFsbCBmb3JtIGZpZWxkcy5cbiAgICogQHN1bW1hcnkgQ29udGFpbnMgdGhlIGNvbXBsZXRlIGNvbGxlY3Rpb24gb2YgVUkgbW9kZWwgbWV0YWRhdGEgdGhhdCBkZWZpbmVzXG4gICAqIHRoZSBzdHJ1Y3R1cmUsIHZhbGlkYXRpb24sIGFuZCBwcmVzZW50YXRpb24gb2YgZm9ybSBmaWVsZHMgYWNyb3NzIGFsbCBwYWdlcy5cbiAgICogRWFjaCBtZXRhZGF0YSBvYmplY3QgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgZmllbGQgdHlwZSwgdmFsaWRhdGlvbiBydWxlcyxcbiAgICogcGFnZSBhc3NpZ25tZW50LCBhbmQgZGlzcGxheSBwcm9wZXJ0aWVzLlxuICAgKlxuICAgKiBAdHlwZSB7VUlNb2RlbE1ldGFkYXRhW119XG4gICAqIEBtZW1iZXJPZiBTdGVwZWRGb3JtQ29tcG9uZW50XG4gICAqL1xuICBASW5wdXQoKVxuICBjaGlsZHJlbiE6IFVJTW9kZWxNZXRhZGF0YVtdO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQW5ndWxhciByZWFjdGl2ZSBGb3JtR3JvdXAgb3IgRm9ybUFycmF5IGZvciBmb3JtIHN0YXRlIG1hbmFnZW1lbnQuXG4gICAqIEBzdW1tYXJ5IFRoZSBmb3JtIGluc3RhbmNlIHRoYXQgbWFuYWdlcyBhbGwgZm9ybSBjb250cm9scywgdmFsaWRhdGlvbiwgYW5kIGZvcm0gc3RhdGUuXG4gICAqIFdoZW4gdXNpbmcgRm9ybUFycmF5LCBlYWNoIGFycmF5IGVsZW1lbnQgcmVwcmVzZW50cyBhIHBhZ2UncyBGb3JtR3JvdXAuIFdoZW4gdXNpbmdcbiAgICogRm9ybUdyb3VwLCBpdCBjb250YWlucyBhbGwgZm9ybSBjb250cm9scyBmb3IgdGhlIGVudGlyZSBzdGVwcGVkIGZvcm0uXG4gICAqXG4gICAqIEB0eXBlIHtGb3JtR3JvdXAgfCBGb3JtQXJyYXkgfCB1bmRlZmluZWR9XG4gICAqIEBtZW1iZXJPZiBTdGVwZWRGb3JtQ29tcG9uZW50XG4gICAqL1xuICBASW5wdXQoKVxuICBmb3JtR3JvdXAhOiBGb3JtR3JvdXAgfCBGb3JtQXJyYXkgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBcnJheSBvZiBVSSBtb2RlbCBtZXRhZGF0YSBmb3IgdGhlIGN1cnJlbnRseSBhY3RpdmUgcGFnZS5cbiAgICogQHN1bW1hcnkgQ29udGFpbnMgb25seSB0aGUgVUkgbW9kZWwgbWV0YWRhdGEgZm9yIGZpZWxkcyB0aGF0IHNob3VsZCBiZSBkaXNwbGF5ZWRcbiAgICogb24gdGhlIGN1cnJlbnRseSBhY3RpdmUgcGFnZS4gVGhpcyBpcyBhIGZpbHRlcmVkIHN1YnNldCBvZiB0aGUgY2hpbGRyZW4gYXJyYXksXG4gICAqIHVwZGF0ZWQgd2hlbmV2ZXIgdGhlIHVzZXIgbmF2aWdhdGVzIGJldHdlZW4gcGFnZXMuXG4gICAqXG4gICAqIEB0eXBlIHtVSU1vZGVsTWV0YWRhdGFbXSB8IHVuZGVmaW5lZH1cbiAgICogQG1lbWJlck9mIFN0ZXBlZEZvcm1Db21wb25lbnRcbiAgICovXG4gIGFjdGl2ZUNoaWxkcmVuOiBVSU1vZGVsTWV0YWRhdGFbXSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEZvcm1Hcm91cCBmb3IgdGhlIGN1cnJlbnRseSBhY3RpdmUgcGFnZS5cbiAgICogQHN1bW1hcnkgVGhlIEZvcm1Hcm91cCBpbnN0YW5jZSB0aGF0IG1hbmFnZXMgZm9ybSBjb250cm9scyBhbmQgdmFsaWRhdGlvblxuICAgKiBmb3IgdGhlIGN1cnJlbnQgcGFnZSBvbmx5LiBUaGlzIGlzIGV4dHJhY3RlZCBmcm9tIHRoZSBtYWluIGZvcm1Hcm91cFxuICAgKiB3aGVuIHVzaW5nIEZvcm1BcnJheSBzdHJ1Y3R1cmUuXG4gICAqXG4gICAqIEB0eXBlIHtGb3JtR3JvdXAgfCB1bmRlZmluZWR9XG4gICAqIEBtZW1iZXJPZiBTdGVwZWRGb3JtQ29tcG9uZW50XG4gICAqL1xuICBhY3RpdmVGb3JtR3JvdXA6IEZvcm1Hcm91cCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBjdXJyZW50bHkgYWN0aXZlIHBhZ2UgbnVtYmVyLlxuICAgKiBAc3VtbWFyeSBUcmFja3Mgd2hpY2ggcGFnZSBvZiB0aGUgbXVsdGktc3RlcCBmb3JtIGlzIGN1cnJlbnRseSBiZWluZyBkaXNwbGF5ZWQuXG4gICAqIFRoaXMgcHJvcGVydHkgaXMgdXBkYXRlZCBhcyB1c2VycyBuYXZpZ2F0ZSB0aHJvdWdoIHRoZSBmb3JtIHN0ZXBzIHVzaW5nXG4gICAqIHRoZSBuZXh0L2JhY2sgYnV0dG9ucyBvciBwcm9ncmFtbWF0aWMgbmF2aWdhdGlvbi5cbiAgICpcbiAgICogQHR5cGUge251bWJlcn1cbiAgICogQG1lbWJlck9mIFN0ZXBlZEZvcm1Db21wb25lbnRcbiAgICovXG4gIGFjdGl2ZVBhZ2U6IG51bWJlciA9IDE7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBcnJheSByZXByZXNlbnRpbmcgdGhlIHN0cnVjdHVyZSBvZiBwYWdlcy5cbiAgICogQHN1bW1hcnkgQ29udGFpbnMgbWV0YWRhdGEgYWJvdXQgZWFjaCBwYWdlLCBpbmNsdWRpbmcgcGFnZSBudW1iZXJzIGFuZCBpbmRpY2VzLlxuICAgKiBUaGlzIGFycmF5IGlzIGJ1aWx0IGR1cmluZyBpbml0aWFsaXphdGlvbiB0byBvcmdhbml6ZSB0aGUgZm9ybSBmaWVsZHMgaW50b1xuICAgKiBsb2dpY2FsIHBhZ2VzIGFuZCBwcm92aWRlIG5hdmlnYXRpb24gc3RydWN0dXJlLlxuICAgKlxuICAgKiBAdHlwZSB7VUlNb2RlbE1ldGFkYXRhW119XG4gICAqIEBtZW1iZXJPZiBTdGVwZWRGb3JtQ29tcG9uZW50XG4gICAqL1xuICBwYWdlc0FycmF5OiBVSU1vZGVsTWV0YWRhdGFbXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU3Vic2NyaXB0aW9uIGZvciB0aW1lci1iYXNlZCBvcGVyYXRpb25zLlxuICAgKiBAc3VtbWFyeSBNYW5hZ2VzIHRoZSB0aW1lciBzdWJzY3JpcHRpb24gdXNlZCBmb3IgYXN5bmNocm9ub3VzIG9wZXJhdGlvbnNcbiAgICogbGlrZSB1cGRhdGluZyBhY3RpdmUgY2hpbGRyZW4gYWZ0ZXIgcGFnZSB0cmFuc2l0aW9ucy4gVGhpcyBzdWJzY3JpcHRpb25cbiAgICogaXMgY2xlYW5lZCB1cCBpbiBuZ09uRGVzdHJveSB0byBwcmV2ZW50IG1lbW9yeSBsZWFrcy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHR5cGUge1N1YnNjcmlwdGlvbn1cbiAgICogQG1lbWJlck9mIFN0ZXBlZEZvcm1Db21wb25lbnRcbiAgICovXG4gIHByaXZhdGUgdGltZXJTdWJzY3JpcHRpb24hOiBTdWJzY3JpcHRpb247XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFdmVudCBlbWl0dGVyIGZvciBmb3JtIHN1Ym1pc3Npb24uXG4gICAqIEBzdW1tYXJ5IEVtaXRzIGV2ZW50cyB3aGVuIHRoZSBmb3JtIGlzIHN1Ym1pdHRlZCwgdHlwaWNhbGx5IG9uIHRoZSBsYXN0IHBhZ2VcbiAgICogd2hlbiBhbGwgdmFsaWRhdGlvbiBwYXNzZXMuIFRoZSBlbWl0dGVkIGV2ZW50IGNvbnRhaW5zIHRoZSBmb3JtIGRhdGEgYW5kXG4gICAqIGV2ZW50IHR5cGUgaW5mb3JtYXRpb24gZm9yIHBhcmVudCBjb21wb25lbnRzIHRvIGhhbmRsZS5cbiAgICpcbiAgICogQHR5cGUge0V2ZW50RW1pdHRlcjxCYXNlQ3VzdG9tRXZlbnQ+fVxuICAgKiBAbWVtYmVyT2YgU3RlcGVkRm9ybUNvbXBvbmVudFxuICAgKi9cbiAgQE91dHB1dCgpXG4gIHN1Ym1pdEV2ZW50OiBFdmVudEVtaXR0ZXI8QmFzZUN1c3RvbUV2ZW50PiA9IG5ldyBFdmVudEVtaXR0ZXI8QmFzZUN1c3RvbUV2ZW50PigpO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBTdGVwZWRGb3JtQ29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBJbml0aWFsaXplcyBhIG5ldyBTdGVwZWRGb3JtQ29tcG9uZW50IGluc3RhbmNlIGFuZCByZWdpc3RlcnMgdGhlIHJlcXVpcmVkXG4gICAqIElvbmljIGljb25zIGZvciBuYXZpZ2F0aW9uIGJ1dHRvbnMgKGZvcndhcmQgYW5kIGJhY2sgYXJyb3dzKS5cbiAgICpcbiAgICogQG1lbWJlck9mIFN0ZXBlZEZvcm1Db21wb25lbnRcbiAgICovXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIGFkZEljb25zKHthcnJvd0ZvcndhcmRPdXRsaW5lLCBhcnJvd0JhY2tPdXRsaW5lfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEluaXRpYWxpemVzIHRoZSBjb21wb25lbnQgYWZ0ZXIgQW5ndWxhciBmaXJzdCBkaXNwbGF5cyB0aGUgZGF0YS1ib3VuZCBwcm9wZXJ0aWVzLlxuICAgKiBAc3VtbWFyeSBTZXRzIHVwIHRoZSBzdGVwcGVkIGZvcm0gYnkgb3JnYW5pemluZyBjaGlsZHJlbiBpbnRvIHBhZ2VzLCBjYWxjdWxhdGluZyB0aGUgdG90YWxcbiAgICogbnVtYmVyIG9mIHBhZ2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSBhY3RpdmUgcGFnZS4gVGhpcyBtZXRob2QgcHJvY2Vzc2VzIHRoZSBVSSBtb2RlbCBtZXRhZGF0YVxuICAgKiB0byBjcmVhdGUgYSBsb2dpY2FsIHBhZ2Ugc3RydWN0dXJlIGFuZCBlbnN1cmVzIHByb3BlciBwYWdlIGFzc2lnbm1lbnRzIGZvciBhbGwgZm9ybSBmaWVsZHMuXG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEEgYXMgQW5ndWxhciBMaWZlY3ljbGVcbiAgICogICBwYXJ0aWNpcGFudCBTIGFzIFN0ZXBlZEZvcm1Db21wb25lbnRcbiAgICogICBwYXJ0aWNpcGFudCBGIGFzIEZvcm0gU2VydmljZVxuICAgKlxuICAgKiAgIEEtPj5TOiBuZ09uSW5pdCgpXG4gICAqICAgUy0+PlM6IFNldCBhY3RpdmVQYWdlID0gc3RhcnRQYWdlXG4gICAqICAgUy0+PlM6IFByb2Nlc3MgY2hpbGRyZW4gaW50byBwYWdlc0FycmF5XG4gICAqICAgUy0+PlM6IENhbGN1bGF0ZSB0b3RhbCBwYWdlc1xuICAgKiAgIFMtPj5TOiBBc3NpZ24gcGFnZSBwcm9wcyB0byBjaGlsZHJlblxuICAgKiAgIFMtPj5TOiBnZXRDdXJyZW50Rm9ybUdyb3VwKGFjdGl2ZVBhZ2UpXG4gICAqICAgUy0+PkY6IEV4dHJhY3QgRm9ybUdyb3VwIGZvciBhY3RpdmUgcGFnZVxuICAgKiAgIEYtLT4+UzogUmV0dXJuIGFjdGl2ZUZvcm1Hcm91cFxuICAgKlxuICAgKiBAbWVtYmVyT2YgU3RlcGVkRm9ybUNvbXBvbmVudFxuICAgKi9cbiAgbmdPbkluaXQoKTogdm9pZCAge1xuICAgIHRoaXMuYWN0aXZlUGFnZSA9IHRoaXMuc3RhcnRQYWdlO1xuXG4gICAgdGhpcy5wYWdlc0FycmF5ID0gKHRoaXMuY2hpbGRyZW4ucmVkdWNlKChhY2MsIGN1cnIsIGluZGV4KSA9PiB7XG4gICAgICBjb25zdCBwYWdlID0gY3Vyci5wcm9wcz8uWydwYWdlJ10gfHwgaW5kZXggKyAxO1xuICAgICAgaWYoIWFjY1twYWdlXSlcbiAgICAgICAgYWNjW3BhZ2VdID0gW107XG4gICAgICBhY2NbcGFnZV0ucHVzaCh7aW5kZXg6IHBhZ2V9KTtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwgW10gYXMgS2V5VmFsdWUpIGFzIFtdKS5maWx0ZXIoQm9vbGVhbik7XG5cbiAgICB0aGlzLnBhZ2VzID0gdGhpcy5wYWdlc0FycmF5Lmxlbmd0aDtcbiAgICB0aGlzLmNoaWxkcmVuID0gWy4uLiB0aGlzLmNoaWxkcmVuLm1hcCgoYykgPT4ge1xuICAgICAgaWYoIWMucHJvcHMpXG4gICAgICAgIGMucHJvcHMgPSB7fTtcbiAgICAgIGNvbnN0IHBhZ2UgPSBjLnByb3BzWydwYWdlJ10gfHwgMTtcbiAgICAgIC8vIHByZXZlbnQgcGFnZSBvdmVyZmxvd1xuICAgICAgYy5wcm9wc1sncGFnZSddID0gcGFnZSA+IHRoaXMucGFnZXMgPyB0aGlzLnBhZ2VzIDogcGFnZTtcbiAgICAgIHJldHVybiBjO1xuICAgIH0pXTtcbiAgICB0aGlzLmdldEN1cnJlbnRGb3JtR3JvdXAodGhpcy5hY3RpdmVQYWdlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ2xlYW51cCBtZXRob2QgY2FsbGVkIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQuXG4gICAqIEBzdW1tYXJ5IFVuc3Vic2NyaWJlcyBmcm9tIGFueSBhY3RpdmUgdGltZXIgc3Vic2NyaXB0aW9ucyB0byBwcmV2ZW50IG1lbW9yeSBsZWFrcy5cbiAgICogVGhpcyBpcyBwYXJ0IG9mIEFuZ3VsYXIncyBjb21wb25lbnQgbGlmZWN5Y2xlIGFuZCBlbnN1cmVzIHByb3BlciByZXNvdXJjZSBjbGVhbnVwLlxuICAgKlxuICAgKiBAbWVtYmVyT2YgU3RlcGVkRm9ybUNvbXBvbmVudFxuICAgKi9cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgaWYodGhpcy50aW1lclN1YnNjcmlwdGlvbilcbiAgICAgIHRoaXMudGltZXJTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSGFuZGxlcyBuYXZpZ2F0aW9uIHRvIHRoZSBuZXh0IHBhZ2Ugb3IgZm9ybSBzdWJtaXNzaW9uLlxuICAgKiBAc3VtbWFyeSBWYWxpZGF0ZXMgdGhlIGN1cnJlbnQgcGFnZSdzIGZvcm0gZmllbGRzIGFuZCBlaXRoZXIgbmF2aWdhdGVzIHRvIHRoZSBuZXh0IHBhZ2VcbiAgICogb3Igc3VibWl0cyB0aGUgZW50aXJlIGZvcm0gaWYgb24gdGhlIGxhc3QgcGFnZS4gRm9ybSB2YWxpZGF0aW9uIG11c3QgcGFzcyBiZWZvcmVcbiAgICogcHJvY2VlZGluZy4gT24gc3VjY2Vzc2Z1bCBzdWJtaXNzaW9uLCBlbWl0cyBhIHN1Ym1pdCBldmVudCB3aXRoIGZvcm0gZGF0YS5cbiAgICpcbiAgICogQHBhcmFtIHtib29sZWFufSBsYXN0UGFnZSAtIFdoZXRoZXIgdGhpcyBpcyB0aGUgbGFzdCBwYWdlIG9mIHRoZSBmb3JtXG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IFUgYXMgVXNlclxuICAgKiAgIHBhcnRpY2lwYW50IFMgYXMgU3RlcGVkRm9ybUNvbXBvbmVudFxuICAgKiAgIHBhcnRpY2lwYW50IEYgYXMgRm9ybSBTZXJ2aWNlXG4gICAqICAgcGFydGljaXBhbnQgUCBhcyBQYXJlbnQgQ29tcG9uZW50XG4gICAqXG4gICAqICAgVS0+PlM6IENsaWNrIE5leHQvU3VibWl0XG4gICAqICAgUy0+PkY6IHZhbGlkYXRlRmllbGRzKGFjdGl2ZUZvcm1Hcm91cClcbiAgICogICBGLS0+PlM6IFJldHVybiB2YWxpZGF0aW9uIHJlc3VsdFxuICAgKiAgIGFsdCBOb3QgbGFzdCBwYWdlIGFuZCB2YWxpZFxuICAgKiAgICAgUy0+PlM6IGFjdGl2ZVBhZ2UrK1xuICAgKiAgICAgUy0+PlM6IGdldEN1cnJlbnRGb3JtR3JvdXAoYWN0aXZlUGFnZSlcbiAgICogICBlbHNlIExhc3QgcGFnZSBhbmQgdmFsaWRcbiAgICogICAgIFMtPj5GOiBnZXRGb3JtRGF0YShmb3JtR3JvdXApXG4gICAqICAgICBGLS0+PlM6IFJldHVybiBmb3JtIGRhdGFcbiAgICogICAgIFMtPj5QOiBzdWJtaXRFdmVudC5lbWl0KHtkYXRhLCBuYW1lOiBTVUJNSVR9KVxuICAgKiAgIGVuZFxuICAgKlxuICAgKiBAbWVtYmVyT2YgU3RlcGVkRm9ybUNvbXBvbmVudFxuICAgKi9cbiAgaGFuZGxlTmV4dChsYXN0UGFnZTogYm9vbGVhbiA9IGZhbHNlKTogdm9pZCB7XG4gICAgY29uc3QgaXNWYWxpZCA9IE5neEZvcm1TZXJ2aWNlLnZhbGlkYXRlRmllbGRzKHRoaXMuYWN0aXZlRm9ybUdyb3VwIGFzIEZvcm1Hcm91cCk7XG4gICAgaWYgKCFsYXN0UGFnZSkge1xuICAgICAgaWYgKGlzVmFsaWQpIHtcbiAgICAgICAgdGhpcy5hY3RpdmVQYWdlID0gdGhpcy5hY3RpdmVQYWdlICsgMTtcbiAgICAgICAgdGhpcy5nZXRDdXJyZW50Rm9ybUdyb3VwKHRoaXMuYWN0aXZlUGFnZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgaWYgKGlzVmFsaWQpIHtcbiAgICAgIGNvbnN0IGRhdGEgPSBPYmplY3QuYXNzaWduKHt9LCAuLi5PYmplY3QudmFsdWVzKE5neEZvcm1TZXJ2aWNlLmdldEZvcm1EYXRhKHRoaXMuZm9ybUdyb3VwIGFzIEZvcm1Hcm91cCkpKTtcbiAgICAgIHRoaXMuc3VibWl0RXZlbnQuZW1pdCh7XG4gICAgICAgIGRhdGEsXG4gICAgICAgIG5hbWU6IEV2ZW50Q29uc3RhbnRzLlNVQk1JVCxcbiAgICAgIH0pO1xuICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIG5hdmlnYXRpb24gdG8gdGhlIHByZXZpb3VzIHBhZ2UuXG4gICAqIEBzdW1tYXJ5IE1vdmVzIHRoZSB1c2VyIGJhY2sgdG8gdGhlIHByZXZpb3VzIHBhZ2UgaW4gdGhlIHN0ZXBwZWQgZm9ybS5cbiAgICogVGhpcyBtZXRob2QgZGVjcmVtZW50cyB0aGUgYWN0aXZlIHBhZ2UgbnVtYmVyIGFuZCB1cGRhdGVzIHRoZSBmb3JtXG4gICAqIGdyb3VwIGFuZCBjaGlsZHJlbiB0byBkaXNwbGF5IHRoZSBwcmV2aW91cyBwYWdlJ3MgY29udGVudC5cbiAgICpcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICpcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgVSBhcyBVc2VyXG4gICAqICAgcGFydGljaXBhbnQgUyBhcyBTdGVwZWRGb3JtQ29tcG9uZW50XG4gICAqXG4gICAqICAgVS0+PlM6IENsaWNrIEJhY2tcbiAgICogICBTLT4+UzogYWN0aXZlUGFnZS0tXG4gICAqICAgUy0+PlM6IGdldEN1cnJlbnRGb3JtR3JvdXAoYWN0aXZlUGFnZSlcbiAgICogICBOb3RlIG92ZXIgUzogVXBkYXRlIGFjdGl2ZSBmb3JtIGFuZCBjaGlsZHJlblxuICAgKlxuICAgKiBAbWVtYmVyT2YgU3RlcGVkRm9ybUNvbXBvbmVudFxuICAgKi9cbiAgaGFuZGxlQmFjaygpOiB2b2lkIHtcbiAgICB0aGlzLmFjdGl2ZVBhZ2UgPSB0aGlzLmFjdGl2ZVBhZ2UgLSAxO1xuICAgIHRoaXMuZ2V0Q3VycmVudEZvcm1Hcm91cCh0aGlzLmFjdGl2ZVBhZ2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIHRoZSBhY3RpdmUgZm9ybSBncm91cCBhbmQgY2hpbGRyZW4gZm9yIHRoZSBzcGVjaWZpZWQgcGFnZS5cbiAgICogQHN1bW1hcnkgRXh0cmFjdHMgdGhlIEZvcm1Hcm91cCBmb3IgdGhlIGdpdmVuIHBhZ2UgZnJvbSB0aGUgRm9ybUFycmF5IGFuZCBmaWx0ZXJzXG4gICAqIHRoZSBjaGlsZHJlbiB0byBzaG93IG9ubHkgZmllbGRzIGJlbG9uZ2luZyB0byB0aGF0IHBhZ2UuIFVzZXMgYSB0aW1lciB0byBlbnN1cmVcbiAgICogcHJvcGVyIEFuZ3VsYXIgY2hhbmdlIGRldGVjdGlvbiB3aGVuIHVwZGF0aW5nIHRoZSBhY3RpdmVDaGlsZHJlbi5cbiAgICpcbiAgICogQHBhcmFtIHtudW1iZXJ9IHBhZ2UgLSBUaGUgcGFnZSBudW1iZXIgdG8gYWN0aXZhdGVcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgUyBhcyBTdGVwZWRGb3JtQ29tcG9uZW50XG4gICAqICAgcGFydGljaXBhbnQgRiBhcyBGb3JtQXJyYXlcbiAgICogICBwYXJ0aWNpcGFudCBUIGFzIFRpbWVyXG4gICAqXG4gICAqICAgUy0+PkY6IEV4dHJhY3QgRm9ybUdyb3VwIGF0IGluZGV4IChwYWdlIC0gMSlcbiAgICogICBGLS0+PlM6IFJldHVybiBwYWdlIEZvcm1Hcm91cFxuICAgKiAgIFMtPj5TOiBTZXQgYWN0aXZlQ2hpbGRyZW4gPSB1bmRlZmluZWRcbiAgICogICBTLT4+VDogdGltZXIoMTApLnN1YnNjcmliZSgpXG4gICAqICAgVC0tPj5TOiBGaWx0ZXIgY2hpbGRyZW4gZm9yIGFjdGl2ZSBwYWdlXG4gICAqICAgUy0+PlM6IFNldCBhY3RpdmVDaGlsZHJlblxuICAgKlxuICAgKiBAbWVtYmVyT2YgU3RlcGVkRm9ybUNvbXBvbmVudFxuICAgKi9cbiAgcHJpdmF0ZSBnZXRDdXJyZW50Rm9ybUdyb3VwKHBhZ2U6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuYWN0aXZlRm9ybUdyb3VwID0gKHRoaXMuZm9ybUdyb3VwIGFzIEZvcm1BcnJheSkuYXQocGFnZSAtIDEpIGFzIEZvcm1Hcm91cDtcbiAgICB0aGlzLmFjdGl2ZUNoaWxkcmVuID0gdW5kZWZpbmVkO1xuICAgIHRoaXMudGltZXJTdWJzY3JpcHRpb24gPSB0aW1lcigxMCkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMuYWN0aXZlQ2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuLmZpbHRlcihjID0+IGMucHJvcHM/LlsncGFnZSddID09PSBwYWdlKTtcbiAgICAgIGNvbnNvbGUubG9nKHRoaXMuYWN0aXZlQ2hpbGRyZW4pO1xuICAgIH0pO1xuICB9XG5cbn1cbiIsIiA8IS0tIEBmb3IoY2hpbGQgb2YgY2hpbGRyZW47IHRyYWNrIHRyYWNrSXRlbUZuKCRpbmRleCwgY2hpbGQpKSB7XG4gICAge3tjaGlsZC50YWcgfX1cbiAgICA8bmd4LWRlY2FmLWNvbXBvbmVudC1yZW5kZXJlclxuICAgICAgW3RhZ109XCJjaGlsZC50YWdcIlxuICAgICAgKGxpc3RlbkV2ZW50KT1cImhhbmRsZUV2ZW50KCRldmVudClcIlxuICAgICAgW2dsb2JhbHNdPSd7cHJvcHM6IGNoaWxkLnByb3BzfSc+XG4gICAgICA8L25neC1kZWNhZi1jb21wb25lbnQtcmVuZGVyZXI+XG4gICAgfSAtLT5cbiAgICA8Zm9ybSBjbGFzcz1cImRjZi1zdGVwZWQtZm9ybVwiIG5vdmFsaWRhdGU+XG4gICAgICA8ZGl2IGNsYXNzPVwiZGNmLXBhZ2Utc3RlcHNcIj5cbiAgICAgICAgPGRpdj5cbiAgICAgICAgICAgQGZvcihwYWdlIG9mIHBhZ2VzQXJyYXk7IHRyYWNrICRpbmRleDspIHtcbiAgICAgICAgICAgIDxkaXYgW2NsYXNzLmRjZi1hY3RpdmVdPVwiYWN0aXZlUGFnZSA9PT0gJGluZGV4ICsgMVwiIFtjbGFzcy5kY2YtcGFzc2VkXT1cIigkaW5kZXggKyAxKSA8IGFjdGl2ZVBhZ2VcIj57eyAkaW5kZXggKyAxIH19PC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICAgQGlmKGZvcm1Hcm91cCkge1xuICAgICAgICBAZm9yKGNoaWxkIG9mIGFjdGl2ZUNoaWxkcmVuOyAgdHJhY2sgJGluZGV4KSB7XG4gICAgICAgICAgPG5neC1kZWNhZi1jb21wb25lbnQtcmVuZGVyZXJcbiAgICAgICAgICAgIFt0YWddPVwiY2hpbGQ/LnRhZ1wiXG4gICAgICAgICAgICAobGlzdGVuRXZlbnQpPVwiaGFuZGxlRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgICBbY2hpbGRyZW5dPVwiY2hpbGQ/LmNoaWxkcmVuIHx8IFtdXCJcbiAgICAgICAgICAgIFtnbG9iYWxzXT1cIntwcm9wczogY2hpbGQucHJvcHN9XCJcbiAgICAgICAgICAvPlxuICAgICAgICB9XG4gICAgICB9IEBlbHNlIHtcbiAgICAgICAgPGlvbi1za2VsZXRvbi10ZXh0IFthbmltYXRlZF09XCJ0cnVlXCI+PC9pb24tc2tlbGV0b24tdGV4dD5cbiAgICAgICAgPGlvbi10ZXh0IGNsYXNzPVwiZGF0ZVwiIHN0eWxlPVwid2lkdGg6IDIwJTtcIj48aW9uLXNrZWxldG9uLXRleHQgW2FuaW1hdGVkXT1cInRydWVcIj48L2lvbi1za2VsZXRvbi10ZXh0PjwvaW9uLXRleHQ+XG4gICAgICAgIDxiciAvPlxuICAgICAgICA8aW9uLXNrZWxldG9uLXRleHQgW2FuaW1hdGVkXT1cInRydWVcIj48L2lvbi1za2VsZXRvbi10ZXh0PlxuICAgICAgICA8aW9uLXRleHQgY2xhc3M9XCJkYXRlXCIgc3R5bGU9XCJ3aWR0aDogMjAlO1wiPjxpb24tc2tlbGV0b24tdGV4dCBbYW5pbWF0ZWRdPVwidHJ1ZVwiPjwvaW9uLXNrZWxldG9uLXRleHQ+PC9pb24tdGV4dD5cbiAgICAgIH1cblxuICAgICAgPGRpdiBjbGFzcz1cImRjZi1idXR0b25zLWNvbnRhaW5lciBkY2YtZ3JpZCBkY2YtZ3JpZC1jb2xsYXBzZSBkY2YtZmxleCBkY2YtZmxleC1sZWZ0XCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkY2Ytd2lkdGgtMS0yQHNcIj5cbiAgICAgICAgICA8aW9uLWJ1dHRvbiBmaWxsPVwiY2xlYXJcIiAoY2xpY2spPVwiaGFuZGxlQmFjaygpXCIgW2Rpc2FibGVkXT1cImFjdGl2ZVBhZ2UgPD0gMVwiPlxuICAgICAgICAgICAgPGlvbi1pY29uIGFyaWEtaGlkZGVuPVwidHJ1ZVwiIG5hbWU9XCJhcnJvdy1iYWNrLW91dGxpbmVcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgUHJldmlvdXNcbiAgICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJkY2Ytd2lkdGgtMS0yQHNcIj5cbiAgICAgICAgICA8aW9uLWJ1dHRvbiBbZmlsbF09XCJhY3RpdmVQYWdlID09PSBwYWdlcyA/ICdzb2xpZCcgOiAnb3V0bGluZSdcIiAgKGNsaWNrKT1cImhhbmRsZU5leHQoYWN0aXZlUGFnZSA9PT0gcGFnZXMgPyB0cnVlIDogZmFsc2UpXCI+XG4gICAgICAgICAgICBAaWYoYWN0aXZlUGFnZSA9PT0gcGFnZXMpIHtcbiAgICAgICAgICAgICAgU3VibWl0XG4gICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgTmV4dFxuICAgICAgICAgICAgICA8aW9uLWljb24gYXJpYS1oaWRkZW49XCJ0cnVlXCIgbmFtZT1cImFycm93LWZvcndhcmQtb3V0bGluZVwiPjwvaW9uLWljb24+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZm9ybT5cbiJdfQ==