@decaf-ts/for-angular 0.0.25 → 0.0.26

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 (78) hide show
  1. package/fesm2022/decaf-ts-for-angular.mjs +1465 -1488
  2. package/fesm2022/decaf-ts-for-angular.mjs.map +1 -1
  3. package/index.d.ts +7470 -3
  4. package/package.json +14 -17
  5. package/components/component-renderer/component-renderer.component.d.ts +0 -278
  6. package/components/crud-field/crud-field.component.d.ts +0 -611
  7. package/components/crud-form/constants.d.ts +0 -5
  8. package/components/crud-form/crud-form.component.d.ts +0 -288
  9. package/components/crud-form/types.d.ts +0 -17
  10. package/components/empty-state/empty-state.component.d.ts +0 -300
  11. package/components/fieldset/fieldset.component.d.ts +0 -555
  12. package/components/filter/filter.component.d.ts +0 -514
  13. package/components/for-angular-components.module.d.ts +0 -20
  14. package/components/index.d.ts +0 -16
  15. package/components/layout/layout.component.d.ts +0 -110
  16. package/components/list/list.component.d.ts +0 -848
  17. package/components/list-item/list-item.component.d.ts +0 -390
  18. package/components/model-renderer/model-renderer.component.d.ts +0 -97
  19. package/components/pagination/constants.d.ts +0 -7
  20. package/components/pagination/pagination.component.d.ts +0 -264
  21. package/components/searchbar/searchbar.component.d.ts +0 -407
  22. package/components/stepped-form/stepped-form.component.d.ts +0 -255
  23. package/directives/collapsable.directive.d.ts +0 -9
  24. package/directives/index.d.ts +0 -1
  25. package/engine/DynamicModule.d.ts +0 -17
  26. package/engine/NgxBaseComponent.d.ts +0 -541
  27. package/engine/NgxCrudFormField.d.ts +0 -123
  28. package/engine/NgxFormService.d.ts +0 -601
  29. package/engine/NgxRenderingEngine.d.ts +0 -282
  30. package/engine/ValidatorFactory.d.ts +0 -15
  31. package/engine/constants.d.ts +0 -168
  32. package/engine/decorators.d.ts +0 -25
  33. package/engine/index.d.ts +0 -18
  34. package/engine/interfaces.d.ts +0 -271
  35. package/engine/types.d.ts +0 -200
  36. package/esm2022/components/component-renderer/component-renderer.component.mjs +0 -321
  37. package/esm2022/components/crud-field/crud-field.component.mjs +0 -518
  38. package/esm2022/components/crud-form/constants.mjs +0 -14
  39. package/esm2022/components/crud-form/crud-form.component.mjs +0 -259
  40. package/esm2022/components/crud-form/types.mjs +0 -2
  41. package/esm2022/components/empty-state/empty-state.component.mjs +0 -345
  42. package/esm2022/components/fieldset/fieldset.component.mjs +0 -677
  43. package/esm2022/components/filter/filter.component.mjs +0 -700
  44. package/esm2022/components/for-angular-components.module.mjs +0 -84
  45. package/esm2022/components/index.mjs +0 -20
  46. package/esm2022/components/layout/layout.component.mjs +0 -150
  47. package/esm2022/components/list/list.component.mjs +0 -1238
  48. package/esm2022/components/list-item/list-item.component.mjs +0 -405
  49. package/esm2022/components/model-renderer/model-renderer.component.mjs +0 -144
  50. package/esm2022/components/pagination/constants.mjs +0 -2
  51. package/esm2022/components/pagination/pagination.component.mjs +0 -321
  52. package/esm2022/components/searchbar/searchbar.component.mjs +0 -491
  53. package/esm2022/components/stepped-form/stepped-form.component.mjs +0 -306
  54. package/esm2022/decaf-ts-for-angular.mjs +0 -5
  55. package/esm2022/directives/collapsable.directive.mjs +0 -29
  56. package/esm2022/directives/index.mjs +0 -2
  57. package/esm2022/engine/DynamicModule.mjs +0 -18
  58. package/esm2022/engine/NgxBaseComponent.mjs +0 -541
  59. package/esm2022/engine/NgxCrudFormField.mjs +0 -137
  60. package/esm2022/engine/NgxFormService.mjs +0 -917
  61. package/esm2022/engine/NgxRenderingEngine.mjs +0 -376
  62. package/esm2022/engine/ValidatorFactory.mjs +0 -106
  63. package/esm2022/engine/constants.mjs +0 -170
  64. package/esm2022/engine/decorators.mjs +0 -38
  65. package/esm2022/engine/index.mjs +0 -19
  66. package/esm2022/engine/interfaces.mjs +0 -4
  67. package/esm2022/engine/types.mjs +0 -2
  68. package/esm2022/for-angular-common.module.mjs +0 -84
  69. package/esm2022/helpers/index.mjs +0 -13
  70. package/esm2022/helpers/utils.mjs +0 -436
  71. package/esm2022/i18n/Loader.mjs +0 -86
  72. package/esm2022/i18n/data/en.json +0 -85
  73. package/esm2022/public-apis.mjs +0 -15
  74. package/for-angular-common.module.d.ts +0 -50
  75. package/helpers/index.d.ts +0 -12
  76. package/helpers/utils.d.ts +0 -279
  77. package/i18n/Loader.d.ts +0 -43
  78. package/public-apis.d.ts +0 -14
@@ -1,321 +0,0 @@
1
- import { Component, EnvironmentInjector, EventEmitter, inject, Input, Output, reflectComponentType, TemplateRef, ViewChild, ViewContainerRef, } from '@angular/core';
2
- import { NgComponentOutlet } from '@angular/common';
3
- import { NgxRenderingEngine } from '../../engine/NgxRenderingEngine';
4
- import { getLogger } from '../../for-angular-common.module';
5
- import { generateRandomValue } from '../../helpers';
6
- import * as i0 from "@angular/core";
7
- /**
8
- * @description Dynamic component renderer for Decaf Angular applications.
9
- * @summary This component provides a flexible way to dynamically render Angular components
10
- * at runtime based on a tag name. It handles the creation, property binding, and event
11
- * subscription for dynamically loaded components. This is particularly useful for
12
- * building configurable UIs where components need to be determined at runtime.
13
- *
14
- * @component {ComponentRendererComponent}
15
- * @example
16
- * <ngx-decaf-component-renderer
17
- * [tag]="tag"
18
- * [globals]="globals"
19
- * (listenEvent)="listenEvent($event)">
20
- * </ngx-decaf-component-renderer>
21
- *
22
- * @mermaid
23
- * classDiagram
24
- * class ComponentRendererComponent {
25
- * +ViewContainerRef vcr
26
- * +string tag
27
- * +Record~string, unknown~ globals
28
- * +EnvironmentInjector injector
29
- * +ComponentRef~unknown~ component
30
- * +EventEmitter~RendererCustomEvent~ listenEvent
31
- * +ngOnInit()
32
- * +ngOnDestroy()
33
- * +ngOnChanges(changes)
34
- * -createComponent(tag, globals)
35
- * -subscribeEvents()
36
- * -unsubscribeEvents()
37
- * }
38
- * ComponentRendererComponent --|> OnInit
39
- * ComponentRendererComponent --|> OnChanges
40
- * ComponentRendererComponent --|> OnDestroy
41
- *
42
- * @implements {OnInit}
43
- * @implements {OnChanges}
44
- * @implements {OnDestroy}
45
- */
46
- export class ComponentRendererComponent {
47
- /**
48
- * @description Creates an instance of ComponentRendererComponent.
49
- * @summary Initializes a new ComponentRendererComponent. This component doesn't require
50
- * any dependencies to be injected in its constructor as it uses the inject function to
51
- * obtain the EnvironmentInjector.
52
- *
53
- * @memberOf ComponentRendererComponent
54
- */
55
- constructor() {
56
- /**
57
- * @description Global properties to pass to the rendered component.
58
- * @summary This input property allows passing a set of properties to the dynamically
59
- * rendered component. These properties will be mapped to the component's inputs if they
60
- * match. Properties that don't match any input on the target component will be filtered out
61
- * with a warning.
62
- *
63
- * @type {Record<string, unknown>}
64
- * @default {}
65
- * @memberOf ComponentRendererComponent
66
- */
67
- this.globals = {};
68
- /**
69
- * @description Injector used for dependency injection in the dynamic component.
70
- * @summary This injector is used when creating the dynamic component to provide it with
71
- * access to the application's dependency injection system. It ensures that the dynamically
72
- * created component can access the same services and dependencies as statically created
73
- * components.
74
- *
75
- * @type {EnvironmentInjector}
76
- * @memberOf ComponentRendererComponent
77
- */
78
- this.injector = inject(EnvironmentInjector);
79
- this.children = [];
80
- /**
81
- * @description Event emitter for events from the rendered component.
82
- * @summary This output property emits events that originate from the dynamically rendered
83
- * component. It allows the parent component to listen for and respond to events from the
84
- * dynamic component, creating a communication channel between the parent and the dynamically
85
- * rendered child.
86
- *
87
- * @type {EventEmitter<RendererCustomEvent>}
88
- * @memberOf ComponentRendererComponent
89
- */
90
- this.listenEvent = new EventEmitter();
91
- this.parent = undefined;
92
- this.uid = generateRandomValue(12);
93
- this.logger = getLogger(this);
94
- }
95
- /**
96
- * @description Initializes the component after Angular first displays the data-bound properties.
97
- * @summary Sets up the component by creating the dynamic component specified by the tag input.
98
- * This method is called once when the component is initialized and triggers the dynamic
99
- * component creation process with the provided tag name and global properties.
100
- *
101
- * @mermaid
102
- * sequenceDiagram
103
- * participant A as Angular Lifecycle
104
- * participant C as ComponentRendererComponent
105
- * participant R as NgxRenderingEngine
106
- *
107
- * A->>C: ngOnInit()
108
- * C->>C: createComponent(tag, globals)
109
- * C->>R: components(tag)
110
- * R-->>C: Return component constructor
111
- * C->>C: Process component inputs
112
- * C->>C: Create component instance
113
- * C->>C: subscribeEvents()
114
- *
115
- * @return {void}
116
- * @memberOf ComponentRendererComponent
117
- */
118
- ngOnInit() {
119
- if (!this.parent) {
120
- this.createComponent(this.tag, this.globals);
121
- }
122
- else {
123
- this.createParentComponent();
124
- }
125
- }
126
- /**
127
- * @description Cleans up resources when the component is destroyed.
128
- * @summary Performs cleanup operations when the component is being destroyed by Angular.
129
- * This includes unsubscribing from all event emitters of the dynamic component and
130
- * destroying the rendering engine instance to prevent memory leaks.
131
- *
132
- * @mermaid
133
- * sequenceDiagram
134
- * participant A as Angular Lifecycle
135
- * participant C as ComponentRendererComponent
136
- * participant R as NgxRenderingEngine
137
- *
138
- * A->>C: ngOnDestroy()
139
- * alt component exists
140
- * C->>C: unsubscribeEvents()
141
- * C->>R: destroy()
142
- * end
143
- *
144
- * @return {Promise<void>} A promise that resolves when cleanup is complete
145
- * @memberOf ComponentRendererComponent
146
- */
147
- async ngOnDestroy() {
148
- if (this.component) {
149
- this.unsubscribeEvents();
150
- NgxRenderingEngine.destroy();
151
- }
152
- }
153
- /**
154
- * @description Creates and renders a dynamic component.
155
- * @summary This method handles the creation of a dynamic component based on the provided tag.
156
- * It retrieves the component constructor from the rendering engine, processes its inputs,
157
- * filters out unmapped properties, creates the component instance, and sets up event subscriptions.
158
- *
159
- * @param {string} tag - The tag name of the component to create
160
- * @param {KeyValue} globals - Global properties to pass to the component
161
- * @return {void}
162
- *
163
- * @mermaid
164
- * sequenceDiagram
165
- * participant C as ComponentRendererComponent
166
- * participant R as NgxRenderingEngine
167
- * participant V as ViewContainerRef
168
- *
169
- * C->>R: components(tag)
170
- * R-->>C: Return component constructor
171
- * C->>C: reflectComponentType(component)
172
- * C->>C: Process input properties
173
- * C->>C: Filter unmapped properties
174
- * C->>V: clear()
175
- * C->>R: createComponent(component, props, metadata, vcr, injector, [])
176
- * R-->>C: Return component reference
177
- * C->>C: subscribeEvents()
178
- *
179
- * @private
180
- * @memberOf ComponentRendererComponent
181
- */
182
- createComponent(tag, globals = {}) {
183
- const component = NgxRenderingEngine.components(tag)
184
- ?.constructor;
185
- const metadata = reflectComponentType(component);
186
- const componentInputs = metadata.inputs;
187
- const props = globals?.['item'] || globals?.['props'] || {};
188
- if (props?.['tag'])
189
- delete props['tag'];
190
- if (props?.['children'] && !this.children.length)
191
- this.children = props['children'];
192
- const inputKeys = Object.keys(props);
193
- const unmappedKeys = [];
194
- for (const input of inputKeys) {
195
- if (!inputKeys.length)
196
- break;
197
- const prop = componentInputs.find((item) => item.propName === input);
198
- if (!prop) {
199
- delete props[input];
200
- unmappedKeys.push(input);
201
- }
202
- }
203
- this.vcr.clear();
204
- const template = this.children?.length ? this.vcr.createEmbeddedView(this.inner, this.injector).rootNodes : [];
205
- this.component = NgxRenderingEngine.createComponent(component, props, metadata, this.vcr, this.injector, template);
206
- this.subscribeEvents();
207
- }
208
- createParentComponent() {
209
- const { component, inputs } = this.parent;
210
- const metadata = reflectComponentType(component);
211
- const template = this.vcr.createEmbeddedView(this.inner, this.injector).rootNodes;
212
- this.component = NgxRenderingEngine.createComponent(component, inputs, metadata, this.vcr, this.injector, template);
213
- this.subscribeEvents();
214
- }
215
- /**
216
- * @description Subscribes to events emitted by the dynamic component.
217
- * @summary This method sets up subscriptions to all EventEmitter properties of the
218
- * dynamically created component. When an event is emitted by the dynamic component,
219
- * it is captured and re-emitted through the listenEvent output property with additional
220
- * metadata about the event source.
221
- *
222
- * @mermaid
223
- * sequenceDiagram
224
- * participant C as ComponentRendererComponent
225
- * participant D as Dynamic Component
226
- * participant P as Parent Component
227
- *
228
- * C->>C: subscribeEvents()
229
- * C->>D: Get instance properties
230
- * loop For each property
231
- * C->>C: Check if property is EventEmitter
232
- * alt is EventEmitter
233
- * C->>D: Subscribe to event
234
- * D-->>C: Event emitted
235
- * C->>P: Re-emit event with metadata
236
- * end
237
- * end
238
- *
239
- * @private
240
- * @return {void}
241
- * @memberOf ComponentRendererComponent
242
- */
243
- subscribeEvents() {
244
- if (this.component) {
245
- const instance = this.component?.instance;
246
- const componentKeys = Object.keys(instance);
247
- for (const key of componentKeys) {
248
- const value = instance[key];
249
- if (value instanceof EventEmitter)
250
- instance[key].subscribe((event) => {
251
- this.listenEvent.emit({
252
- name: key,
253
- ...event,
254
- });
255
- });
256
- }
257
- }
258
- }
259
- /**
260
- * @description Unsubscribes from all events of the dynamic component.
261
- * @summary This method cleans up event subscriptions when the component is being destroyed.
262
- * It iterates through all properties of the dynamic component instance and unsubscribes
263
- * from any EventEmitter properties to prevent memory leaks and unexpected behavior after
264
- * the component is destroyed.
265
- *
266
- * @mermaid
267
- * sequenceDiagram
268
- * participant C as ComponentRendererComponent
269
- * participant D as Dynamic Component
270
- *
271
- * C->>C: unsubscribeEvents()
272
- * C->>D: Get instance properties
273
- * loop For each property
274
- * C->>C: Check if property is EventEmitter
275
- * alt is EventEmitter
276
- * C->>D: Unsubscribe from event
277
- * end
278
- * end
279
- *
280
- * @private
281
- * @return {void}
282
- * @memberOf ComponentRendererComponent
283
- */
284
- unsubscribeEvents() {
285
- if (this.component) {
286
- const instance = this.component?.instance;
287
- const componentKeys = Object.keys(instance);
288
- for (const key of componentKeys) {
289
- const value = instance[key];
290
- if (value instanceof EventEmitter)
291
- instance[key].unsubscribe();
292
- }
293
- }
294
- }
295
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
296
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentRendererComponent, isStandalone: true, selector: "ngx-decaf-component-renderer", inputs: { tag: "tag", globals: "globals", children: "children", model: "model", parent: "parent" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "vcr", first: true, predicate: ["componentViewContainer"], descendants: true, read: ViewContainerRef, static: true }, { propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }], ngImport: i0, template: "<!-- Keep to avoid id conflicts -->\n<div [id]=\"uid\"></div>\n\n<ng-template #componentViewContainer></ng-template>\n<ng-template #inner>\n @if(parent?.children?.length) {\n @for(child of parent.children; track child) {\n @if(!child.children?.length) {\n <ng-container\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n } @else {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n }\n }\n }\n @if(children?.length) {\n @for(child of children; track child) {\n @if(child.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\" />\n }\n }\n }\n</ng-template>\n\n\n", styles: [""], dependencies: [{ kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }] }); }
297
- }
298
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentRendererComponent, decorators: [{
299
- type: Component,
300
- args: [{ selector: 'ngx-decaf-component-renderer', imports: [NgComponentOutlet], standalone: true, host: { '[attr.id]': 'uid' }, template: "<!-- Keep to avoid id conflicts -->\n<div [id]=\"uid\"></div>\n\n<ng-template #componentViewContainer></ng-template>\n<ng-template #inner>\n @if(parent?.children?.length) {\n @for(child of parent.children; track child) {\n @if(!child.children?.length) {\n <ng-container\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n } @else {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n }\n }\n }\n @if(children?.length) {\n @for(child of children; track child) {\n @if(child.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\" />\n }\n }\n }\n</ng-template>\n\n\n" }]
301
- }], ctorParameters: () => [], propDecorators: { vcr: [{
302
- type: ViewChild,
303
- args: ['componentViewContainer', { static: true, read: ViewContainerRef }]
304
- }], tag: [{
305
- type: Input,
306
- args: [{ required: true }]
307
- }], globals: [{
308
- type: Input
309
- }], children: [{
310
- type: Input
311
- }], listenEvent: [{
312
- type: Output
313
- }], model: [{
314
- type: Input
315
- }], parent: [{
316
- type: Input
317
- }], inner: [{
318
- type: ViewChild,
319
- args: ['inner', { read: TemplateRef, static: true }]
320
- }] } });
321
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LXJlbmRlcmVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9jb21wb25lbnQtcmVuZGVyZXIvY29tcG9uZW50LXJlbmRlcmVyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9jb21wb25lbnQtcmVuZGVyZXIvY29tcG9uZW50LXJlbmRlcmVyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBR1QsbUJBQW1CLEVBQ25CLFlBQVksRUFDWixNQUFNLEVBRU4sS0FBSyxFQUdMLE1BQU0sRUFDTixvQkFBb0IsRUFDcEIsV0FBVyxFQUVYLFNBQVMsRUFDVCxnQkFBZ0IsR0FDakIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFcEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFckUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRzVELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGVBQWUsQ0FBQzs7QUFFcEQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0NHO0FBU0gsTUFBTSxPQUFPLDBCQUEwQjtJQWdIckM7Ozs7Ozs7T0FPRztJQUNIO1FBNUZBOzs7Ozs7Ozs7O1dBVUc7UUFFSCxZQUFPLEdBQTRCLEVBQUUsQ0FBQztRQUV0Qzs7Ozs7Ozs7O1dBU0c7UUFDSCxhQUFRLEdBQXdCLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBYzVELGFBQVEsR0FBZSxFQUFFLENBQUM7UUFFMUI7Ozs7Ozs7OztXQVNHO1FBRUgsZ0JBQVcsR0FDVCxJQUFJLFlBQVksRUFBdUIsQ0FBQztRQXlCMUMsV0FBTSxHQUF5QixT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QkFESixTQUFTO3VCQUFDLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgQ29tcG9uZW50TWlycm9yLFxuICBDb21wb25lbnRSZWYsXG4gIEVudmlyb25tZW50SW5qZWN0b3IsXG4gIEV2ZW50RW1pdHRlcixcbiAgaW5qZWN0LFxuICBJbmplY3RvcixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG4gIHJlZmxlY3RDb21wb25lbnRUeXBlLFxuICBUZW1wbGF0ZVJlZixcbiAgVHlwZSxcbiAgVmlld0NoaWxkLFxuICBWaWV3Q29udGFpbmVyUmVmLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE5nQ29tcG9uZW50T3V0bGV0IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcblxuaW1wb3J0IHsgTmd4UmVuZGVyaW5nRW5naW5lIH0gZnJvbSAnLi4vLi4vZW5naW5lL05neFJlbmRlcmluZ0VuZ2luZSc7XG5pbXBvcnQgeyBCYXNlQ3VzdG9tRXZlbnQsIEtleVZhbHVlLCBSZW5kZXJlckN1c3RvbUV2ZW50IH0gZnJvbSAnLi4vLi4vZW5naW5lJztcbmltcG9ydCB7IGdldExvZ2dlciB9IGZyb20gJy4uLy4uL2Zvci1hbmd1bGFyLWNvbW1vbi5tb2R1bGUnO1xuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnQGRlY2FmLXRzL2xvZ2dpbmcnO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tICdAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb24nO1xuaW1wb3J0IHsgZ2VuZXJhdGVSYW5kb21WYWx1ZSB9IGZyb20gJy4uLy4uL2hlbHBlcnMnO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEeW5hbWljIGNvbXBvbmVudCByZW5kZXJlciBmb3IgRGVjYWYgQW5ndWxhciBhcHBsaWNhdGlvbnMuXG4gKiBAc3VtbWFyeSBUaGlzIGNvbXBvbmVudCBwcm92aWRlcyBhIGZsZXhpYmxlIHdheSB0byBkeW5hbWljYWxseSByZW5kZXIgQW5ndWxhciBjb21wb25lbnRzXG4gKiBhdCBydW50aW1lIGJhc2VkIG9uIGEgdGFnIG5hbWUuIEl0IGhhbmRsZXMgdGhlIGNyZWF0aW9uLCBwcm9wZXJ0eSBiaW5kaW5nLCBhbmQgZXZlbnRcbiAqIHN1YnNjcmlwdGlvbiBmb3IgZHluYW1pY2FsbHkgbG9hZGVkIGNvbXBvbmVudHMuIFRoaXMgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCBmb3JcbiAqIGJ1aWxkaW5nIGNvbmZpZ3VyYWJsZSBVSXMgd2hlcmUgY29tcG9uZW50cyBuZWVkIHRvIGJlIGRldGVybWluZWQgYXQgcnVudGltZS5cbiAqXG4gKiBAY29tcG9uZW50IHtDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudH1cbiAqIEBleGFtcGxlXG4gKiA8bmd4LWRlY2FmLWNvbXBvbmVudC1yZW5kZXJlclxuICogICBbdGFnXT1cInRhZ1wiXG4gKiAgIFtnbG9iYWxzXT1cImdsb2JhbHNcIlxuICogICAobGlzdGVuRXZlbnQpPVwibGlzdGVuRXZlbnQoJGV2ZW50KVwiPlxuICogPC9uZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyPlxuICpcbiAqIEBtZXJtYWlkXG4gKiBjbGFzc0RpYWdyYW1cbiAqICAgY2xhc3MgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnQge1xuICogICAgICtWaWV3Q29udGFpbmVyUmVmIHZjclxuICogICAgICtzdHJpbmcgdGFnXG4gKiAgICAgK1JlY29yZH5zdHJpbmcsIHVua25vd25+IGdsb2JhbHNcbiAqICAgICArRW52aXJvbm1lbnRJbmplY3RvciBpbmplY3RvclxuICogICAgICtDb21wb25lbnRSZWZ+dW5rbm93bn4gY29tcG9uZW50XG4gKiAgICAgK0V2ZW50RW1pdHRlcn5SZW5kZXJlckN1c3RvbUV2ZW50fiBsaXN0ZW5FdmVudFxuICogICAgICtuZ09uSW5pdCgpXG4gKiAgICAgK25nT25EZXN0cm95KClcbiAqICAgICArbmdPbkNoYW5nZXMoY2hhbmdlcylcbiAqICAgICAtY3JlYXRlQ29tcG9uZW50KHRhZywgZ2xvYmFscylcbiAqICAgICAtc3Vic2NyaWJlRXZlbnRzKClcbiAqICAgICAtdW5zdWJzY3JpYmVFdmVudHMoKVxuICogICB9XG4gKiAgIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50IC0tfD4gT25Jbml0XG4gKiAgIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50IC0tfD4gT25DaGFuZ2VzXG4gKiAgIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50IC0tfD4gT25EZXN0cm95XG4gKlxuICogQGltcGxlbWVudHMge09uSW5pdH1cbiAqIEBpbXBsZW1lbnRzIHtPbkNoYW5nZXN9XG4gKiBAaW1wbGVtZW50cyB7T25EZXN0cm95fVxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NvbXBvbmVudC1yZW5kZXJlci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2NvbXBvbmVudC1yZW5kZXJlci5jb21wb25lbnQuc2NzcyddLFxuICBpbXBvcnRzOiBbTmdDb21wb25lbnRPdXRsZXRdLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBob3N0OiB7J1thdHRyLmlkXSc6ICd1aWQnfSxcbn0pXG5leHBvcnQgY2xhc3MgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVmZXJlbmNlIHRvIHRoZSBjb250YWluZXIgd2hlcmUgdGhlIGR5bmFtaWMgY29tcG9uZW50IHdpbGwgYmUgcmVuZGVyZWQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgVmlld0NvbnRhaW5lclJlZiBwcm92aWRlcyB0aGUgY29udGFpbmVyIHdoZXJlIHRoZSBkeW5hbWljYWxseSBjcmVhdGVkXG4gICAqIGNvbXBvbmVudCB3aWxsIGJlIGluc2VydGVkIGludG8gdGhlIERPTS4gSXQncyBtYXJrZWQgYXMgc3RhdGljIHRvIGVuc3VyZSBpdCdzIGF2YWlsYWJsZVxuICAgKiBkdXJpbmcgdGhlIG5nT25Jbml0IGxpZmVjeWNsZSBob29rIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBjcmVhdGVkLlxuICAgKlxuICAgKiBAdHlwZSB7Vmlld0NvbnRhaW5lclJlZn1cbiAgICogQG1lbWJlck9mIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqL1xuICBAVmlld0NoaWxkKCdjb21wb25lbnRWaWV3Q29udGFpbmVyJywgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IFZpZXdDb250YWluZXJSZWYgfSlcbiAgdmNyITogVmlld0NvbnRhaW5lclJlZjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSB0YWcgbmFtZSBvZiB0aGUgY29tcG9uZW50IHRvIGJlIGR5bmFtaWNhbGx5IHJlbmRlcmVkLlxuICAgKiBAc3VtbWFyeSBUaGlzIGlucHV0IHByb3BlcnR5IHNwZWNpZmllcyB3aGljaCBjb21wb25lbnQgc2hvdWxkIGJlIHJlbmRlcmVkIGJ5IHByb3ZpZGluZ1xuICAgKiBpdHMgcmVnaXN0ZXJlZCB0YWcgbmFtZS4gVGhlIHRhZyBtdXN0IGNvcnJlc3BvbmQgdG8gYSBjb21wb25lbnQgdGhhdCBoYXMgYmVlbiByZWdpc3RlcmVkXG4gICAqIHdpdGggdGhlIE5neFJlbmRlcmluZ0VuZ2luZS4gVGhpcyBpcyBhIHJlcXVpcmVkIGlucHV0IGFzIGl0IGRldGVybWluZXMgd2hpY2ggY29tcG9uZW50XG4gICAqIHRvIGNyZWF0ZS5cbiAgICpcbiAgICogQHR5cGUge3N0cmluZ31cbiAgICogQHJlcXVpcmVkXG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgQElucHV0KHsgcmVxdWlyZWQ6IHRydWUgfSlcbiAgdGFnITogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2xvYmFsIHByb3BlcnRpZXMgdG8gcGFzcyB0byB0aGUgcmVuZGVyZWQgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIGlucHV0IHByb3BlcnR5IGFsbG93cyBwYXNzaW5nIGEgc2V0IG9mIHByb3BlcnRpZXMgdG8gdGhlIGR5bmFtaWNhbGx5XG4gICAqIHJlbmRlcmVkIGNvbXBvbmVudC4gVGhlc2UgcHJvcGVydGllcyB3aWxsIGJlIG1hcHBlZCB0byB0aGUgY29tcG9uZW50J3MgaW5wdXRzIGlmIHRoZXlcbiAgICogbWF0Y2guIFByb3BlcnRpZXMgdGhhdCBkb24ndCBtYXRjaCBhbnkgaW5wdXQgb24gdGhlIHRhcmdldCBjb21wb25lbnQgd2lsbCBiZSBmaWx0ZXJlZCBvdXRcbiAgICogd2l0aCBhIHdhcm5pbmcuXG4gICAqXG4gICAqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCB1bmtub3duPn1cbiAgICogQGRlZmF1bHQge31cbiAgICogQG1lbWJlck9mIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqL1xuICBASW5wdXQoKVxuICBnbG9iYWxzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSW5qZWN0b3IgdXNlZCBmb3IgZGVwZW5kZW5jeSBpbmplY3Rpb24gaW4gdGhlIGR5bmFtaWMgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIGluamVjdG9yIGlzIHVzZWQgd2hlbiBjcmVhdGluZyB0aGUgZHluYW1pYyBjb21wb25lbnQgdG8gcHJvdmlkZSBpdCB3aXRoXG4gICAqIGFjY2VzcyB0byB0aGUgYXBwbGljYXRpb24ncyBkZXBlbmRlbmN5IGluamVjdGlvbiBzeXN0ZW0uIEl0IGVuc3VyZXMgdGhhdCB0aGUgZHluYW1pY2FsbHlcbiAgICogY3JlYXRlZCBjb21wb25lbnQgY2FuIGFjY2VzcyB0aGUgc2FtZSBzZXJ2aWNlcyBhbmQgZGVwZW5kZW5jaWVzIGFzIHN0YXRpY2FsbHkgY3JlYXRlZFxuICAgKiBjb21wb25lbnRzLlxuICAgKlxuICAgKiBAdHlwZSB7RW52aXJvbm1lbnRJbmplY3Rvcn1cbiAgICogQG1lbWJlck9mIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqL1xuICBpbmplY3RvcjogRW52aXJvbm1lbnRJbmplY3RvciA9IGluamVjdChFbnZpcm9ubWVudEluamVjdG9yKTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlZmVyZW5jZSB0byB0aGUgZHluYW1pY2FsbHkgY3JlYXRlZCBjb21wb25lbnQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgcHJvcGVydHkgaG9sZHMgYSByZWZlcmVuY2UgdG8gdGhlIENvbXBvbmVudFJlZiBvZiB0aGUgZHluYW1pY2FsbHkgY3JlYXRlZFxuICAgKiBjb21wb25lbnQuIEl0J3MgdXNlZCB0byBpbnRlcmFjdCB3aXRoIHRoZSBjb21wb25lbnQgaW5zdGFuY2UsIHN1YnNjcmliZSB0byBpdHMgZXZlbnRzLFxuICAgKiBhbmQgcHJvcGVybHkgZGVzdHJveSBpdCB3aGVuIHRoZSByZW5kZXJlciBpcyBkZXN0cm95ZWQuXG4gICAqXG4gICAqIEB0eXBlIHtDb21wb25lbnRSZWY8dW5rbm93bj59XG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgY29tcG9uZW50ITogQ29tcG9uZW50UmVmPHVua25vd24+O1xuXG4gIEBJbnB1dCgpXG4gIGNoaWxkcmVuOiBLZXlWYWx1ZVtdID0gW107XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFdmVudCBlbWl0dGVyIGZvciBldmVudHMgZnJvbSB0aGUgcmVuZGVyZWQgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIG91dHB1dCBwcm9wZXJ0eSBlbWl0cyBldmVudHMgdGhhdCBvcmlnaW5hdGUgZnJvbSB0aGUgZHluYW1pY2FsbHkgcmVuZGVyZWRcbiAgICogY29tcG9uZW50LiBJdCBhbGxvd3MgdGhlIHBhcmVudCBjb21wb25lbnQgdG8gbGlzdGVuIGZvciBhbmQgcmVzcG9uZCB0byBldmVudHMgZnJvbSB0aGVcbiAgICogZHluYW1pYyBjb21wb25lbnQsIGNyZWF0aW5nIGEgY29tbXVuaWNhdGlvbiBjaGFubmVsIGJldHdlZW4gdGhlIHBhcmVudCBhbmQgdGhlIGR5bmFtaWNhbGx5XG4gICAqIHJlbmRlcmVkIGNoaWxkLlxuICAgKlxuICAgKiBAdHlwZSB7RXZlbnRFbWl0dGVyPFJlbmRlcmVyQ3VzdG9tRXZlbnQ+fVxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIEBPdXRwdXQoKVxuICBsaXN0ZW5FdmVudDogRXZlbnRFbWl0dGVyPFJlbmRlcmVyQ3VzdG9tRXZlbnQ+ID1cbiAgICBuZXcgRXZlbnRFbWl0dGVyPFJlbmRlcmVyQ3VzdG9tRXZlbnQ+KCk7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dnZXIgaW5zdGFuY2UgZm9yIHRoZSBjb21wb25lbnQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgcHJvcGVydHkgaG9sZHMgYSBMb2dnZXIgaW5zdGFuY2Ugc3BlY2lmaWMgdG8gdGhpcyBjb21wb25lbnQuXG4gICAqIEl0J3MgdXNlZCB0byBsb2cgaW5mb3JtYXRpb24sIHdhcm5pbmdzLCBhbmQgZXJyb3JzIHJlbGF0ZWQgdG8gdGhlIGNvbXBvbmVudCdzXG4gICAqIG9wZXJhdGlvbnMsIHBhcnRpY3VsYXJseSB1c2VmdWwgZm9yIGRlYnVnZ2luZyBhbmQgbW9uaXRvcmluZyB0aGUgZHluYW1pY1xuICAgKiBjb21wb25lbnQgcmVuZGVyaW5nIHByb2Nlc3MuXG4gICAqXG4gICAqIEB0eXBlIHtMb2dnZXJ9XG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgbG9nZ2VyITogTG9nZ2VyO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVwb3NpdG9yeSBtb2RlbCBmb3IgZGF0YSBvcGVyYXRpb25zLlxuICAgKiBAc3VtbWFyeSBUaGUgZGF0YSBtb2RlbCByZXBvc2l0b3J5IHRoYXQgdGhpcyBjb21wb25lbnQgd2lsbCB1c2UgZm9yIENSVUQgb3BlcmF0aW9ucy5cbiAgICogVGhpcyBwcm92aWRlcyBhIGNvbm5lY3Rpb24gdG8gdGhlIGRhdGEgbGF5ZXIgZm9yIHJldHJpZXZpbmcgYW5kIG1hbmlwdWxhdGluZyBkYXRhLlxuICAgKlxuICAgKiBAdHlwZSB7TW9kZWx8IHVuZGVmaW5lZH1cbiAgICovXG4gIEBJbnB1dCgpXG4gIG1vZGVsITogIE1vZGVsIHwgdW5kZWZpbmVkO1xuXG4gIEBJbnB1dCgpXG4gIHBhcmVudDogdW5kZWZpbmVkIHwgS2V5VmFsdWUgPSB1bmRlZmluZWQ7XG5cbiAgQFZpZXdDaGlsZCgnaW5uZXInLCB7IHJlYWQ6IFRlbXBsYXRlUmVmLCBzdGF0aWM6IHRydWUgfSlcbiAgaW5uZXI/OiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcblxuICB1aWQ6IHN0cmluZyA9IGdlbmVyYXRlUmFuZG9tVmFsdWUoMTIpO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudC5cbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSBuZXcgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnQuIFRoaXMgY29tcG9uZW50IGRvZXNuJ3QgcmVxdWlyZVxuICAgKiBhbnkgZGVwZW5kZW5jaWVzIHRvIGJlIGluamVjdGVkIGluIGl0cyBjb25zdHJ1Y3RvciBhcyBpdCB1c2VzIHRoZSBpbmplY3QgZnVuY3Rpb24gdG9cbiAgICogb2J0YWluIHRoZSBFbnZpcm9ubWVudEluamVjdG9yLlxuICAgKlxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMubG9nZ2VyID0gZ2V0TG9nZ2VyKHRoaXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbml0aWFsaXplcyB0aGUgY29tcG9uZW50IGFmdGVyIEFuZ3VsYXIgZmlyc3QgZGlzcGxheXMgdGhlIGRhdGEtYm91bmQgcHJvcGVydGllcy5cbiAgICogQHN1bW1hcnkgU2V0cyB1cCB0aGUgY29tcG9uZW50IGJ5IGNyZWF0aW5nIHRoZSBkeW5hbWljIGNvbXBvbmVudCBzcGVjaWZpZWQgYnkgdGhlIHRhZyBpbnB1dC5cbiAgICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIG9uY2Ugd2hlbiB0aGUgY29tcG9uZW50IGlzIGluaXRpYWxpemVkIGFuZCB0cmlnZ2VycyB0aGUgZHluYW1pY1xuICAgKiBjb21wb25lbnQgY3JlYXRpb24gcHJvY2VzcyB3aXRoIHRoZSBwcm92aWRlZCB0YWcgbmFtZSBhbmQgZ2xvYmFsIHByb3BlcnRpZXMuXG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEEgYXMgQW5ndWxhciBMaWZlY3ljbGVcbiAgICogICBwYXJ0aWNpcGFudCBDIGFzIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqICAgcGFydGljaXBhbnQgUiBhcyBOZ3hSZW5kZXJpbmdFbmdpbmVcbiAgICpcbiAgICogICBBLT4+QzogbmdPbkluaXQoKVxuICAgKiAgIEMtPj5DOiBjcmVhdGVDb21wb25lbnQodGFnLCBnbG9iYWxzKVxuICAgKiAgIEMtPj5SOiBjb21wb25lbnRzKHRhZylcbiAgICogICBSLS0+PkM6IFJldHVybiBjb21wb25lbnQgY29uc3RydWN0b3JcbiAgICogICBDLT4+QzogUHJvY2VzcyBjb21wb25lbnQgaW5wdXRzXG4gICAqICAgQy0+PkM6IENyZWF0ZSBjb21wb25lbnQgaW5zdGFuY2VcbiAgICogICBDLT4+Qzogc3Vic2NyaWJlRXZlbnRzKClcbiAgICpcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICogQG1lbWJlck9mIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqL1xuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMucGFyZW50KSB7XG4gICAgICB0aGlzLmNyZWF0ZUNvbXBvbmVudCh0aGlzLnRhZywgdGhpcy5nbG9iYWxzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5jcmVhdGVQYXJlbnRDb21wb25lbnQoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENsZWFucyB1cCByZXNvdXJjZXMgd2hlbiB0aGUgY29tcG9uZW50IGlzIGRlc3Ryb3llZC5cbiAgICogQHN1bW1hcnkgUGVyZm9ybXMgY2xlYW51cCBvcGVyYXRpb25zIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBiZWluZyBkZXN0cm95ZWQgYnkgQW5ndWxhci5cbiAgICogVGhpcyBpbmNsdWRlcyB1bnN1YnNjcmliaW5nIGZyb20gYWxsIGV2ZW50IGVtaXR0ZXJzIG9mIHRoZSBkeW5hbWljIGNvbXBvbmVudCBhbmRcbiAgICogZGVzdHJveWluZyB0aGUgcmVuZGVyaW5nIGVuZ2luZSBpbnN0YW5jZSB0byBwcmV2ZW50IG1lbW9yeSBsZWFrcy5cbiAgICpcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgQSBhcyBBbmd1bGFyIExpZmVjeWNsZVxuICAgKiAgIHBhcnRpY2lwYW50IEMgYXMgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICogICBwYXJ0aWNpcGFudCBSIGFzIE5neFJlbmRlcmluZ0VuZ2luZVxuICAgKlxuICAgKiAgIEEtPj5DOiBuZ09uRGVzdHJveSgpXG4gICAqICAgYWx0IGNvbXBvbmVudCBleGlzdHNcbiAgICogICAgIEMtPj5DOiB1bnN1YnNjcmliZUV2ZW50cygpXG4gICAqICAgICBDLT4+UjogZGVzdHJveSgpXG4gICAqICAgZW5kXG4gICAqXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gY2xlYW51cCBpcyBjb21wbGV0ZVxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIGFzeW5jIG5nT25EZXN0cm95KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNvbXBvbmVudCkge1xuICAgICAgdGhpcy51bnN1YnNjcmliZUV2ZW50cygpO1xuICAgICAgTmd4UmVuZGVyaW5nRW5naW5lLmRlc3Ryb3koKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYW5kIHJlbmRlcnMgYSBkeW5hbWljIGNvbXBvbmVudC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgaGFuZGxlcyB0aGUgY3JlYXRpb24gb2YgYSBkeW5hbWljIGNvbXBvbmVudCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgdGFnLlxuICAgKiBJdCByZXRyaWV2ZXMgdGhlIGNvbXBvbmVudCBjb25zdHJ1Y3RvciBmcm9tIHRoZSByZW5kZXJpbmcgZW5naW5lLCBwcm9jZXNzZXMgaXRzIGlucHV0cyxcbiAgICogZmlsdGVycyBvdXQgdW5tYXBwZWQgcHJvcGVydGllcywgY3JlYXRlcyB0aGUgY29tcG9uZW50IGluc3RhbmNlLCBhbmQgc2V0cyB1cCBldmVudCBzdWJzY3JpcHRpb25zLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFnIC0gVGhlIHRhZyBuYW1lIG9mIHRoZSBjb21wb25lbnQgdG8gY3JlYXRlXG4gICAqIEBwYXJhbSB7S2V5VmFsdWV9IGdsb2JhbHMgLSBHbG9iYWwgcHJvcGVydGllcyB0byBwYXNzIHRvIHRoZSBjb21wb25lbnRcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICpcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgQyBhcyBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKiAgIHBhcnRpY2lwYW50IFIgYXMgTmd4UmVuZGVyaW5nRW5naW5lXG4gICAqICAgcGFydGljaXBhbnQgViBhcyBWaWV3Q29udGFpbmVyUmVmXG4gICAqXG4gICAqICAgQy0+PlI6IGNvbXBvbmVudHModGFnKVxuICAgKiAgIFItLT4+QzogUmV0dXJuIGNvbXBvbmVudCBjb25zdHJ1Y3RvclxuICAgKiAgIEMtPj5DOiByZWZsZWN0Q29tcG9uZW50VHlwZShjb21wb25lbnQpXG4gICAqICAgQy0+PkM6IFByb2Nlc3MgaW5wdXQgcHJvcGVydGllc1xuICAgKiAgIEMtPj5DOiBGaWx0ZXIgdW5tYXBwZWQgcHJvcGVydGllc1xuICAgKiAgIEMtPj5WOiBjbGVhcigpXG4gICAqICAgQy0+PlI6IGNyZWF0ZUNvbXBvbmVudChjb21wb25lbnQsIHByb3BzLCBtZXRhZGF0YSwgdmNyLCBpbmplY3RvciwgW10pXG4gICAqICAgUi0tPj5DOiBSZXR1cm4gY29tcG9uZW50IHJlZmVyZW5jZVxuICAgKiAgIEMtPj5DOiBzdWJzY3JpYmVFdmVudHMoKVxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlQ29tcG9uZW50KHRhZzogc3RyaW5nLCBnbG9iYWxzOiBLZXlWYWx1ZSA9IHt9KTogdm9pZCB7XG5cblxuICAgIGNvbnN0IGNvbXBvbmVudCA9IE5neFJlbmRlcmluZ0VuZ2luZS5jb21wb25lbnRzKHRhZylcbiAgICAgID8uY29uc3RydWN0b3IgYXMgVHlwZTx1bmtub3duPjtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHJlZmxlY3RDb21wb25lbnRUeXBlKGNvbXBvbmVudCk7XG4gICAgY29uc3QgY29tcG9uZW50SW5wdXRzID0gKG1ldGFkYXRhIGFzIENvbXBvbmVudE1pcnJvcjx1bmtub3duPikuaW5wdXRzO1xuICAgIGNvbnN0IHByb3BzID0gZ2xvYmFscz8uWydpdGVtJ10gfHwgZ2xvYmFscz8uWydwcm9wcyddIHx8IHt9O1xuICAgIGlmKHByb3BzPy5bJ3RhZyddKVxuICAgICAgZGVsZXRlIHByb3BzWyd0YWcnXTtcbiAgICAgaWYocHJvcHM/LlsnY2hpbGRyZW4nXSAmJiAhdGhpcy5jaGlsZHJlbi5sZW5ndGgpXG4gICAgICB0aGlzLmNoaWxkcmVuID0gcHJvcHNbJ2NoaWxkcmVuJ10gYXMgS2V5VmFsdWVbXTtcbiAgICBjb25zdCBpbnB1dEtleXMgPSBPYmplY3Qua2V5cyhwcm9wcyk7XG4gICAgY29uc3QgdW5tYXBwZWRLZXlzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBpbnB1dCBvZiBpbnB1dEtleXMpIHtcbiAgICAgIGlmICghaW5wdXRLZXlzLmxlbmd0aCkgYnJlYWs7XG4gICAgICBjb25zdCBwcm9wID0gY29tcG9uZW50SW5wdXRzLmZpbmQoXG4gICAgICAgIChpdGVtOiB7IHByb3BOYW1lOiBzdHJpbmcgfSkgPT4gaXRlbS5wcm9wTmFtZSA9PT0gaW5wdXQsXG4gICAgICApO1xuICAgICAgaWYgKCFwcm9wKSB7XG4gICAgICAgIGRlbGV0ZSBwcm9wc1tpbnB1dF07XG4gICAgICAgIHVubWFwcGVkS2V5cy5wdXNoKGlucHV0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnZjci5jbGVhcigpO1xuICAgIGNvbnN0IHRlbXBsYXRlID0gdGhpcy5jaGlsZHJlbj8ubGVuZ3RoID8gdGhpcy52Y3IuY3JlYXRlRW1iZWRkZWRWaWV3KHRoaXMuaW5uZXIgYXMgVGVtcGxhdGVSZWY8dW5rbm93bj4sIHRoaXMuaW5qZWN0b3IpLnJvb3ROb2RlcyA6IFtdO1xuICAgIHRoaXMuY29tcG9uZW50ID0gTmd4UmVuZGVyaW5nRW5naW5lLmNyZWF0ZUNvbXBvbmVudChcbiAgICAgIGNvbXBvbmVudCxcbiAgICAgIHByb3BzLFxuICAgICAgbWV0YWRhdGEgYXMgQ29tcG9uZW50TWlycm9yPHVua25vd24+LFxuICAgICAgdGhpcy52Y3IsXG4gICAgICB0aGlzLmluamVjdG9yIGFzIEluamVjdG9yLFxuICAgICAgdGVtcGxhdGUsXG4gICAgKTtcbiAgICB0aGlzLnN1YnNjcmliZUV2ZW50cygpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVQYXJlbnRDb21wb25lbnQoKSB7XG4gICAgY29uc3QgeyBjb21wb25lbnQsIGlucHV0cyB9ID0gdGhpcy5wYXJlbnQgYXMgS2V5VmFsdWU7XG4gICAgY29uc3QgbWV0YWRhdGEgPSByZWZsZWN0Q29tcG9uZW50VHlwZShjb21wb25lbnQpIGFzIENvbXBvbmVudE1pcnJvcjx1bmtub3duPjtcbiAgICBjb25zdCB0ZW1wbGF0ZSA9IHRoaXMudmNyLmNyZWF0ZUVtYmVkZGVkVmlldyh0aGlzLmlubmVyIGFzIFRlbXBsYXRlUmVmPHVua25vd24+LCB0aGlzLmluamVjdG9yKS5yb290Tm9kZXM7XG4gICAgdGhpcy5jb21wb25lbnQgPSBOZ3hSZW5kZXJpbmdFbmdpbmUuY3JlYXRlQ29tcG9uZW50KFxuICAgICAgY29tcG9uZW50LFxuICAgICAgaW5wdXRzLFxuICAgICAgbWV0YWRhdGEsXG4gICAgICB0aGlzLnZjcixcbiAgICAgIHRoaXMuaW5qZWN0b3IsXG4gICAgICB0ZW1wbGF0ZSxcbiAgICApO1xuICAgIHRoaXMuc3Vic2NyaWJlRXZlbnRzKCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFN1YnNjcmliZXMgdG8gZXZlbnRzIGVtaXR0ZWQgYnkgdGhlIGR5bmFtaWMgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIG1ldGhvZCBzZXRzIHVwIHN1YnNjcmlwdGlvbnMgdG8gYWxsIEV2ZW50RW1pdHRlciBwcm9wZXJ0aWVzIG9mIHRoZVxuICAgKiBkeW5hbWljYWxseSBjcmVhdGVkIGNvbXBvbmVudC4gV2hlbiBhbiBldmVudCBpcyBlbWl0dGVkIGJ5IHRoZSBkeW5hbWljIGNvbXBvbmVudCxcbiAgICogaXQgaXMgY2FwdHVyZWQgYW5kIHJlLWVtaXR0ZWQgdGhyb3VnaCB0aGUgbGlzdGVuRXZlbnQgb3V0cHV0IHByb3BlcnR5IHdpdGggYWRkaXRpb25hbFxuICAgKiBtZXRhZGF0YSBhYm91dCB0aGUgZXZlbnQgc291cmNlLlxuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDIGFzIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqICAgcGFydGljaXBhbnQgRCBhcyBEeW5hbWljIENvbXBvbmVudFxuICAgKiAgIHBhcnRpY2lwYW50IFAgYXMgUGFyZW50IENvbXBvbmVudFxuICAgKlxuICAgKiAgIEMtPj5DOiBzdWJzY3JpYmVFdmVudHMoKVxuICAgKiAgIEMtPj5EOiBHZXQgaW5zdGFuY2UgcHJvcGVydGllc1xuICAgKiAgIGxvb3AgRm9yIGVhY2ggcHJvcGVydHlcbiAgICogICAgIEMtPj5DOiBDaGVjayBpZiBwcm9wZXJ0eSBpcyBFdmVudEVtaXR0ZXJcbiAgICogICAgIGFsdCBpcyBFdmVudEVtaXR0ZXJcbiAgICogICAgICAgQy0+PkQ6IFN1YnNjcmliZSB0byBldmVudFxuICAgKiAgICAgICBELS0+PkM6IEV2ZW50IGVtaXR0ZWRcbiAgICogICAgICAgQy0+PlA6IFJlLWVtaXQgZXZlbnQgd2l0aCBtZXRhZGF0YVxuICAgKiAgICAgZW5kXG4gICAqICAgZW5kXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgcHJpdmF0ZSBzdWJzY3JpYmVFdmVudHMoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuY29tcG9uZW50KSB7XG4gICAgICBjb25zdCBpbnN0YW5jZSA9IHRoaXMuY29tcG9uZW50Py5pbnN0YW5jZSBhcyBLZXlWYWx1ZTtcbiAgICAgIGNvbnN0IGNvbXBvbmVudEtleXMgPSBPYmplY3Qua2V5cyhpbnN0YW5jZSk7XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBjb21wb25lbnRLZXlzKSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gaW5zdGFuY2Vba2V5XTtcbiAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgRXZlbnRFbWl0dGVyKVxuICAgICAgICAgIChpbnN0YW5jZSBhcyBLZXlWYWx1ZSlba2V5XS5zdWJzY3JpYmUoXG4gICAgICAgICAgICAoZXZlbnQ6IFBhcnRpYWw8QmFzZUN1c3RvbUV2ZW50PikgPT4ge1xuICAgICAgICAgICAgICB0aGlzLmxpc3RlbkV2ZW50LmVtaXQoe1xuICAgICAgICAgICAgICAgIG5hbWU6IGtleSxcbiAgICAgICAgICAgICAgICAuLi5ldmVudCxcbiAgICAgICAgICAgICAgfSBhcyBSZW5kZXJlckN1c3RvbUV2ZW50KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVuc3Vic2NyaWJlcyBmcm9tIGFsbCBldmVudHMgb2YgdGhlIGR5bmFtaWMgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIG1ldGhvZCBjbGVhbnMgdXAgZXZlbnQgc3Vic2NyaXB0aW9ucyB3aGVuIHRoZSBjb21wb25lbnQgaXMgYmVpbmcgZGVzdHJveWVkLlxuICAgKiBJdCBpdGVyYXRlcyB0aHJvdWdoIGFsbCBwcm9wZXJ0aWVzIG9mIHRoZSBkeW5hbWljIGNvbXBvbmVudCBpbnN0YW5jZSBhbmQgdW5zdWJzY3JpYmVzXG4gICAqIGZyb20gYW55IEV2ZW50RW1pdHRlciBwcm9wZXJ0aWVzIHRvIHByZXZlbnQgbWVtb3J5IGxlYWtzIGFuZCB1bmV4cGVjdGVkIGJlaGF2aW9yIGFmdGVyXG4gICAqIHRoZSBjb21wb25lbnQgaXMgZGVzdHJveWVkLlxuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDIGFzIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqICAgcGFydGljaXBhbnQgRCBhcyBEeW5hbWljIENvbXBvbmVudFxuICAgKlxuICAgKiAgIEMtPj5DOiB1bnN1YnNjcmliZUV2ZW50cygpXG4gICAqICAgQy0+PkQ6IEdldCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAqICAgbG9vcCBGb3IgZWFjaCBwcm9wZXJ0eVxuICAgKiAgICAgQy0+PkM6IENoZWNrIGlmIHByb3BlcnR5IGlzIEV2ZW50RW1pdHRlclxuICAgKiAgICAgYWx0IGlzIEV2ZW50RW1pdHRlclxuICAgKiAgICAgICBDLT4+RDogVW5zdWJzY3JpYmUgZnJvbSBldmVudFxuICAgKiAgICAgZW5kXG4gICAqICAgZW5kXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgcHJpdmF0ZSB1bnN1YnNjcmliZUV2ZW50cygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jb21wb25lbnQpIHtcbiAgICAgIGNvbnN0IGluc3RhbmNlID0gdGhpcy5jb21wb25lbnQ/Lmluc3RhbmNlIGFzIEtleVZhbHVlO1xuICAgICAgY29uc3QgY29tcG9uZW50S2V5cyA9IE9iamVjdC5rZXlzKGluc3RhbmNlKTtcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIGNvbXBvbmVudEtleXMpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBpbnN0YW5jZVtrZXldO1xuICAgICAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBFdmVudEVtaXR0ZXIpIGluc3RhbmNlW2tleV0udW5zdWJzY3JpYmUoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiIsIjwhLS0gS2VlcCB0byBhdm9pZCBpZCBjb25mbGljdHMgLS0+XG48ZGl2IFtpZF09XCJ1aWRcIj48L2Rpdj5cblxuPG5nLXRlbXBsYXRlICNjb21wb25lbnRWaWV3Q29udGFpbmVyPjwvbmctdGVtcGxhdGU+XG48bmctdGVtcGxhdGUgI2lubmVyPlxuICBAaWYocGFyZW50Py5jaGlsZHJlbj8ubGVuZ3RoKSB7XG4gICAgQGZvcihjaGlsZCBvZiBwYXJlbnQuY2hpbGRyZW47IHRyYWNrIGNoaWxkKSB7XG4gICAgICAgIEBpZighY2hpbGQuY2hpbGRyZW4/Lmxlbmd0aCkge1xuICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICAqbmdDb21wb25lbnRPdXRsZXQ9XCJcbiAgICAgICAgICAgICAgICAgIGNoaWxkLmNvbXBvbmVudDtcbiAgICAgICAgICAgICAgICAgIGluamVjdG9yOiBjaGlsZC5pbmplY3RvcjtcbiAgICAgICAgICAgICAgICAgIGlucHV0czogY2hpbGQuaW5wdXRzO1xuICAgICAgICAgICAgICAgICAgY29udGVudDpjaGlsZC5jb250ZW50O1xuICAgICAgICAgICAgICAgIFwiXG4gICAgICAgICAgLz5cbiAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgPG5neC1kZWNhZi1jb21wb25lbnQtcmVuZGVyZXIgW3BhcmVudF09XCJjaGlsZFwiPiA8L25neC1kZWNhZi1jb21wb25lbnQtcmVuZGVyZXI+XG4gICAgICAgIH1cbiAgICB9XG4gIH1cbiAgQGlmKGNoaWxkcmVuPy5sZW5ndGgpIHtcbiAgICBAZm9yKGNoaWxkIG9mIGNoaWxkcmVuOyB0cmFjayBjaGlsZCkge1xuICAgICAgQGlmKGNoaWxkLmNoaWxkcmVuPy5sZW5ndGgpIHtcbiAgICAgIDxuZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyIFtwYXJlbnRdPVwiY2hpbGRcIj4gPC9uZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyPlxuICAgICAgfSBAZWxzZSB7XG4gICAgICAgIDxuZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyXG4gICAgICAgICAgW3RhZ109XCJjaGlsZD8udGFnXCJcbiAgICAgICAgICAobGlzdGVuRXZlbnQpPVwiaGFuZGxlRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgW2dsb2JhbHNdPVwie3Byb3BzOiBjaGlsZC5wcm9wc31cIiAvPlxuICAgICAgfVxuICAgIH1cbiAgfVxuPC9uZy10ZW1wbGF0ZT5cblxuXG4iXX0=