UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

293 lines 50.6 kB
import { Injectable } from '@angular/core'; import { AuditRecordType, AuditService, EventService, IdentityService, InventoryService, QueriesUtil, UserService } from '@c8y/client'; import { AlertService, AppStateService, gettext, toObservable } from '@c8y/ngx-components'; import { cloneDeep, pick } from 'lodash-es'; import { BehaviorSubject, combineLatest, forkJoin, from, of, pipe, Subject } from 'rxjs'; import { catchError, concatMap, distinctUntilChanged, map, scan, share, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators'; import { isValidReplaceDeviceStepState, REPLACE_DEVICE_STEP_STATE } from './replace-device-wizard.model'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/client"; import * as i2 from "@c8y/ngx-components"; export class ReplaceDeviceWizardService { static { this.NON_REENTRANT_STATES = [ 'Executing', 'Successful' ]; } get deviceToReplace$() { return this.deviceToReplaceObs$; } get replacementDeviceId$() { return this.replacementDeviceIdObs$; } constructor(inventory, identity, audit, event, user, appState, alert) { this.inventory = inventory; this.identity = identity; this.audit = audit; this.event = event; this.user = user; this.appState = appState; this.alert = alert; this.steps = []; this.deviceToReplaceSubject$ = new BehaviorSubject(null); this.deviceToReplaceObs$ = this.deviceToReplaceSubject$ .asObservable() .pipe(shareReplay()); this.replacementDeviceIdSubject$ = new Subject(); this.replacementDeviceIdObs$ = this.replacementDeviceIdSubject$ .asObservable() .pipe(shareReplay()); this.checkExternalId$ = new Subject(); this.externalIdsLoadingSubject$ = new BehaviorSubject(false); this.triggerDeviceReplacementSubject$ = new Subject(); this.deviceReplacementInProgressSubject$ = new Subject(); this.queriesUtil = new QueriesUtil(); this.externalIdsLoading$ = this.externalIdsLoadingSubject$.asObservable().pipe(shareReplay()); this.externalIds$ = this.replacementDeviceIdSubject$.pipe(distinctUntilChanged(), tap(() => this.externalIdsLoadingSubject$.next(true)), switchMap(deviceId => this.identity.list(deviceId)), tap(() => this.externalIdsLoadingSubject$.next(false)), tap(() => this.checkExternalId(null, false)), catchError(err => { this.alert.addServerFailure(err); return of(null); }), shareReplay()); this.externalIdsWithSelection$ = combineLatest([ this.externalIds$.pipe(map(result => result?.data), map(externalIds => externalIds?.map(id => ({ id, selected: true })))), this.checkExternalId$ ]).pipe(scan((acc, val) => { const [selectedIds, lastAction] = acc; const [_, checkAction] = val; if (!(lastAction?.checked === checkAction?.checked && this.areExtIdsEqual(lastAction?.id, checkAction?.id))) { selectedIds.forEach(id => (id.selected = this.areExtIdsEqual(id.id, checkAction.id) ? checkAction.checked : id.selected)); } return val; }), map(([externalIds]) => externalIds), shareReplay()); this.selectedExternalIds$ = this.externalIdsWithSelection$.pipe(map(ids => ids.filter(id => id.selected).map(id => id.id)), shareReplay()); this.defineSteps(); const toContext = ([_, deviceToReplace, replacementDeviceId, newExternalIds]) => ({ deviceToReplace, replacementDeviceId, newExternalIds }); this.deviceReplaced$ = this.triggerDeviceReplacementSubject$.pipe(tap(() => this.deviceReplacementInProgressSubject$.next(true)), withLatestFrom(this.deviceToReplace$, this.replacementDeviceId$, this.selectedExternalIds$), map(toContext), concatMap(context => this.steps .map(step => this.executeStep(step)) .reduce((ctx, step) => ctx.pipe(step), of(context))), tap(() => this.deviceReplacementInProgressSubject$.next(false)), map(() => !this.steps.some(step => step.state === 'Failed')), share()); this.deviceReplacementInProgress$ = this.deviceReplacementInProgressSubject$ .asObservable() .pipe(shareReplay()); } forDevice(deviceToReplace) { this.deviceToReplaceSubject$.next(deviceToReplace); } changeReplacementDeviceId(replacementDeviceId) { this.replacementDeviceIdSubject$.next(replacementDeviceId); } checkExternalId(id, checked) { this.checkExternalId$.next({ id, checked }); } replaceDevice() { this.triggerDeviceReplacementSubject$.next(); } retryStep(step) { this.steps.forEach(s => { if ((s.label === step?.label || !step) && !ReplaceDeviceWizardService.NON_REENTRANT_STATES.includes(s.state)) { s.skip = false; s.seed = s.context; s.state = 'Pending'; delete s.error; } else { s.skip = true; } }); this.replaceDevice(); } defineSteps() { this.steps = [ { label: gettext('Gather required data'), overrideContext: true, action: (context) => { const { deviceToReplace, replacementDeviceId, newExternalIds } = context; if (deviceToReplace.id === replacementDeviceId) { throw new Error(gettext('The device to replace and the replacement device cannot be one and the same device.')); } return forkJoin([ from(this.inventory.list({ query: this.queriesUtil.buildQuery({ owner: deviceToReplace.owner }) })).pipe(map(result => result?.data?.length === 1)), from(this.inventory.detail(replacementDeviceId)).pipe(map(result => result?.data)), from(this.identity.list(deviceToReplace.id)).pipe(map(result => result?.data)) ]).pipe(map(([deleteReplacedDeviceOwner, replacementDevice, oldExternalIds]) => ({ deviceToReplace, replacementDevice, newExternalIds, oldExternalIds, deleteReplacedDeviceOwner, time: new Date().toISOString() }))); } }, { label: gettext('Delete external IDs of replacement device'), action: (context) => { const { newExternalIds } = context; return forkJoin(newExternalIds.map(id => this.identity.delete(id))); } }, { label: gettext('Create new external IDs for the original device'), action: (context) => { const { newExternalIds, deviceToReplace } = context; return forkJoin(newExternalIds .map(extId => ({ ...pick(extId, ['type', 'externalId']), managedObject: { ...pick(deviceToReplace, ['id']) } })) .map(id => this.identity.create(id))); } }, { label: gettext('Delete old external IDs of original device'), action: (context) => { const { oldExternalIds } = context; return oldExternalIds?.length ? forkJoin(oldExternalIds.map(id => this.identity.delete(id))) : of(REPLACE_DEVICE_STEP_STATE.SKIPPED); }, info: { getMessage: (_, step) => step.state === 'Skipped' ? gettext('No existing external IDs were determined.') : undefined } }, { label: gettext('Change owner of original device`owner may be a human or system user`'), action: (context) => { const { deviceToReplace, replacementDevice, oldExternalIds, time } = context; return this.inventory.update({ id: deviceToReplace.id, owner: replacementDevice.owner, c8y_LastReplacement: { time, user: this.appState.currentUser.value.id, previousExternalIds: oldExternalIds.map(id => pick(id, ['externalId', 'type'])) } }); } }, { label: gettext('Delete old owner of original device'), action: (context) => { const { deleteReplacedDeviceOwner, deviceToReplace } = context; return deleteReplacedDeviceOwner ? this.user.delete(deviceToReplace.owner) : of(REPLACE_DEVICE_STEP_STATE.SKIPPED); }, info: { getMessage: (_, step) => step.state === 'Skipped' ? gettext('User was not deleted because it is assigned as an owner of other devices.') : undefined } }, { label: gettext('Delete replacement device'), action: (context) => { const { replacementDevice } = context; return this.inventory.delete(replacementDevice.id); } }, { label: gettext('Create event'), action: (context) => { const { deviceToReplace, oldExternalIds, newExternalIds, time } = context; return this.event.create({ source: { id: deviceToReplace.id }, text: `Device with external ID(s) ${this.extIdsToString(oldExternalIds)} was replaced by device with external ID(s) ${this.extIdsToString(newExternalIds)}`, time, type: 'c8y_DeviceReplaced' }); } }, { label: gettext('Create audit log'), action: (context) => { const { deviceToReplace, oldExternalIds, newExternalIds, time } = context; return this.audit.create({ activity: gettext('Device replaced'), source: { id: deviceToReplace.id }, text: `Device with external ID(s) ${this.extIdsToString(oldExternalIds)} was replaced by device with external ID(s) ${this.extIdsToString(newExternalIds)}`, time, type: AuditRecordType.INVENTORY, user: this.appState.currentUser.value.id }); } } ]; } executeStep(step) { return pipe(tap((ctx) => (step.state = step?.skip || ctx.skip ? step.state : REPLACE_DEVICE_STEP_STATE.EXECUTING)), concatMap((ctx) => { if (!step.context && !ctx.skip) { step.context = cloneDeep(ctx); } const context = cloneDeep(step.seed ?? ctx); return step?.skip || ctx.skip ? of(context) : toObservable(this.unwrapStepAction(context, step.action)).pipe(tap(result => (step.state = isValidReplaceDeviceStepState(result) ? result : REPLACE_DEVICE_STEP_STATE.SUCCESSFUL)), catchError(err => { step.state = REPLACE_DEVICE_STEP_STATE.FAILED; step.error = this.toError(err); context.skip = step.overrideContext; return of(context); }), tap(() => { if (typeof step.info?.getMessage === 'function') { step.info.msg = step.info.getMessage(context, step); } }), map(result => (step.overrideContext ? result : context))); })); } unwrapStepAction(context, action) { try { return action(context); } catch (err) { // bubble up any runtime errors return of({}).pipe(tap(() => { throw err; })); } } areExtIdsEqual(idA, idB) { return idA?.type === idB?.type && idA?.externalId === idB?.externalId; } extIdsToString(extnernalIds) { return extnernalIds?.map(id => `${id.externalId} [${id.type}]`).join(', '); } toError(err) { const { data, res, message } = err; let text = data?.message || message; let detailedData; if (data) { if (typeof data === 'object') { detailedData = data.exceptionMessage; } else if (typeof data === 'string') { detailedData = data; } } const hasRelevantMessage = !!(text || detailedData); if (!text) { text = gettext('A server error occurred.'); } if (res && !hasRelevantMessage) { detailedData = pick(res, ['status', 'statusText']); } return { text, detailedData }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ReplaceDeviceWizardService, deps: [{ token: i1.InventoryService }, { token: i1.IdentityService }, { token: i1.AuditService }, { token: i1.EventService }, { token: i1.UserService }, { token: i2.AppStateService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ReplaceDeviceWizardService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ReplaceDeviceWizardService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: i1.InventoryService }, { type: i1.IdentityService }, { type: i1.AuditService }, { type: i1.EventService }, { type: i1.UserService }, { type: i2.AppStateService }, { type: i2.AlertService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwbGFjZS1kZXZpY2Utd2l6YXJkLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9yZXBsYWNlLWRldmljZS9yZXBsYWNlLWRldmljZS13aXphcmQvcmVwbGFjZS1kZXZpY2Utd2l6YXJkLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQ0wsZUFBZSxFQUNmLFlBQVksRUFDWixZQUFZLEVBQ1osZUFBZSxFQUdmLGdCQUFnQixFQUVoQixXQUFXLEVBQ1gsV0FBVyxFQUNaLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSxZQUFZLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUMzRixPQUFPLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUM1QyxPQUFPLEVBQ0wsZUFBZSxFQUNmLGFBQWEsRUFDYixRQUFRLEVBQ1IsSUFBSSxFQUVKLEVBQUUsRUFDRixJQUFJLEVBQ0osT0FBTyxFQUNSLE1BQU0sTUFBTSxDQUFDO0FBQ2QsT0FBTyxFQUNMLFVBQVUsRUFDVixTQUFTLEVBQ1Qsb0JBQW9CLEVBQ3BCLEdBQUcsRUFDSCxJQUFJLEVBQ0osS0FBSyxFQUNMLFdBQVcsRUFDWCxTQUFTLEVBQ1QsR0FBRyxFQUNILGNBQWMsRUFDZixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFFTCw2QkFBNkIsRUFJN0IseUJBQXlCLEVBQzFCLE1BQU0sK0JBQStCLENBQUM7Ozs7QUFHdkMsTUFBTSxPQUFPLDBCQUEwQjthQUNiLHlCQUFvQixHQUE2QjtRQUN2RSxXQUFXO1FBQ1gsWUFBWTtLQUNiLEFBSDJDLENBRzFDO0lBRUYsSUFBSSxnQkFBZ0I7UUFDbEIsT0FBTyxJQUFJLENBQUMsbUJBQW1CLENBQUM7SUFDbEMsQ0FBQztJQUNE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QUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDN0UsQ0FBQztJQUVPLE9BQU8sQ0FBQyxHQUFHO1FBQ2pCLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxHQUFHLEdBQUcsQ0FBQztRQUNuQyxJQUFJLElBQUksR0FBRyxJQUFJLEVBQUUsT0FBTyxJQUFJLE9BQU8sQ0FBQztRQUNwQyxJQUFJLFlBQVksQ0FBQztRQUNqQixJQUFJLElBQUksRUFBRSxDQUFDO1lBQ1QsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDN0IsWUFBWSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztZQUN2QyxDQUFDO2lCQUFNLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ3BDLFlBQVksR0FBRyxJQUFJLENBQUM7WUFDdEIsQ0FBQztRQUNILENBQUM7UUFDRCxNQUFNLGtCQUFrQixHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxZQUFZLENBQUMsQ0FBQztRQUNwRCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDVixJQUFJLEdBQUcsT0FBTyxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDN0MsQ0FBQztRQUNELElBQUksR0FBRyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztZQUMvQixZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDO1FBQ3JELENBQUM7UUFFRCxPQUFPLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxDQUFDO0lBQ2hDLENBQUM7K0dBdlhVLDBCQUEwQjttSEFBMUIsMEJBQTBCOzs0RkFBMUIsMEJBQTBCO2tCQUR0QyxVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQXVkaXRSZWNvcmRUeXBlLFxuICBBdWRpdFNlcnZpY2UsXG4gIEV2ZW50U2VydmljZSxcbiAgSWRlbnRpdHlTZXJ2aWNlLFxuICBJRXh0ZXJuYWxJZGVudGl0eSxcbiAgSU1hbmFnZWRPYmplY3QsXG4gIEludmVudG9yeVNlcnZpY2UsXG4gIElSZXN1bHRMaXN0LFxuICBRdWVyaWVzVXRpbCxcbiAgVXNlclNlcnZpY2Vcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgQWxlcnRTZXJ2aWNlLCBBcHBTdGF0ZVNlcnZpY2UsIGdldHRleHQsIHRvT2JzZXJ2YWJsZSB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgY2xvbmVEZWVwLCBwaWNrIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7XG4gIEJlaGF2aW9yU3ViamVjdCxcbiAgY29tYmluZUxhdGVzdCxcbiAgZm9ya0pvaW4sXG4gIGZyb20sXG4gIE9ic2VydmFibGUsXG4gIG9mLFxuICBwaXBlLFxuICBTdWJqZWN0XG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtcbiAgY2F0Y2hFcnJvcixcbiAgY29uY2F0TWFwLFxuICBkaXN0aW5jdFVudGlsQ2hhbmdlZCxcbiAgbWFwLFxuICBzY2FuLFxuICBzaGFyZSxcbiAgc2hhcmVSZXBsYXksXG4gIHN3aXRjaE1hcCxcbiAgdGFwLFxuICB3aXRoTGF0ZXN0RnJvbVxufSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge1xuICBFcnJvcixcbiAgaXNWYWxpZFJlcGxhY2VEZXZpY2VTdGVwU3RhdGUsXG4gIFJlcGxhY2VEZXZpY2VDb250ZXh0LFxuICBSZXBsYWNlRGV2aWNlU3RlcCxcbiAgUmVwbGFjZURldmljZVN0ZXBTdGF0ZSxcbiAgUkVQTEFDRV9ERVZJQ0VfU1RFUF9TVEFURVxufSBmcm9tICcuL3JlcGxhY2UtZGV2aWNlLXdpemFyZC5tb2RlbCc7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBSZXBsYWNlRGV2aWNlV2l6YXJkU2VydmljZSB7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IE5PTl9SRUVOVFJBTlRfU1RBVEVTOiBSZXBsYWNlRGV2aWNlU3RlcFN0YXRlW10gPSBbXG4gICAgJ0V4ZWN1dGluZycsXG4gICAgJ1N1Y2Nlc3NmdWwnXG4gIF07XG5cbiAgZ2V0IGRldmljZVRvUmVwbGFjZSQoKTogT2JzZXJ2YWJsZTxJTWFuYWdlZE9iamVjdD4ge1xuICAgIHJldHVybiB0aGlzLmRldmljZVRvUmVwbGFjZU9icyQ7XG4gIH1cbiAgZ2V0IHJlcGxhY2VtZW50RGV2aWNlSWQkKCk6IE9ic2VydmFibGU8c3RyaW5nPiB7XG4gICAgcmV0dXJuIHRoaXMucmVwbGFjZW1lbnREZXZpY2VJZE9icyQ7XG4gIH1cblxuICBleHRlcm5hbElkcyQ6IE9ic2VydmFibGU8SVJlc3VsdExpc3Q8SUV4dGVybmFsSWRlbnRpdHk+PjtcbiAgZXh0ZXJuYWxJZHNMb2FkaW5nJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgZXh0ZXJuYWxJZHNXaXRoU2VsZWN0aW9uJDogT2JzZXJ2YWJsZTxBcnJheTx7IGlkOiBJRXh0ZXJuYWxJZGVudGl0eTsgc2VsZWN0ZWQ6IGJvb2xlYW4gfT4+O1xuICBzZWxlY3RlZEV4dGVybmFsSWRzJDogT2JzZXJ2YWJsZTxJRXh0ZXJuYWxJZGVudGl0eVtdPjtcbiAgZGV2aWNlUmVwbGFjZWQkOiBPYnNlcnZhYmxlPGJvb2xlYW4+O1xuICBkZXZpY2VSZXBsYWNlbWVudEluUHJvZ3Jlc3MkOiBPYnNlcnZhYmxlPGJvb2xlYW4+O1xuXG4gIHN0ZXBzOiBSZXBsYWNlRGV2aWNlU3RlcFtdID0gW107XG5cbiAgcHJpdmF0ZSBkZXZpY2VUb1JlcGxhY2VTdWJqZWN0JDogQmVoYXZpb3JTdWJqZWN0PElNYW5hZ2VkT2JqZWN0PiA9IG5ldyBCZWhhdmlvclN1YmplY3QobnVsbCk7XG4gIHByaXZhdGUgZGV2aWNlVG9SZXBsYWNlT2JzJDogT2JzZXJ2YWJsZTxJTWFuYWdlZE9iamVjdD4gPSB0aGlzLmRldmljZVRvUmVwbGFjZVN1YmplY3QkXG4gICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgLnBpcGUoc2hhcmVSZXBsYXkoKSk7XG4gIHByaXZhdGUgcmVwbGFjZW1lbnREZXZpY2VJZFN1YmplY3QkOiBTdWJqZWN0PHN0cmluZz4gPSBuZXcgU3ViamVjdCgpO1xuICBwcml2YXRlIHJlcGxhY2VtZW50RGV2aWNlSWRPYnMkOiBPYnNlcnZhYmxlPHN0cmluZz4gPSB0aGlzLnJlcGxhY2VtZW50RGV2aWNlSWRTdWJqZWN0JFxuICAgIC5hc09ic2VydmFibGUoKVxuICAgIC5waXBlKHNoYXJlUmVwbGF5KCkpO1xuICBwcml2YXRlIGNoZWNrRXh0ZXJuYWxJZCQ6IFN1YmplY3Q8eyBpZDogSUV4dGVybmFsSWRlbnRpdHk7IGNoZWNrZWQ6IGJvb2xlYW4gfT4gPSBuZXcgU3ViamVjdCgpO1xuICBwcml2YXRlIGV4dGVybmFsSWRzTG9hZGluZ1N1YmplY3QkOiBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KGZhbHNlKTtcbiAgcHJpdmF0ZSB0cmlnZ2VyRGV2aWNlUmVwbGFjZW1lbnRTdWJqZWN0JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0KCk7XG4gIHByaXZhdGUgZGV2aWNlUmVwbGFjZW1lbnRJblByb2dyZXNzU3ViamVjdCQ6IFN1YmplY3Q8Ym9vbGVhbj4gPSBuZXcgU3ViamVjdCgpO1xuXG4gIHByaXZhdGUgcXVlcmllc1V0aWw6IFF1ZXJpZXNVdGlsID0gbmV3IFF1ZXJpZXNVdGlsKCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBpbnZlbnRvcnk6IEludmVudG9yeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBpZGVudGl0eTogSWRlbnRpdHlTZXJ2aWNlLFxuICAgIHByaXZhdGUgYXVkaXQ6IEF1ZGl0U2VydmljZSxcbiAgICBwcml2YXRlIGV2ZW50OiBFdmVudFNlcnZpY2UsXG4gICAgcHJpdmF0ZSB1c2VyOiBVc2VyU2VydmljZSxcbiAgICBwcml2YXRlIGFwcFN0YXRlOiBBcHBTdGF0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGVydDogQWxlcnRTZXJ2aWNlXG4gICkge1xuICAgIHRoaXMuZXh0ZXJuYWxJZHNMb2FkaW5nJCA9IHRoaXMuZXh0ZXJuYWxJZHNMb2FkaW5nU3ViamVjdCQuYXNPYnNlcnZhYmxlKCkucGlwZShzaGFyZVJlcGxheSgpKTtcbiAgICB0aGlzLmV4dGVybmFsSWRzJCA9IHRoaXMucmVwbGFjZW1lbnREZXZpY2VJZFN1YmplY3QkLnBpcGUoXG4gICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpLFxuICAgICAgdGFwKCgpID0+IHRoaXMuZXh0ZXJuYWxJZHNMb2FkaW5nU3ViamVjdCQubmV4dCh0cnVlKSksXG4gICAgICBzd2l0Y2hNYXAoZGV2aWNlSWQgPT4gdGhpcy5pZGVudGl0eS5saXN0KGRldmljZUlkKSksXG4gICAgICB0YXAoKCkgPT4gdGhpcy5leHRlcm5hbElkc0xvYWRpbmdTdWJqZWN0JC5uZXh0KGZhbHNlKSksXG4gICAgICB0YXAoKCkgPT4gdGhpcy5jaGVja0V4dGVybmFsSWQobnVsbCwgZmFsc2UpKSxcbiAgICAgIGNhdGNoRXJyb3IoZXJyID0+IHtcbiAgICAgICAgdGhpcy5hbGVydC5hZGRTZXJ2ZXJGYWlsdXJlKGVycik7XG4gICAgICAgIHJldHVybiBvZihudWxsKTtcbiAgICAgIH0pLFxuICAgICAgc2hhcmVSZXBsYXkoKVxuICAgICk7XG5cbiAgICB0aGlzLmV4dGVybmFsSWRzV2l0aFNlbGVjdGlvbiQgPSBjb21iaW5lTGF0ZXN0KFtcbiAgICAgIHRoaXMuZXh0ZXJuYWxJZHMkLnBpcGUoXG4gICAgICAgIG1hcChyZXN1bHQgPT4gcmVzdWx0Py5kYXRhKSxcbiAgICAgICAgbWFwKGV4dGVybmFsSWRzID0+IGV4dGVybmFsSWRzPy5tYXAoaWQgPT4gKHsgaWQsIHNlbGVjdGVkOiB0cnVlIH0pKSlcbiAgICAgICksXG4gICAgICB0aGlzLmNoZWNrRXh0ZXJuYWxJZCRcbiAgICBdKS5waXBlKFxuICAgICAgc2NhbigoYWNjLCB2YWwpID0+IHtcbiAgICAgICAgY29uc3QgW3NlbGVjdGVkSWRzLCBsYXN0QWN0aW9uXSA9IGFjYztcbiAgICAgICAgY29uc3QgW18sIGNoZWNrQWN0aW9uXSA9IHZhbDtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICEoXG4gICAgICAgICAgICBsYXN0QWN0aW9uPy5jaGVja2VkID09PSBjaGVja0FjdGlvbj8uY2hlY2tlZCAmJlxuICAgICAgICAgICAgdGhpcy5hcmVFeHRJZHNFcXVhbChsYXN0QWN0aW9uPy5pZCwgY2hlY2tBY3Rpb24/LmlkKVxuICAgICAgICAgIClcbiAgICAgICAgKSB7XG4gICAgICAgICAgc2VsZWN0ZWRJZHMuZm9yRWFjaChcbiAgICAgICAgICAgIGlkID0+XG4gICAgICAgICAgICAgIChpZC5zZWxlY3RlZCA9IHRoaXMuYXJlRXh0SWRzRXF1YWwoaWQuaWQsIGNoZWNrQWN0aW9uLmlkKVxuICAgICAgICAgICAgICAgID8gY2hlY2tBY3Rpb24uY2hlY2tlZFxuICAgICAgICAgICAgICAgIDogaWQuc2VsZWN0ZWQpXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdmFsO1xuICAgICAgfSksXG4gICAgICBtYXAoKFtleHRlcm5hbElkc10pID0+IGV4dGVybmFsSWRzKSxcbiAgICAgIHNoYXJlUmVwbGF5KClcbiAgICApO1xuXG4gICAgdGhpcy5zZWxlY3RlZEV4dGVybmFsSWRzJCA9IHRoaXMuZXh0ZXJuYWxJZHNXaXRoU2VsZWN0aW9uJC5waXBlKFxuICAgICAgbWFwKGlkcyA9PiBpZHMuZmlsdGVyKGlkID0+IGlkLnNlbGVjdGVkKS5tYXAoaWQgPT4gaWQuaWQpKSxcbiAgICAgIHNoYXJlUmVwbGF5KClcbiAgICApO1xuXG4gICAgdGhpcy5kZWZpbmVTdGVwcygpO1xuXG4gICAgY29uc3QgdG9Db250ZXh0ID0gKFtfLCBkZXZpY2VUb1JlcGxhY2UsIHJlcGxhY2VtZW50RGV2aWNlSWQsIG5ld0V4dGVybmFsSWRzXSkgPT4gKHtcbiAgICAgIGRldmljZVRvUmVwbGFjZSxcbiAgICAgIHJlcGxhY2VtZW50RGV2aWNlSWQsXG4gICAgICBuZXdFeHRlcm5hbElkc1xuICAgIH0pO1xuXG4gICAgdGhpcy5kZXZpY2VSZXBsYWNlZCQgPSB0aGlzLnRyaWdnZXJEZXZpY2VSZXBsYWNlbWVudFN1YmplY3QkLnBpcGUoXG4gICAgICB0YXAoKCkgPT4gdGhpcy5kZXZpY2VSZXBsYWNlbWVudEluUHJvZ3Jlc3NTdWJqZWN0JC5uZXh0KHRydWUpKSxcbiAgICAgIHdpdGhMYXRlc3RGcm9tKHRoaXMuZGV2aWNlVG9SZXBsYWNlJCwgdGhpcy5yZXBsYWNlbWVudERldmljZUlkJCwgdGhpcy5zZWxlY3RlZEV4dGVybmFsSWRzJCksXG4gICAgICBtYXAodG9Db250ZXh0KSxcbiAgICAgIGNvbmNhdE1hcChjb250ZXh0ID0+XG4gICAgICAgIHRoaXMuc3RlcHNcbiAgICAgICAgICAubWFwKHN0ZXAgPT4gdGhpcy5leGVjdXRlU3RlcChzdGVwKSlcbiAgICAgICAgICAucmVkdWNlKChjdHgsIHN0ZXApID0+IGN0eC5waXBlKHN0ZXApLCBvZihjb250ZXh0KSlcbiAgICAgICksXG4gICAgICB0YXAoKCkgPT4gdGhpcy5kZXZpY2VSZXBsYWNlbWVudEluUHJvZ3Jlc3NTdWJqZWN0JC5uZXh0KGZhbHNlKSksXG4gICAgICBtYXAoKCkgPT4gIXRoaXMuc3RlcHMuc29tZShzdGVwID0+IHN0ZXAuc3RhdGUgPT09ICdGYWlsZWQnKSksXG4gICAgICBzaGFyZSgpXG4gICAgKTtcblxuICAgIHRoaXMuZGV2aWNlUmVwbGFjZW1lbnRJblByb2dyZXNzJCA9IHRoaXMuZGV2aWNlUmVwbGFjZW1lbnRJblByb2dyZXNzU3ViamVjdCRcbiAgICAgIC5hc09ic2VydmFibGUoKVxuICAgICAgLnBpcGUoc2hhcmVSZXBsYXkoKSk7XG4gIH1cblxuICBmb3JEZXZpY2UoZGV2aWNlVG9SZXBsYWNlOiBJTWFuYWdlZE9iamVjdCkge1xuICAgIHRoaXMuZGV2aWNlVG9SZXBsYWNlU3ViamVjdCQubmV4dChkZXZpY2VUb1JlcGxhY2UpO1xuICB9XG5cbiAgY2hhbmdlUmVwbGFjZW1lbnREZXZpY2VJZChyZXBsYWNlbWVudERldmljZUlkOiBzdHJpbmcpIHtcbiAgICB0aGlzLnJlcGxhY2VtZW50RGV2aWNlSWRTdWJqZWN0JC5uZXh0KHJlcGxhY2VtZW50RGV2aWNlSWQpO1xuICB9XG5cbiAgY2hlY2tFeHRlcm5hbElkKGlkOiBJRXh0ZXJuYWxJZGVudGl0eSwgY2hlY2tlZDogYm9vbGVhbikge1xuICAgIHRoaXMuY2hlY2tFeHRlcm5hbElkJC5uZXh0KHsgaWQsIGNoZWNrZWQgfSk7XG4gIH1cblxuICByZXBsYWNlRGV2aWNlKCkge1xuICAgIHRoaXMudHJpZ2dlckRldmljZVJlcGxhY2VtZW50U3ViamVjdCQubmV4dCgpO1xuICB9XG5cbiAgcmV0cnlTdGVwKHN0ZXA/OiBSZXBsYWNlRGV2aWNlU3RlcCkge1xuICAgIHRoaXMuc3RlcHMuZm9yRWFjaChzID0+IHtcbiAgICAgIGlmIChcbiAgICAgICAgKHMubGFiZWwgPT09IHN0ZXA/LmxhYmVsIHx8ICFzdGVwKSAmJlxuICAgICAgICAhUmVwbGFjZURldmljZVdpemFyZFNlcnZpY2UuTk9OX1JFRU5UUkFOVF9TVEFURVMuaW5jbHVkZXMocy5zdGF0ZSlcbiAgICAgICkge1xuICAgICAgICBzLnNraXAgPSBmYWxzZTtcbiAgICAgICAgcy5zZWVkID0gcy5jb250ZXh0O1xuICAgICAgICBzLnN0YXRlID0gJ1BlbmRpbmcnO1xuICAgICAgICBkZWxldGUgcy5lcnJvcjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHMuc2tpcCA9IHRydWU7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5yZXBsYWNlRGV2aWNlKCk7XG4gIH1cblxuICBwcml2YXRlIGRlZmluZVN0ZXBzKCkge1xuICAgIHRoaXMuc3RlcHMgPSBbXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiBnZXR0ZXh0KCdHYXRoZXIgcmVxdWlyZWQgZGF0YScpLFxuICAgICAgICBvdmVycmlkZUNvbnRleHQ6IHRydWUsXG4gICAgICAgIGFjdGlvbjogKGNvbnRleHQ6IFJlcGxhY2VEZXZpY2VDb250ZXh0KSA9PiB7XG4gICAgICAgICAgY29uc3QgeyBkZXZpY2VUb1JlcGxhY2UsIHJlcGxhY2VtZW50RGV2aWNlSWQsIG5ld0V4dGVybmFsSWRzIH0gPSBjb250ZXh0O1xuICAgICAgICAgIGlmIChkZXZpY2VUb1JlcGxhY2UuaWQgPT09IHJlcGxhY2VtZW50RGV2aWNlSWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgZ2V0dGV4dChcbiAgICAgICAgICAgICAgICAnVGhlIGRldmljZSB0byByZXBsYWNlIGFuZCB0aGUgcmVwbGFjZW1lbnQgZGV2aWNlIGNhbm5vdCBiZSBvbmUgYW5kIHRoZSBzYW1lIGRldmljZS4nXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBmb3JrSm9pbihbXG4gICAgICAgICAgICBmcm9tKFxuICAgICAgICAgICAgICB0aGlzLmludmVudG9yeS5saXN0KHtcbiAgICAgICAgICAgICAgICBxdWVyeTogdGhpcy5xdWVyaWVzVXRpbC5idWlsZFF1ZXJ5KHsgb3duZXI6IGRldmljZVRvUmVwbGFjZS5vd25lciB9KVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgKS5waXBlKG1hcChyZXN1bHQgPT4gcmVzdWx0Py5kYXRhPy5sZW5ndGggPT09IDEpKSxcbiAgICAgICAgICAgIGZyb20odGhpcy5pbnZlbnRvcnkuZGV0YWlsKHJlcGxhY2VtZW50RGV2aWNlSWQpKS5waXBlKG1hcChyZXN1bHQgPT4gcmVzdWx0Py5kYXRhKSksXG4gICAgICAgICAgICBmcm9tKHRoaXMuaWRlbnRpdHkubGlzdChkZXZpY2VUb1JlcGxhY2UuaWQpKS5waXBlKG1hcChyZXN1bHQgPT4gcmVzdWx0Py5kYXRhKSlcbiAgICAgICAgICBdKS5waXBlKFxuICAgICAgICAgICAgbWFwKChbZGVsZXRlUmVwbGFjZWREZXZpY2VPd25lciwgcmVwbGFjZW1lbnREZXZpY2UsIG9sZEV4dGVybmFsSWRzXSkgPT4gKHtcbiAgICAgICAgICAgICAgZGV2aWNlVG9SZXBsYWNlLFxuICAgICAgICAgICAgICByZXBsYWNlbWVudERldmljZSxcbiAgICAgICAgICAgICAgbmV3RXh0ZXJuYWxJZHMsXG4gICAgICAgICAgICAgIG9sZEV4dGVybmFsSWRzLFxuICAgICAgICAgICAgICBkZWxldGVSZXBsYWNlZERldmljZU93bmVyLFxuICAgICAgICAgICAgICB0aW1lOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiBnZXR0ZXh0KCdEZWxldGUgZXh0ZXJuYWwgSURzIG9mIHJlcGxhY2VtZW50IGRldmljZScpLFxuICAgICAgICBhY3Rpb246IChjb250ZXh0OiBSZXBsYWNlRGV2aWNlQ29udGV4dCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgbmV3RXh0ZXJuYWxJZHMgfSA9IGNvbnRleHQ7XG4gICAgICAgICAgcmV0dXJuIGZvcmtKb2luKG5ld0V4dGVybmFsSWRzLm1hcChpZCA9PiB0aGlzLmlkZW50aXR5LmRlbGV0ZShpZCkpKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgbGFiZWw6IGdldHRleHQoJ0NyZWF0ZSBuZXcgZXh0ZXJuYWwgSURzIGZvciB0aGUgb3JpZ2luYWwgZGV2aWNlJyksXG4gICAgICAgIGFjdGlvbjogKGNvbnRleHQ6IFJlcGxhY2VEZXZpY2VDb250ZXh0KSA9PiB7XG4gICAgICAgICAgY29uc3QgeyBuZXdFeHRlcm5hbElkcywgZGV2aWNlVG9SZXBsYWNlIH0gPSBjb250ZXh0O1xuICAgICAgICAgIHJldHVybiBmb3JrSm9pbihcbiAgICAgICAgICAgIG5ld0V4dGVybmFsSWRzXG4gICAgICAgICAgICAgIC5tYXAoZXh0SWQgPT4gKHtcbiAgICAgICAgICAgICAgICAuLi5waWNrKGV4dElkLCBbJ3R5cGUnLCAnZXh0ZXJuYWxJZCddKSxcbiAgICAgICAgICAgICAgICBtYW5hZ2VkT2JqZWN0OiB7IC4uLnBpY2soZGV2aWNlVG9SZXBsYWNlLCBbJ2lkJ10pIH1cbiAgICAgICAgICAgICAgfSkpXG4gICAgICAgICAgICAgIC5tYXAoaWQgPT4gdGhpcy5pZGVudGl0eS5jcmVhdGUoaWQpKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiBnZXR0ZXh0KCdEZWxldGUgb2xkIGV4dGVybmFsIElEcyBvZiBvcmlnaW5hbCBkZXZpY2UnKSxcbiAgICAgICAgYWN0aW9uOiAoY29udGV4dDogUmVwbGFjZURldmljZUNvbnRleHQpID0+IHtcbiAgICAgICAgICBjb25zdCB7IG9sZEV4dGVybmFsSWRzIH0gPSBjb250ZXh0O1xuICAgICAgICAgIHJldHVybiBvbGRFeHRlcm5hbElkcz8ubGVuZ3RoXG4gICAgICAgICAgICA/IGZvcmtKb2luKG9sZEV4dGVybmFsSWRzLm1hcChpZCA9PiB0aGlzLmlkZW50aXR5LmRlbGV0ZShpZCkpKVxuICAgICAgICAgICAgOiBvZihSRVBMQUNFX0RFVklDRV9TVEVQX1NUQVRFLlNLSVBQRUQpO1xuICAgICAgICB9LFxuICAgICAgICBpbmZvOiB7XG4gICAgICAgICAgZ2V0TWVzc2FnZTogKF8sIHN0ZXApID0+XG4gICAgICAgICAgICBzdGVwLnN0YXRlID09PSAnU2tpcHBlZCdcbiAgICAgICAgICAgICAgPyBnZXR0ZXh0KCdObyBleGlzdGluZyBleHRlcm5hbCBJRHMgd2VyZSBkZXRlcm1pbmVkLicpXG4gICAgICAgICAgICAgIDogdW5kZWZpbmVkXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiBnZXR0ZXh0KCdDaGFuZ2Ugb3duZXIgb2Ygb3JpZ2luYWwgZGV2aWNlYG93bmVyIG1heSBiZSBhIGh1bWFuIG9yIHN5c3RlbSB1c2VyYCcpLFxuICAgICAgICBhY3Rpb246IChjb250ZXh0OiBSZXBsYWNlRGV2aWNlQ29udGV4dCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgZGV2aWNlVG9SZXBsYWNlLCByZXBsYWNlbWVudERldmljZSwgb2xkRXh0ZXJuYWxJZHMsIHRpbWUgfSA9IGNvbnRleHQ7XG4gICAgICAgICAgcmV0dXJuIHRoaXMuaW52ZW50b3J5LnVwZGF0ZSh7XG4gICAgICAgICAgICBpZDogZGV2aWNlVG9SZXBsYWNlLmlkLFxuICAgICAgICAgICAgb3duZXI6IHJlcGxhY2VtZW50RGV2aWNlLm93bmVyLFxuICAgICAgICAgICAgYzh5X0xhc3RSZXBsYWNlbWVudDoge1xuICAgICAgICAgICAgICB0aW1lLFxuICAgICAgICAgICAgICB1c2VyOiB0aGlzLmFwcFN0YXRlLmN1cnJlbnRVc2VyLnZhbHVlLmlkLFxuICAgICAgICAgICAgICBwcmV2aW91c0V4dGVybmFsSWRzOiBvbGRFeHRlcm5hbElkcy5tYXAoaWQgPT4gcGljayhpZCwgWydleHRlcm5hbElkJywgJ3R5cGUnXSkpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiBnZXR0ZXh0KCdEZWxldGUgb2xkIG93bmVyIG9mIG9yaWdpbmFsIGRldmljZScpLFxuICAgICAgICBhY3Rpb246IChjb250ZXh0OiBSZXBsYWNlRGV2aWNlQ29udGV4dCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgZGVsZXRlUmVwbGFjZWREZXZpY2VPd25lciwgZGV2aWNlVG9SZXBsYWNlIH0gPSBjb250ZXh0O1xuICAgICAgICAgIHJldHVybiBkZWxldGVSZXBsYWNlZERldmljZU93bmVyXG4gICAgICAgICAgICA/IHRoaXMudXNlci5kZWxldGUoZGV2aWNlVG9SZXBsYWNlLm93bmVyKVxuICAgICAgICAgICAgOiBvZihSRVBMQUNFX0RFVklDRV9TVEVQX1NUQVRFLlNLSVBQRUQpO1xuICAgICAgICB9LFxuICAgICAgICBpbmZvOiB7XG4gICAgICAgICAgZ2V0TWVzc2FnZTogKF8sIHN0ZXApID0+XG4gICAgICAgICAgICBzdGVwLnN0YXRlID09PSAnU2tpcHBlZCdcbiAgICAgICAgICAgICAgPyBnZXR0ZXh0KCdVc2VyIHdhcyBub3QgZGVsZXRlZCBiZWNhdXNlIGl0IGlzIGFzc2lnbmVkIGFzIGFuIG93bmVyIG9mIG90aGVyIGRldmljZXMuJylcbiAgICAgICAgICAgICAgOiB1bmRlZmluZWRcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgbGFiZWw6IGdldHRleHQoJ0RlbGV0ZSByZXBsYWNlbWVudCBkZXZpY2UnKSxcbiAgICAgICAgYWN0aW9uOiAoY29udGV4dDogUmVwbGFjZURldmljZUNvbnRleHQpID0+IHtcbiAgICAgICAgICBjb25zdCB7IHJlcGxhY2VtZW50RGV2aWNlIH0gPSBjb250ZXh0O1xuICAgICAgICAgIHJldHVybiB0aGlzLmludmVudG9yeS5kZWxldGUocmVwbGFjZW1lbnREZXZpY2UuaWQpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBsYWJlbDogZ2V0dGV4dCgnQ3JlYXRlIGV2ZW50JyksXG4gICAgICAgIGFjdGlvbjogKGNvbnRleHQ6IFJlcGxhY2VEZXZpY2VDb250ZXh0KSA9PiB7XG4gICAgICAgICAgY29uc3QgeyBkZXZpY2VUb1JlcGxhY2UsIG9sZEV4dGVybmFsSWRzLCBuZXdFeHRlcm5hbElkcywgdGltZSB9ID0gY29udGV4dDtcbiAgICAgICAgICByZXR1cm4gdGhpcy5ldmVudC5jcmVhdGUoe1xuICAgICAgICAgICAgc291cmNlOiB7IGlkOiBkZXZpY2VUb1JlcGxhY2UuaWQgfSxcbiAgICAgICAgICAgIHRleHQ6IGBEZXZpY2Ugd2l0aCBleHRlcm5hbCBJRChzKSAke3RoaXMuZXh0SWRzVG9TdHJpbmcoXG4gICAgICAgICAgICAgIG9sZEV4dGVybmFsSWRzXG4gICAgICAgICAgICApfSB3YXMgcmVwbGFjZWQgYnkgZGV2aWNlIHdpdGggZXh0ZXJuYWwgSUQocykgJHt0aGlzLmV4dElkc1RvU3RyaW5nKG5ld0V4dGVybmFsSWRzKX1gLFxuICAgICAgICAgICAgdGltZSxcbiAgICAgICAgICAgIHR5cGU6ICdjOHlfRGV2aWNlUmVwbGFjZWQnXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiBnZXR0ZXh0KCdDcmVhdGUgYXVkaXQgbG9nJyksXG4gICAgICAgIGFjdGlvbjogKGNvbnRleHQ6IFJlcGxhY2VEZXZpY2VDb250ZXh0KSA9PiB7XG4gICAgICAgICAgY29uc3QgeyBkZXZpY2VUb1JlcGxhY2UsIG9sZEV4dGVybmFsSWRzLCBuZXdFeHRlcm5hbElkcywgdGltZSB9ID0gY29udGV4dDtcbiAgICAgICAgICByZXR1cm4gdGhpcy5hdWRpdC5jcmVhdGUoe1xuICAgICAgICAgICAgYWN0aXZpdHk6IGdldHRleHQoJ0RldmljZSByZXBsYWNlZCcpLFxuICAgICAgICAgICAgc291cmNlOiB7IGlkOiBkZXZpY2VUb1JlcGxhY2UuaWQgfSxcbiAgICAgICAgICAgIHRleHQ6IGBEZXZpY2Ugd2l0aCBleHRlcm5hbCBJRChzKSAke3RoaXMuZXh0SWRzVG9TdHJpbmcoXG4gICAgICAgICAgICAgIG9sZEV4dGVybmFsSWRzXG4gICAgICAgICAgICApfSB3YXMgcmVwbGFjZWQgYnkgZGV2aWNlIHdpdGggZXh0ZXJuYWwgSUQocykgJHt0aGlzLmV4dElkc1RvU3RyaW5nKG5ld0V4dGVybmFsSWRzKX1gLFxuICAgICAgICAgICAgdGltZSxcbiAgICAgICAgICAgIHR5cGU6IEF1ZGl0UmVjb3JkVHlwZS5JTlZFTlRPUlksXG4gICAgICAgICAgICB1c2VyOiB0aGlzLmFwcFN0YXRlLmN1cnJlbnRVc2VyLnZhbHVlLmlkXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBleGVjdXRlU3RlcChzdGVwOiBSZXBsYWNlRGV2aWNlU3RlcCkge1xuICAgIHJldHVybiBwaXBlKFxuICAgICAgdGFwKFxuICAgICAgICAoY3R4OiBSZXBsYWNlRGV2aWNlQ29udGV4dCkgPT5cbiAgICAgICAgICAoc3RlcC5zdGF0ZSA9IHN0ZXA/LnNraXAgfHwgY3R4LnNraXAgPyBzdGVwLnN0YXRlIDogUkVQTEFDRV9ERVZJQ0VfU1RFUF9TVEFURS5FWEVDVVRJTkcpXG4gICAgICApLFxuICAgICAgY29uY2F0TWFwKChjdHg6IFJlcGxhY2VEZXZpY2VDb250ZXh0KSA9PiB7XG4gICAgICAgIGlmICghc3RlcC5jb250ZXh0ICYmICFjdHguc2tpcCkge1xuICAgICAgICAgIHN0ZXAuY29udGV4dCA9IGNsb25lRGVlcChjdHgpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSBjbG9uZURlZXAoc3RlcC5zZWVkID8/IGN0eCk7XG4gICAgICAgIHJldHVybiBzdGVwPy5za2lwIHx8IGN0eC5za2lwXG4gICAgICAgICAgPyBvZihjb250ZXh0KVxuICAgICAgICAgIDogdG9PYnNlcnZhYmxlKHRoaXMudW53cmFwU3RlcEFjdGlvbihjb250ZXh0LCBzdGVwLmFjdGlvbikpLnBpcGUoXG4gICAgICAgICAgICAgIHRhcChcbiAgICAgICAgICAgICAgICByZXN1bHQgPT5cbiAgICAgICAgICAgICAgICAgIChzdGVwLnN0YXRlID0gaXNWYWxpZFJlcGxhY2VEZXZpY2VTdGVwU3RhdGUocmVzdWx0KVxuICAgICAgICAgICAgICAgICAgICA/IHJlc3VsdFxuICAgICAgICAgICAgICAgICAgICA6IFJFUExBQ0VfREVWSUNFX1NURVBfU1RBVEUuU1VDQ0VTU0ZVTClcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgY2F0Y2hFcnJvcihlcnIgPT4ge1xuICAgICAgICAgICAgICAgIHN0ZXAuc3RhdGUgPSBSRVBMQUNFX0RFVklDRV9TVEVQX1NUQVRFLkZBSUxFRDtcbiAgICAgICAgICAgICAgICBzdGVwLmVycm9yID0gdGhpcy50b0Vycm9yKGVycik7XG4gICAgICAgICAgICAgICAgY29udGV4dC5za2lwID0gc3RlcC5vdmVycmlkZUNvbnRleHQ7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG9mKGNvbnRleHQpO1xuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgdGFwKCgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHN0ZXAuaW5mbz8uZ2V0TWVzc2FnZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgc3RlcC5pbmZvLm1zZyA9IHN0ZXAuaW5mby5nZXRNZXNzYWdlKGNvbnRleHQsIHN0ZXApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgIG1hcChyZXN1bHQgPT4gKHN0ZXAub3ZlcnJpZGVDb250ZXh0ID8gcmVzdWx0IDogY29udGV4dCkpXG4gICAgICAgICAgICApO1xuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSB1bndyYXBTdGVwQWN0aW9uKFxuICAgIGNvbnRleHQ6IFJlcGxhY2VEZXZpY2VDb250ZXh0LFxuICAgIGFjdGlvbjogKGNvbnRleHQ6IFJlcGxhY2VEZXZpY2VDb250ZXh0KSA9PiBPYnNlcnZhYmxlPHVua25vd24+IHwgUHJvbWlzZTx1bmtub3duPlxuICApIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGFjdGlvbihjb250ZXh0KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIGJ1YmJsZSB1cCBhbnkgcnVudGltZSBlcnJvcnNcbiAgICAgIHJldHVybiBvZih7fSkucGlwZShcbiAgICAgICAgdGFwKCgpID0+IHtcbiAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXJlRXh0SWRzRXF1YWwoaWRBOiBJRXh0ZXJuYWxJZGVudGl0eSwgaWRCOiBJRXh0ZXJuYWxJZGVudGl0eSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBpZEE/LnR5cGUgPT09IGlkQj8udHlwZSAmJiBpZEE/LmV4dGVybmFsSWQgPT09IGlkQj8uZXh0ZXJuYWxJZDtcbiAgfVxuXG4gIHByaXZhdGUgZXh0SWRzVG9TdHJpbmcoZXh0bmVybmFsSWRzOiBJRXh0ZXJuYWxJZGVudGl0eVtdKSB7XG4gICAgcmV0dXJuIGV4dG5lcm5hbElkcz8ubWFwKGlkID0+IGAke2lkLmV4dGVybmFsSWR9IFske2lkLnR5cGV9XWApLmpvaW4oJywgJyk7XG4gIH1cblxuICBwcml2YXRlIHRvRXJyb3IoZXJyKTogRXJyb3Ige1xuICAgIGNvbnN0IHsgZGF0YSwgcmVzLCBtZXNzYWdlIH0gPSBlcnI7XG4gICAgbGV0IHRleHQgPSBkYXRhPy5tZXNzYWdlIHx8IG1lc3NhZ2U7XG4gICAgbGV0IGRldGFpbGVkRGF0YTtcbiAgICBpZiAoZGF0YSkge1xuICAgICAgaWYgKHR5cGVvZiBkYXRhID09PSAnb2JqZWN0J