@decaf-ts/for-angular 0.0.3 → 0.0.5

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 (87) hide show
  1. package/LICENSE.md +659 -21
  2. package/README.md +37 -242
  3. package/dist/lib/README.md +92 -0
  4. package/dist/lib/assets/i18n/en.json +131 -0
  5. package/dist/lib/assets/images/angular-logo.svg +45 -0
  6. package/dist/lib/assets/images/decaf-logo-black.svg +22 -0
  7. package/dist/lib/assets/images/decaf-logo-lw.svg +50 -0
  8. package/dist/lib/assets/images/decaf-logo-white.svg +22 -0
  9. package/dist/lib/assets/images/decaf-logo.svg +54 -0
  10. package/dist/lib/components/component-renderer/component-renderer.component.d.ts +267 -0
  11. package/dist/lib/components/crud-field/crud-field.component.d.ts +447 -0
  12. package/dist/lib/components/crud-form/crud-form.component.d.ts +102 -0
  13. package/dist/lib/components/model-renderer/model-renderer.component.d.ts +97 -0
  14. package/dist/lib/engine/DynamicModule.d.ts +17 -0
  15. package/dist/{for-angular → lib}/engine/NgxCrudFormField.d.ts +37 -30
  16. package/dist/lib/engine/NgxFormService.d.ts +167 -0
  17. package/dist/lib/engine/NgxRenderingEngine.d.ts +128 -0
  18. package/dist/lib/engine/NgxRenderingEngine2.d.ts +251 -0
  19. package/dist/lib/engine/ValidatorFactory.d.ts +15 -0
  20. package/dist/lib/engine/constants.d.ts +151 -0
  21. package/dist/lib/engine/decorators.d.ts +25 -0
  22. package/dist/lib/engine/index.d.ts +15 -0
  23. package/dist/lib/engine/types.d.ts +293 -0
  24. package/dist/lib/esm2022/components/component-renderer/component-renderer.component.mjs +309 -0
  25. package/dist/lib/esm2022/components/crud-field/crud-field.component.mjs +288 -0
  26. package/dist/lib/esm2022/components/crud-form/constants.mjs +14 -0
  27. package/dist/lib/esm2022/components/crud-form/crud-form.component.mjs +140 -0
  28. package/dist/lib/esm2022/components/crud-form/types.mjs +2 -0
  29. package/dist/lib/esm2022/components/model-renderer/model-renderer.component.mjs +137 -0
  30. package/dist/lib/esm2022/engine/DynamicModule.mjs +18 -0
  31. package/dist/lib/esm2022/engine/NgxCrudFormField.mjs +117 -0
  32. package/dist/lib/esm2022/engine/NgxFormService.mjs +315 -0
  33. package/dist/lib/esm2022/engine/NgxRenderingEngine.mjs +194 -0
  34. package/dist/lib/esm2022/engine/NgxRenderingEngine2.mjs +333 -0
  35. package/dist/lib/esm2022/engine/ValidatorFactory.mjs +102 -0
  36. package/dist/lib/esm2022/engine/constants.mjs +160 -0
  37. package/dist/lib/esm2022/engine/decorators.mjs +38 -0
  38. package/dist/lib/esm2022/engine/index.mjs +16 -0
  39. package/dist/lib/esm2022/engine/types.mjs +2 -0
  40. package/dist/lib/esm2022/for-angular.module.mjs +118 -0
  41. package/dist/lib/esm2022/interfaces.mjs +2 -0
  42. package/dist/lib/esm2022/public-apis.mjs +13 -0
  43. package/dist/lib/fesm2022/decaf-ts-for-angular.mjs +2138 -0
  44. package/dist/lib/fesm2022/decaf-ts-for-angular.mjs.map +1 -0
  45. package/dist/lib/for-angular.module.d.ts +44 -0
  46. package/dist/lib/interfaces.d.ts +28 -0
  47. package/dist/lib/public-apis.d.ts +12 -0
  48. package/package.json +74 -25
  49. package/dist/for-angular/README.md +0 -297
  50. package/dist/for-angular/assets/i18n/en.json +0 -21
  51. package/dist/for-angular/components/decaf-crud-field/decaf-crud-field.component.d.ts +0 -22
  52. package/dist/for-angular/components/decaf-crud-form/decaf-crud-form.component.d.ts +0 -28
  53. package/dist/for-angular/components/decaf-model-renderer/decaf-model-renderer.component.d.ts +0 -20
  54. package/dist/for-angular/directives/decaf-field.directive.d.ts +0 -8
  55. package/dist/for-angular/engine/DynamicModule.d.ts +0 -2
  56. package/dist/for-angular/engine/NgxFormService.d.ts +0 -119
  57. package/dist/for-angular/engine/NgxRenderingEngine.d.ts +0 -17
  58. package/dist/for-angular/engine/ValidatorFactory.d.ts +0 -4
  59. package/dist/for-angular/engine/constants.d.ts +0 -10
  60. package/dist/for-angular/engine/decorators.d.ts +0 -1
  61. package/dist/for-angular/engine/index.d.ts +0 -5
  62. package/dist/for-angular/engine/types.d.ts +0 -32
  63. package/dist/for-angular/esm2022/components/decaf-crud-field/decaf-crud-field.component.mjs +0 -66
  64. package/dist/for-angular/esm2022/components/decaf-crud-form/constants.mjs +0 -14
  65. package/dist/for-angular/esm2022/components/decaf-crud-form/decaf-crud-form.component.mjs +0 -84
  66. package/dist/for-angular/esm2022/components/decaf-crud-form/types.mjs +0 -2
  67. package/dist/for-angular/esm2022/components/decaf-model-renderer/decaf-model-renderer.component.mjs +0 -46
  68. package/dist/for-angular/esm2022/directives/decaf-field.directive.mjs +0 -23
  69. package/dist/for-angular/esm2022/engine/DynamicModule.mjs +0 -3
  70. package/dist/for-angular/esm2022/engine/NgxCrudFormField.mjs +0 -118
  71. package/dist/for-angular/esm2022/engine/NgxFormService.mjs +0 -232
  72. package/dist/for-angular/esm2022/engine/NgxRenderingEngine.mjs +0 -35
  73. package/dist/for-angular/esm2022/engine/ValidatorFactory.mjs +0 -48
  74. package/dist/for-angular/esm2022/engine/constants.mjs +0 -12
  75. package/dist/for-angular/esm2022/engine/decorators.mjs +0 -17
  76. package/dist/for-angular/esm2022/engine/index.mjs +0 -6
  77. package/dist/for-angular/esm2022/engine/types.mjs +0 -2
  78. package/dist/for-angular/esm2022/interfaces.mjs +0 -2
  79. package/dist/for-angular/esm2022/public-apis.mjs +0 -5
  80. package/dist/for-angular/fesm2022/decaf-ts-for-angular.mjs +0 -675
  81. package/dist/for-angular/fesm2022/decaf-ts-for-angular.mjs.map +0 -1
  82. package/dist/for-angular/interfaces.d.ts +0 -8
  83. package/dist/for-angular/public-apis.d.ts +0 -4
  84. /package/dist/{for-angular/components/decaf-crud-form → lib/components/crud-form}/constants.d.ts +0 -0
  85. /package/dist/{for-angular/components/decaf-crud-form → lib/components/crud-form}/types.d.ts +0 -0
  86. /package/dist/{for-angular → lib}/esm2022/decaf-ts-for-angular.mjs +0 -0
  87. /package/dist/{for-angular → lib}/index.d.ts +0 -0
@@ -0,0 +1,293 @@
1
+ import { IonCheckbox, IonInput, IonSelect, IonTextarea } from '@ionic/angular';
2
+ import { TextFieldTypes } from '@ionic/core';
3
+ import { Injector, Type } from '@angular/core';
4
+ import { FormControl, FormGroup } from '@angular/forms';
5
+ import { FieldProperties } from '@decaf-ts/ui-decorators';
6
+ export type KeyValue = Record<string, any>;
7
+ /**
8
+ * @description Element size options for UI components
9
+ * @summary Defines the possible size values that can be applied to UI elements.
10
+ * These sizes control the dimensions and layout behavior of components.
11
+ * @typedef {('small'|'medium'|'large'|'xlarge'|'2xlarge'|'auto'|'expand'|'block')} ElementSizes
12
+ * @memberOf module:engine
13
+ */
14
+ export type ElementSizes = 'small' | 'medium' | 'large' | 'xlarge' | '2xlarge' | 'auto' | 'expand' | 'block';
15
+ /**
16
+ * @description Basic position options for UI elements
17
+ * @summary Defines the possible position values that can be applied to UI elements.
18
+ * These positions control the alignment and placement of components.
19
+ * @typedef {('left'|'center'|'right'|'top'|'bottom')} ElementPositions
20
+ * @memberOf module:engine
21
+ */
22
+ export type ElementPositions = 'left' | 'center' | 'right' | 'top' | 'bottom';
23
+ /**
24
+ * @description Extended position options for flex layouts
25
+ * @summary Extends the basic ElementPositions with additional flex-specific position values.
26
+ * These positions are used for controlling alignment and distribution in flex containers.
27
+ * @typedef {(ElementPositions|'stretch'|'middle'|'around'|'between')} FlexPositions
28
+ * @memberOf module:engine
29
+ */
30
+ export type FlexPositions = ElementPositions | 'stretch' | 'middle' | 'around' | 'between';
31
+ /**
32
+ * @description Update mode options for form fields
33
+ * @summary Defines when form field values should be updated in the model.
34
+ * - 'change': Update on every change event
35
+ * - 'blur': Update when the field loses focus
36
+ * - 'submit': Update only when the form is submitted
37
+ * @typedef {('change'|'blur'|'submit')} FieldUpdateMode
38
+ * @memberOf module:engine
39
+ */
40
+ export type FieldUpdateMode = 'change' | 'blur' | 'submit';
41
+ /**
42
+ * @description Metadata structure for Angular components
43
+ * @summary Defines the structure of metadata for Angular components, including
44
+ * change detection strategy, selector, standalone status, imports, template, and styles.
45
+ * This is used for reflection and dynamic component creation.
46
+ * @interface ComponentMetadata
47
+ * @property {number} changeDetection - The change detection strategy number
48
+ * @property {string} selector - The CSS selector for the component
49
+ * @property {boolean} standalone - Whether the component is standalone
50
+ * @property imports - Array of imported modules/components
51
+ * @property {string} template - The HTML template for the component
52
+ * @property {string[]} styles - Array of CSS styles for the component
53
+ * @memberOf module:engine
54
+ */
55
+ export interface ComponentMetadata {
56
+ changeDetection: number;
57
+ selector: string;
58
+ standalone: boolean;
59
+ imports: (new (...args: unknown[]) => unknown)[];
60
+ template: string;
61
+ styles: string[];
62
+ }
63
+ /**
64
+ * @description Output structure from the Angular rendering engine
65
+ * @summary Defines the structure of the output produced by the NgxRenderingEngine
66
+ * when rendering a component. Contains the component type, inputs, injector,
67
+ * content nodes, and child components.
68
+ * @typedef {Object} AngularDynamicOutput
69
+ * @property {Type<unknown>} component - The Angular component type
70
+ * @property {string} [rendererId] - Optional unique ID for the rendered component
71
+ * @property {Record<string, unknown>} [inputs] - Optional input properties for the component
72
+ * @property {Injector} [injector] - Optional Angular injector for dependency injection
73
+ * @property {Node[][]} [content] - Optional content nodes for projection
74
+ * @property {AngularDynamicOutput[]} [children] - Optional child components
75
+ * @property {Type<unknown>} [instance] - Optional component instance
76
+ * @property {FormGroup} [formGroup] - Optional component FormGroup
77
+ * @property {FormControl} [formControl] - Optional component FormControl
78
+ * @memberOf module:engine
79
+ */
80
+ export interface AngularDynamicOutput {
81
+ component: Type<unknown>;
82
+ rendererId?: string;
83
+ inputs?: Record<string, unknown>;
84
+ injector?: Injector;
85
+ content?: Node[][];
86
+ children?: AngularDynamicOutput[];
87
+ instance?: Type<unknown>;
88
+ formGroup?: FormGroup;
89
+ formControl?: FormControl;
90
+ }
91
+ /**
92
+ * @description Interface for models that can be rendered
93
+ * @summary Defines the basic structure for models that can be rendered by the engine.
94
+ * Contains an optional rendererId that uniquely identifies the rendered instance.
95
+ * @interface RenderedModel
96
+ * @property {string} [rendererId] - Optional unique ID for the rendered model instance
97
+ * @memberOf module:engine
98
+ */
99
+ export interface RenderedModel {
100
+ rendererId?: string;
101
+ }
102
+ /**
103
+ * @description Possible input types for form fields
104
+ * @summary Defines the possible input types that can be used in form fields.
105
+ * Includes standard HTML input types like checkbox, radio, and select,
106
+ * as well as Ionic's TextFieldTypes and textarea.
107
+ * @typedef {('checkbox'|'radio'|'select'|TextFieldTypes|'textarea')} PossibleInputTypes
108
+ * @memberOf module:engine
109
+ */
110
+ export type PossibleInputTypes = 'checkbox' | 'radio' | 'select' | TextFieldTypes | 'textarea';
111
+ /**
112
+ * @description Field definition for Angular components
113
+ * @summary A comprehensive type that combines properties from various Ionic components
114
+ * to define the structure of a field in an Angular form. It omits certain properties
115
+ * from IonInput, picks specific properties from IonSelect, IonTextarea, and IonCheckbox,
116
+ * and adds custom properties like type and className.
117
+ * @typedef {Object} AngularFieldDefinition
118
+ * @property {PossibleInputTypes} type - The type of input field
119
+ * @property {string|string[]} className - CSS class name(s) for the field
120
+ * @property {string} [cancelText] - Text for the cancel button (from IonSelect)
121
+ * @property {string} [interface] - Interface style for select (from IonSelect)
122
+ * @property {string} [selectedText] - Text for selected option (from IonSelect)
123
+ * @property {Object} [interfaceOptions] - Options for the interface (from IonSelect)
124
+ * @property {number} [rows] - Number of rows for textarea (from IonTextarea)
125
+ * @property {number} [cols] - Number of columns for textarea (from IonTextarea)
126
+ * @property {string} [alignment] - Alignment of checkbox (from IonCheckbox)
127
+ * @property {string} [justify] - Justification of checkbox (from IonCheckbox)
128
+ * @property {boolean} [checked] - Whether checkbox is checked (from IonCheckbox)
129
+ * @memberOf module:engine
130
+ */
131
+ export type AngularFieldDefinition = Omit<IonInput, 'ionInput' | 'ionFocus' | 'ionChange' | 'ionBlur' | 'getInputElement' | 'setFocus' | 'label' | 'el' | 'z' | 'type'> & Pick<IonSelect, 'cancelText' | 'interface' | 'selectedText' | 'interfaceOptions'> & Pick<IonTextarea, 'rows' | 'cols'> & Pick<IonCheckbox, 'alignment' | 'justify' | 'checked'> & {
132
+ type: PossibleInputTypes;
133
+ className: string | string[];
134
+ } & Record<string, unknown>;
135
+ /**
136
+ * @description String or boolean representation of a boolean value
137
+ * @summary Represents a value that can be either a boolean or a string representation of a boolean.
138
+ * This is useful for handling attribute values that can be specified as either strings or booleans.
139
+ * @typedef {('true'|'false'|boolean)} StringOrBoolean
140
+ * @memberOf module:engine
141
+ */
142
+ export type StringOrBoolean = 'true' | 'false' | boolean;
143
+ /**
144
+ * @description Option type for select inputs
145
+ * @summary Extends the InputOption interface with a selected property to indicate
146
+ * whether the option is selected by default.
147
+ * @memberOf module:engine
148
+ */
149
+ export type SelectOption = InputOption & {
150
+ selected?: boolean;
151
+ };
152
+ /**
153
+ * @description Option type for radio inputs
154
+ * @summary Extends the InputOption interface with a checked property to indicate
155
+ * whether the option is checked by default.
156
+ * @memberOf module:engine
157
+ */
158
+ export type RadioOption = InputOption & {
159
+ checked?: boolean;
160
+ };
161
+ /**
162
+ * @description Option type for checkbox inputs
163
+ * @summary Alias for RadioOption, as checkbox options have the same structure as radio options.
164
+ * @typedef {RadioOption} CheckboxOption
165
+ * @memberOf module:engine
166
+ */
167
+ export type CheckboxOption = RadioOption;
168
+ /**
169
+ * @description Base option type for input components
170
+ * @summary Defines the common structure for options used in select, radio, and checkbox inputs.
171
+ * Contains properties for the display text, value, disabled state, CSS class, and icon.
172
+ * @interface InputOption
173
+ * @property {string} text - The display text for the option
174
+ * @property {string|number} value - The value associated with the option
175
+ * @property {StringOrBoolean} [disabled] - Whether the option is disabled
176
+ * @property {string} [className] - CSS class name for styling the option
177
+ * @property {string} [icon] - Icon to display with the option
178
+ * @memberOf module:engine
179
+ */
180
+ export interface InputOption {
181
+ text: string;
182
+ value: string | number;
183
+ disabled?: StringOrBoolean;
184
+ className?: string;
185
+ icon?: string;
186
+ }
187
+ /**
188
+ * @description Target options for HTML forms
189
+ * @summary Defines the possible target values for HTML forms, including standard targets
190
+ * like '_blank', '_self', '_parent', and '_top', as well as custom string values.
191
+ * @typedef {('_blank'|'_self'|'_parent'|'_top'|string)} HTMLFormTarget
192
+ * @memberOf module:engine
193
+ */
194
+ export type HTMLFormTarget = '_blank' | '_self' | '_parent' | '_top' | string;
195
+ /**
196
+ * @description Interface for list component refresh events
197
+ * @summary Defines the structure of a refresh event for list components.
198
+ * Contains an array of key-value pairs representing the new data for the list.
199
+ * @interface IListComponentRefreshEvent
200
+ * @property {KeyValue[]} data - Array of key-value pairs representing the new data
201
+ * @memberOf module:engine
202
+ */
203
+ export interface IListComponentRefreshEvent {
204
+ data: KeyValue[];
205
+ }
206
+ export interface FormServiceControl {
207
+ control: FormGroup;
208
+ props: AngularFieldDefinition;
209
+ }
210
+ /**
211
+ * @description Type for form service controls
212
+ * @summary Defines the structure of form controls managed by the form service.
213
+ * It's a nested record where the outer key is the form group name, the inner key
214
+ * is the control name, and the value contains the form group and field properties.
215
+ * @typedef {Record<string, Record<string, { control: FormGroup; props: AngularFieldDefinition }>>} FormServiceControls
216
+ * @memberOf module:engine
217
+ */
218
+ export type FormServiceControls = Record<string, Record<string, FormServiceControl>>;
219
+ /**
220
+ * @description Interface for model render custom events
221
+ * @summary Defines the structure of custom events triggered during model rendering.
222
+ * Contains the event detail, component name, and event name.
223
+ * @interface ModelRenderCustomEvent
224
+ * @property {BaseCustomEvent} detail - The detailed event information
225
+ * @property {string} component - The component that triggered the event
226
+ * @property {string} name - The name of the event
227
+ * @memberOf module:engine
228
+ */
229
+ export interface ModelRenderCustomEvent {
230
+ detail: BaseCustomEvent;
231
+ component: string;
232
+ name: string;
233
+ }
234
+ /**
235
+ * @description Interface for list item custom events
236
+ * @summary Defines the structure of custom events triggered by list items.
237
+ * Extends BaseCustomEvent with additional properties for the action and primary key.
238
+ * @interface ListItemCustomEvent
239
+ * @property {string} action - The action performed on the list item
240
+ * @property {string} [pk] - Optional primary key of the affected item
241
+ * @property {any} data - The data associated with the event (inherited from BaseCustomEvent)
242
+ * @property {HTMLElement} [target] - The target element (inherited from BaseCustomEvent)
243
+ * @property {string} [name] - The name of the event (inherited from BaseCustomEvent)
244
+ * @property {string} component - The component that triggered the event (inherited from BaseCustomEvent)
245
+ * @memberOf module:engine
246
+ */
247
+ export interface ListItemCustomEvent extends BaseCustomEvent {
248
+ action: string;
249
+ pk?: string;
250
+ }
251
+ /**
252
+ * @description Base interface for custom events
253
+ * @summary Defines the base structure for custom events in the application.
254
+ * Contains properties for the event data, target element, name, and component.
255
+ * @interface BaseCustomEvent
256
+ * @property {any} data - The data associated with the event
257
+ * @property {HTMLElement} [target] - The target element that triggered the event
258
+ * @property {string} [name] - The name of the event
259
+ * @property {string} component - The component that triggered the event
260
+ * @memberOf module:engine
261
+ */
262
+ export interface BaseCustomEvent {
263
+ data: any;
264
+ target?: HTMLElement;
265
+ name?: string;
266
+ component: string;
267
+ }
268
+ /**
269
+ * @description Base interface for custom events
270
+ * @summary Defines the base structure for custom events in the application.
271
+ * Contains properties for the event data, target element, name, and component.
272
+ * @interface BaseCustomEvent
273
+ * @property {any} data - The data associated with the event
274
+ * @property {HTMLElement} [target] - The target element that triggered the event
275
+ * @property {string} [name] - The name of the event
276
+ * @property {string} component - The component that triggered the event
277
+ * @memberOf module:engine
278
+ */
279
+ export type CrudFormEvent = BaseCustomEvent & {
280
+ handlers?: Record<string, any>;
281
+ };
282
+ export interface ComponentInput extends FieldProperties {
283
+ updateMode?: FieldUpdateMode;
284
+ formGroup?: FormGroup;
285
+ formControl?: FormControl;
286
+ }
287
+ export interface ComponentConfig {
288
+ component: string;
289
+ inputs: ComponentInput;
290
+ injector: any;
291
+ children?: ComponentConfig[];
292
+ }
293
+ export type FormParentGroup = [FormGroup, string];
@@ -0,0 +1,309 @@
1
+ import { Component, EnvironmentInjector, EventEmitter, inject, Input, Output, reflectComponentType, TemplateRef, ViewChild, ViewContainerRef, } from '@angular/core';
2
+ import { NgxRenderingEngine2 } from 'src/lib/engine/NgxRenderingEngine2';
3
+ import { ForAngularModule, getLogger } from 'src/lib/for-angular.module';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/common";
6
+ /**
7
+ * @description Dynamic component renderer for Decaf Angular applications.
8
+ * @summary This component provides a flexible way to dynamically render Angular components
9
+ * at runtime based on a tag name. It handles the creation, property binding, and event
10
+ * subscription for dynamically loaded components. This is particularly useful for
11
+ * building configurable UIs where components need to be determined at runtime.
12
+ *
13
+ * @component {ComponentRendererComponent}
14
+ * @example
15
+ * <ngx-decaf-component-renderer
16
+ * [tag]="tag"
17
+ * [globals]="globals"
18
+ * (listenEvent)="listenEvent($event)">
19
+ * </ngx-decaf-component-renderer>
20
+ *
21
+ * @mermaid
22
+ * classDiagram
23
+ * class ComponentRendererComponent {
24
+ * +ViewContainerRef vcr
25
+ * +string tag
26
+ * +Record~string, unknown~ globals
27
+ * +EnvironmentInjector injector
28
+ * +ComponentRef~unknown~ component
29
+ * +EventEmitter~ModelRenderCustomEvent~ listenEvent
30
+ * +ngOnInit()
31
+ * +ngOnDestroy()
32
+ * +ngOnChanges(changes)
33
+ * -createComponent(tag, globals)
34
+ * -subscribeEvents()
35
+ * -unsubscribeEvents()
36
+ * }
37
+ * ComponentRendererComponent --|> OnInit
38
+ * ComponentRendererComponent --|> OnChanges
39
+ * ComponentRendererComponent --|> OnDestroy
40
+ *
41
+ * @implements {OnInit}
42
+ * @implements {OnChanges}
43
+ * @implements {OnDestroy}
44
+ */
45
+ export class ComponentRendererComponent {
46
+ /**
47
+ * @description Creates an instance of ComponentRendererComponent.
48
+ * @summary Initializes a new ComponentRendererComponent. This component doesn't require
49
+ * any dependencies to be injected in its constructor as it uses the inject function to
50
+ * obtain the EnvironmentInjector.
51
+ *
52
+ * @memberOf ComponentRendererComponent
53
+ */
54
+ constructor() {
55
+ /**
56
+ * @description Global properties to pass to the rendered component.
57
+ * @summary This input property allows passing a set of properties to the dynamically
58
+ * rendered component. These properties will be mapped to the component's inputs if they
59
+ * match. Properties that don't match any input on the target component will be filtered out
60
+ * with a warning.
61
+ *
62
+ * @type {Record<string, unknown>}
63
+ * @default {}
64
+ * @memberOf ComponentRendererComponent
65
+ */
66
+ this.globals = {};
67
+ /**
68
+ * @description Injector used for dependency injection in the dynamic component.
69
+ * @summary This injector is used when creating the dynamic component to provide it with
70
+ * access to the application's dependency injection system. It ensures that the dynamically
71
+ * created component can access the same services and dependencies as statically created
72
+ * components.
73
+ *
74
+ * @type {EnvironmentInjector}
75
+ * @memberOf ComponentRendererComponent
76
+ */
77
+ this.injector = inject(EnvironmentInjector);
78
+ /**
79
+ * @description Event emitter for events from the rendered component.
80
+ * @summary This output property emits events that originate from the dynamically rendered
81
+ * component. It allows the parent component to listen for and respond to events from the
82
+ * dynamic component, creating a communication channel between the parent and the dynamically
83
+ * rendered child.
84
+ *
85
+ * @type {EventEmitter<ModelRenderCustomEvent>}
86
+ * @memberOf ComponentRendererComponent
87
+ */
88
+ this.listenEvent = new EventEmitter();
89
+ this.parent = undefined;
90
+ this.logger = getLogger(this);
91
+ }
92
+ /**
93
+ * @description Initializes the component after Angular first displays the data-bound properties.
94
+ * @summary Sets up the component by creating the dynamic component specified by the tag input.
95
+ * This method is called once when the component is initialized and triggers the dynamic
96
+ * component creation process with the provided tag name and global properties.
97
+ *
98
+ * @mermaid
99
+ * sequenceDiagram
100
+ * participant A as Angular Lifecycle
101
+ * participant C as ComponentRendererComponent
102
+ * participant R as NgxRenderingEngine2
103
+ *
104
+ * A->>C: ngOnInit()
105
+ * C->>C: createComponent(tag, globals)
106
+ * C->>R: components(tag)
107
+ * R-->>C: Return component constructor
108
+ * C->>C: Process component inputs
109
+ * C->>C: Create component instance
110
+ * C->>C: subscribeEvents()
111
+ *
112
+ * @return {void}
113
+ * @memberOf ComponentRendererComponent
114
+ */
115
+ ngOnInit() {
116
+ if (!this.parent)
117
+ this.createComponent(this.tag, this.globals);
118
+ this.createParentComponent();
119
+ }
120
+ /**
121
+ * @description Cleans up resources when the component is destroyed.
122
+ * @summary Performs cleanup operations when the component is being destroyed by Angular.
123
+ * This includes unsubscribing from all event emitters of the dynamic component and
124
+ * destroying the rendering engine instance to prevent memory leaks.
125
+ *
126
+ * @mermaid
127
+ * sequenceDiagram
128
+ * participant A as Angular Lifecycle
129
+ * participant C as ComponentRendererComponent
130
+ * participant R as NgxRenderingEngine2
131
+ *
132
+ * A->>C: ngOnDestroy()
133
+ * alt component exists
134
+ * C->>C: unsubscribeEvents()
135
+ * C->>R: destroy()
136
+ * end
137
+ *
138
+ * @return {Promise<void>} A promise that resolves when cleanup is complete
139
+ * @memberOf ComponentRendererComponent
140
+ */
141
+ async ngOnDestroy() {
142
+ if (this.component) {
143
+ this.unsubscribeEvents();
144
+ NgxRenderingEngine2.destroy();
145
+ }
146
+ }
147
+ /**
148
+ * @description Creates and renders a dynamic component.
149
+ * @summary This method handles the creation of a dynamic component based on the provided tag.
150
+ * It retrieves the component constructor from the rendering engine, processes its inputs,
151
+ * filters out unmapped properties, creates the component instance, and sets up event subscriptions.
152
+ *
153
+ * @param {string} tag - The tag name of the component to create
154
+ * @param {KeyValue} globals - Global properties to pass to the component
155
+ * @return {void}
156
+ *
157
+ * @mermaid
158
+ * sequenceDiagram
159
+ * participant C as ComponentRendererComponent
160
+ * participant R as NgxRenderingEngine2
161
+ * participant V as ViewContainerRef
162
+ *
163
+ * C->>R: components(tag)
164
+ * R-->>C: Return component constructor
165
+ * C->>C: reflectComponentType(component)
166
+ * C->>C: Process input properties
167
+ * C->>C: Filter unmapped properties
168
+ * C->>V: clear()
169
+ * C->>R: createComponent(component, props, metadata, vcr, injector, [])
170
+ * R-->>C: Return component reference
171
+ * C->>C: subscribeEvents()
172
+ *
173
+ * @private
174
+ * @memberOf ComponentRendererComponent
175
+ */
176
+ createComponent(tag, globals = {}) {
177
+ const component = NgxRenderingEngine2.components(tag)
178
+ ?.constructor;
179
+ const metadata = reflectComponentType(component);
180
+ const componentInputs = metadata.inputs;
181
+ const props = globals?.['item'];
182
+ delete props['tag'];
183
+ const inputKeys = Object.keys(props);
184
+ const unmappedKeys = [];
185
+ for (const input of inputKeys) {
186
+ if (!inputKeys.length)
187
+ break;
188
+ const prop = componentInputs.find((item) => item.propName === input);
189
+ if (!prop) {
190
+ delete props[input];
191
+ unmappedKeys.push(input);
192
+ }
193
+ }
194
+ if (unmappedKeys.length)
195
+ this.logger.info(`Unmapped input properties for component ${tag}: ${unmappedKeys.join(', ')}`);
196
+ this.vcr.clear();
197
+ this.component = NgxRenderingEngine2.createComponent(component, props, metadata, this.vcr, this.injector, []);
198
+ this.subscribeEvents();
199
+ }
200
+ createParentComponent() {
201
+ const { component, inputs } = this.parent;
202
+ const metadata = reflectComponentType(component);
203
+ const template = this.vcr.createEmbeddedView(this.inner, this.injector).rootNodes;
204
+ this.component = NgxRenderingEngine2.createComponent(component, inputs, metadata, this.vcr, this.injector, template);
205
+ this.subscribeEvents();
206
+ }
207
+ /**
208
+ * @description Subscribes to events emitted by the dynamic component.
209
+ * @summary This method sets up subscriptions to all EventEmitter properties of the
210
+ * dynamically created component. When an event is emitted by the dynamic component,
211
+ * it is captured and re-emitted through the listenEvent output property with additional
212
+ * metadata about the event source.
213
+ *
214
+ * @mermaid
215
+ * sequenceDiagram
216
+ * participant C as ComponentRendererComponent
217
+ * participant D as Dynamic Component
218
+ * participant P as Parent Component
219
+ *
220
+ * C->>C: subscribeEvents()
221
+ * C->>D: Get instance properties
222
+ * loop For each property
223
+ * C->>C: Check if property is EventEmitter
224
+ * alt is EventEmitter
225
+ * C->>D: Subscribe to event
226
+ * D-->>C: Event emitted
227
+ * C->>P: Re-emit event with metadata
228
+ * end
229
+ * end
230
+ *
231
+ * @private
232
+ * @return {void}
233
+ * @memberOf ComponentRendererComponent
234
+ */
235
+ subscribeEvents() {
236
+ if (this.component) {
237
+ const instance = this.component?.instance;
238
+ const componentKeys = Object.keys(instance);
239
+ for (const key of componentKeys) {
240
+ const value = instance[key];
241
+ if (value instanceof EventEmitter)
242
+ instance[key].subscribe((event) => {
243
+ this.listenEvent.emit({
244
+ name: key,
245
+ ...event,
246
+ });
247
+ });
248
+ }
249
+ }
250
+ }
251
+ /**
252
+ * @description Unsubscribes from all events of the dynamic component.
253
+ * @summary This method cleans up event subscriptions when the component is being destroyed.
254
+ * It iterates through all properties of the dynamic component instance and unsubscribes
255
+ * from any EventEmitter properties to prevent memory leaks and unexpected behavior after
256
+ * the component is destroyed.
257
+ *
258
+ * @mermaid
259
+ * sequenceDiagram
260
+ * participant C as ComponentRendererComponent
261
+ * participant D as Dynamic Component
262
+ *
263
+ * C->>C: unsubscribeEvents()
264
+ * C->>D: Get instance properties
265
+ * loop For each property
266
+ * C->>C: Check if property is EventEmitter
267
+ * alt is EventEmitter
268
+ * C->>D: Unsubscribe from event
269
+ * end
270
+ * end
271
+ *
272
+ * @private
273
+ * @return {void}
274
+ * @memberOf ComponentRendererComponent
275
+ */
276
+ unsubscribeEvents() {
277
+ if (this.component) {
278
+ const instance = this.component?.instance;
279
+ const componentKeys = Object.keys(instance);
280
+ for (const key of componentKeys) {
281
+ const value = instance[key];
282
+ if (value instanceof EventEmitter)
283
+ instance[key].unsubscribe();
284
+ }
285
+ }
286
+ }
287
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ComponentRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
288
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ComponentRendererComponent, isStandalone: true, selector: "ngx-decaf-component-renderer", inputs: { tag: "tag", globals: "globals", parent: "parent" }, outputs: { listenEvent: "listenEvent" }, 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: "<ng-template #componentViewContainer></ng-template>\n\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</ng-template>\n\n\n", styles: [""], dependencies: [{ kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "parent"], outputs: ["listenEvent"] }, { kind: "ngmodule", type: ForAngularModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }] }); }
289
+ }
290
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ComponentRendererComponent, decorators: [{
291
+ type: Component,
292
+ args: [{ selector: 'ngx-decaf-component-renderer', imports: [ForAngularModule], standalone: true, template: "<ng-template #componentViewContainer></ng-template>\n\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</ng-template>\n\n\n" }]
293
+ }], ctorParameters: () => [], propDecorators: { vcr: [{
294
+ type: ViewChild,
295
+ args: ['componentViewContainer', { static: true, read: ViewContainerRef }]
296
+ }], tag: [{
297
+ type: Input,
298
+ args: [{ required: true }]
299
+ }], globals: [{
300
+ type: Input
301
+ }], listenEvent: [{
302
+ type: Output
303
+ }], parent: [{
304
+ type: Input
305
+ }], inner: [{
306
+ type: ViewChild,
307
+ args: ['inner', { read: TemplateRef, static: true }]
308
+ }] } });
309
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LXJlbmRlcmVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9jb21wb25lbnQtcmVuZGVyZXIvY29tcG9uZW50LXJlbmRlcmVyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9jb21wb25lbnQtcmVuZGVyZXIvY29tcG9uZW50LXJlbmRlcmVyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBR1QsbUJBQW1CLEVBQ25CLFlBQVksRUFDWixNQUFNLEVBRU4sS0FBSyxFQUdMLE1BQU0sRUFDTixvQkFBb0IsRUFDcEIsV0FBVyxFQUVYLFNBQVMsRUFDVCxnQkFBZ0IsR0FDakIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFFekUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFNBQVMsRUFBRSxNQUFNLDRCQUE0QixDQUFDOzs7QUFHekU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0NHO0FBUUgsTUFBTSxPQUFPLDBCQUEwQjtJQWtHckM7Ozs7Ozs7T0FPRztJQUNIO1FBOUVBOzs7Ozs7Ozs7O1dBVUc7UUFFSCxZQUFPLEdBQTRCLEVBQUUsQ0FBQztRQUV0Qzs7Ozs7Ozs7O1dBU0c7UUFDSCxhQUFRLEdBQXdCLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBYTVEOzs7Ozs7Ozs7V0FTRztRQUVILGdCQUFXLEdBQ1QsSUFBSSxZQUFZLEVBQTBCLENBQUM7UUFlN0MsV0FBTSxHQUFRLFNBQVMsQ0FBQztRQWV0QixJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FzQkc7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R0F2VVUsMEJBQTBCO21HQUExQiwwQkFBMEIseVJBV3NCLGdCQUFnQix1R0FvRi9DLFdBQVcsMkNDcEt6QywrbUJBc0JBLDBERCtDYSwwQkFBMEIsd0lBSDNCLGdCQUFnQjs7NEZBR2YsMEJBQTBCO2tCQVB0QyxTQUFTOytCQUNFLDhCQUE4QixXQUcvQixDQUFDLGdCQUFnQixDQUFDLGNBQ2YsSUFBSTt3REFjaEIsR0FBRztzQkFERixTQUFTO3VCQUFDLHdCQUF3QixFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBZTdFLEdBQUc7c0JBREYsS0FBSzt1QkFBQyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUU7Z0JBZXpCLE9BQU87c0JBRE4sS0FBSztnQkFxQ04sV0FBVztzQkFEVixNQUFNO2dCQWlCUCxNQUFNO3NCQURMLEtBQUs7Z0JBS04sS0FBSztzQkFESixTQUFTO3VCQUFDLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgQ29tcG9uZW50TWlycm9yLFxuICBDb21wb25lbnRSZWYsXG4gIEVudmlyb25tZW50SW5qZWN0b3IsXG4gIEV2ZW50RW1pdHRlcixcbiAgaW5qZWN0LFxuICBJbmplY3RvcixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG4gIHJlZmxlY3RDb21wb25lbnRUeXBlLFxuICBUZW1wbGF0ZVJlZixcbiAgVHlwZSxcbiAgVmlld0NoaWxkLFxuICBWaWV3Q29udGFpbmVyUmVmLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE5neFJlbmRlcmluZ0VuZ2luZTIgfSBmcm9tICdzcmMvbGliL2VuZ2luZS9OZ3hSZW5kZXJpbmdFbmdpbmUyJztcbmltcG9ydCB7IEJhc2VDdXN0b21FdmVudCwgS2V5VmFsdWUsIE1vZGVsUmVuZGVyQ3VzdG9tRXZlbnQgfSBmcm9tICcuLi8uLi9lbmdpbmUnO1xuaW1wb3J0IHsgRm9yQW5ndWxhck1vZHVsZSwgZ2V0TG9nZ2VyIH0gZnJvbSAnc3JjL2xpYi9mb3ItYW5ndWxhci5tb2R1bGUnO1xuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnQGRlY2FmLXRzL2xvZ2dpbmcnO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEeW5hbWljIGNvbXBvbmVudCByZW5kZXJlciBmb3IgRGVjYWYgQW5ndWxhciBhcHBsaWNhdGlvbnMuXG4gKiBAc3VtbWFyeSBUaGlzIGNvbXBvbmVudCBwcm92aWRlcyBhIGZsZXhpYmxlIHdheSB0byBkeW5hbWljYWxseSByZW5kZXIgQW5ndWxhciBjb21wb25lbnRzXG4gKiBhdCBydW50aW1lIGJhc2VkIG9uIGEgdGFnIG5hbWUuIEl0IGhhbmRsZXMgdGhlIGNyZWF0aW9uLCBwcm9wZXJ0eSBiaW5kaW5nLCBhbmQgZXZlbnRcbiAqIHN1YnNjcmlwdGlvbiBmb3IgZHluYW1pY2FsbHkgbG9hZGVkIGNvbXBvbmVudHMuIFRoaXMgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCBmb3JcbiAqIGJ1aWxkaW5nIGNvbmZpZ3VyYWJsZSBVSXMgd2hlcmUgY29tcG9uZW50cyBuZWVkIHRvIGJlIGRldGVybWluZWQgYXQgcnVudGltZS5cbiAqXG4gKiBAY29tcG9uZW50IHtDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudH1cbiAqIEBleGFtcGxlXG4gKiA8bmd4LWRlY2FmLWNvbXBvbmVudC1yZW5kZXJlclxuICogICBbdGFnXT1cInRhZ1wiXG4gKiAgIFtnbG9iYWxzXT1cImdsb2JhbHNcIlxuICogICAobGlzdGVuRXZlbnQpPVwibGlzdGVuRXZlbnQoJGV2ZW50KVwiPlxuICogPC9uZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyPlxuICpcbiAqIEBtZXJtYWlkXG4gKiBjbGFzc0RpYWdyYW1cbiAqICAgY2xhc3MgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnQge1xuICogICAgICtWaWV3Q29udGFpbmVyUmVmIHZjclxuICogICAgICtzdHJpbmcgdGFnXG4gKiAgICAgK1JlY29yZH5zdHJpbmcsIHVua25vd25+IGdsb2JhbHNcbiAqICAgICArRW52aXJvbm1lbnRJbmplY3RvciBpbmplY3RvclxuICogICAgICtDb21wb25lbnRSZWZ+dW5rbm93bn4gY29tcG9uZW50XG4gKiAgICAgK0V2ZW50RW1pdHRlcn5Nb2RlbFJlbmRlckN1c3RvbUV2ZW50fiBsaXN0ZW5FdmVudFxuICogICAgICtuZ09uSW5pdCgpXG4gKiAgICAgK25nT25EZXN0cm95KClcbiAqICAgICArbmdPbkNoYW5nZXMoY2hhbmdlcylcbiAqICAgICAtY3JlYXRlQ29tcG9uZW50KHRhZywgZ2xvYmFscylcbiAqICAgICAtc3Vic2NyaWJlRXZlbnRzKClcbiAqICAgICAtdW5zdWJzY3JpYmVFdmVudHMoKVxuICogICB9XG4gKiAgIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50IC0tfD4gT25Jbml0XG4gKiAgIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50IC0tfD4gT25DaGFuZ2VzXG4gKiAgIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50IC0tfD4gT25EZXN0cm95XG4gKlxuICogQGltcGxlbWVudHMge09uSW5pdH1cbiAqIEBpbXBsZW1lbnRzIHtPbkNoYW5nZXN9XG4gKiBAaW1wbGVtZW50cyB7T25EZXN0cm95fVxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NvbXBvbmVudC1yZW5kZXJlci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2NvbXBvbmVudC1yZW5kZXJlci5jb21wb25lbnQuc2NzcyddLFxuICBpbXBvcnRzOiBbRm9yQW5ndWxhck1vZHVsZV0sXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gIGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlZmVyZW5jZSB0byB0aGUgY29udGFpbmVyIHdoZXJlIHRoZSBkeW5hbWljIGNvbXBvbmVudCB3aWxsIGJlIHJlbmRlcmVkLlxuICAgKiBAc3VtbWFyeSBUaGlzIFZpZXdDb250YWluZXJSZWYgcHJvdmlkZXMgdGhlIGNvbnRhaW5lciB3aGVyZSB0aGUgZHluYW1pY2FsbHkgY3JlYXRlZFxuICAgKiBjb21wb25lbnQgd2lsbCBiZSBpbnNlcnRlZCBpbnRvIHRoZSBET00uIEl0J3MgbWFya2VkIGFzIHN0YXRpYyB0byBlbnN1cmUgaXQncyBhdmFpbGFibGVcbiAgICogZHVyaW5nIHRoZSBuZ09uSW5pdCBsaWZlY3ljbGUgaG9vayB3aGVuIHRoZSBjb21wb25lbnQgaXMgY3JlYXRlZC5cbiAgICpcbiAgICogQHR5cGUge1ZpZXdDb250YWluZXJSZWZ9XG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgQFZpZXdDaGlsZCgnY29tcG9uZW50Vmlld0NvbnRhaW5lcicsIHsgc3RhdGljOiB0cnVlLCByZWFkOiBWaWV3Q29udGFpbmVyUmVmIH0pXG4gIHZjciE6IFZpZXdDb250YWluZXJSZWY7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgdGFnIG5hbWUgb2YgdGhlIGNvbXBvbmVudCB0byBiZSBkeW5hbWljYWxseSByZW5kZXJlZC5cbiAgICogQHN1bW1hcnkgVGhpcyBpbnB1dCBwcm9wZXJ0eSBzcGVjaWZpZXMgd2hpY2ggY29tcG9uZW50IHNob3VsZCBiZSByZW5kZXJlZCBieSBwcm92aWRpbmdcbiAgICogaXRzIHJlZ2lzdGVyZWQgdGFnIG5hbWUuIFRoZSB0YWcgbXVzdCBjb3JyZXNwb25kIHRvIGEgY29tcG9uZW50IHRoYXQgaGFzIGJlZW4gcmVnaXN0ZXJlZFxuICAgKiB3aXRoIHRoZSBOZ3hSZW5kZXJpbmdFbmdpbmUyLiBUaGlzIGlzIGEgcmVxdWlyZWQgaW5wdXQgYXMgaXQgZGV0ZXJtaW5lcyB3aGljaCBjb21wb25lbnRcbiAgICogdG8gY3JlYXRlLlxuICAgKlxuICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgKiBAcmVxdWlyZWRcbiAgICogQG1lbWJlck9mIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqL1xuICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KVxuICB0YWchOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHbG9iYWwgcHJvcGVydGllcyB0byBwYXNzIHRvIHRoZSByZW5kZXJlZCBjb21wb25lbnQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgaW5wdXQgcHJvcGVydHkgYWxsb3dzIHBhc3NpbmcgYSBzZXQgb2YgcHJvcGVydGllcyB0byB0aGUgZHluYW1pY2FsbHlcbiAgICogcmVuZGVyZWQgY29tcG9uZW50LiBUaGVzZSBwcm9wZXJ0aWVzIHdpbGwgYmUgbWFwcGVkIHRvIHRoZSBjb21wb25lbnQncyBpbnB1dHMgaWYgdGhleVxuICAgKiBtYXRjaC4gUHJvcGVydGllcyB0aGF0IGRvbid0IG1hdGNoIGFueSBpbnB1dCBvbiB0aGUgdGFyZ2V0IGNvbXBvbmVudCB3aWxsIGJlIGZpbHRlcmVkIG91dFxuICAgKiB3aXRoIGEgd2FybmluZy5cbiAgICpcbiAgICogQHR5cGUge1JlY29yZDxzdHJpbmcsIHVua25vd24+fVxuICAgKiBAZGVmYXVsdCB7fVxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIEBJbnB1dCgpXG4gIGdsb2JhbHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbmplY3RvciB1c2VkIGZvciBkZXBlbmRlbmN5IGluamVjdGlvbiBpbiB0aGUgZHluYW1pYyBjb21wb25lbnQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgaW5qZWN0b3IgaXMgdXNlZCB3aGVuIGNyZWF0aW5nIHRoZSBkeW5hbWljIGNvbXBvbmVudCB0byBwcm92aWRlIGl0IHdpdGhcbiAgICogYWNjZXNzIHRvIHRoZSBhcHBsaWNhdGlvbidzIGRlcGVuZGVuY3kgaW5qZWN0aW9uIHN5c3RlbS4gSXQgZW5zdXJlcyB0aGF0IHRoZSBkeW5hbWljYWxseVxuICAgKiBjcmVhdGVkIGNvbXBvbmVudCBjYW4gYWNjZXNzIHRoZSBzYW1lIHNlcnZpY2VzIGFuZCBkZXBlbmRlbmNpZXMgYXMgc3RhdGljYWxseSBjcmVhdGVkXG4gICAqIGNvbXBvbmVudHMuXG4gICAqXG4gICAqIEB0eXBlIHtFbnZpcm9ubWVudEluamVjdG9yfVxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIGluamVjdG9yOiBFbnZpcm9ubWVudEluamVjdG9yID0gaW5qZWN0KEVudmlyb25tZW50SW5qZWN0b3IpO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVmZXJlbmNlIHRvIHRoZSBkeW5hbWljYWxseSBjcmVhdGVkIGNvbXBvbmVudC5cbiAgICogQHN1bW1hcnkgVGhpcyBwcm9wZXJ0eSBob2xkcyBhIHJlZmVyZW5jZSB0byB0aGUgQ29tcG9uZW50UmVmIG9mIHRoZSBkeW5hbWljYWxseSBjcmVhdGVkXG4gICAqIGNvbXBvbmVudC4gSXQncyB1c2VkIHRvIGludGVyYWN0IHdpdGggdGhlIGNvbXBvbmVudCBpbnN0YW5jZSwgc3Vic2NyaWJlIHRvIGl0cyBldmVudHMsXG4gICAqIGFuZCBwcm9wZXJseSBkZXN0cm95IGl0IHdoZW4gdGhlIHJlbmRlcmVyIGlzIGRlc3Ryb3llZC5cbiAgICpcbiAgICogQHR5cGUge0NvbXBvbmVudFJlZjx1bmtub3duPn1cbiAgICogQG1lbWJlck9mIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqL1xuICBjb21wb25lbnQhOiBDb21wb25lbnRSZWY8dW5rbm93bj47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFdmVudCBlbWl0dGVyIGZvciBldmVudHMgZnJvbSB0aGUgcmVuZGVyZWQgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIG91dHB1dCBwcm9wZXJ0eSBlbWl0cyBldmVudHMgdGhhdCBvcmlnaW5hdGUgZnJvbSB0aGUgZHluYW1pY2FsbHkgcmVuZGVyZWRcbiAgICogY29tcG9uZW50LiBJdCBhbGxvd3MgdGhlIHBhcmVudCBjb21wb25lbnQgdG8gbGlzdGVuIGZvciBhbmQgcmVzcG9uZCB0byBldmVudHMgZnJvbSB0aGVcbiAgICogZHluYW1pYyBjb21wb25lbnQsIGNyZWF0aW5nIGEgY29tbXVuaWNhdGlvbiBjaGFubmVsIGJldHdlZW4gdGhlIHBhcmVudCBhbmQgdGhlIGR5bmFtaWNhbGx5XG4gICAqIHJlbmRlcmVkIGNoaWxkLlxuICAgKlxuICAgKiBAdHlwZSB7RXZlbnRFbWl0dGVyPE1vZGVsUmVuZGVyQ3VzdG9tRXZlbnQ+fVxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIEBPdXRwdXQoKVxuICBsaXN0ZW5FdmVudDogRXZlbnRFbWl0dGVyPE1vZGVsUmVuZGVyQ3VzdG9tRXZlbnQ+ID1cbiAgICBuZXcgRXZlbnRFbWl0dGVyPE1vZGVsUmVuZGVyQ3VzdG9tRXZlbnQ+KCk7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dnZXIgaW5zdGFuY2UgZm9yIHRoZSBjb21wb25lbnQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgcHJvcGVydHkgaG9sZHMgYSBMb2dnZXIgaW5zdGFuY2Ugc3BlY2lmaWMgdG8gdGhpcyBjb21wb25lbnQuXG4gICAqIEl0J3MgdXNlZCB0byBsb2cgaW5mb3JtYXRpb24sIHdhcm5pbmdzLCBhbmQgZXJyb3JzIHJlbGF0ZWQgdG8gdGhlIGNvbXBvbmVudCdzXG4gICAqIG9wZXJhdGlvbnMsIHBhcnRpY3VsYXJseSB1c2VmdWwgZm9yIGRlYnVnZ2luZyBhbmQgbW9uaXRvcmluZyB0aGUgZHluYW1pY1xuICAgKiBjb21wb25lbnQgcmVuZGVyaW5nIHByb2Nlc3MuXG4gICAqXG4gICAqIEB0eXBlIHtMb2dnZXJ9XG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgbG9nZ2VyITogTG9nZ2VyO1xuXG4gIEBJbnB1dCgpXG4gIHBhcmVudDogYW55ID0gdW5kZWZpbmVkO1xuXG5cbiAgQFZpZXdDaGlsZCgnaW5uZXInLCB7IHJlYWQ6IFRlbXBsYXRlUmVmLCBzdGF0aWM6IHRydWUgfSlcbiAgaW5uZXI/OiBUZW1wbGF0ZVJlZjxhbnk+O1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudC5cbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSBuZXcgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnQuIFRoaXMgY29tcG9uZW50IGRvZXNuJ3QgcmVxdWlyZVxuICAgKiBhbnkgZGVwZW5kZW5jaWVzIHRvIGJlIGluamVjdGVkIGluIGl0cyBjb25zdHJ1Y3RvciBhcyBpdCB1c2VzIHRoZSBpbmplY3QgZnVuY3Rpb24gdG9cbiAgICogb2J0YWluIHRoZSBFbnZpcm9ubWVudEluamVjdG9yLlxuICAgKlxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMubG9nZ2VyID0gZ2V0TG9nZ2VyKHRoaXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbml0aWFsaXplcyB0aGUgY29tcG9uZW50IGFmdGVyIEFuZ3VsYXIgZmlyc3QgZGlzcGxheXMgdGhlIGRhdGEtYm91bmQgcHJvcGVydGllcy5cbiAgICogQHN1bW1hcnkgU2V0cyB1cCB0aGUgY29tcG9uZW50IGJ5IGNyZWF0aW5nIHRoZSBkeW5hbWljIGNvbXBvbmVudCBzcGVjaWZpZWQgYnkgdGhlIHRhZyBpbnB1dC5cbiAgICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIG9uY2Ugd2hlbiB0aGUgY29tcG9uZW50IGlzIGluaXRpYWxpemVkIGFuZCB0cmlnZ2VycyB0aGUgZHluYW1pY1xuICAgKiBjb21wb25lbnQgY3JlYXRpb24gcHJvY2VzcyB3aXRoIHRoZSBwcm92aWRlZCB0YWcgbmFtZSBhbmQgZ2xvYmFsIHByb3BlcnRpZXMuXG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEEgYXMgQW5ndWxhciBMaWZlY3ljbGVcbiAgICogICBwYXJ0aWNpcGFudCBDIGFzIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqICAgcGFydGljaXBhbnQgUiBhcyBOZ3hSZW5kZXJpbmdFbmdpbmUyXG4gICAqXG4gICAqICAgQS0+PkM6IG5nT25Jbml0KClcbiAgICogICBDLT4+QzogY3JlYXRlQ29tcG9uZW50KHRhZywgZ2xvYmFscylcbiAgICogICBDLT4+UjogY29tcG9uZW50cyh0YWcpXG4gICAqICAgUi0tPj5DOiBSZXR1cm4gY29tcG9uZW50IGNvbnN0cnVjdG9yXG4gICAqICAgQy0+PkM6IFByb2Nlc3MgY29tcG9uZW50IGlucHV0c1xuICAgKiAgIEMtPj5DOiBDcmVhdGUgY29tcG9uZW50IGluc3RhbmNlXG4gICAqICAgQy0+PkM6IHN1YnNjcmliZUV2ZW50cygpXG4gICAqXG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnBhcmVudClcbiAgICAgIHRoaXMuY3JlYXRlQ29tcG9uZW50KHRoaXMudGFnLCB0aGlzLmdsb2JhbHMpO1xuICAgIHRoaXMuY3JlYXRlUGFyZW50Q29tcG9uZW50KCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENsZWFucyB1cCByZXNvdXJjZXMgd2hlbiB0aGUgY29tcG9uZW50IGlzIGRlc3Ryb3llZC5cbiAgICogQHN1bW1hcnkgUGVyZm9ybXMgY2xlYW51cCBvcGVyYXRpb25zIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBiZWluZyBkZXN0cm95ZWQgYnkgQW5ndWxhci5cbiAgICogVGhpcyBpbmNsdWRlcyB1bnN1YnNjcmliaW5nIGZyb20gYWxsIGV2ZW50IGVtaXR0ZXJzIG9mIHRoZSBkeW5hbWljIGNvbXBvbmVudCBhbmRcbiAgICogZGVzdHJveWluZyB0aGUgcmVuZGVyaW5nIGVuZ2luZSBpbnN0YW5jZSB0byBwcmV2ZW50IG1lbW9yeSBsZWFrcy5cbiAgICpcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgQSBhcyBBbmd1bGFyIExpZmVjeWNsZVxuICAgKiAgIHBhcnRpY2lwYW50IEMgYXMgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICogICBwYXJ0aWNpcGFudCBSIGFzIE5neFJlbmRlcmluZ0VuZ2luZTJcbiAgICpcbiAgICogICBBLT4+QzogbmdPbkRlc3Ryb3koKVxuICAgKiAgIGFsdCBjb21wb25lbnQgZXhpc3RzXG4gICAqICAgICBDLT4+QzogdW5zdWJzY3JpYmVFdmVudHMoKVxuICAgKiAgICAgQy0+PlI6IGRlc3Ryb3koKVxuICAgKiAgIGVuZFxuICAgKlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGNsZWFudXAgaXMgY29tcGxldGVcbiAgICogQG1lbWJlck9mIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqL1xuICBhc3luYyBuZ09uRGVzdHJveSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jb21wb25lbnQpIHtcbiAgICAgIHRoaXMudW5zdWJzY3JpYmVFdmVudHMoKTtcbiAgICAgIE5neFJlbmRlcmluZ0VuZ2luZTIuZGVzdHJveSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhbmQgcmVuZGVycyBhIGR5bmFtaWMgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIG1ldGhvZCBoYW5kbGVzIHRoZSBjcmVhdGlvbiBvZiBhIGR5bmFtaWMgY29tcG9uZW50IGJhc2VkIG9uIHRoZSBwcm92aWRlZCB0YWcuXG4gICAqIEl0IHJldHJpZXZlcyB0aGUgY29tcG9uZW50IGNvbnN0cnVjdG9yIGZyb20gdGhlIHJlbmRlcmluZyBlbmdpbmUsIHByb2Nlc3NlcyBpdHMgaW5wdXRzLFxuICAgKiBmaWx0ZXJzIG91dCB1bm1hcHBlZCBwcm9wZXJ0aWVzLCBjcmVhdGVzIHRoZSBjb21wb25lbnQgaW5zdGFuY2UsIGFuZCBzZXRzIHVwIGV2ZW50IHN1YnNjcmlwdGlvbnMuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWcgLSBUaGUgdGFnIG5hbWUgb2YgdGhlIGNvbXBvbmVudCB0byBjcmVhdGVcbiAgICogQHBhcmFtIHtLZXlWYWx1ZX0gZ2xvYmFscyAtIEdsb2JhbCBwcm9wZXJ0aWVzIHRvIHBhc3MgdG8gdGhlIGNvbXBvbmVudFxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDIGFzIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqICAgcGFydGljaXBhbnQgUiBhcyBOZ3hSZW5kZXJpbmdFbmdpbmUyXG4gICAqICAgcGFydGljaXBhbnQgViBhcyBWaWV3Q29udGFpbmVyUmVmXG4gICAqXG4gICAqICAgQy0+PlI6IGNvbXBvbmVudHModGFnKVxuICAgKiAgIFItLT4+QzogUmV0dXJuIGNvbXBvbmVudCBjb25zdHJ1Y3RvclxuICAgKiAgIEMtPj5DOiByZWZsZWN0Q29tcG9uZW50VHlwZShjb21wb25lbnQpXG4gICAqICAgQy0+PkM6IFByb2Nlc3MgaW5wdXQgcHJvcGVydGllc1xuICAgKiAgIEMtPj5DOiBGaWx0ZXIgdW5tYXBwZWQgcHJvcGVydGllc1xuICAgKiAgIEMtPj5WOiBjbGVhcigpXG4gICAqICAgQy0+PlI6IGNyZWF0ZUNvbXBvbmVudChjb21wb25lbnQsIHByb3BzLCBtZXRhZGF0YSwgdmNyLCBpbmplY3RvciwgW10pXG4gICAqICAgUi0tPj5DOiBSZXR1cm4gY29tcG9uZW50IHJlZmVyZW5jZVxuICAgKiAgIEMtPj5DOiBzdWJzY3JpYmVFdmVudHMoKVxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlQ29tcG9uZW50KHRhZzogc3RyaW5nLCBnbG9iYWxzOiBLZXlWYWx1ZSA9IHt9KTogdm9pZCB7XG4gICAgY29uc3QgY29tcG9uZW50ID0gTmd4UmVuZGVyaW5nRW5naW5lMi5jb21wb25lbnRzKHRhZylcbiAgICAgID8uY29uc3RydWN0b3IgYXMgVHlwZTx1bmtub3duPjtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHJlZmxlY3RDb21wb25lbnRUeXBlKGNvbXBvbmVudCk7XG4gICAgY29uc3QgY29tcG9uZW50SW5wdXRzID0gKG1ldGFkYXRhIGFzIENvbXBvbmVudE1pcnJvcjx1bmtub3duPikuaW5wdXRzO1xuICAgIGNvbnN0IHByb3BzID0gZ2xvYmFscz8uWydpdGVtJ107XG4gICAgZGVsZXRlIHByb3BzWyd0YWcnXTtcbiAgICBjb25zdCBpbnB1dEtleXMgPSBPYmplY3Qua2V5cyhwcm9wcyk7XG4gICAgY29uc3QgdW5tYXBwZWRLZXlzID0gW107XG5cbiAgICBmb3IgKGNvbnN0IGlucHV0IG9mIGlucHV0S2V5cykge1xuICAgICAgaWYgKCFpbnB1dEtleXMubGVuZ3RoKSBicmVhaztcbiAgICAgIGNvbnN0IHByb3AgPSBjb21wb25lbnRJbnB1dHMuZmluZChcbiAgICAgICAgKGl0ZW06IHsgcHJvcE5hbWU6IHN0cmluZyB9KSA9PiBpdGVtLnByb3BOYW1lID09PSBpbnB1dCxcbiAgICAgICk7XG4gICAgICBpZiAoIXByb3ApIHtcbiAgICAgICAgZGVsZXRlIHByb3BzW2lucHV0XTtcbiAgICAgICAgdW5tYXBwZWRLZXlzLnB1c2goaW5wdXQpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAodW5tYXBwZWRLZXlzLmxlbmd0aClcbiAgICAgIHRoaXMubG9nZ2VyLmluZm8oYFVubWFwcGVkIGlucHV0IHByb3BlcnRpZXMgZm9yIGNvbXBvbmVudCAke3RhZ306ICR7dW5tYXBwZWRLZXlzLmpvaW4oJywgJyl9YCk7XG5cbiAgICB0aGlzLnZjci5jbGVhcigpO1xuICAgIHRoaXMuY29tcG9uZW50ID0gTmd4UmVuZGVyaW5nRW5naW5lMi5jcmVhdGVDb21wb25lbnQoXG4gICAgICBjb21wb25lbnQsXG4gICAgICBwcm9wcyxcbiAgICAgIG1ldGFkYXRhIGFzIENvbXBvbmVudE1pcnJvcjx1bmtub3duPixcbiAgICAgIHRoaXMudmNyLFxuICAgICAgdGhpcy5pbmplY3RvciBhcyBJbmplY3RvcixcbiAgICAgIFtdLFxuICAgICk7XG4gICAgdGhpcy5zdWJzY3JpYmVFdmVudHMoKTtcbiAgfVxuXG4gIGNyZWF0ZVBhcmVudENvbXBvbmVudCgpIHtcbiAgICBjb25zdCB7IGNvbXBvbmVudCwgaW5wdXRzIH0gPSB0aGlzLnBhcmVudDtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHJlZmxlY3RDb21wb25lbnRUeXBlKGNvbXBvbmVudCkgYXMgQ29tcG9uZW50TWlycm9yPHVua25vd24+O1xuICAgIGNvbnN0IHRlbXBsYXRlID0gdGhpcy52Y3IuY3JlYXRlRW1iZWRkZWRWaWV3KHRoaXMuaW5uZXIgYXMgVGVtcGxhdGVSZWY8YW55PiwgdGhpcy5pbmplY3Rvcikucm9vdE5vZGVzO1xuICAgIHRoaXMuY29tcG9uZW50ID0gTmd4UmVuZGVyaW5nRW5naW5lMi5jcmVhdGVDb21wb25lbnQoXG4gICAgICBjb21wb25lbnQsXG4gICAgICBpbnB1dHMsXG4gICAgICBtZXRhZGF0YSxcbiAgICAgIHRoaXMudmNyLFxuICAgICAgdGhpcy5pbmplY3RvcixcbiAgICAgIHRlbXBsYXRlLFxuICAgICk7XG4gICAgdGhpcy5zdWJzY3JpYmVFdmVudHMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU3Vic2NyaWJlcyB0byBldmVudHMgZW1pdHRlZCBieSB0aGUgZHluYW1pYyBjb21wb25lbnQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgbWV0aG9kIHNldHMgdXAgc3Vic2NyaXB0aW9ucyB0byBhbGwgRXZlbnRFbWl0dGVyIHByb3BlcnRpZXMgb2YgdGhlXG4gICAqIGR5bmFtaWNhbGx5IGNyZWF0ZWQgY29tcG9uZW50LiBXaGVuIGFuIGV2ZW50IGlzIGVtaXR0ZWQgYnkgdGhlIGR5bmFtaWMgY29tcG9uZW50LFxuICAgKiBpdCBpcyBjYXB0dXJlZCBhbmQgcmUtZW1pdHRlZCB0aHJvdWdoIHRoZSBsaXN0ZW5FdmVudCBvdXRwdXQgcHJvcGVydHkgd2l0aCBhZGRpdGlvbmFsXG4gICAqIG1ldGFkYXRhIGFib3V0IHRoZSBldmVudCBzb3VyY2UuXG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEMgYXMgQ29tcG9uZW50UmVuZGVyZXJDb21wb25lbnRcbiAgICogICBwYXJ0aWNpcGFudCBEIGFzIER5bmFtaWMgQ29tcG9uZW50XG4gICAqICAgcGFydGljaXBhbnQgUCBhcyBQYXJlbnQgQ29tcG9uZW50XG4gICAqXG4gICAqICAgQy0+PkM6IHN1YnNjcmliZUV2ZW50cygpXG4gICAqICAgQy0+PkQ6IEdldCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAqICAgbG9vcCBGb3IgZWFjaCBwcm9wZXJ0eVxuICAgKiAgICAgQy0+PkM6IENoZWNrIGlmIHByb3BlcnR5IGlzIEV2ZW50RW1pdHRlclxuICAgKiAgICAgYWx0IGlzIEV2ZW50RW1pdHRlclxuICAgKiAgICAgICBDLT4+RDogU3Vic2NyaWJlIHRvIGV2ZW50XG4gICAqICAgICAgIEQtLT4+QzogRXZlbnQgZW1pdHRlZFxuICAgKiAgICAgICBDLT4+UDogUmUtZW1pdCBldmVudCB3aXRoIG1ldGFkYXRhXG4gICAqICAgICBlbmRcbiAgICogICBlbmRcbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICogQG1lbWJlck9mIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqL1xuICBwcml2YXRlIHN1YnNjcmliZUV2ZW50cygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jb21wb25lbnQpIHtcbiAgICAgIGNvbnN0IGluc3RhbmNlID0gdGhpcy5jb21wb25lbnQ/Lmluc3RhbmNlIGFzIGFueTtcbiAgICAgIGNvbnN0IGNvbXBvbmVudEtleXMgPSBPYmplY3Qua2V5cyhpbnN0YW5jZSk7XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBjb21wb25lbnRLZXlzKSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gaW5zdGFuY2Vba2V5XTtcbiAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgRXZlbnRFbWl0dGVyKVxuICAgICAgICAgIChpbnN0YW5jZSBhcyBLZXlWYWx1ZSlba2V5XS5zdWJzY3JpYmUoXG4gICAgICAgICAgICAoZXZlbnQ6IFBhcnRpYWw8QmFzZUN1c3RvbUV2ZW50PikgPT4ge1xuICAgICAgICAgICAgICB0aGlzLmxpc3RlbkV2ZW50LmVtaXQoe1xuICAgICAgICAgICAgICAgIG5hbWU6IGtleSxcbiAgICAgICAgICAgICAgICAuLi5ldmVudCxcbiAgICAgICAgICAgICAgfSBhcyBNb2RlbFJlbmRlckN1c3RvbUV2ZW50KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVuc3Vic2NyaWJlcyBmcm9tIGFsbCBldmVudHMgb2YgdGhlIGR5bmFtaWMgY29tcG9uZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIG1ldGhvZCBjbGVhbnMgdXAgZXZlbnQgc3Vic2NyaXB0aW9ucyB3aGVuIHRoZSBjb21wb25lbnQgaXMgYmVpbmcgZGVzdHJveWVkLlxuICAgKiBJdCBpdGVyYXRlcyB0aHJvdWdoIGFsbCBwcm9wZXJ0aWVzIG9mIHRoZSBkeW5hbWljIGNvbXBvbmVudCBpbnN0YW5jZSBhbmQgdW5zdWJzY3JpYmVzXG4gICAqIGZyb20gYW55IEV2ZW50RW1pdHRlciBwcm9wZXJ0aWVzIHRvIHByZXZlbnQgbWVtb3J5IGxlYWtzIGFuZCB1bmV4cGVjdGVkIGJlaGF2aW9yIGFmdGVyXG4gICAqIHRoZSBjb21wb25lbnQgaXMgZGVzdHJveWVkLlxuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDIGFzIENvbXBvbmVudFJlbmRlcmVyQ29tcG9uZW50XG4gICAqICAgcGFydGljaXBhbnQgRCBhcyBEeW5hbWljIENvbXBvbmVudFxuICAgKlxuICAgKiAgIEMtPj5DOiB1bnN1YnNjcmliZUV2ZW50cygpXG4gICAqICAgQy0+PkQ6IEdldCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAqICAgbG9vcCBGb3IgZWFjaCBwcm9wZXJ0eVxuICAgKiAgICAgQy0+PkM6IENoZWNrIGlmIHByb3BlcnR5IGlzIEV2ZW50RW1pdHRlclxuICAgKiAgICAgYWx0IGlzIEV2ZW50RW1pdHRlclxuICAgKiAgICAgICBDLT4+RDogVW5zdWJzY3JpYmUgZnJvbSBldmVudFxuICAgKiAgICAgZW5kXG4gICAqICAgZW5kXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqIEBtZW1iZXJPZiBDb21wb25lbnRSZW5kZXJlckNvbXBvbmVudFxuICAgKi9cbiAgcHJpdmF0ZSB1bnN1YnNjcmliZUV2ZW50cygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jb21wb25lbnQpIHtcbiAgICAgIGNvbnN0IGluc3RhbmNlID0gdGhpcy5jb21wb25lbnQ/Lmluc3RhbmNlIGFzIGFueTtcbiAgICAgIGNvbnN0IGNvbXBvbmVudEtleXMgPSBPYmplY3Qua2V5cyhpbnN0YW5jZSk7XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBjb21wb25lbnRLZXlzKSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gaW5zdGFuY2Vba2V5XTtcbiAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgRXZlbnRFbWl0dGVyKSBpbnN0YW5jZVtrZXldLnVuc3Vic2NyaWJlKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iLCI8bmctdGVtcGxhdGUgI2NvbXBvbmVudFZpZXdDb250YWluZXI+PC9uZy10ZW1wbGF0ZT5cblxuPG5nLXRlbXBsYXRlICNpbm5lcj5cbiAgQGlmKHBhcmVudD8uY2hpbGRyZW4/Lmxlbmd0aCkge1xuICAgIEBmb3IoY2hpbGQgb2YgcGFyZW50LmNoaWxkcmVuOyB0cmFjayBjaGlsZCkge1xuICAgICAgICBAaWYoIWNoaWxkLmNoaWxkcmVuPy5sZW5ndGgpIHtcbiAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICAgKm5nQ29tcG9uZW50T3V0bGV0PVwiXG4gICAgICAgICAgICAgICAgICBjaGlsZC5jb21wb25lbnQ7XG4gICAgICAgICAgICAgICAgICBpbmplY3RvcjogY2hpbGQuaW5qZWN0b3I7XG4gICAgICAgICAgICAgICAgICBpbnB1dHM6IGNoaWxkLmlucHV0cztcbiAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6Y2hpbGQuY29udGVudDtcbiAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgIC8+XG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgIDxuZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyIFtwYXJlbnRdPVwiY2hpbGRcIj4gPC9uZ3gtZGVjYWYtY29tcG9uZW50LXJlbmRlcmVyPlxuICAgICAgICB9XG4gICAgIH1cbiAgfVxuPC9uZy10ZW1wbGF0ZT5cblxuXG4iXX0=