ngx-dynamic-entity 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -139
- package/esm2022/lib/field-types/array-field.component.mjs +101 -101
- package/esm2022/lib/field-types/boolean-field.component.mjs +59 -59
- package/esm2022/lib/field-types/checkbox-field.component.mjs +45 -45
- package/esm2022/lib/field-types/currency-field.component.mjs +51 -51
- package/esm2022/lib/field-types/date-field.component.mjs +43 -43
- package/esm2022/lib/field-types/dropdown-field.component.mjs +81 -81
- package/esm2022/lib/field-types/email-field.component.mjs +61 -61
- package/esm2022/lib/field-types/entity-ref-field.component.mjs +67 -67
- package/esm2022/lib/field-types/file-field.component.mjs +85 -85
- package/esm2022/lib/field-types/group-field.component.mjs +47 -47
- package/esm2022/lib/field-types/image-field.component.mjs +89 -89
- package/esm2022/lib/field-types/month-year-field.component.mjs +77 -77
- package/esm2022/lib/field-types/multi-select-field.component.mjs +63 -63
- package/esm2022/lib/field-types/number-field.component.mjs +65 -65
- package/esm2022/lib/field-types/password-field.component.mjs +65 -65
- package/esm2022/lib/field-types/radio-field.component.mjs +63 -63
- package/esm2022/lib/field-types/text-field.component.mjs +59 -59
- package/esm2022/lib/field-types/textarea-field.component.mjs +45 -45
- package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +1 -1
- package/esm2022/lib/form/dynamic-form.component.mjs +183 -10
- package/esm2022/lib/form/dynamic-record-form.component.mjs +36 -11
- package/esm2022/lib/providers/provide-field-types.mjs +1 -1
- package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +3 -2
- package/esm2022/lib/services/cascade-data.service.mjs +1 -1
- package/esm2022/lib/services/entity-ref-cache.mjs +1 -1
- package/esm2022/lib/services/entity-ref-registry.service.mjs +1 -1
- package/esm2022/lib/services/entity-ref-selection.service.mjs +1 -1
- package/esm2022/lib/services/entity-reference.service.mjs +1 -1
- package/esm2022/lib/services/field-registry.service.mjs +1 -1
- package/esm2022/lib/services/file-upload.service.mjs +1 -1
- package/esm2022/lib/services/rbac.service.mjs +1 -1
- package/esm2022/lib/services/validator-registry.service.mjs +12 -1
- package/esm2022/lib/tokens/injection-tokens.mjs +17 -1
- package/esm2022/public-api.mjs +18 -2
- package/fesm2022/ngx-dynamic-entity.mjs +1392 -1166
- package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
- package/lib/field-types/dropdown-field.component.d.ts +1 -1
- package/lib/field-types/entity-ref-field.component.d.ts +1 -1
- package/lib/field-types/multi-select-field.component.d.ts +1 -1
- package/lib/field-types/radio-field.component.d.ts +1 -1
- package/lib/form/dynamic-form.component.d.ts +93 -6
- package/lib/form/dynamic-record-form.component.d.ts +13 -2
- package/lib/providers/provide-ngx-dynamic-entity.d.ts +8 -2
- package/lib/tokens/injection-tokens.d.ts +24 -2
- package/package.json +17 -18
- package/public-api.d.ts +10 -0
package/README.md
CHANGED
|
@@ -1,139 +1,129 @@
|
|
|
1
|
-
# ngx-dynamic-entity
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
| Token | Purpose |
|
|
131
|
-
|---|---|
|
|
132
|
-
| `MASKED_ROLES` | Roles that see `XXXXXXXXX` for masked fields |
|
|
133
|
-
| `FIELD_TYPE_REGISTRY` | Consumer overrides: field type → component (highest priority) |
|
|
134
|
-
| `FIELD_TYPE_SETS` | Multi: field-type sets contributed by `provideFieldTypes()` |
|
|
135
|
-
| `ENTITY_REF_REGISTRY` | Entity key → `EntityReferenceLoader` |
|
|
136
|
-
| `VALIDATOR_REGISTRY` | Validator name → `ValidatorFn` |
|
|
137
|
-
| `HOOK_REGISTRY` | Hook key → handler (e.g. `entity:beforeSave`) |
|
|
138
|
-
| `COMMON_MODULES_REGISTRY` | Consumer-provided shared tab modules |
|
|
139
|
-
| `UPLOAD_HANDLER` | `(file) => UploadResult \| Promise \| Observable` |
|
|
1
|
+
# ngx-dynamic-entity
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ngx-dynamic-entity)
|
|
4
|
+
[](../../LICENSE)
|
|
5
|
+
|
|
6
|
+
Angular dynamic form renderer and tabbed record editor, powered by `@dynamic-entity/core`. Supports Angular 17 through 22.
|
|
7
|
+
|
|
8
|
+
> This package renders **forms**. It ships no data table — rendering a table over your records is the consumer's choice.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 📦 Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install ngx-dynamic-entity @dynamic-entity/core
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
No Angular Material required. This package has no dependency on Material or the CDK.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ✨ Features
|
|
23
|
+
|
|
24
|
+
- **`DynamicFormComponent`** — tabbed dynamic forms generated from an `EntityFormConfig`, built on Angular Reactive Forms.
|
|
25
|
+
- **`DynamicRecordFormComponent`** — record editor with summary drawer (`showOnMinimize`), profile header, and per-section saving.
|
|
26
|
+
- **Reactive rules** — real-time condition evaluation driving field/tab visibility, validation errors and warnings, and info banners.
|
|
27
|
+
- **Entity references & cascades** — consumer-registered loaders, parent→child dropdown filtering, and `autoPatch` record copying.
|
|
28
|
+
- **19 field types** — each a standalone component, registered explicitly so unused types are never bundled.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 🚀 Setup & Registration
|
|
33
|
+
|
|
34
|
+
Field types are **not** registered automatically. Without this step the form renders no fields.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// app.config.ts
|
|
38
|
+
import { ApplicationConfig } from '@angular/core';
|
|
39
|
+
import { provideNgxDynamicEntity, provideBuiltInFieldTypes } from 'ngx-dynamic-entity';
|
|
40
|
+
|
|
41
|
+
export const appConfig: ApplicationConfig = {
|
|
42
|
+
providers: [
|
|
43
|
+
provideNgxDynamicEntity({
|
|
44
|
+
maskedRoles: ['IT_SUPPORT'],
|
|
45
|
+
entityRefs: {
|
|
46
|
+
countries: () => fetch('/api/countries').then(res => res.json()),
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
provideBuiltInFieldTypes(),
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
To bundle only the types you use, register them individually instead:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { provideFieldTypes, TextFieldComponent, DropdownFieldComponent } from 'ngx-dynamic-entity';
|
|
58
|
+
|
|
59
|
+
provideFieldTypes({ text: TextFieldComponent, dropdown: DropdownFieldComponent });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Multiple `provideFieldTypes` calls merge; on a key collision the later registration wins. Pass your own component for a key to override a built-in, or add a key of your own for a custom type.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 💡 Usage
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<ngx-dynamic-form
|
|
70
|
+
[config]="formConfig"
|
|
71
|
+
[initialData]="record"
|
|
72
|
+
[userRoles]="['editor']"
|
|
73
|
+
[language]="'en'"
|
|
74
|
+
(formSubmit)="onSave($event)"
|
|
75
|
+
/>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Inputs
|
|
79
|
+
|
|
80
|
+
| Input | Type | Notes |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `config` | `EntityFormConfig` | Required. |
|
|
83
|
+
| `initialData` | `Record<string, any>` | See **Record shape** below. |
|
|
84
|
+
| `userRoles` | `string[]` | Drives permission and masking checks. Defaults to `[]`. |
|
|
85
|
+
| `language` | `string` | Defaults to `'en'`. |
|
|
86
|
+
| `rules` | `FormRule[]` | Optional reactive rules. |
|
|
87
|
+
| `originalData` | `Record<string, any>` | Baseline for the `VALUE_CHANGED` operator. |
|
|
88
|
+
| `readonly` | `boolean` | Renders the whole form read-only. |
|
|
89
|
+
| `readOnlyFields` | `string[]` | Read-only by field id. |
|
|
90
|
+
| `loading` / `error` | `boolean` / `string \| null` | Render loading and error states. |
|
|
91
|
+
|
|
92
|
+
### Outputs
|
|
93
|
+
|
|
94
|
+
| Output | Payload |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `formSubmit` | `Record<string, any>` |
|
|
97
|
+
| `formChange` | `Record<string, any>` |
|
|
98
|
+
| `formReset` | `void` |
|
|
99
|
+
| `activeTabChange` | `string` (tab id) |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 🗂 Record shape
|
|
104
|
+
|
|
105
|
+
A record is **nested by tab id** by default:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const record = { general: { firstName: 'Alice' }, billing: { vatNumber: 'GB123' } };
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Set `flatData: true` on a tab to store that tab's fields at the record root:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const record = { firstName: 'Alice', lastName: 'Smith' };
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This applies in both directions — `initialData` is read with it and `formSubmit` emits with it. **Passing a flat record to a tab that is not marked `flatData` leaves those fields empty**, with no error.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 🔐 Security
|
|
122
|
+
|
|
123
|
+
`userRoles`, `EntityPermissions`, and `maskData` affect **rendering only**. A masked field displays `XXXXXXXXX` while the real value stays in the form control and is included in the `formSubmit` payload. Enforce authorization on the server and never send a user data they may not see.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 🎨 Styling
|
|
128
|
+
|
|
129
|
+
This package ships no CSS. Field components emit `ngx-field`, `ngx-field__label`, `ngx-field__input`, and `ngx-field__error` for you to style. See `packages/demo-angular/src/styles.css` in the repository for a working reference.
|
|
@@ -37,110 +37,110 @@ export class ArrayFieldComponent {
|
|
|
37
37
|
this.formArray.removeAt(index);
|
|
38
38
|
}
|
|
39
39
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
40
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ArrayFieldComponent, isStandalone: true, selector: "ngx-array-field", inputs: { field: "field", control: "control", config: "config", language: "language", readonly: "readonly", masked: "masked", userRoles: "userRoles" }, ngImport: i0, template: `
|
|
41
|
-
<div class="ngx-field ngx-field--array"
|
|
42
|
-
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
43
|
-
<div class="ngx-field__array-header">
|
|
44
|
-
<label class="ngx-field__label">{{ label }}</label>
|
|
45
|
-
@if (!readonly && !masked) {
|
|
46
|
-
<button type="button" class="ngx-field__array-add-btn"
|
|
47
|
-
[attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
|
|
48
|
-
+ Add Item
|
|
49
|
-
</button>
|
|
50
|
-
}
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
@if (masked) {
|
|
54
|
-
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
55
|
-
} @else {
|
|
56
|
-
<div class="ngx-field__array-list">
|
|
57
|
-
@for (itemGroup of formArray.controls; track idx; let idx = $index) {
|
|
58
|
-
<div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
|
|
59
|
-
<div class="ngx-field__array-item-header">
|
|
60
|
-
<span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
|
|
61
|
-
@if (!readonly) {
|
|
62
|
-
<button type="button" class="ngx-field__array-remove-btn"
|
|
63
|
-
[attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
|
|
64
|
-
Remove
|
|
65
|
-
</button>
|
|
66
|
-
}
|
|
67
|
-
</div>
|
|
68
|
-
<div class="ngx-field__array-item-fields">
|
|
69
|
-
@for (child of field.children ?? []; track child.id) {
|
|
70
|
-
@if (child.visibility !== false) {
|
|
71
|
-
<ngx-dynamic-field
|
|
72
|
-
[field]="child"
|
|
73
|
-
[control]="getItemChildControl(itemGroup, child.id)"
|
|
74
|
-
[config]="config"
|
|
75
|
-
[language]="language"
|
|
76
|
-
[readonly]="readonly || !!child.readonly"
|
|
77
|
-
[userRoles]="userRoles"
|
|
78
|
-
/>
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
}
|
|
84
|
-
@if (formArray.controls.length === 0) {
|
|
85
|
-
<div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
|
|
86
|
-
}
|
|
87
|
-
</div>
|
|
88
|
-
}
|
|
89
|
-
</div>
|
|
40
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ArrayFieldComponent, isStandalone: true, selector: "ngx-array-field", inputs: { field: "field", control: "control", config: "config", language: "language", readonly: "readonly", masked: "masked", userRoles: "userRoles" }, ngImport: i0, template: `
|
|
41
|
+
<div class="ngx-field ngx-field--array"
|
|
42
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
43
|
+
<div class="ngx-field__array-header">
|
|
44
|
+
<label class="ngx-field__label">{{ label }}</label>
|
|
45
|
+
@if (!readonly && !masked) {
|
|
46
|
+
<button type="button" class="ngx-field__array-add-btn"
|
|
47
|
+
[attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
|
|
48
|
+
+ Add Item
|
|
49
|
+
</button>
|
|
50
|
+
}
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
@if (masked) {
|
|
54
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
55
|
+
} @else {
|
|
56
|
+
<div class="ngx-field__array-list">
|
|
57
|
+
@for (itemGroup of formArray.controls; track idx; let idx = $index) {
|
|
58
|
+
<div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
|
|
59
|
+
<div class="ngx-field__array-item-header">
|
|
60
|
+
<span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
|
|
61
|
+
@if (!readonly) {
|
|
62
|
+
<button type="button" class="ngx-field__array-remove-btn"
|
|
63
|
+
[attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
|
|
64
|
+
Remove
|
|
65
|
+
</button>
|
|
66
|
+
}
|
|
67
|
+
</div>
|
|
68
|
+
<div class="ngx-field__array-item-fields">
|
|
69
|
+
@for (child of field.children ?? []; track child.id) {
|
|
70
|
+
@if (child.visibility !== false) {
|
|
71
|
+
<ngx-dynamic-field
|
|
72
|
+
[field]="child"
|
|
73
|
+
[control]="getItemChildControl(itemGroup, child.id)"
|
|
74
|
+
[config]="config"
|
|
75
|
+
[language]="language"
|
|
76
|
+
[readonly]="readonly || !!child.readonly"
|
|
77
|
+
[userRoles]="userRoles"
|
|
78
|
+
/>
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
}
|
|
84
|
+
@if (formArray.controls.length === 0) {
|
|
85
|
+
<div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
|
|
86
|
+
}
|
|
87
|
+
</div>
|
|
88
|
+
}
|
|
89
|
+
</div>
|
|
90
90
|
`, isInline: true, styles: [".ngx-field--array{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#f8fafc}.ngx-field__array-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ngx-field__array-add-btn{background:#2563eb;color:#fff;border:none;padding:6px 12px;border-radius:4px;font-weight:500;cursor:pointer}.ngx-field__array-add-btn:hover{background:#1d4ed8}.ngx-field__array-list{display:flex;flex-direction:column;gap:12px}.ngx-field__array-item{background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:12px}.ngx-field__array-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;border-bottom:1px solid #f1f5f9;padding-bottom:6px}.ngx-field__array-item-title{font-weight:600;font-size:13px;color:#475569}.ngx-field__array-remove-btn{background:#ef4444;color:#fff;border:none;padding:4px 8px;border-radius:4px;font-size:12px;cursor:pointer}.ngx-field__array-empty{color:#94a3b8;font-style:italic;font-size:13px}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "component", type: i0.forwardRef(() => DynamicFieldComponent), selector: "ngx-dynamic-field", inputs: ["field", "control", "config", "currentTabId", "language", "readonly", "userRoles"] }] });
|
|
91
91
|
}
|
|
92
92
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayFieldComponent, decorators: [{
|
|
93
93
|
type: Component,
|
|
94
|
-
args: [{ selector: 'ngx-array-field', standalone: true, imports: [ReactiveFormsModule, forwardRef(() => DynamicFieldComponent)], template: `
|
|
95
|
-
<div class="ngx-field ngx-field--array"
|
|
96
|
-
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
97
|
-
<div class="ngx-field__array-header">
|
|
98
|
-
<label class="ngx-field__label">{{ label }}</label>
|
|
99
|
-
@if (!readonly && !masked) {
|
|
100
|
-
<button type="button" class="ngx-field__array-add-btn"
|
|
101
|
-
[attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
|
|
102
|
-
+ Add Item
|
|
103
|
-
</button>
|
|
104
|
-
}
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
@if (masked) {
|
|
108
|
-
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
109
|
-
} @else {
|
|
110
|
-
<div class="ngx-field__array-list">
|
|
111
|
-
@for (itemGroup of formArray.controls; track idx; let idx = $index) {
|
|
112
|
-
<div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
|
|
113
|
-
<div class="ngx-field__array-item-header">
|
|
114
|
-
<span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
|
|
115
|
-
@if (!readonly) {
|
|
116
|
-
<button type="button" class="ngx-field__array-remove-btn"
|
|
117
|
-
[attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
|
|
118
|
-
Remove
|
|
119
|
-
</button>
|
|
120
|
-
}
|
|
121
|
-
</div>
|
|
122
|
-
<div class="ngx-field__array-item-fields">
|
|
123
|
-
@for (child of field.children ?? []; track child.id) {
|
|
124
|
-
@if (child.visibility !== false) {
|
|
125
|
-
<ngx-dynamic-field
|
|
126
|
-
[field]="child"
|
|
127
|
-
[control]="getItemChildControl(itemGroup, child.id)"
|
|
128
|
-
[config]="config"
|
|
129
|
-
[language]="language"
|
|
130
|
-
[readonly]="readonly || !!child.readonly"
|
|
131
|
-
[userRoles]="userRoles"
|
|
132
|
-
/>
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
}
|
|
138
|
-
@if (formArray.controls.length === 0) {
|
|
139
|
-
<div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
|
|
140
|
-
}
|
|
141
|
-
</div>
|
|
142
|
-
}
|
|
143
|
-
</div>
|
|
94
|
+
args: [{ selector: 'ngx-array-field', standalone: true, imports: [ReactiveFormsModule, forwardRef(() => DynamicFieldComponent)], template: `
|
|
95
|
+
<div class="ngx-field ngx-field--array"
|
|
96
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
97
|
+
<div class="ngx-field__array-header">
|
|
98
|
+
<label class="ngx-field__label">{{ label }}</label>
|
|
99
|
+
@if (!readonly && !masked) {
|
|
100
|
+
<button type="button" class="ngx-field__array-add-btn"
|
|
101
|
+
[attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
|
|
102
|
+
+ Add Item
|
|
103
|
+
</button>
|
|
104
|
+
}
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
@if (masked) {
|
|
108
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
109
|
+
} @else {
|
|
110
|
+
<div class="ngx-field__array-list">
|
|
111
|
+
@for (itemGroup of formArray.controls; track idx; let idx = $index) {
|
|
112
|
+
<div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
|
|
113
|
+
<div class="ngx-field__array-item-header">
|
|
114
|
+
<span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
|
|
115
|
+
@if (!readonly) {
|
|
116
|
+
<button type="button" class="ngx-field__array-remove-btn"
|
|
117
|
+
[attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
|
|
118
|
+
Remove
|
|
119
|
+
</button>
|
|
120
|
+
}
|
|
121
|
+
</div>
|
|
122
|
+
<div class="ngx-field__array-item-fields">
|
|
123
|
+
@for (child of field.children ?? []; track child.id) {
|
|
124
|
+
@if (child.visibility !== false) {
|
|
125
|
+
<ngx-dynamic-field
|
|
126
|
+
[field]="child"
|
|
127
|
+
[control]="getItemChildControl(itemGroup, child.id)"
|
|
128
|
+
[config]="config"
|
|
129
|
+
[language]="language"
|
|
130
|
+
[readonly]="readonly || !!child.readonly"
|
|
131
|
+
[userRoles]="userRoles"
|
|
132
|
+
/>
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
}
|
|
138
|
+
@if (formArray.controls.length === 0) {
|
|
139
|
+
<div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
|
|
140
|
+
}
|
|
141
|
+
</div>
|
|
142
|
+
}
|
|
143
|
+
</div>
|
|
144
144
|
`, styles: [".ngx-field--array{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#f8fafc}.ngx-field__array-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ngx-field__array-add-btn{background:#2563eb;color:#fff;border:none;padding:6px 12px;border-radius:4px;font-weight:500;cursor:pointer}.ngx-field__array-add-btn:hover{background:#1d4ed8}.ngx-field__array-list{display:flex;flex-direction:column;gap:12px}.ngx-field__array-item{background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:12px}.ngx-field__array-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;border-bottom:1px solid #f1f5f9;padding-bottom:6px}.ngx-field__array-item-title{font-weight:600;font-size:13px;color:#475569}.ngx-field__array-remove-btn{background:#ef4444;color:#fff;border:none;padding:4px 8px;border-radius:4px;font-size:12px;cursor:pointer}.ngx-field__array-empty{color:#94a3b8;font-style:italic;font-size:13px}\n"] }]
|
|
145
145
|
}], propDecorators: { field: [{
|
|
146
146
|
type: Input
|
|
@@ -157,4 +157,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
157
157
|
}], userRoles: [{
|
|
158
158
|
type: Input
|
|
159
159
|
}] } });
|
|
160
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXktZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9hcnJheS1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNyRSxPQUFPLEVBQThCLFdBQVcsRUFBYSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUN0RixPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQzs7QUFFbEYscUdBQXFHO0FBNEhyRyxNQUFNLE9BQU8sbUJBQW1CO0lBQ3JCLEtBQUssQ0FBcUI7SUFDMUIsT0FBTyxDQUFtQjtJQUMxQixNQUFNLENBQW9CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBQ3hCLFNBQVMsR0FBYSxFQUFFLENBQUM7SUFFakIsRUFBRSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN6QixpQkFBaUIsR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsQ0FBQztJQUV0RSxJQUFJLEtBQUs7UUFDUCxPQUFPLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVELElBQUksU0FBUztRQUNYLE9BQU8sSUFBSSxDQUFDLE9BQW9CLENBQUM7SUFDbkMsQ0FBQztJQUVELG1CQUFtQixDQUFDLFNBQTBCLEVBQUUsT0FBZTtRQUM3RCxPQUFRLFNBQXVCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBb0IsQ0FBQztJQUNsRSxDQUFDO0lBRUQsT0FBTztRQUNMLE1BQU0sUUFBUSxHQUF3QixFQUFFLENBQUM7UUFDekMsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUM5QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzlFLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxJQUFJLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDdEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVELFVBQVUsQ0FBQyxLQUFhO1FBQ3RCLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7d0dBcENVLG1CQUFtQjs0RkFBbkIsbUJBQW1CLG1PQXZIcEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0RULDZrQ0FuRFMsbUJBQW1CLG9EQUFtQixxQkFBcUI7OzRGQXdIMUQsbUJBQW1CO2tCQTNIL0IsU0FBUzsrQkFDRSxpQkFBaUIsY0FDZixJQUFJLFdBQ1AsQ0FBQyxtQkFBbUIsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMscUJBQXFCLENBQUMsQ0FBQyxZQUM3RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrRFQ7OEJBc0VRLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIGluamVjdCwgZm9yd2FyZFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1BcnJheSwgRm9ybUJ1aWxkZXIsIEZvcm1Hcm91cCwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHR5cGUgeyBOZXN0ZWRGaWVsZENvbmZpZywgRW50aXR5Rm9ybUNvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xyXG5pbXBvcnQgeyBEeW5hbWljRmllbGRDb21wb25lbnQgfSBmcm9tICcuLi9mb3JtL2R5bmFtaWMtZmllbGQvZHluYW1pYy1maWVsZC5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy92YWxpZGF0b3ItcmVnaXN0cnkuc2VydmljZSc7XHJcblxyXG4vKiogQURSLTAwODogQXJyYXlGaWVsZENvbXBvbmVudCDigJQgcmVuZGVycyByZXBlYXRpbmcgcm93cyBmb3IgRm9ybUFycmF5IHdpdGggKyBBZGQgSXRlbSBhbmQgUmVtb3ZlICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmd4LWFycmF5LWZpZWxkJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlLCBmb3J3YXJkUmVmKCgpID0+IER5bmFtaWNGaWVsZENvbXBvbmVudCldLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkIG5neC1maWVsZC0tYXJyYXlcIlxyXG4gICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCIgW2F0dHIuZGF0YS1maWVsZC10eXBlXT1cImZpZWxkLnR5cGVcIiBbY2xhc3Mubmd4LWZpZWxkLS1yZWFkb25seV09XCJyZWFkb25seVwiIFtjbGFzcy5uZ3gtZmllbGQtLW1hc2tlZF09XCJtYXNrZWRcIj5cclxuICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaGVhZGVyXCI+XHJcbiAgICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX19sYWJlbFwiPnt7IGxhYmVsIH19PC9sYWJlbD5cclxuICAgICAgICBAaWYgKCFyZWFkb25seSAmJiAhbWFza2VkKSB7XHJcbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktYWRkLWJ0blwiXHJcbiAgICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLWFkZCdcIiAoY2xpY2spPVwiYWRkSXRlbSgpXCI+XHJcbiAgICAgICAgICAgICsgQWRkIEl0ZW1cclxuICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgIH1cclxuICAgICAgPC9kaXY+XHJcblxyXG4gICAgICBAaWYgKG1hc2tlZCkge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxyXG4gICAgICB9IEBlbHNlIHtcclxuICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1saXN0XCI+XHJcbiAgICAgICAgICBAZm9yIChpdGVtR3JvdXAgb2YgZm9ybUFycmF5LmNvbnRyb2xzOyB0cmFjayBpZHg7IGxldCBpZHggPSAkaW5kZXgpIHtcclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaXRlbVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXJvdydcIj5cclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1pdGVtLWhlYWRlclwiPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWl0ZW0tdGl0bGVcIj5JdGVtICN7eyBpZHggKyAxIH19PC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgQGlmICghcmVhZG9ubHkpIHtcclxuICAgICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LXJlbW92ZS1idG5cIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXJlbW92ZS0nICsgaWR4XCIgKGNsaWNrKT1cInJlbW92ZUl0ZW0oaWR4KVwiPlxyXG4gICAgICAgICAgICAgICAgICAgIFJlbW92ZVxyXG4gICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1pdGVtLWZpZWxkc1wiPlxyXG4gICAgICAgICAgICAgICAgQGZvciAoY2hpbGQgb2YgZmllbGQuY2hpbGRyZW4gPz8gW107IHRyYWNrIGNoaWxkLmlkKSB7XHJcbiAgICAgICAgICAgICAgICAgIEBpZiAoY2hpbGQudmlzaWJpbGl0eSAhPT0gZmFsc2UpIHtcclxuICAgICAgICAgICAgICAgICAgICA8bmd4LWR5bmFtaWMtZmllbGRcclxuICAgICAgICAgICAgICAgICAgICAgIFtmaWVsZF09XCJjaGlsZFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbY29udHJvbF09XCJnZXRJdGVtQ2hpbGRDb250cm9sKGl0ZW1Hcm91cCwgY2hpbGQuaWQpXCJcclxuICAgICAgICAgICAgICAgICAgICAgIFtjb25maWddPVwiY29uZmlnXCJcclxuICAgICAgICAgICAgICAgICAgICAgIFtsYW5ndWFnZV09XCJsYW5ndWFnZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbcmVhZG9ubHldPVwicmVhZG9ubHkgfHwgISFjaGlsZC5yZWFkb25seVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbdXNlclJvbGVzXT1cInVzZXJSb2xlc1wiXHJcbiAgICAgICAgICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIEBpZiAoZm9ybUFycmF5LmNvbnRyb2xzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1lbXB0eVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLWVtcHR5J1wiPk5vIGl0ZW1zIGFkZGVkIHlldC48L2Rpdj5cclxuICAgICAgICAgIH1cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxuICBzdHlsZXM6IFtcclxuICAgIGBcclxuICAgICAgLm5neC1maWVsZC0tYXJyYXkge1xyXG4gICAgICAgIGJvcmRlcjogMXB4IHNvbGlkICNlMmU4ZjA7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogOHB4O1xyXG4gICAgICAgIHBhZGRpbmc6IDE2cHg7XHJcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMTZweDtcclxuICAgICAgICBiYWNrZ3JvdW5kOiAjZjhmYWZjO1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWhlYWRlciB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAxMnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWFkZC1idG4ge1xyXG4gICAgICAgIGJhY2tncm91bmQ6ICMyNTYzZWI7XHJcbiAgICAgICAgY29sb3I6ICNmZmY7XHJcbiAgICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICAgIHBhZGRpbmc6IDZweCAxMnB4O1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDRweDtcclxuICAgICAgICBmb250LXdlaWdodDogNTAwO1xyXG4gICAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgfVxyXG4gICAgICAubmd4LWZpZWxkX19hcnJheS1hZGQtYnRuOmhvdmVyIHtcclxuICAgICAgICBiYWNrZ3JvdW5kOiAjMWQ0ZWQ4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWxpc3Qge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgICBnYXA6IDEycHg7XHJcbiAgICAgIH1cclxuICAgICAgLm5neC1maWVsZF9fYXJyYXktaXRlbSB7XHJcbiAgICAgICAgYmFja2dyb3VuZDogI2ZmZjtcclxuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCAjY2JkNWUxO1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDZweDtcclxuICAgICAgICBwYWRkaW5nOiAxMnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWl0ZW0taGVhZGVyIHtcclxuICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcclxuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDhweDtcclxuICAgICAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2YxZjVmOTtcclxuICAgICAgICBwYWRkaW5nLWJvdHRvbTogNnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWl0ZW0tdGl0bGUge1xyXG4gICAgICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICAgICAgZm9udC1zaXplOiAxM3B4O1xyXG4gICAgICAgIGNvbG9yOiAjNDc1NTY5O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LXJlbW92ZS1idG4ge1xyXG4gICAgICAgIGJhY2tncm91bmQ6ICNlZjQ0NDQ7XHJcbiAgICAgICAgY29sb3I6ICNmZmY7XHJcbiAgICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICAgIHBhZGRpbmc6IDRweCA4cHg7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNHB4O1xyXG4gICAgICAgIGZvbnQtc2l6ZTogMTJweDtcclxuICAgICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIH1cclxuICAgICAgLm5neC1maWVsZF9fYXJyYXktZW1wdHkge1xyXG4gICAgICAgIGNvbG9yOiAjOTRhM2I4O1xyXG4gICAgICAgIGZvbnQtc3R5bGU6IGl0YWxpYztcclxuICAgICAgICBmb250LXNpemU6IDEzcHg7XHJcbiAgICAgIH1cclxuICAgIGAsXHJcbiAgXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIEFycmF5RmllbGRDb21wb25lbnQge1xyXG4gIEBJbnB1dCgpIGZpZWxkITogTmVzdGVkRmllbGRDb25maWc7XHJcbiAgQElucHV0KCkgY29udHJvbCE6IEFic3RyYWN0Q29udHJvbDtcclxuICBASW5wdXQoKSBjb25maWchOiBFbnRpdHlGb3JtQ29uZmlnO1xyXG4gIEBJbnB1dCgpIGxhbmd1YWdlOiBzdHJpbmcgPSAnZW4nO1xyXG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgdXNlclJvbGVzOiBzdHJpbmdbXSA9IFtdO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGZiID0gaW5qZWN0KEZvcm1CdWlsZGVyKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IHZhbGlkYXRvclJlZ2lzdHJ5ID0gaW5qZWN0KFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSk7XHJcblxyXG4gIGdldCBsYWJlbCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XHJcbiAgfVxyXG5cclxuICBnZXQgZm9ybUFycmF5KCk6IEZvcm1BcnJheSB7XHJcbiAgICByZXR1cm4gdGhpcy5jb250cm9sIGFzIEZvcm1BcnJheTtcclxuICB9XHJcblxyXG4gIGdldEl0ZW1DaGlsZENvbnRyb2woaXRlbUdyb3VwOiBBYnN0cmFjdENvbnRyb2wsIGNoaWxkSWQ6IHN0cmluZyk6IEFic3RyYWN0Q29udHJvbCB7XHJcbiAgICByZXR1cm4gKGl0ZW1Hcm91cCBhcyBGb3JtR3JvdXApLmdldChjaGlsZElkKSBhcyBBYnN0cmFjdENvbnRyb2w7XHJcbiAgfVxyXG5cclxuICBhZGRJdGVtKCk6IHZvaWQge1xyXG4gICAgY29uc3QgY29udHJvbHM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcclxuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgdGhpcy5maWVsZC5jaGlsZHJlbiA/PyBbXSkge1xyXG4gICAgICBjb25zdCB2YWxpZGF0b3JzID0gdGhpcy52YWxpZGF0b3JSZWdpc3RyeS5yZXNvbHZlRnJvbUNvbmZpZyhjaGlsZC52YWxpZGF0b3JzKTtcclxuICAgICAgY29udHJvbHNbY2hpbGQuaWRdID0gW2NoaWxkLmRlZmF1bHRWYWx1ZSA/PyBudWxsLCB2YWxpZGF0b3JzXTtcclxuICAgIH1cclxuICAgIGNvbnN0IGdyb3VwID0gdGhpcy5mYi5ncm91cChjb250cm9scyk7XHJcbiAgICB0aGlzLmZvcm1BcnJheS5wdXNoKGdyb3VwKTtcclxuICB9XHJcblxyXG4gIHJlbW92ZUl0ZW0oaW5kZXg6IG51bWJlcik6IHZvaWQge1xyXG4gICAgdGhpcy5mb3JtQXJyYXkucmVtb3ZlQXQoaW5kZXgpO1xyXG4gIH1cclxufVxyXG4iXX0=
|
|
160
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXktZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9hcnJheS1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNyRSxPQUFPLEVBQThCLFdBQVcsRUFBYSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUN0RixPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQzs7QUFFbEYscUdBQXFHO0FBNEhyRyxNQUFNLE9BQU8sbUJBQW1CO0lBQ3JCLEtBQUssQ0FBcUI7SUFDMUIsT0FBTyxDQUFtQjtJQUMxQixNQUFNLENBQW9CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBQ3hCLFNBQVMsR0FBYSxFQUFFLENBQUM7SUFFakIsRUFBRSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN6QixpQkFBaUIsR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsQ0FBQztJQUV0RSxJQUFJLEtBQUs7UUFDUCxPQUFPLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVELElBQUksU0FBUztRQUNYLE9BQU8sSUFBSSxDQUFDLE9BQW9CLENBQUM7SUFDbkMsQ0FBQztJQUVELG1CQUFtQixDQUFDLFNBQTBCLEVBQUUsT0FBZTtRQUM3RCxPQUFRLFNBQXVCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBb0IsQ0FBQztJQUNsRSxDQUFDO0lBRUQsT0FBTztRQUNMLE1BQU0sUUFBUSxHQUF3QixFQUFFLENBQUM7UUFDekMsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUM5QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzlFLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxJQUFJLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDdEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVELFVBQVUsQ0FBQyxLQUFhO1FBQ3RCLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7d0dBcENVLG1CQUFtQjs0RkFBbkIsbUJBQW1CLG1PQXZIcEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0RULDZrQ0FuRFMsbUJBQW1CLG9EQUFtQixxQkFBcUI7OzRGQXdIMUQsbUJBQW1CO2tCQTNIL0IsU0FBUzsrQkFDRSxpQkFBaUIsY0FDZixJQUFJLFdBQ1AsQ0FBQyxtQkFBbUIsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMscUJBQXFCLENBQUMsQ0FBQyxZQUM3RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrRFQ7OEJBc0VRLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIGluamVjdCwgZm9yd2FyZFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBGb3JtQXJyYXksIEZvcm1CdWlsZGVyLCBGb3JtR3JvdXAsIFJlYWN0aXZlRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgdHlwZSB7IE5lc3RlZEZpZWxkQ29uZmlnLCBFbnRpdHlGb3JtQ29uZmlnIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgRHluYW1pY0ZpZWxkQ29tcG9uZW50IH0gZnJvbSAnLi4vZm9ybS9keW5hbWljLWZpZWxkL2R5bmFtaWMtZmllbGQuY29tcG9uZW50JztcbmltcG9ydCB7IFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL3ZhbGlkYXRvci1yZWdpc3RyeS5zZXJ2aWNlJztcblxuLyoqIEFEUi0wMDg6IEFycmF5RmllbGRDb21wb25lbnQg4oCUIHJlbmRlcnMgcmVwZWF0aW5nIHJvd3MgZm9yIEZvcm1BcnJheSB3aXRoICsgQWRkIEl0ZW0gYW5kIFJlbW92ZSAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LWFycmF5LWZpZWxkJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1JlYWN0aXZlRm9ybXNNb2R1bGUsIGZvcndhcmRSZWYoKCkgPT4gRHluYW1pY0ZpZWxkQ29tcG9uZW50KV0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZCBuZ3gtZmllbGQtLWFycmF5XCJcbiAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWRcIiBbYXR0ci5kYXRhLWZpZWxkLXR5cGVdPVwiZmllbGQudHlwZVwiIFtjbGFzcy5uZ3gtZmllbGQtLXJlYWRvbmx5XT1cInJlYWRvbmx5XCIgW2NsYXNzLm5neC1maWVsZC0tbWFza2VkXT1cIm1hc2tlZFwiPlxuICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaGVhZGVyXCI+XG4gICAgICAgIDxsYWJlbCBjbGFzcz1cIm5neC1maWVsZF9fbGFiZWxcIj57eyBsYWJlbCB9fTwvbGFiZWw+XG4gICAgICAgIEBpZiAoIXJlYWRvbmx5ICYmICFtYXNrZWQpIHtcbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktYWRkLWJ0blwiXG4gICAgICAgICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1hZGQnXCIgKGNsaWNrKT1cImFkZEl0ZW0oKVwiPlxuICAgICAgICAgICAgKyBBZGQgSXRlbVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cblxuICAgICAgQGlmIChtYXNrZWQpIHtcbiAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlIG5neC1maWVsZF9fdmFsdWUtLW1hc2tlZFwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLW1hc2tlZCdcIj5YWFhYWFhYWFg8L3NwYW4+XG4gICAgICB9IEBlbHNlIHtcbiAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktbGlzdFwiPlxuICAgICAgICAgIEBmb3IgKGl0ZW1Hcm91cCBvZiBmb3JtQXJyYXkuY29udHJvbHM7IHRyYWNrIGlkeDsgbGV0IGlkeCA9ICRpbmRleCkge1xuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaXRlbVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXJvdydcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaXRlbS1oZWFkZXJcIj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaXRlbS10aXRsZVwiPkl0ZW0gI3t7IGlkeCArIDEgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgQGlmICghcmVhZG9ubHkpIHtcbiAgICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1yZW1vdmUtYnRuXCJcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctcmVtb3ZlLScgKyBpZHhcIiAoY2xpY2spPVwicmVtb3ZlSXRlbShpZHgpXCI+XG4gICAgICAgICAgICAgICAgICAgIFJlbW92ZVxuICAgICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaXRlbS1maWVsZHNcIj5cbiAgICAgICAgICAgICAgICBAZm9yIChjaGlsZCBvZiBmaWVsZC5jaGlsZHJlbiA/PyBbXTsgdHJhY2sgY2hpbGQuaWQpIHtcbiAgICAgICAgICAgICAgICAgIEBpZiAoY2hpbGQudmlzaWJpbGl0eSAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgPG5neC1keW5hbWljLWZpZWxkXG4gICAgICAgICAgICAgICAgICAgICAgW2ZpZWxkXT1cImNoaWxkXCJcbiAgICAgICAgICAgICAgICAgICAgICBbY29udHJvbF09XCJnZXRJdGVtQ2hpbGRDb250cm9sKGl0ZW1Hcm91cCwgY2hpbGQuaWQpXCJcbiAgICAgICAgICAgICAgICAgICAgICBbY29uZmlnXT1cImNvbmZpZ1wiXG4gICAgICAgICAgICAgICAgICAgICAgW2xhbmd1YWdlXT1cImxhbmd1YWdlXCJcbiAgICAgICAgICAgICAgICAgICAgICBbcmVhZG9ubHldPVwicmVhZG9ubHkgfHwgISFjaGlsZC5yZWFkb25seVwiXG4gICAgICAgICAgICAgICAgICAgICAgW3VzZXJSb2xlc109XCJ1c2VyUm9sZXNcIlxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG4gICAgICAgICAgQGlmIChmb3JtQXJyYXkuY29udHJvbHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1lbXB0eVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLWVtcHR5J1wiPk5vIGl0ZW1zIGFkZGVkIHlldC48L2Rpdj5cbiAgICAgICAgICB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgfVxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZXM6IFtcbiAgICBgXG4gICAgICAubmd4LWZpZWxkLS1hcnJheSB7XG4gICAgICAgIGJvcmRlcjogMXB4IHNvbGlkICNlMmU4ZjA7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDhweDtcbiAgICAgICAgcGFkZGluZzogMTZweDtcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMTZweDtcbiAgICAgICAgYmFja2dyb3VuZDogI2Y4ZmFmYztcbiAgICAgIH1cbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWhlYWRlciB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMTJweDtcbiAgICAgIH1cbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWFkZC1idG4ge1xuICAgICAgICBiYWNrZ3JvdW5kOiAjMjU2M2ViO1xuICAgICAgICBjb2xvcjogI2ZmZjtcbiAgICAgICAgYm9yZGVyOiBub25lO1xuICAgICAgICBwYWRkaW5nOiA2cHggMTJweDtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNHB4O1xuICAgICAgICBmb250LXdlaWdodDogNTAwO1xuICAgICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICB9XG4gICAgICAubmd4LWZpZWxkX19hcnJheS1hZGQtYnRuOmhvdmVyIHtcbiAgICAgICAgYmFja2dyb3VuZDogIzFkNGVkODtcbiAgICAgIH1cbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWxpc3Qge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICAgICAgICBnYXA6IDEycHg7XG4gICAgICB9XG4gICAgICAubmd4LWZpZWxkX19hcnJheS1pdGVtIHtcbiAgICAgICAgYmFja2dyb3VuZDogI2ZmZjtcbiAgICAgICAgYm9yZGVyOiAxcHggc29saWQgI2NiZDVlMTtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNnB4O1xuICAgICAgICBwYWRkaW5nOiAxMnB4O1xuICAgICAgfVxuICAgICAgLm5neC1maWVsZF9fYXJyYXktaXRlbS1oZWFkZXIge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDhweDtcbiAgICAgICAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNmMWY1Zjk7XG4gICAgICAgIHBhZGRpbmctYm90dG9tOiA2cHg7XG4gICAgICB9XG4gICAgICAubmd4LWZpZWxkX19hcnJheS1pdGVtLXRpdGxlIHtcbiAgICAgICAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgICAgICAgZm9udC1zaXplOiAxM3B4O1xuICAgICAgICBjb2xvcjogIzQ3NTU2OTtcbiAgICAgIH1cbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LXJlbW92ZS1idG4ge1xuICAgICAgICBiYWNrZ3JvdW5kOiAjZWY0NDQ0O1xuICAgICAgICBjb2xvcjogI2ZmZjtcbiAgICAgICAgYm9yZGVyOiBub25lO1xuICAgICAgICBwYWRkaW5nOiA0cHggOHB4O1xuICAgICAgICBib3JkZXItcmFkaXVzOiA0cHg7XG4gICAgICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgfVxuICAgICAgLm5neC1maWVsZF9fYXJyYXktZW1wdHkge1xuICAgICAgICBjb2xvcjogIzk0YTNiODtcbiAgICAgICAgZm9udC1zdHlsZTogaXRhbGljO1xuICAgICAgICBmb250LXNpemU6IDEzcHg7XG4gICAgICB9XG4gICAgYCxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgQXJyYXlGaWVsZENvbXBvbmVudCB7XG4gIEBJbnB1dCgpIGZpZWxkITogTmVzdGVkRmllbGRDb25maWc7XG4gIEBJbnB1dCgpIGNvbnRyb2whOiBBYnN0cmFjdENvbnRyb2w7XG4gIEBJbnB1dCgpIGNvbmZpZyE6IEVudGl0eUZvcm1Db25maWc7XG4gIEBJbnB1dCgpIGxhbmd1YWdlOiBzdHJpbmcgPSAnZW4nO1xuICBASW5wdXQoKSByZWFkb25seTogYm9vbGVhbiA9IGZhbHNlO1xuICBASW5wdXQoKSBtYXNrZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgdXNlclJvbGVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZmIgPSBpbmplY3QoRm9ybUJ1aWxkZXIpO1xuICBwcml2YXRlIHJlYWRvbmx5IHZhbGlkYXRvclJlZ2lzdHJ5ID0gaW5qZWN0KFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSk7XG5cbiAgZ2V0IGxhYmVsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XG4gIH1cblxuICBnZXQgZm9ybUFycmF5KCk6IEZvcm1BcnJheSB7XG4gICAgcmV0dXJuIHRoaXMuY29udHJvbCBhcyBGb3JtQXJyYXk7XG4gIH1cblxuICBnZXRJdGVtQ2hpbGRDb250cm9sKGl0ZW1Hcm91cDogQWJzdHJhY3RDb250cm9sLCBjaGlsZElkOiBzdHJpbmcpOiBBYnN0cmFjdENvbnRyb2wge1xuICAgIHJldHVybiAoaXRlbUdyb3VwIGFzIEZvcm1Hcm91cCkuZ2V0KGNoaWxkSWQpIGFzIEFic3RyYWN0Q29udHJvbDtcbiAgfVxuXG4gIGFkZEl0ZW0oKTogdm9pZCB7XG4gICAgY29uc3QgY29udHJvbHM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIHRoaXMuZmllbGQuY2hpbGRyZW4gPz8gW10pIHtcbiAgICAgIGNvbnN0IHZhbGlkYXRvcnMgPSB0aGlzLnZhbGlkYXRvclJlZ2lzdHJ5LnJlc29sdmVGcm9tQ29uZmlnKGNoaWxkLnZhbGlkYXRvcnMpO1xuICAgICAgY29udHJvbHNbY2hpbGQuaWRdID0gW2NoaWxkLmRlZmF1bHRWYWx1ZSA/PyBudWxsLCB2YWxpZGF0b3JzXTtcbiAgICB9XG4gICAgY29uc3QgZ3JvdXAgPSB0aGlzLmZiLmdyb3VwKGNvbnRyb2xzKTtcbiAgICB0aGlzLmZvcm1BcnJheS5wdXNoKGdyb3VwKTtcbiAgfVxuXG4gIHJlbW92ZUl0ZW0oaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuZm9ybUFycmF5LnJlbW92ZUF0KGluZGV4KTtcbiAgfVxufVxuIl19
|