alimetry-detail-edit 1.0.0 → 1.2.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 +8 -4
- package/esm2020/lib/detail-edit.component.mjs +68 -55
- package/esm2020/lib/utils.mjs +6 -1
- package/fesm2015/alimetry-detail-edit.mjs +72 -56
- package/fesm2015/alimetry-detail-edit.mjs.map +1 -1
- package/fesm2020/alimetry-detail-edit.mjs +71 -53
- package/fesm2020/alimetry-detail-edit.mjs.map +1 -1
- package/lib/detail-edit.component.d.ts +15 -7
- package/lib/utils.d.ts +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,10 +6,14 @@ Selector: `lib-detail-edit`
|
|
|
6
6
|
|
|
7
7
|
### Config Object
|
|
8
8
|
|
|
9
|
+
```js
|
|
9
10
|
{
|
|
10
|
-
owners:
|
|
11
|
-
deviceDataModelId,
|
|
12
|
-
|
|
11
|
+
owners: string[], // user ids
|
|
12
|
+
deviceDataModelId: string,
|
|
13
|
+
currentUserId: string
|
|
13
14
|
}
|
|
15
|
+
```
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
### Dependencies
|
|
18
|
+
|
|
19
|
+
`alimetry-shared` library as a peer dependency
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Component, Input } from '@angular/core';
|
|
2
2
|
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
|
3
3
|
import { forkJoin, tap } from 'rxjs';
|
|
4
|
-
import { getAge, globaliseDateTime, localiseDateTime, shallowCompare } from './utils';
|
|
4
|
+
import { getAge, globaliseDateTime, localiseDateTime, shallowCompare, shallowDiff } from './utils';
|
|
5
5
|
import { dateComparison, withinNYears, withinNHours, translateError } from './validators';
|
|
6
6
|
import * as i0 from "@angular/core";
|
|
7
|
-
import * as i1 from "shared";
|
|
7
|
+
import * as i1 from "alimetry-shared";
|
|
8
8
|
import * as i2 from "@angular/forms";
|
|
9
9
|
import * as i3 from "@angular/common";
|
|
10
10
|
import * as i4 from "./entries.pipe";
|
|
@@ -12,8 +12,10 @@ const appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';
|
|
|
12
12
|
const deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';
|
|
13
13
|
const propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];
|
|
14
14
|
export class DetailEditComponent {
|
|
15
|
-
constructor(shared) {
|
|
15
|
+
constructor(shared, kvDiffers, itDiffers) {
|
|
16
16
|
this.shared = shared;
|
|
17
|
+
this.kvDiffers = kvDiffers;
|
|
18
|
+
this.itDiffers = itDiffers;
|
|
17
19
|
this.status = 'loading';
|
|
18
20
|
this.formGroup = new FormGroup({
|
|
19
21
|
dob: new FormControl('', [Validators.required, withinNYears(120, 'before')]),
|
|
@@ -65,7 +67,7 @@ export class DetailEditComponent {
|
|
|
65
67
|
patient.age = getAge(mods.dob);
|
|
66
68
|
recordingSession.mealStart = globaliseDateTime(mods.mealStart);
|
|
67
69
|
recordingSession.mealEnd = globaliseDateTime(mods.mealEnd);
|
|
68
|
-
this.
|
|
70
|
+
this.logChange(mods);
|
|
69
71
|
return {
|
|
70
72
|
'Age': patient.age,
|
|
71
73
|
'RecordingSession': JSON.stringify(recordingSession),
|
|
@@ -73,55 +75,27 @@ export class DetailEditComponent {
|
|
|
73
75
|
};
|
|
74
76
|
}
|
|
75
77
|
postDeviceData(devicePropertySetId, data) {
|
|
76
|
-
return this.shared.saveDeviceData(this.config.deviceDataModelId, this.deviceDataId, devicePropertySetId, this.config.owners[0]
|
|
78
|
+
return this.shared.saveDeviceData(this.config.deviceDataModelId, this.deviceDataId, devicePropertySetId, this.config.owners[0], data);
|
|
77
79
|
}
|
|
78
80
|
// patch the device data record with the modifications
|
|
79
81
|
saveModifications() {
|
|
80
82
|
const mods = this.formGroup.getRawValue();
|
|
81
83
|
const patchedDeviceData = this.integrateFields(mods, this.recordingSession);
|
|
82
|
-
const patchedUserData = Object.assign(this.
|
|
84
|
+
const patchedUserData = Object.assign(this.owner, { dateOfBirth: mods.dob });
|
|
83
85
|
this.status = 'sending';
|
|
84
86
|
forkJoin([
|
|
85
87
|
this.postDeviceData(appDataPropertySetId, patchedDeviceData),
|
|
86
|
-
this.shared.updateUser(this.config.owners[0]
|
|
88
|
+
this.shared.updateUser(this.config.owners[0], patchedUserData)
|
|
87
89
|
]).pipe(tap(() => this.regenReport())).subscribe();
|
|
88
90
|
}
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
const newChangeLog = {};
|
|
92
|
-
// Only include fields that have changed
|
|
93
|
-
for (const key in mods) {
|
|
94
|
-
if (this.initialFormState[key] !== mods[key]) {
|
|
95
|
-
prevChangeLog[key] = this.initialFormState[key];
|
|
96
|
-
newChangeLog[key] = mods[key];
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
const changeLog = {
|
|
91
|
+
logChange(mods) {
|
|
92
|
+
const entry = {
|
|
100
93
|
author: this.currentUser.emailAddress,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
timestamp: new Date().toISOString()
|
|
94
|
+
timestamp: new Date().toISOString(),
|
|
95
|
+
...shallowDiff(this.initialFormState, mods)
|
|
104
96
|
};
|
|
105
|
-
this.detailChangeLog.push(
|
|
106
|
-
|
|
107
|
-
// get the device data record and initialise the form
|
|
108
|
-
loadDeviceData() {
|
|
109
|
-
this.shared.getDeviceData(this.config.deviceDataModelId, this.config.owners[0].userId, propertyCodes).subscribe({
|
|
110
|
-
next: (res) => {
|
|
111
|
-
this.deviceDataId = res.deviceDataId;
|
|
112
|
-
this.recordingSession = JSON.parse(res.data['RecordingSession'].value);
|
|
113
|
-
this.initialiseForm(this.extractFields(this.recordingSession));
|
|
114
|
-
// checking for undefined in case no changes have been logged yet
|
|
115
|
-
this.detailChangeLog = res.data['UserDetailChangeLog'] === undefined ? [] : res.data['UserDetailChangeLog'].value;
|
|
116
|
-
this.status = res.data['Status']?.value === 'Generating Report' ?
|
|
117
|
-
'generating' :
|
|
118
|
-
'success';
|
|
119
|
-
},
|
|
120
|
-
error: (err) => {
|
|
121
|
-
console.error(err);
|
|
122
|
-
this.status = "error";
|
|
123
|
-
}
|
|
124
|
-
});
|
|
97
|
+
this.detailChangeLog.push(entry);
|
|
98
|
+
console.log(this.detailChangeLog);
|
|
125
99
|
}
|
|
126
100
|
regenReport() {
|
|
127
101
|
this.postDeviceData(deviceDataPropertySetId, { 'Algorithmhasrun': false, 'AlgorithmRun': true }).subscribe(() => {
|
|
@@ -131,26 +105,65 @@ export class DetailEditComponent {
|
|
|
131
105
|
resetModifications() {
|
|
132
106
|
this.formGroup.patchValue(this.initialFormState);
|
|
133
107
|
}
|
|
134
|
-
|
|
135
|
-
|
|
108
|
+
loadData(currentUserId, ownerId, deviceDataModelId) {
|
|
109
|
+
forkJoin([
|
|
110
|
+
this.shared.getUser(currentUserId),
|
|
111
|
+
this.shared.getUser(ownerId),
|
|
112
|
+
this.shared.getDeviceData(deviceDataModelId, ownerId, propertyCodes)
|
|
113
|
+
]).subscribe({
|
|
114
|
+
next: ([currentUser, owner, { deviceDataId, data: deviceData }]) => {
|
|
115
|
+
this.currentUser = currentUser;
|
|
116
|
+
this.owner = owner;
|
|
117
|
+
this.deviceDataId = deviceDataId;
|
|
118
|
+
this.recordingSession = JSON.parse(deviceData['RecordingSession'].value);
|
|
119
|
+
this.initialiseForm(this.extractFields(this.recordingSession));
|
|
120
|
+
// data field uninitialised for unmodified record
|
|
121
|
+
this.detailChangeLog = deviceData['UserDetailChangeLog']?.value ?? [];
|
|
122
|
+
this.status = deviceData['Status']?.value === 'Generating Report' ?
|
|
123
|
+
'generating' : 'success';
|
|
124
|
+
},
|
|
125
|
+
error: (err) => {
|
|
126
|
+
console.error(err);
|
|
127
|
+
this.status = "error";
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
init() {
|
|
132
|
+
if (!this.config?.currentUserId || !this.config.deviceDataModelId) {
|
|
133
|
+
this.status = 'cfgerror';
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
else if (!this.config?.owners?.[0]) {
|
|
136
137
|
this.status = 'nouser';
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
|
-
this.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
this.status = 'loading';
|
|
141
|
+
this.loadData(this.config.currentUserId, this.config.owners[0], this.config.deviceDataModelId);
|
|
142
|
+
}
|
|
143
|
+
// this should be called from the parent using the ViewChild attr
|
|
144
|
+
refresh() {
|
|
145
|
+
this.init();
|
|
146
|
+
}
|
|
147
|
+
// NOTE: there could be something wrong / unusual here but it seems to work ok
|
|
148
|
+
ngOnInit() {
|
|
149
|
+
if (this.config && !this.configDiffer)
|
|
150
|
+
this.configDiffer = this.kvDiffers.find(this.config).create();
|
|
151
|
+
if (this.config?.owners && !this.ownersDiffer)
|
|
152
|
+
this.ownersDiffer = this.itDiffers.find(this.config.owners).create();
|
|
153
|
+
}
|
|
154
|
+
ngDoCheck() {
|
|
155
|
+
const configChanges = this.configDiffer?.diff(this.config);
|
|
156
|
+
const ownersChanges = this.ownersDiffer?.diff(this.config?.owners);
|
|
157
|
+
if (configChanges || ownersChanges)
|
|
158
|
+
this.init();
|
|
146
159
|
}
|
|
147
160
|
}
|
|
148
|
-
DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }], target: i0.ɵɵFactoryTarget.Component });
|
|
149
|
-
DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status
|
|
161
|
+
DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }, { token: i0.KeyValueDiffers }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Component });
|
|
162
|
+
DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i4.EntriesPipe, name: "entries" }] });
|
|
150
163
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, decorators: [{
|
|
151
164
|
type: Component,
|
|
152
|
-
args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status
|
|
153
|
-
}], ctorParameters: function () { return [{ type: i1.SharedService }]; }, propDecorators: { config: [{
|
|
165
|
+
args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"] }]
|
|
166
|
+
}], ctorParameters: function () { return [{ type: i1.SharedService }, { type: i0.KeyValueDiffers }, { type: i0.IterableDiffers }]; }, propDecorators: { config: [{
|
|
154
167
|
type: Input
|
|
155
168
|
}] } });
|
|
156
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV0YWlsLWVkaXQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvZGV0YWlsLWVkaXQvc3JjL2xpYi9kZXRhaWwtZWRpdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9kZXRhaWwtZWRpdC9zcmMvbGliL2RldGFpbC1lZGl0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pELE9BQU8sRUFBbUIsV0FBVyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyRixPQUFPLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVyQyxPQUFPLEVBQUUsTUFBTSxFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUN0RixPQUFPLEVBQUUsY0FBYyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLE1BQU0sY0FBYyxDQUFDOzs7Ozs7QUFFMUYsTUFBTSxvQkFBb0IsR0FBRyxzQ0FBc0MsQ0FBQztBQUNwRSxNQUFNLHVCQUF1QixHQUFHLHNDQUFzQyxDQUFDO0FBQ3ZFLE1BQU0sYUFBYSxHQUFHLENBQUMsa0JBQWtCLEVBQUUsUUFBUSxFQUFFLHFCQUFxQixDQUFDLENBQUM7QUFNNUUsTUFBTSxPQUFPLG1CQUFtQjtJQXlCOUIsWUFBb0IsTUFBcUI7UUFBckIsV0FBTSxHQUFOLE1BQU0sQ0FBZTtRQXRCekMsV0FBTSxHQUEwRSxTQUFTLENBQUM7UUFXMUYsY0FBUyxHQUFHLElBQUksU0FBUyxDQUFDO1lBQ3hCLEdBQUcsRUFBRSxJQUFJLFdBQVcsQ0FBUyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLFlBQVksQ0FBQyxHQUFHLEVBQUUs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QixxRkNmaEMsMHdFQW9EQTs0RkRyQ2EsbUJBQW1CO2tCQUovQixTQUFTOytCQUNFLGlCQUFpQjtvR0FJbEIsTUFBTTtzQkFBZCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBGb3JtQ29udHJvbCwgRm9ybUdyb3VwLCBWYWxpZGF0b3JzIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgZm9ya0pvaW4sIHRhcCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQ29uZmlnLCBTaGFyZWRTZXJ2aWNlLCBVc2VyIH0gZnJvbSAnc2hhcmVkJztcbmltcG9ydCB7IGdldEFnZSwgZ2xvYmFsaXNlRGF0ZVRpbWUsIGxvY2FsaXNlRGF0ZVRpbWUsIHNoYWxsb3dDb21wYXJlIH0gZnJvbSAnLi91dGlscyc7XG5pbXBvcnQgeyBkYXRlQ29tcGFyaXNvbiwgd2l0aGluTlllYXJzLCB3aXRoaW5OSG91cnMsIHRyYW5zbGF0ZUVycm9yIH0gZnJvbSAnLi92YWxpZGF0b3JzJztcblxuY29uc3QgYXBwRGF0YVByb3BlcnR5U2V0SWQgPSAnMzRkNDY0NzctYWQ0Yi00N2I0LWI1NTUtMDYzNThiOTJmNjBjJztcbmNvbnN0IGRldmljZURhdGFQcm9wZXJ0eVNldElkID0gJzdhMzJkODUxLTVlODktNDZhNi1hNGI2LWNjYTE2MmRhY2UyOSc7XG5jb25zdCBwcm9wZXJ0eUNvZGVzID0gWydSZWNvcmRpbmdTZXNzaW9uJywgJ1N0YXR1cycsICdVc2VyRGV0YWlsQ2hhbmdlTG9nJ107XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1kZXRhaWwtZWRpdCcsIHRlbXBsYXRlVXJsOiAnLi9kZXRhaWwtZWRpdC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2RldGFpbC1lZGl0LmNvbXBvbmVudC5jc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBEZXRhaWxFZGl0Q29tcG9uZW50IHtcbiAgQElucHV0KCkgY29uZmlnITogQ29uZmlnO1xuXG4gIHN0YXR1czogJ2Vycm9yJyB8ICdsb2FkaW5nJyB8ICdzdWNjZXNzJyB8ICdnZW5lcmF0aW5nJyB8ICdzZW5kaW5nJyB8ICdub3VzZXInID0gJ2xvYWRpbmcnO1xuXG4gIC8vIHBvcHVsYXRlZCBieSBsb2FkIHJlcXVlc3RcbiAgcHJpdmF0ZSBkZXZpY2VEYXRhSWQ6IHN0cmluZztcbiAgcHJpdmF0ZSByZWNvcmRpbmdTZXNzaW9uOiBvYmplY3Q7XG4gIHByaXZhdGUgcmVjb3JkaW5nU3RhcnQ6IHN0cmluZztcbiAgcHJpdmF0ZSBpbml0aWFsRm9ybVN0YXRlOiBvYmplY3Q7XG4gIHByaXZhdGUgZGV0YWlsQ2hhbmdlTG9nOiBvYmplY3RbXTtcbiAgcHJpdmF0ZSBjdXJyZW50VXNlcjogVXNlcjtcbiAgcHJpdmF0ZSBvd25lcjogVXNlcjtcblxuICBmb3JtR3JvdXAgPSBuZXcgRm9ybUdyb3VwKHtcbiAgICBkb2I6IG5ldyBGb3JtQ29udHJvbDxzdHJpbmc+KCcnLCBbVmFsaWRhdG9ycy5yZXF1aXJlZCwgd2l0aGluTlllYXJzKDEyMCwgJ2JlZm9yZScpXSksXG4gICAgaGVpZ2h0OiBuZXcgRm9ybUNvbnRyb2w8bnVtYmVyPigwLCBbVmFsaWRhdG9ycy5yZXF1aXJlZCwgVmFsaWRhdG9ycy5taW4oMzApLCBWYWxpZGF0b3JzLm1heCgyNzIpXSksXG4gICAgd2VpZ2h0OiBuZXcgRm9ybUNvbnRyb2w8bnVtYmVyPigwLCBbVmFsaWRhdG9ycy5yZXF1aXJlZCwgVmFsaWRhdG9ycy5taW4oMSksIFZhbGlkYXRvcnMubWF4KDYzNSldKSxcbiAgICBtZWFsU3RhcnQ6IG5ldyBGb3JtQ29udHJvbDxzdHJpbmc+KCcnLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF0pLFxuICAgIG1lYWxFbmQ6IG5ldyBGb3JtQ29udHJvbDxzdHJpbmc+KCcnLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF0pXG4gIH0sIFtcbiAgICBkYXRlQ29tcGFyaXNvbignbWVhbEVuZCcsICdtZWFsU3RhcnQnLCAnYWZ0ZXInKSxcbiAgICBkYXRlQ29tcGFyaXNvbignbWVhbFN0YXJ0JywgJ2RvYicsICdhZnRlcicpLFxuICBdKTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHNoYXJlZDogU2hhcmVkU2VydmljZSkgeyB9XG5cbiAgcGFyc2VJbnB1dEVycm9ycyhuYW1lOiBzdHJpbmcsIGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCkge1xuICAgIHJldHVybiB0cmFuc2xhdGVFcnJvcihuYW1lLCBjb250cm9sKTtcbiAgfVxuXG4gIC8vIG1ha2Ugc3VyZSB0aGFuIG1vZGlmaWNhdGlvbnMgdGhhdCBkb24ndCBhY3R1YWxseSBkaWZmZXIgZnJvbSB0aGUgY3VycmVudCBhcmUgbWFya2VkIGFzIHN1Y2hcbiAgcHJpdmF0ZSBtb25pdG9yRm9ybUNoYW5nZXMoKSB7XG4gICAgdGhpcy5mb3JtR3JvdXAudmFsdWVDaGFuZ2VzLnN1YnNjcmliZShjdXJyZW50ID0+IHtcbiAgICAgIGlmIChzaGFsbG93Q29tcGFyZShjdXJyZW50LCB0aGlzLmluaXRpYWxGb3JtU3RhdGUpKSB7XG4gICAgICAgIHRoaXMuZm9ybUdyb3VwLm1hcmtBc1ByaXN0aW5lKCk7XG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIC8vIGhhbmRsZSB0aGUgcmVsZXZhbnQgZGF0YSBmcm9tIHRoZSByZXNwb25zZSBib2R5XG4gIHByaXZhdGUgZXh0cmFjdEZpZWxkcyhyZWNvcmRpbmdTZXNzaW9uOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KSB7XG4gICAgY29uc3QgeyBwYXRpZW50LCBtZWFsU3RhcnQsIG1lYWxFbmQsIHJlY29yZGluZ1N0YXJ0IH0gPSByZWNvcmRpbmdTZXNzaW9uO1xuICAgIHRoaXMucmVjb3JkaW5nU3RhcnQgPSByZWNvcmRpbmdTdGFydDtcblxuICAgIHJldHVybiB7XG4gICAgICBkb2I6IHRoaXMub3duZXIuZGF0ZU9mQmlydGgsXG4gICAgICBoZWlnaHQ6IHBhdGllbnQuaGVpZ2h0LFxuICAgICAgd2VpZ2h0OiBwYXRpZW50LndlaWdodCxcbiAgICAgIG1lYWxTdGFydDogbG9jYWxpc2VEYXRlVGltZShtZWFsU3RhcnQpLFxuICAgICAgbWVhbEVuZDogbG9jYWxpc2VEYXRlVGltZShtZWFsRW5kKVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaW5pdGlhbGlzZUZvcm0oc3RhdGU6IG9iamVjdCkge1xuICAgIHRoaXMuZm9ybUdyb3VwLnBhdGNoVmFsdWUoc3RhdGUpO1xuICAgIHRoaXMuZm9ybUdyb3VwLm1hcmtBc1ByaXN0aW5lKCk7XG5cbiAgICB0aGlzLmZvcm1Hcm91cC5nZXQoJ21lYWxTdGFydCcpLmFkZFZhbGlkYXRvcnMod2l0aGluTkhvdXJzKDI0LCAnYWZ0ZXInLCBuZXcgRGF0ZSh0aGlzLnJlY29yZGluZ1N0YXJ0KSkpO1xuICAgIHRoaXMuZm9ybUdyb3VwLmdldCgnbWVhbEVuZCcpLmFkZFZhbGlkYXRvcnMod2l0aGluTkhvdXJzKDI0LCAnYWZ0ZXInLCBuZXcgRGF0ZSh0aGlzLnJlY29yZGluZ1N0YXJ0KSkpO1xuXG4gICAgdGhpcy5pbml0aWFsRm9ybVN0YXRlID0gc3RhdGU7IC8vIHNhdmUgdGhpcyBmb3IgdXNlIGluIHJlc2V0c1xuICAgIHRoaXMubW9uaXRvckZvcm1DaGFuZ2VzKCk7XG4gIH1cblxuICAvLyBjb25zdHJ1Y3QgYSBwYXRjaCBvYmplY3QgZm9yIHRoZSBzYXZlIHJlcXVlc3RcbiAgcHJpdmF0ZSBpbnRlZ3JhdGVGaWVsZHMobW9kczogdHlwZW9mIHRoaXMuZm9ybUdyb3VwLnZhbHVlLCByZWNvcmRpbmdTZXNzaW9uOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KSB7XG4gICAgY29uc3QgeyBwYXRpZW50IH0gPSByZWNvcmRpbmdTZXNzaW9uO1xuICAgIHBhdGllbnQuaGVpZ2h0ID0gbW9kcy5oZWlnaHQ7XG4gICAgcGF0aWVudC53ZWlnaHQgPSBtb2RzLndlaWdodDtcbiAgICBwYXRpZW50LmFnZSA9IGdldEFnZShtb2RzLmRvYik7XG5cbiAgICByZWNvcmRpbmdTZXNzaW9uLm1lYWxTdGFydCA9IGdsb2JhbGlzZURhdGVUaW1lKG1vZHMubWVhbFN0YXJ0KTtcbiAgICByZWNvcmRpbmdTZXNzaW9uLm1lYWxFbmQgPSBnbG9iYWxpc2VEYXRlVGltZShtb2RzLm1lYWxFbmQpO1xuXG4gICAgdGhpcy5hcHBlbmRDaGFuZ2VMb2cobW9kcyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgJ0FnZSc6IHBhdGllbnQuYWdlLFxuICAgICAgJ1JlY29yZGluZ1Nlc3Npb24nOiBKU09OLnN0cmluZ2lmeShyZWNvcmRpbmdTZXNzaW9uKSxcbiAgICAgICdVc2VyRGV0YWlsQ2hhbmdlTG9nJzogdGhpcy5kZXRhaWxDaGFuZ2VMb2dcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHBvc3REZXZpY2VEYXRhKGRldmljZVByb3BlcnR5U2V0SWQ6IHN0cmluZywgZGF0YTogb2JqZWN0KSB7XG4gICAgcmV0dXJuIHRoaXMuc2hhcmVkLnNhdmVEZXZpY2VEYXRhKFxuICAgICAgdGhpcy5jb25maWcuZGV2aWNlRGF0YU1vZGVsSWQsXG4gICAgICB0aGlzLmRldmljZURhdGFJZCxcbiAgICAgIGRldmljZVByb3BlcnR5U2V0SWQsXG4gICAgICB0aGlzLmNvbmZpZy5vd25lcnNbMF0udXNlcklkLFxuICAgICAgZGF0YVxuICAgICk7XG4gIH1cblxuICAvLyBwYXRjaCB0aGUgZGV2aWNlIGRhdGEgcmVjb3JkIHdpdGggdGhlIG1vZGlmaWNhdGlvbnNcbiAgc2F2ZU1vZGlmaWNhdGlvbnMoKSB7XG4gICAgY29uc3QgbW9kcyA9IHRoaXMuZm9ybUdyb3VwLmdldFJhd1ZhbHVlKCk7XG4gICAgY29uc3QgcGF0Y2hlZERldmljZURhdGEgPSB0aGlzLmludGVncmF0ZUZpZWxkcyhtb2RzLCB0aGlzLnJlY29yZGluZ1Nlc3Npb24pO1xuICAgIGNvbnN0IHBhdGNoZWRVc2VyRGF0YSA9IE9iamVjdC5hc3NpZ24odGhpcy5jb25maWcub3duZXJzWzBdLCB7IGRhdGVPZkJpcnRoOiBtb2RzLmRvYiB9KTtcblxuICAgIHRoaXMuc3RhdHVzID0gJ3NlbmRpbmcnO1xuICAgIGZvcmtKb2luKFtcbiAgICAgIHRoaXMucG9zdERldmljZURhdGEoYXBwRGF0YVByb3BlcnR5U2V0SWQsIHBhdGNoZWREZXZpY2VEYXRhKSxcbiAgICAgIHRoaXMuc2hhcmVkLnVwZGF0ZVVzZXIodGhpcy5jb25maWcub3duZXJzWzBdLnVzZXJJZCwgcGF0Y2hlZFVzZXJEYXRhKVxuICAgIF0pLnBpcGUoXG4gICAgICB0YXAoKCkgPT4gdGhpcy5yZWdlblJlcG9ydCgpKVxuICAgICkuc3Vic2NyaWJlKCk7XG4gIH1cblxuICBwcml2YXRlIGFwcGVuZENoYW5nZUxvZyhtb2RzOiB0eXBlb2YgdGhpcy5mb3JtR3JvdXAudmFsdWUpIHtcbiAgICBjb25zdCBwcmV2Q2hhbmdlTG9nOiBQYXJ0aWFsPHR5cGVvZiB0aGlzLmZvcm1Hcm91cC52YWx1ZT4gPSB7fTtcbiAgICBjb25zdCBuZXdDaGFuZ2VMb2c6IFBhcnRpYWw8dHlwZW9mIHRoaXMuZm9ybUdyb3VwLnZhbHVlPiA9IHt9O1xuXG4gICAgLy8gT25seSBpbmNsdWRlIGZpZWxkcyB0aGF0IGhhdmUgY2hhbmdlZFxuICAgIGZvciAoY29uc3Qga2V5IGluIG1vZHMpIHtcbiAgICAgIGlmICh0aGlzLmluaXRpYWxGb3JtU3RhdGVba2V5XSAhPT0gbW9kc1trZXldKSB7XG4gICAgICAgIHByZXZDaGFuZ2VMb2dba2V5XSA9IHRoaXMuaW5pdGlhbEZvcm1TdGF0ZVtrZXldO1xuICAgICAgICBuZXdDaGFuZ2VMb2dba2V5XSA9IG1vZHNba2V5XTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBjaGFuZ2VMb2cgPSB7XG4gICAgICBhdXRob3I6IHRoaXMuY3VycmVudFVzZXIuZW1haWxBZGRyZXNzLFxuICAgICAgcHJldkNoYW5nZUxvZzogcHJldkNoYW5nZUxvZyxcbiAgICAgIG5ld0NoYW5nZUxvZzogbmV3Q2hhbmdlTG9nLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcbiAgICB9XG5cbiAgICB0aGlzLmRldGFpbENoYW5nZUxvZy5wdXNoKGNoYW5nZUxvZyk7XG4gIH1cblxuICAvLyBnZXQgdGhlIGRldmljZSBkYXRhIHJlY29yZCBhbmQgaW5pdGlhbGlzZSB0aGUgZm9ybVxuICBwcml2YXRlIGxvYWREZXZpY2VEYXRhKCkge1xuICAgIHRoaXMuc2hhcmVkLmdldERldmljZURhdGEoXG4gICAgICB0aGlzLmNvbmZpZy5kZXZpY2VEYXRhTW9kZWxJZCxcbiAgICAgIHRoaXMuY29uZmlnLm93bmVyc1swXS51c2VySWQsXG4gICAgICBwcm9wZXJ0eUNvZGVzXG4gICAgKS5zdWJzY3JpYmUoe1xuICAgICAgbmV4dDogKHJlcykgPT4ge1xuICAgICAgICB0aGlzLmRldmljZURhdGFJZCA9IHJlcy5kZXZpY2VEYXRhSWQ7XG4gICAgICAgIHRoaXMucmVjb3JkaW5nU2Vzc2lvbiA9IEpTT04ucGFyc2UocmVzLmRhdGFbJ1JlY29yZGluZ1Nlc3Npb24nXS52YWx1ZSk7XG4gICAgICAgIHRoaXMuaW5pdGlhbGlzZUZvcm0odGhpcy5leHRyYWN0RmllbGRzKHRoaXMucmVjb3JkaW5nU2Vzc2lvbikpO1xuICAgICAgICAvLyBjaGVja2luZyBmb3IgdW5kZWZpbmVkIGluIGNhc2Ugbm8gY2hhbmdlcyBoYXZlIGJlZW4gbG9nZ2VkIHlldFxuICAgICAgICB0aGlzLmRldGFpbENoYW5nZUxvZyA9IHJlcy5kYXRhWydVc2VyRGV0YWlsQ2hhbmdlTG9nJ10gPT09IHVuZGVmaW5lZCA/IFtdIDogcmVzLmRhdGFbJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnXS52YWx1ZTtcblxuICAgICAgICB0aGlzLnN0YXR1cyA9IHJlcy5kYXRhWydTdGF0dXMnXT8udmFsdWUgPT09ICdHZW5lcmF0aW5nIFJlcG9ydCcgP1xuICAgICAgICAgICdnZW5lcmF0aW5nJyA6XG4gICAgICAgICAgJ3N1Y2Nlc3MnO1xuICAgICAgfSxcbiAgICAgIGVycm9yOiAoZXJyKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgICAgdGhpcy5zdGF0dXMgPSBcImVycm9yXCI7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZWdlblJlcG9ydCgpIHtcbiAgICB0aGlzLnBvc3REZXZpY2VEYXRhKFxuICAgICAgZGV2aWNlRGF0YVByb3BlcnR5U2V0SWQsXG4gICAgICB7ICdBbGdvcml0aG1oYXNydW4nOiBmYWxzZSwgJ0FsZ29yaXRobVJ1bic6IHRydWUgfVxuICAgICkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMuc3RhdHVzID0gJ2dlbmVyYXRpbmcnOyAvLyBhc3N1bWUgcmVwb3J0IHN0YXJ0cyBnZW5lcmF0aW5nIGltbWVkaWF0ZWx5XG4gICAgfSlcbiAgfVxuXG4gIHJlc2V0TW9kaWZpY2F0aW9ucygpIHtcbiAgICB0aGlzLmZvcm1Hcm91cC5wYXRjaFZhbHVlKHRoaXMuaW5pdGlhbEZvcm1TdGF0ZSk7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICBpZiAoIXRoaXMuY29uZmlnPy5vd25lcnM/LlswXT8udXNlcklkKSB7XG4gICAgICB0aGlzLnN0YXR1cyA9ICdub3VzZXInO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnNoYXJlZC5nZXRVc2VyKHRoaXMuY29uZmlnLmN1cnJlbnRVc2VyLnVzZXJJZCkuc3Vic2NyaWJlKHVzZXIgPT4ge1xuICAgICAgdGhpcy5jdXJyZW50VXNlciA9IHVzZXI7XG4gICAgfSk7XG5cbiAgICB0aGlzLnNoYXJlZC5nZXRVc2VyKHRoaXMuY29uZmlnLm93bmVyc1swXS51c2VySWQpLnN1YnNjcmliZShvd25lciA9PiB7XG4gICAgICB0aGlzLm93bmVyID0gb3duZXI7XG4gICAgfSk7XG5cbiAgICB0aGlzLmxvYWREZXZpY2VEYXRhKCk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJ3cmFwcGVyXCI+XG4gIDxkaXYgY2xhc3M9XCJzdGF0dXNcIiAqbmdJZj1cInN0YXR1cyA9PT0gJ2Vycm9yJ1wiPlxuICAgIEFuIGVycm9yIG9jY3VyZWQgd2hpbGUgdHJ5aW5nIHRvIGdldCB0aGUgZGV0YWlscy5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJzdGF0dXNcIiAqbmdJZj1cInN0YXR1cyA9PT0gJ25vdXNlcidcIj5cbiAgICBUaGVyZSBpcyBubyB1c2VyIHNwZWNpZmllZCBhcyB0aGUgZGF0YSBvd25lci5cbiAgPC9kaXY+XG4gIDxmb3JtICpuZ0lmPVwic3RhdHVzICE9PSAnZXJyb3InICYmIHN0YXR1cyAhPT0gJ25vdXNlcidcIiBbZm9ybUdyb3VwXT1cImZvcm1Hcm91cFwiIChuZ1N1Ym1pdCk9XCJzYXZlTW9kaWZpY2F0aW9ucygpXCI+XG4gICAgPGRpdiBjbGFzcz1cImlucHV0c1wiPlxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJkb2JcIj5EYXRlIG9mIEJpcnRoOjwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCBpZD1cImRvYlwiIHR5cGU9XCJkYXRlXCIgZm9ybUNvbnRyb2xOYW1lPVwiZG9iXCI+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJ3ZWlnaHRcIj5QYXRpZW50IFdlaWdodCAoa2cpOjwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCBpZD1cIndlaWdodFwiIHR5cGU9XCJudW1iZXJcIiBmb3JtQ29udHJvbE5hbWU9XCJ3ZWlnaHRcIj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cbiAgICAgICAgPGxhYmVsIGZvcj1cImhlaWdodFwiPlBhdGllbnQgSGVpZ2h0IChjbSk6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwiaGVpZ2h0XCIgdHlwZT1cIm51bWJlclwiIGZvcm1Db250cm9sTmFtZT1cImhlaWdodFwiPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLXJvd1wiPlxuICAgICAgICA8bGFiZWwgZm9yPVwibWVhbFN0YXJ0XCI+TWVhbCBTdGFydCBUaW1lOjwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCBpZD1cIm1lYWxTdGFydFwiIHR5cGU9XCJkYXRldGltZS1sb2NhbFwiIGZvcm1Db250cm9sTmFtZT1cIm1lYWxTdGFydFwiPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLXJvd1wiPlxuICAgICAgICA8bGFiZWwgZm9yPVwibWVhbEVuZFwiPk1lYWwgRW5kIFRpbWU6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwibWVhbEVuZFwiIHR5cGU9XCJkYXRldGltZS1sb2NhbFwiIGZvcm1Db250cm9sTmFtZT1cIm1lYWxFbmRcIj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cIiFmb3JtR3JvdXAudmFsaWQgJiYgZm9ybUdyb3VwLmRpcnR5XCIgY2xhc3M9XCJlcnJvcnNcIj5cbiAgICAgIDxkaXYgKm5nRm9yPVwibGV0IGNvbnRyb2wgb2YgZm9ybUdyb3VwLmNvbnRyb2xzIHwgZW50cmllc1wiPlxuICAgICAgICB7eyBwYXJzZUlucHV0RXJyb3JzKGNvbnRyb2xbMF0sIGNvbnRyb2xbMV0pIH19XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgKm5nSWY9XCJzdGF0dXMgPT09ICdnZW5lcmF0aW5nJ1wiIGNsYXNzPVwiaW5mb1wiPlxuICAgICAgPGRpdj5UaGUgcmVwb3J0IGlzIGdlbmVyYXRpbmcgYXQgdGhlIG1vbWVudCwgY2hlY2sgYmFjayBsYXRlciBpZiB5b3UgbmVlZCB0byBtb2RpZnkgdGhpcyBlbnRyeS48L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJidXR0b25zXCI+XG4gICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiAoY2xpY2spPVwicmVnZW5SZXBvcnQoKVwiIFtkaXNhYmxlZF09XCJzdGF0dXMgPT09ICdzZW5kaW5nJyB8fCBzdGF0dXMgPT09ICdnZW5lcmF0aW5nJyB8fCBzdGF0dXMgPT09ICdsb2FkaW5nJ1wiPlJlZ2VuZXJhdGUgUmVwb3J0PC9idXR0b24+XG4gICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiAoY2xpY2spPVwicmVzZXRNb2RpZmljYXRpb25zKClcIiBbZGlzYWJsZWRdPVwic3RhdHVzID09PSAnc2VuZGluZycgfHwgc3RhdHVzID09PSAnZ2VuZXJhdGluZycgfHwgZm9ybUdyb3VwLnByaXN0aW5lXCI+Q2FuY2VsIE1vZGlmaWNhdGlvbjwvYnV0dG9uPlxuICAgICAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCIgW2Rpc2FibGVkXT1cInN0YXR1cyA9PT0gJ3NlbmRpbmcnIHx8IHN0YXR1cyA9PT0gJ2dlbmVyYXRpbmcnIHx8ICFmb3JtR3JvdXAudmFsaWQgfHwgZm9ybUdyb3VwLnByaXN0aW5lXCI+U2F2ZSBEZXRhaWxzPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIDwvZm9ybT5cbjwvZGl2PlxuIl19
|
|
169
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV0YWlsLWVkaXQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvZGV0YWlsLWVkaXQvc3JjL2xpYi9kZXRhaWwtZWRpdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9kZXRhaWwtZWRpdC9zcmMvbGliL2RldGFpbC1lZGl0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVcsS0FBSyxFQUFvRSxNQUFNLGVBQWUsQ0FBQztBQUM1SCxPQUFPLEVBQW1CLFdBQVcsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDckYsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFckMsT0FBTyxFQUFFLE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsV0FBVyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ25HLE9BQU8sRUFBRSxjQUFjLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUUsTUFBTSxjQUFjLENBQUM7Ozs7OztBQUUxRixNQUFNLG9CQUFvQixHQUFHLHNDQUFzQyxDQUFDO0FBQ3BFLE1BQU0sdUJBQXVCLEdBQUcsc0NBQXNDLENBQUM7QUFDdkUsTUFBTSxhQUFhLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxRQUFRLEVBQUUscUJBQXFCLENBQUMsQ0FBQztBQXNCNUUsTUFBTSxPQUFPLG1CQUFtQjtJQStCOUIsWUFBb0IsTUFBcUIsRUFBVSxTQUEwQixFQUFVLFNBQTBCO1FBQTdGLFdBQU0sR0FBTixNQUFNLENBQWU7UUFBVSxjQUFTLEdBQVQsU0FBUyxDQUFpQjtRQUFVLGNBQVMsR0FBVCxTQUFTLENBQWlCO1FBekJqSCxXQUFNLEdBQXVGLFNBQVMsQ0FBQztRQWN2RyxjQUFTLEdBQUcsSUFBSSxTQUFTLENBQUM7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QUUsQ0FBQztRQUNyRyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVk7WUFBRSxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDdEgsQ0FBQztJQUVELFNBQVM7UUFDUCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDM0QsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVuRSxJQUFJLGFBQWEsSUFBSSxhQUFhO1lBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2xELENBQUM7O2lIQXBNVSxtQkFBbUI7cUdBQW5CLG1CQUFtQixxRkMvQmhDLGk3RUF1REE7NEZEeEJhLG1CQUFtQjtrQkFML0IsU0FBUzsrQkFDRSxpQkFBaUI7Z0tBS2xCLE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRG9DaGVjaywgSW5wdXQsIEtleVZhbHVlRGlmZmVycywgS2V5VmFsdWVEaWZmZXIsIEl0ZXJhYmxlRGlmZmVyLCBJdGVyYWJsZURpZmZlcnMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IGZvcmtKb2luLCB0YXAgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IENvbmZpZywgU2hhcmVkU2VydmljZSwgVXNlciB9IGZyb20gJ2FsaW1ldHJ5LXNoYXJlZCc7XG5pbXBvcnQgeyBnZXRBZ2UsIGdsb2JhbGlzZURhdGVUaW1lLCBsb2NhbGlzZURhdGVUaW1lLCBzaGFsbG93Q29tcGFyZSwgc2hhbGxvd0RpZmYgfSBmcm9tICcuL3V0aWxzJztcbmltcG9ydCB7IGRhdGVDb21wYXJpc29uLCB3aXRoaW5OWWVhcnMsIHdpdGhpbk5Ib3VycywgdHJhbnNsYXRlRXJyb3IgfSBmcm9tICcuL3ZhbGlkYXRvcnMnO1xuXG5jb25zdCBhcHBEYXRhUHJvcGVydHlTZXRJZCA9ICczNGQ0NjQ3Ny1hZDRiLTQ3YjQtYjU1NS0wNjM1OGI5MmY2MGMnO1xuY29uc3QgZGV2aWNlRGF0YVByb3BlcnR5U2V0SWQgPSAnN2EzMmQ4NTEtNWU4OS00NmE2LWE0YjYtY2NhMTYyZGFjZTI5JztcbmNvbnN0IHByb3BlcnR5Q29kZXMgPSBbJ1JlY29yZGluZ1Nlc3Npb24nLCAnU3RhdHVzJywgJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnXTtcblxuaW50ZXJmYWNlIEZvcm1WYWx1ZSB7XG4gIGRvYjogc3RyaW5nLFxuICBoZWlnaHQ6IG51bWJlcixcbiAgd2VpZ2h0OiBudW1iZXIsXG4gIG1lYWxTdGFydDogc3RyaW5nLFxuICBtZWFsRW5kOiBzdHJpbmdcbn1cblxuaW50ZXJmYWNlIENoYW5nZSB7XG4gIHRpbWVzdGFtcDogc3RyaW5nLFxuICBhdXRob3I6IHN0cmluZyxcbiAgZnJvbTogUGFydGlhbDxGb3JtVmFsdWU+LFxuICB0bzogUGFydGlhbDxGb3JtVmFsdWU+XG59XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1kZXRhaWwtZWRpdCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9kZXRhaWwtZWRpdC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2RldGFpbC1lZGl0LmNvbXBvbmVudC5jc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBEZXRhaWxFZGl0Q29tcG9uZW50IGltcGxlbWVudHMgRG9DaGVjayB7XG4gIEBJbnB1dCgpIGNvbmZpZyE6IENvbmZpZztcblxuICBwcml2YXRlIGNvbmZpZ0RpZmZlcj86IEtleVZhbHVlRGlmZmVyPGtleW9mIENvbmZpZywgYW55PjtcbiAgcHJpdmF0ZSBvd25lcnNEaWZmZXI/OiBJdGVyYWJsZURpZmZlcjxzdHJpbmc+O1xuXG4gIHN0YXR1czogJ2Vycm9yJyB8ICdjZmdlcnJvcicgfCAnbG9hZGluZycgfCAnc3VjY2VzcycgfCAnZ2VuZXJhdGluZycgfCAnc2VuZGluZycgfCAnbm91c2VyJyA9ICdsb2FkaW5nJztcblxuICAvLyBkZXZpY2UgZGF0YSBwb3B1bGF0ZWQgYnkgbG9hZCByZXF1ZXN0XG4gIHByaXZhdGUgZGV2aWNlRGF0YUlkOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVjb3JkaW5nU2Vzc2lvbjogb2JqZWN0O1xuICBwcml2YXRlIHJlY29yZGluZ1N0YXJ0OiBzdHJpbmc7XG4gIHByaXZhdGUgaW5pdGlhbEZvcm1TdGF0ZTogb2JqZWN0O1xuXG4gIC8vIHVzZXIgZGF0YSBleHBhbmRlZCBmcm9tIGlkcyBwYXNzZWQgaW4gY29uZmlnXG4gIHByaXZhdGUgY3VycmVudFVzZXI6IFVzZXI7XG4gIHByaXZhdGUgb3duZXI6IFVzZXI7XG5cbiAgcHJpdmF0ZSBkZXRhaWxDaGFuZ2VMb2c6IENoYW5nZVtdO1xuXG4gIGZvcm1Hcm91cCA9IG5ldyBGb3JtR3JvdXAoe1xuICAgIGRvYjogbmV3IEZvcm1Db250cm9sPHN0cmluZz4oJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCB3aXRoaW5OWWVhcnMoMTIwLCAnYmVmb3JlJyldKSxcbiAgICBoZWlnaHQ6IG5ldyBGb3JtQ29udHJvbDxudW1iZXI+KDAsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCBWYWxpZGF0b3JzLm1pbigzMCksIFZhbGlkYXRvcnMubWF4KDI3MildKSxcbiAgICB3ZWlnaHQ6IG5ldyBGb3JtQ29udHJvbDxudW1iZXI+KDAsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCBWYWxpZGF0b3JzLm1pbigxKSwgVmFsaWRhdG9ycy5tYXgoNjM1KV0pLFxuICAgIG1lYWxTdGFydDogbmV3IEZvcm1Db250cm9sPHN0cmluZz4oJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXSksXG4gICAgbWVhbEVuZDogbmV3IEZvcm1Db250cm9sPHN0cmluZz4oJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXSlcbiAgfSwgW1xuICAgIGRhdGVDb21wYXJpc29uKCdtZWFsRW5kJywgJ21lYWxTdGFydCcsICdhZnRlcicpLFxuICAgIGRhdGVDb21wYXJpc29uKCdtZWFsU3RhcnQnLCAnZG9iJywgJ2FmdGVyJyksXG4gIF0pO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgc2hhcmVkOiBTaGFyZWRTZXJ2aWNlLCBwcml2YXRlIGt2RGlmZmVyczogS2V5VmFsdWVEaWZmZXJzLCBwcml2YXRlIGl0RGlmZmVyczogSXRlcmFibGVEaWZmZXJzKSB7IH1cblxuICBwYXJzZUlucHV0RXJyb3JzKG5hbWU6IHN0cmluZywgY29udHJvbDogQWJzdHJhY3RDb250cm9sKSB7XG4gICAgcmV0dXJuIHRyYW5zbGF0ZUVycm9yKG5hbWUsIGNvbnRyb2wpO1xuICB9XG5cbiAgLy8gbWFrZSBzdXJlIHRoYW4gbW9kaWZpY2F0aW9ucyB0aGF0IGRvbid0IGFjdHVhbGx5IGRpZmZlciBmcm9tIHRoZSBjdXJyZW50IGFyZSBtYXJrZWQgYXMgc3VjaFxuICBwcml2YXRlIG1vbml0b3JGb3JtQ2hhbmdlcygpIHtcbiAgICB0aGlzLmZvcm1Hcm91cC52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKGN1cnJlbnQgPT4ge1xuICAgICAgaWYgKHNoYWxsb3dDb21wYXJlKGN1cnJlbnQsIHRoaXMuaW5pdGlhbEZvcm1TdGF0ZSkpIHtcbiAgICAgICAgdGhpcy5mb3JtR3JvdXAubWFya0FzUHJpc3RpbmUoKTtcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLy8gaGFuZGxlIHRoZSByZWxldmFudCBkYXRhIGZyb20gdGhlIHJlc3BvbnNlIGJvZHlcbiAgcHJpdmF0ZSBleHRyYWN0RmllbGRzKHJlY29yZGluZ1Nlc3Npb246IFJlY29yZDxzdHJpbmcsIGFueT4pIHtcbiAgICBjb25zdCB7IHBhdGllbnQsIG1lYWxTdGFydCwgbWVhbEVuZCwgcmVjb3JkaW5nU3RhcnQgfSA9IHJlY29yZGluZ1Nlc3Npb247XG4gICAgdGhpcy5yZWNvcmRpbmdTdGFydCA9IHJlY29yZGluZ1N0YXJ0O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRvYjogdGhpcy5vd25lci5kYXRlT2ZCaXJ0aCxcbiAgICAgIGhlaWdodDogcGF0aWVudC5oZWlnaHQsXG4gICAgICB3ZWlnaHQ6IHBhdGllbnQud2VpZ2h0LFxuICAgICAgbWVhbFN0YXJ0OiBsb2NhbGlzZURhdGVUaW1lKG1lYWxTdGFydCksXG4gICAgICBtZWFsRW5kOiBsb2NhbGlzZURhdGVUaW1lKG1lYWxFbmQpXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXNlRm9ybShzdGF0ZTogb2JqZWN0KSB7XG4gICAgdGhpcy5mb3JtR3JvdXAucGF0Y2hWYWx1ZShzdGF0ZSk7XG4gICAgdGhpcy5mb3JtR3JvdXAubWFya0FzUHJpc3RpbmUoKTtcblxuICAgIHRoaXMuZm9ybUdyb3VwLmdldCgnbWVhbFN0YXJ0JykuYWRkVmFsaWRhdG9ycyh3aXRoaW5OSG91cnMoMjQsICdhZnRlcicsIG5ldyBEYXRlKHRoaXMucmVjb3JkaW5nU3RhcnQpKSk7XG4gICAgdGhpcy5mb3JtR3JvdXAuZ2V0KCdtZWFsRW5kJykuYWRkVmFsaWRhdG9ycyh3aXRoaW5OSG91cnMoMjQsICdhZnRlcicsIG5ldyBEYXRlKHRoaXMucmVjb3JkaW5nU3RhcnQpKSk7XG5cbiAgICB0aGlzLmluaXRpYWxGb3JtU3RhdGUgPSBzdGF0ZTsgLy8gc2F2ZSB0aGlzIGZvciB1c2UgaW4gcmVzZXRzXG4gICAgdGhpcy5tb25pdG9yRm9ybUNoYW5nZXMoKTtcbiAgfVxuXG4gIC8vIGNvbnN0cnVjdCBhIHBhdGNoIG9iamVjdCBmb3IgdGhlIHNhdmUgcmVxdWVzdFxuICBwcml2YXRlIGludGVncmF0ZUZpZWxkcyhtb2RzOiBGb3JtVmFsdWUsIHJlY29yZGluZ1Nlc3Npb246IFJlY29yZDxzdHJpbmcsIGFueT4pIHtcbiAgICBjb25zdCB7IHBhdGllbnQgfSA9IHJlY29yZGluZ1Nlc3Npb247XG4gICAgcGF0aWVudC5oZWlnaHQgPSBtb2RzLmhlaWdodDtcbiAgICBwYXRpZW50LndlaWdodCA9IG1vZHMud2VpZ2h0O1xuICAgIHBhdGllbnQuYWdlID0gZ2V0QWdlKG1vZHMuZG9iKTtcblxuICAgIHJlY29yZGluZ1Nlc3Npb24ubWVhbFN0YXJ0ID0gZ2xvYmFsaXNlRGF0ZVRpbWUobW9kcy5tZWFsU3RhcnQpO1xuICAgIHJlY29yZGluZ1Nlc3Npb24ubWVhbEVuZCA9IGdsb2JhbGlzZURhdGVUaW1lKG1vZHMubWVhbEVuZCk7XG5cbiAgICB0aGlzLmxvZ0NoYW5nZShtb2RzKTtcblxuICAgIHJldHVybiB7XG4gICAgICAnQWdlJzogcGF0aWVudC5hZ2UsXG4gICAgICAnUmVjb3JkaW5nU2Vzc2lvbic6IEpTT04uc3RyaW5naWZ5KHJlY29yZGluZ1Nlc3Npb24pLFxuICAgICAgJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnOiB0aGlzLmRldGFpbENoYW5nZUxvZ1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcG9zdERldmljZURhdGEoZGV2aWNlUHJvcGVydHlTZXRJZDogc3RyaW5nLCBkYXRhOiBvYmplY3QpIHtcbiAgICByZXR1cm4gdGhpcy5zaGFyZWQuc2F2ZURldmljZURhdGEoXG4gICAgICB0aGlzLmNvbmZpZy5kZXZpY2VEYXRhTW9kZWxJZCxcbiAgICAgIHRoaXMuZGV2aWNlRGF0YUlkLFxuICAgICAgZGV2aWNlUHJvcGVydHlTZXRJZCxcbiAgICAgIHRoaXMuY29uZmlnLm93bmVyc1swXSxcbiAgICAgIGRhdGFcbiAgICApO1xuICB9XG5cbiAgLy8gcGF0Y2ggdGhlIGRldmljZSBkYXRhIHJlY29yZCB3aXRoIHRoZSBtb2RpZmljYXRpb25zXG4gIHNhdmVNb2RpZmljYXRpb25zKCkge1xuICAgIGNvbnN0IG1vZHMgPSB0aGlzLmZvcm1Hcm91cC5nZXRSYXdWYWx1ZSgpO1xuICAgIGNvbnN0IHBhdGNoZWREZXZpY2VEYXRhID0gdGhpcy5pbnRlZ3JhdGVGaWVsZHMobW9kcywgdGhpcy5yZWNvcmRpbmdTZXNzaW9uKTtcbiAgICBjb25zdCBwYXRjaGVkVXNlckRhdGEgPSBPYmplY3QuYXNzaWduKHRoaXMub3duZXIsIHsgZGF0ZU9mQmlydGg6IG1vZHMuZG9iIH0pO1xuXG4gICAgdGhpcy5zdGF0dXMgPSAnc2VuZGluZyc7XG4gICAgZm9ya0pvaW4oW1xuICAgICAgdGhpcy5wb3N0RGV2aWNlRGF0YShhcHBEYXRhUHJvcGVydHlTZXRJZCwgcGF0Y2hlZERldmljZURhdGEpLFxuICAgICAgdGhpcy5zaGFyZWQudXBkYXRlVXNlcih0aGlzLmNvbmZpZy5vd25lcnNbMF0sIHBhdGNoZWRVc2VyRGF0YSlcbiAgICBdKS5waXBlKFxuICAgICAgdGFwKCgpID0+IHRoaXMucmVnZW5SZXBvcnQoKSlcbiAgICApLnN1YnNjcmliZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBsb2dDaGFuZ2UobW9kczogRm9ybVZhbHVlKSB7XG4gICAgY29uc3QgZW50cnkgPSB7XG4gICAgICBhdXRob3I6IHRoaXMuY3VycmVudFVzZXIuZW1haWxBZGRyZXNzLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAuLi5zaGFsbG93RGlmZih0aGlzLmluaXRpYWxGb3JtU3RhdGUsIG1vZHMpXG4gICAgfVxuXG4gICAgdGhpcy5kZXRhaWxDaGFuZ2VMb2cucHVzaChlbnRyeSk7XG5cbiAgICBjb25zb2xlLmxvZyh0aGlzLmRldGFpbENoYW5nZUxvZyk7XG4gIH1cblxuICByZWdlblJlcG9ydCgpIHtcbiAgICB0aGlzLnBvc3REZXZpY2VEYXRhKFxuICAgICAgZGV2aWNlRGF0YVByb3BlcnR5U2V0SWQsXG4gICAgICB7ICdBbGdvcml0aG1oYXNydW4nOiBmYWxzZSwgJ0FsZ29yaXRobVJ1bic6IHRydWUgfVxuICAgICkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMuc3RhdHVzID0gJ2dlbmVyYXRpbmcnOyAvLyBhc3N1bWUgcmVwb3J0IHN0YXJ0cyBnZW5lcmF0aW5nIGltbWVkaWF0ZWx5XG4gICAgfSlcbiAgfVxuXG4gIHJlc2V0TW9kaWZpY2F0aW9ucygpIHtcbiAgICB0aGlzLmZvcm1Hcm91cC5wYXRjaFZhbHVlKHRoaXMuaW5pdGlhbEZvcm1TdGF0ZSk7XG4gIH1cblxuICBwcml2YXRlIGxvYWREYXRhKGN1cnJlbnRVc2VySWQ6IHN0cmluZywgb3duZXJJZDogc3RyaW5nLCBkZXZpY2VEYXRhTW9kZWxJZDogc3RyaW5nKSB7XG4gICAgZm9ya0pvaW4oW1xuICAgICAgdGhpcy5zaGFyZWQuZ2V0VXNlcihjdXJyZW50VXNlcklkKSxcbiAgICAgIHRoaXMuc2hhcmVkLmdldFVzZXIob3duZXJJZCksXG4gICAgICB0aGlzLnNoYXJlZC5nZXREZXZpY2VEYXRhKGRldmljZURhdGFNb2RlbElkLCBvd25lcklkLCBwcm9wZXJ0eUNvZGVzKVxuICAgIF0pLnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAoW2N1cnJlbnRVc2VyLCBvd25lciwgeyBkZXZpY2VEYXRhSWQsIGRhdGE6IGRldmljZURhdGEgfV0pID0+IHtcbiAgICAgICAgdGhpcy5jdXJyZW50VXNlciA9IGN1cnJlbnRVc2VyO1xuICAgICAgICB0aGlzLm93bmVyID0gb3duZXI7XG4gICAgICAgIHRoaXMuZGV2aWNlRGF0YUlkID0gZGV2aWNlRGF0YUlkO1xuXG4gICAgICAgIHRoaXMucmVjb3JkaW5nU2Vzc2lvbiA9IEpTT04ucGFyc2UoZGV2aWNlRGF0YVsnUmVjb3JkaW5nU2Vzc2lvbiddLnZhbHVlKTtcbiAgICAgICAgdGhpcy5pbml0aWFsaXNlRm9ybSh0aGlzLmV4dHJhY3RGaWVsZHModGhpcy5yZWNvcmRpbmdTZXNzaW9uKSk7XG5cbiAgICAgICAgLy8gZGF0YSBmaWVsZCB1bmluaXRpYWxpc2VkIGZvciB1bm1vZGlmaWVkIHJlY29yZFxuICAgICAgICB0aGlzLmRldGFpbENoYW5nZUxvZyA9IGRldmljZURhdGFbJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnXT8udmFsdWUgPz8gW107XG5cbiAgICAgICAgdGhpcy5zdGF0dXMgPSBkZXZpY2VEYXRhWydTdGF0dXMnXT8udmFsdWUgPT09ICdHZW5lcmF0aW5nIFJlcG9ydCcgP1xuICAgICAgICAgICdnZW5lcmF0aW5nJyA6ICdzdWNjZXNzJztcbiAgICAgIH0sXG4gICAgICBlcnJvcjogKGVycikgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAgIHRoaXMuc3RhdHVzID0gXCJlcnJvclwiO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBpbml0KCkge1xuICAgIGlmICghdGhpcy5jb25maWc/LmN1cnJlbnRVc2VySWQgfHwgIXRoaXMuY29uZmlnLmRldmljZURhdGFNb2RlbElkKSB7XG4gICAgICB0aGlzLnN0YXR1cyA9ICdjZmdlcnJvcidcbiAgICAgIHJldHVybjtcbiAgICB9IGVsc2UgaWYgKCF0aGlzLmNvbmZpZz8ub3duZXJzPy5bMF0pIHtcbiAgICAgIHRoaXMuc3RhdHVzID0gJ25vdXNlcic7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5zdGF0dXMgPSAnbG9hZGluZyc7XG4gICAgdGhpcy5sb2FkRGF0YSh0aGlzLmNvbmZpZy5jdXJyZW50VXNlcklkLCB0aGlzLmNvbmZpZy5vd25lcnNbMF0sIHRoaXMuY29uZmlnLmRldmljZURhdGFNb2RlbElkKTtcbiAgfVxuXG4gIC8vIHRoaXMgc2hvdWxkIGJlIGNhbGxlZCBmcm9tIHRoZSBwYXJlbnQgdXNpbmcgdGhlIFZpZXdDaGlsZCBhdHRyXG4gIHJlZnJlc2goKSB7XG4gICAgdGhpcy5pbml0KCk7XG4gIH1cblxuICAvLyBOT1RFOiB0aGVyZSBjb3VsZCBiZSBzb21ldGhpbmcgd3JvbmcgLyB1bnVzdWFsIGhlcmUgYnV0IGl0IHNlZW1zIHRvIHdvcmsgb2tcbiAgbmdPbkluaXQoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnICYmICF0aGlzLmNvbmZpZ0RpZmZlcikgdGhpcy5jb25maWdEaWZmZXIgPSB0aGlzLmt2RGlmZmVycy5maW5kKHRoaXMuY29uZmlnKS5jcmVhdGUoKTtcbiAgICBpZiAodGhpcy5jb25maWc/Lm93bmVycyAmJiAhdGhpcy5vd25lcnNEaWZmZXIpIHRoaXMub3duZXJzRGlmZmVyID0gdGhpcy5pdERpZmZlcnMuZmluZCh0aGlzLmNvbmZpZy5vd25lcnMpLmNyZWF0ZSgpO1xuICB9XG5cbiAgbmdEb0NoZWNrKCkge1xuICAgIGNvbnN0IGNvbmZpZ0NoYW5nZXMgPSB0aGlzLmNvbmZpZ0RpZmZlcj8uZGlmZih0aGlzLmNvbmZpZyk7XG4gICAgY29uc3Qgb3duZXJzQ2hhbmdlcyA9IHRoaXMub3duZXJzRGlmZmVyPy5kaWZmKHRoaXMuY29uZmlnPy5vd25lcnMpO1xuXG4gICAgaWYgKGNvbmZpZ0NoYW5nZXMgfHwgb3duZXJzQ2hhbmdlcykgdGhpcy5pbml0KCk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJ3cmFwcGVyXCI+XG4gIDxkaXYgY2xhc3M9XCJzdGF0dXNcIiAqbmdJZj1cInN0YXR1cyA9PT0gJ2Vycm9yJ1wiPlxuICAgIEFuIGVycm9yIG9jY3VyZWQgd2hpbGUgdHJ5aW5nIHRvIGdldCB0aGUgZGV0YWlscy5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJzdGF0dXNcIiAqbmdJZj1cInN0YXR1cyA9PT0gJ2NmZ2Vycm9yJ1wiPlxuICAgIFRoZSB3aWRnZXQgaGFzIG5vdCBiZWVuIGNvbmZpZ3VyZWQgY29ycmVjdGx5LCBvciBpcyBtaXNzaW5nIGNvbmZpZ3VyYXRpb24gaW5mb3JtYXRpb24uXG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwic3RhdHVzXCIgKm5nSWY9XCJzdGF0dXMgPT09ICdub3VzZXInXCI+XG4gICAgVGhlcmUgaXMgbm8gdXNlciBzcGVjaWZpZWQgYXMgdGhlIGRhdGEgb3duZXIuXG4gIDwvZGl2PlxuICA8Zm9ybSAqbmdJZj1cIiFzdGF0dXMuaW5jbHVkZXMoJ2Vycm9yJykgJiYgc3RhdHVzICE9PSAnbm91c2VyJ1wiIFtmb3JtR3JvdXBdPVwiZm9ybUdyb3VwXCIgKG5nU3VibWl0KT1cInNhdmVNb2RpZmljYXRpb25zKClcIj5cbiAgICA8ZGl2IGNsYXNzPVwiaW5wdXRzXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cbiAgICAgICAgPGxhYmVsIGZvcj1cImRvYlwiPkRhdGUgb2YgQmlydGg6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwiZG9iXCIgdHlwZT1cImRhdGVcIiBmb3JtQ29udHJvbE5hbWU9XCJkb2JcIj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cbiAgICAgICAgPGxhYmVsIGZvcj1cIndlaWdodFwiPlBhdGllbnQgV2VpZ2h0IChrZyk6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwid2VpZ2h0XCIgdHlwZT1cIm51bWJlclwiIGZvcm1Db250cm9sTmFtZT1cIndlaWdodFwiPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLXJvd1wiPlxuICAgICAgICA8bGFiZWwgZm9yPVwiaGVpZ2h0XCI+UGF0aWVudCBIZWlnaHQgKGNtKTo8L2xhYmVsPlxuICAgICAgICA8aW5wdXQgaWQ9XCJoZWlnaHRcIiB0eXBlPVwibnVtYmVyXCIgZm9ybUNvbnRyb2xOYW1lPVwiaGVpZ2h0XCI+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJtZWFsU3RhcnRcIj5NZWFsIFN0YXJ0IFRpbWU6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwibWVhbFN0YXJ0XCIgdHlwZT1cImRhdGV0aW1lLWxvY2FsXCIgZm9ybUNvbnRyb2xOYW1lPVwibWVhbFN0YXJ0XCI+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJtZWFsRW5kXCI+TWVhbCBFbmQgVGltZTo8L2xhYmVsPlxuICAgICAgICA8aW5wdXQgaWQ9XCJtZWFsRW5kXCIgdHlwZT1cImRhdGV0aW1lLWxvY2FsXCIgZm9ybUNvbnRyb2xOYW1lPVwibWVhbEVuZFwiPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2ICpuZ0lmPVwiIWZvcm1Hcm91cC52YWxpZCAmJiBmb3JtR3JvdXAuZGlydHlcIiBjbGFzcz1cImVycm9yc1wiPlxuICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgY29udHJvbCBvZiBmb3JtR3JvdXAuY29udHJvbHMgfCBlbnRyaWVzXCI+XG4gICAgICAgIHt7IHBhcnNlSW5wdXRFcnJvcnMoY29udHJvbFswXSwgY29udHJvbFsxXSkgfX1cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cInN0YXR1cyA9PT0gJ2dlbmVyYXRpbmcnXCIgY2xhc3M9XCJpbmZvXCI+XG4gICAgICA8ZGl2PlRoZSByZXBvcnQgaXMgZ2VuZXJhdGluZyBhdCB0aGUgbW9tZW50LCBjaGVjayBiYWNrIGxhdGVyIGlmIHlvdSBuZWVkIHRvIG1vZGlmeSB0aGlzIGVudHJ5LjwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiBjbGFzcz1cImJ1dHRvbnNcIj5cbiAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJyZWdlblJlcG9ydCgpXCIgW2Rpc2FibGVkXT1cInN0YXR1cyA9PT0gJ3NlbmRpbmcnIHx8IHN0YXR1cyA9PT0gJ2dlbmVyYXRpbmcnIHx8IHN0YXR1cyA9PT0gJ2xvYWRpbmcnXCI+UmVnZW5lcmF0ZSBSZXBvcnQ8L2J1dHRvbj5cbiAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJyZXNldE1vZGlmaWNhdGlvbnMoKVwiIFtkaXNhYmxlZF09XCJzdGF0dXMgPT09ICdzZW5kaW5nJyB8fCBzdGF0dXMgPT09ICdnZW5lcmF0aW5nJyB8fCBmb3JtR3JvdXAucHJpc3RpbmVcIj5DYW5jZWwgTW9kaWZpY2F0aW9uPC9idXR0b24+XG4gICAgICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIiBbZGlzYWJsZWRdPVwic3RhdHVzID09PSAnc2VuZGluZycgfHwgc3RhdHVzID09PSAnZ2VuZXJhdGluZycgfHwgIWZvcm1Hcm91cC52YWxpZCB8fCBmb3JtR3JvdXAucHJpc3RpbmVcIj5TYXZlIERldGFpbHM8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9mb3JtPlxuPC9kaXY+XG4iXX0=
|
package/esm2020/lib/utils.mjs
CHANGED
|
@@ -45,4 +45,9 @@ export function titleise(camel) {
|
|
|
45
45
|
export function shallowCompare(a, b) {
|
|
46
46
|
return Object.entries(a).every(([k, v]) => b[k] === v);
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
export function shallowDiff(a, b) {
|
|
49
|
+
const from = Object.fromEntries(Object.entries(a).filter(([k, v]) => b[k] !== v));
|
|
50
|
+
const to = Object.fromEntries(Object.entries(b).filter(([k, _]) => from[k]));
|
|
51
|
+
return { from, to };
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9kZXRhaWwtZWRpdC9zcmMvbGliL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtEQUErRDtBQUMvRCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsUUFBZ0I7SUFDL0MsTUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFaEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQUMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNqRyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN2RCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN6RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUM3RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUU3RCxPQUFPLEdBQUcsSUFBSSxJQUFJLEtBQUssSUFBSSxHQUFHLElBQUksSUFBSSxJQUFJLE1BQU0sSUFBSSxNQUFNLEVBQUUsQ0FBQztBQUMvRCxDQUFDO0FBRUQsa0NBQWtDO0FBQ2xDLE1BQU0sVUFBVSxpQkFB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LENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQUVELE1BQU0sVUFBVSxjQUFjLENBQUMsQ0FBUyxFQUFFLENBQVM7SUFDakQsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDekQsQ0FBQztBQUVELE1BQU0sVUFBVSxXQUFXLENBQUMsQ0FBUyxFQUFFLENBQVM7SUFDOUMsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRixNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0UsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQztBQUN0QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gc3RyaXAgdGhlIHRpbWV6b25lIG9mZnNldCB0byBjcmVhdGUgZm9ybWF0IHVzYWJsZSBieSA8aW5wdXQ+XG5leHBvcnQgZnVuY3Rpb24gbG9jYWxpc2VEYXRlVGltZShkYXRldGltZTogc3RyaW5nKSB7XG4gIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShkYXRldGltZSk7XG5cbiAgY29uc3QgeWVhciA9IGRhdGUuZ2V0RnVsbFllYXIoKTsgY29uc3QgbW9udGggPSAoZGF0ZS5nZXRNb250aCgpICsgMSkudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpO1xuICBjb25zdCBkYXkgPSBkYXRlLmdldERhdGUoKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyk7XG4gIGNvbnN0IGhvdXIgPSBkYXRlLmdldEhvdXJzKCkudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpO1xuICBjb25zdCBtaW51dGUgPSBkYXRlLmdldE1pbnV0ZXMoKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyk7XG4gIGNvbnN0IHNlY29uZCA9IGRhdGUuZ2V0U2Vjb25kcygpLnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgJzAnKTtcblxuICByZXR1cm4gYCR7eWVhcn0tJHttb250aH0tJHtkYXl9VCR7aG91cn06JHttaW51dGV9OiR7c2Vjb25kfWA7XG59XG5cbi8vIHJlY29uc3RydWN0IG9yaWdpbmFsIElTTyBmb3JtYXRcbmV4cG9ydCBmdW5jdGlvbiBnbG9iYWxpc2VEYXRlVGltZShkYXRldGltZTogc3RyaW5nKSB7XG4gIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShkYXRldGltZSk7XG5cbiAgY29uc3Qgb2Zmc2V0ID0gLWRhdGUuZ2V0VGltZXpvbmVPZmZzZXQoKTtcbiAgY29uc3Qgb2Zmc2V0QWJzID0gTWF0aC5hYnMob2Zmc2V0KTtcblxuICBjb25zdCBzaWduID0gb2Zmc2V0ID49IDAgPyAnKycgOiAnLSc7XG4gIGNvbnN0IGhvdXJzID0gU3RyaW5nKE1hdGguZmxvb3Iob2Zmc2V0QWJzIC8gNjApKS5wYWRTdGFydCgyLCAnMCcpO1xuICBjb25zdCBtaW51dGVzID0gU3RyaW5nKG9mZnNldEFicyAlIDYwKS5wYWRTdGFydCgyLCAnMCcpO1xuICBjb25zdCBvZmZzZXRTdHJpbmcgPSBgJHtzaWdufSR7aG91cnN9OiR7bWludXRlc31gO1xuICBjb25zdCB5ZWFyID0gZGF0ZS5nZXRGdWxsWWVhcigpO1xuICBjb25zdCBtb250aCA9IFN0cmluZyhkYXRlLmdldE1vbnRoKCkgKyAxKS5wYWRTdGFydCgyLCAnMCcpO1xuICBjb25zdCBkYXkgPSBTdHJpbmcoZGF0ZS5nZXREYXRlKCkpLnBhZFN0YXJ0KDIsICcwJyk7XG4gIGNvbnN0IGhvdXIgPSBTdHJpbmcoZGF0ZS5nZXRIb3VycygpKS5wYWRTdGFydCgyLCAnMCcpO1xuICBjb25zdCBtaW51dGUgPSBTdHJpbmcoZGF0ZS5nZXRNaW51dGVzKCkpLnBhZFN0YXJ0KDIsICcwJyk7XG4gIGNvbnN0IHNlY29uZCA9IFN0cmluZyhkYXRlLmdldFNlY29uZHMoKSkucGFkU3RhcnQoMiwgJzAnKTtcblxuICBjb25zdCBkYXRlUGFydCA9IGAke3llYXJ9LSR7bW9udGh9LSR7ZGF5fWA7XG4gIGNvbnN0IHRpbWVQYXJ0ID0gYCR7aG91cn06JHttaW51dGV9OiR7c2Vjb25kfS4wMDBgO1xuXG4gIHJldHVybiBgJHtkYXRlUGFydH1UJHt0aW1lUGFydH0ke29mZnNldFN0cmluZ31gO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWdlKGRvYjogc3RyaW5nKSB7XG4gIGNvbnN0IHRoZW4gPSBuZXcgRGF0ZShkb2IpO1xuICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xuXG4gIGxldCBhZ2UgPSBub3cuZ2V0RnVsbFllYXIoKSAtIHRoZW4uZ2V0RnVsbFllYXIoKTtcblxuICBpZiAobm93LmdldE1vbnRoKCkgPCB0aGVuLmdldE1vbnRoKCkgfHxcbiAgICAobm93LmdldE1vbnRoKCkgPT09IHRoZW4uZ2V0TW9udGgoKSAmJiBub3cuZ2V0RGF0ZSgpIDwgdGhlbi5nZXREYXRlKCkpKSB7XG4gICAgYWdlLS07XG4gIH1cblxuICByZXR1cm4gYWdlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGl0bGVpc2UoY2FtZWw6IHN0cmluZykge1xuICBsZXQgc3BhY2VkID0gY2FtZWwucmVwbGFjZSgvKD89W0EtWl0pL2csICcgJyk7XG4gIHJldHVybiBzcGFjZWQudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9cXGJcXHcvZywgY2ggPT4gY2gudG9VcHBlckNhc2UoKSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzaGFsbG93Q29tcGFyZShhOiBvYmplY3QsIGI6IG9iamVjdCkge1xuICByZXR1cm4gT2JqZWN0LmVudHJpZXMoYSkuZXZlcnkoKFtrLCB2XSkgPT4gYltrXSA9PT0gdik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzaGFsbG93RGlmZihhOiBvYmplY3QsIGI6IG9iamVjdCkge1xuICBjb25zdCBmcm9tID0gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKGEpLmZpbHRlcigoW2ssIHZdKSA9PiBiW2tdICE9PSB2KSk7XG4gIGNvbnN0IHRvID0gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKGIpLmZpbHRlcigoW2ssIF9dKSA9PiBmcm9tW2tdKSk7XG4gIHJldHVybiB7IGZyb20sIHRvIH07XG59XG4iXX0=
|
|
@@ -3,7 +3,7 @@ import { Injectable, Pipe, Component, Input, NgModule } from '@angular/core';
|
|
|
3
3
|
import * as i2 from '@angular/forms';
|
|
4
4
|
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
5
5
|
import { forkJoin, tap } from 'rxjs';
|
|
6
|
-
import * as i1 from 'shared';
|
|
6
|
+
import * as i1 from 'alimetry-shared';
|
|
7
7
|
import * as i3 from '@angular/common';
|
|
8
8
|
import { JsonPipe, CommonModule } from '@angular/common';
|
|
9
9
|
|
|
@@ -66,6 +66,11 @@ function titleise(camel) {
|
|
|
66
66
|
function shallowCompare(a, b) {
|
|
67
67
|
return Object.entries(a).every(([k, v]) => b[k] === v);
|
|
68
68
|
}
|
|
69
|
+
function shallowDiff(a, b) {
|
|
70
|
+
const from = Object.fromEntries(Object.entries(a).filter(([k, v]) => b[k] !== v));
|
|
71
|
+
const to = Object.fromEntries(Object.entries(b).filter(([k, _]) => from[k]));
|
|
72
|
+
return { from, to };
|
|
73
|
+
}
|
|
69
74
|
|
|
70
75
|
function setControlError(control, errorKey, errorValue) {
|
|
71
76
|
const currentErrors = control.errors || {};
|
|
@@ -182,8 +187,10 @@ const appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';
|
|
|
182
187
|
const deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';
|
|
183
188
|
const propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];
|
|
184
189
|
class DetailEditComponent {
|
|
185
|
-
constructor(shared) {
|
|
190
|
+
constructor(shared, kvDiffers, itDiffers) {
|
|
186
191
|
this.shared = shared;
|
|
192
|
+
this.kvDiffers = kvDiffers;
|
|
193
|
+
this.itDiffers = itDiffers;
|
|
187
194
|
this.status = 'loading';
|
|
188
195
|
this.formGroup = new FormGroup({
|
|
189
196
|
dob: new FormControl('', [Validators.required, withinNYears(120, 'before')]),
|
|
@@ -235,7 +242,7 @@ class DetailEditComponent {
|
|
|
235
242
|
patient.age = getAge(mods.dob);
|
|
236
243
|
recordingSession.mealStart = globaliseDateTime(mods.mealStart);
|
|
237
244
|
recordingSession.mealEnd = globaliseDateTime(mods.mealEnd);
|
|
238
|
-
this.
|
|
245
|
+
this.logChange(mods);
|
|
239
246
|
return {
|
|
240
247
|
'Age': patient.age,
|
|
241
248
|
'RecordingSession': JSON.stringify(recordingSession),
|
|
@@ -243,56 +250,23 @@ class DetailEditComponent {
|
|
|
243
250
|
};
|
|
244
251
|
}
|
|
245
252
|
postDeviceData(devicePropertySetId, data) {
|
|
246
|
-
return this.shared.saveDeviceData(this.config.deviceDataModelId, this.deviceDataId, devicePropertySetId, this.config.owners[0]
|
|
253
|
+
return this.shared.saveDeviceData(this.config.deviceDataModelId, this.deviceDataId, devicePropertySetId, this.config.owners[0], data);
|
|
247
254
|
}
|
|
248
255
|
// patch the device data record with the modifications
|
|
249
256
|
saveModifications() {
|
|
250
257
|
const mods = this.formGroup.getRawValue();
|
|
251
258
|
const patchedDeviceData = this.integrateFields(mods, this.recordingSession);
|
|
252
|
-
const patchedUserData = Object.assign(this.
|
|
259
|
+
const patchedUserData = Object.assign(this.owner, { dateOfBirth: mods.dob });
|
|
253
260
|
this.status = 'sending';
|
|
254
261
|
forkJoin([
|
|
255
262
|
this.postDeviceData(appDataPropertySetId, patchedDeviceData),
|
|
256
|
-
this.shared.updateUser(this.config.owners[0]
|
|
263
|
+
this.shared.updateUser(this.config.owners[0], patchedUserData)
|
|
257
264
|
]).pipe(tap(() => this.regenReport())).subscribe();
|
|
258
265
|
}
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
for (const key in mods) {
|
|
264
|
-
if (this.initialFormState[key] !== mods[key]) {
|
|
265
|
-
prevChangeLog[key] = this.initialFormState[key];
|
|
266
|
-
newChangeLog[key] = mods[key];
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
const changeLog = {
|
|
270
|
-
author: this.currentUser.emailAddress,
|
|
271
|
-
prevChangeLog: prevChangeLog,
|
|
272
|
-
newChangeLog: newChangeLog,
|
|
273
|
-
timestamp: new Date().toISOString()
|
|
274
|
-
};
|
|
275
|
-
this.detailChangeLog.push(changeLog);
|
|
276
|
-
}
|
|
277
|
-
// get the device data record and initialise the form
|
|
278
|
-
loadDeviceData() {
|
|
279
|
-
this.shared.getDeviceData(this.config.deviceDataModelId, this.config.owners[0].userId, propertyCodes).subscribe({
|
|
280
|
-
next: (res) => {
|
|
281
|
-
var _a;
|
|
282
|
-
this.deviceDataId = res.deviceDataId;
|
|
283
|
-
this.recordingSession = JSON.parse(res.data['RecordingSession'].value);
|
|
284
|
-
this.initialiseForm(this.extractFields(this.recordingSession));
|
|
285
|
-
// checking for undefined in case no changes have been logged yet
|
|
286
|
-
this.detailChangeLog = res.data['UserDetailChangeLog'] === undefined ? [] : res.data['UserDetailChangeLog'].value;
|
|
287
|
-
this.status = ((_a = res.data['Status']) === null || _a === void 0 ? void 0 : _a.value) === 'Generating Report' ?
|
|
288
|
-
'generating' :
|
|
289
|
-
'success';
|
|
290
|
-
},
|
|
291
|
-
error: (err) => {
|
|
292
|
-
console.error(err);
|
|
293
|
-
this.status = "error";
|
|
294
|
-
}
|
|
295
|
-
});
|
|
266
|
+
logChange(mods) {
|
|
267
|
+
const entry = Object.assign({ author: this.currentUser.emailAddress, timestamp: new Date().toISOString() }, shallowDiff(this.initialFormState, mods));
|
|
268
|
+
this.detailChangeLog.push(entry);
|
|
269
|
+
console.log(this.detailChangeLog);
|
|
296
270
|
}
|
|
297
271
|
regenReport() {
|
|
298
272
|
this.postDeviceData(deviceDataPropertySetId, { 'Algorithmhasrun': false, 'AlgorithmRun': true }).subscribe(() => {
|
|
@@ -302,27 +276,69 @@ class DetailEditComponent {
|
|
|
302
276
|
resetModifications() {
|
|
303
277
|
this.formGroup.patchValue(this.initialFormState);
|
|
304
278
|
}
|
|
305
|
-
|
|
279
|
+
loadData(currentUserId, ownerId, deviceDataModelId) {
|
|
280
|
+
forkJoin([
|
|
281
|
+
this.shared.getUser(currentUserId),
|
|
282
|
+
this.shared.getUser(ownerId),
|
|
283
|
+
this.shared.getDeviceData(deviceDataModelId, ownerId, propertyCodes)
|
|
284
|
+
]).subscribe({
|
|
285
|
+
next: ([currentUser, owner, { deviceDataId, data: deviceData }]) => {
|
|
286
|
+
var _a, _b, _c;
|
|
287
|
+
this.currentUser = currentUser;
|
|
288
|
+
this.owner = owner;
|
|
289
|
+
this.deviceDataId = deviceDataId;
|
|
290
|
+
this.recordingSession = JSON.parse(deviceData['RecordingSession'].value);
|
|
291
|
+
this.initialiseForm(this.extractFields(this.recordingSession));
|
|
292
|
+
// data field uninitialised for unmodified record
|
|
293
|
+
this.detailChangeLog = (_b = (_a = deviceData['UserDetailChangeLog']) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : [];
|
|
294
|
+
this.status = ((_c = deviceData['Status']) === null || _c === void 0 ? void 0 : _c.value) === 'Generating Report' ?
|
|
295
|
+
'generating' : 'success';
|
|
296
|
+
},
|
|
297
|
+
error: (err) => {
|
|
298
|
+
console.error(err);
|
|
299
|
+
this.status = "error";
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
init() {
|
|
306
304
|
var _a, _b, _c;
|
|
307
|
-
if (!((
|
|
305
|
+
if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.currentUserId) || !this.config.deviceDataModelId) {
|
|
306
|
+
this.status = 'cfgerror';
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
else if (!((_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.owners) === null || _c === void 0 ? void 0 : _c[0])) {
|
|
308
310
|
this.status = 'nouser';
|
|
309
311
|
return;
|
|
310
312
|
}
|
|
311
|
-
this.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
this.status = 'loading';
|
|
314
|
+
this.loadData(this.config.currentUserId, this.config.owners[0], this.config.deviceDataModelId);
|
|
315
|
+
}
|
|
316
|
+
// this should be called from the parent using the ViewChild attr
|
|
317
|
+
refresh() {
|
|
318
|
+
this.init();
|
|
319
|
+
}
|
|
320
|
+
// NOTE: there could be something wrong / unusual here but it seems to work ok
|
|
321
|
+
ngOnInit() {
|
|
322
|
+
var _a;
|
|
323
|
+
if (this.config && !this.configDiffer)
|
|
324
|
+
this.configDiffer = this.kvDiffers.find(this.config).create();
|
|
325
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.owners) && !this.ownersDiffer)
|
|
326
|
+
this.ownersDiffer = this.itDiffers.find(this.config.owners).create();
|
|
327
|
+
}
|
|
328
|
+
ngDoCheck() {
|
|
329
|
+
var _a, _b, _c;
|
|
330
|
+
const configChanges = (_a = this.configDiffer) === null || _a === void 0 ? void 0 : _a.diff(this.config);
|
|
331
|
+
const ownersChanges = (_b = this.ownersDiffer) === null || _b === void 0 ? void 0 : _b.diff((_c = this.config) === null || _c === void 0 ? void 0 : _c.owners);
|
|
332
|
+
if (configChanges || ownersChanges)
|
|
333
|
+
this.init();
|
|
318
334
|
}
|
|
319
335
|
}
|
|
320
|
-
DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }], target: i0.ɵɵFactoryTarget.Component });
|
|
321
|
-
DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status
|
|
336
|
+
DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }, { token: i0.KeyValueDiffers }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Component });
|
|
337
|
+
DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: EntriesPipe, name: "entries" }] });
|
|
322
338
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, decorators: [{
|
|
323
339
|
type: Component,
|
|
324
|
-
args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status
|
|
325
|
-
}], ctorParameters: function () { return [{ type: i1.SharedService }]; }, propDecorators: { config: [{
|
|
340
|
+
args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"] }]
|
|
341
|
+
}], ctorParameters: function () { return [{ type: i1.SharedService }, { type: i0.KeyValueDiffers }, { type: i0.IterableDiffers }]; }, propDecorators: { config: [{
|
|
326
342
|
type: Input
|
|
327
343
|
}] } });
|
|
328
344
|
|