@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
261 lines • 34.5 kB
JavaScript
import { Injectable } from '@angular/core';
import { ALARM_STATUS_LABELS, AlarmService, AlarmStatus, Severity } from '@c8y/client';
import { OptionsService, ViewContext, gettext } from '@c8y/ngx-components';
import { BehaviorSubject, Subject } from 'rxjs';
import { ALARMS_PATH, INTERVALS_EXTENDED } from './alarms.model';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/client";
import * as i2 from "@c8y/ngx-components";
/**
* Service for managing and retrieving alarms data within the alarms view.
*
* The `AlarmsViewService` provides functionality to interact with alarms,
* including filtering, counting, and translation-related operations in an alarms view.
*
* This service relies on the `AlarmService` for fetching alarm data and the `OptionsService`
* for configuring alarms view options.
*/
export class AlarmsViewService {
constructor(alarmService, optionsService) {
this.alarmService = alarmService;
this.optionsService = optionsService;
this.ALARM_REFRESH_TYPE_KEY = 'alarmsRefreshType';
this.DEFAULT_INTERVAL_VALUE = 30_000;
this.DEFAULT_REFRESH_OPTION_VALUE = 'interval';
this.DEFAULT_INTERVAL_VALUES = [5_000, 10_000, 15_000, 30_000, 60_000];
this.REALTIME_UPDATE_ALARMS_MESSAGE = gettext('The list was updated, click to refresh.');
this.reloadAlarmsList$ = new Subject();
if (this.isIntervalRefresh()) {
this._isIntervalEnabled = new BehaviorSubject(true);
this.isIntervalEnabled$ = this._isIntervalEnabled.asObservable();
}
}
/**
* Emits a subject to initialize the alarms reloading.
*/
updateAlarmList() {
this.reloadAlarmsList$.next();
}
/**
* Retrieves a list of alarms filtered by specified severities and other optional query filters.
*
* @param severities an array of severities to filter the alarms.
* @param showCleared flag indicating whether to show cleared alarms. Defaults to false.
* @param selectedDates an array of two dates to filter alarms by creation and last update dates.
* @param filter additional query filters for retrieving alarms.
*
* @returns A promise that resolves to a list of alarms satisfying the specified filters.
*/
retrieveFilteredAlarms(severities, showCleared = false, selectedDates, filter) {
const severitiesQuery = this.getSeverityQueryParameter(severities);
const statusesQuery = this.getStatusQueryParameter(showCleared);
const _filter = {
pageSize: 50,
withTotalPages: true,
...(severitiesQuery && { severity: severitiesQuery }),
...(statusesQuery && { status: statusesQuery }),
...(selectedDates && {
lastUpdatedFrom: selectedDates[0].toISOString(),
createdTo: selectedDates[1].toISOString()
}),
...filter
};
return this.alarmService.list(_filter);
}
retrieveAlarmsByDate(dates) {
return this.alarmService.list({
lastUpdatedFrom: dates[0].toISOString(),
createdTo: dates[1].toISOString(),
pageSize: 50,
withTotalPages: true
});
}
/**
* Updates the state to enable or disable intervals.
* @param value - A boolean value to indicate whether to enable intervals.
*/
updateIntervalState(value) {
this._isIntervalEnabled?.next(value);
}
/**
* Fetches the count of alarms filtered by severity and clearance status.
*
* @param severity - The severity level to filter by (e.g., CRITICAL, MAJOR, etc.).
* @param showCleared - Whether or not to include cleared alarms in the count.
* @param filter - Additional filter criteria for alarms.
*
* @returns A promise that resolves to the number of alarms that match the filter criteria.
*
*/
async getAlarmsCountBySeverity(severity, showCleared, filter) {
const statusesQuery = this.getStatusQueryParameter(showCleared);
const _filter = {
...(severity && { severity: severity }),
...(statusesQuery && { status: statusesQuery }),
...filter
};
const { data } = await this.alarmService.count(_filter);
return data;
}
/**
* Retrieves the current alarms refresh type from the OptionsService
* and determines whether it is set to "interval".
*
* @returns `true` if the alarms refresh type is "interval," otherwise `false`.
*/
isIntervalRefresh() {
const value = this.optionsService.get(this.ALARM_REFRESH_TYPE_KEY, 'interval');
return value === 'interval';
}
/**
* Updates the list of selected severities based on the new severity filter.
*
* @param severityUpdates - The object representing the updates to each severity.
*
* @returns An array representing the updated selected severities.
*/
updateSelectedSeverities(severityUpdates) {
return Object.keys(severityUpdates)
.filter(key => severityUpdates[key])
.map(key => key.toUpperCase());
}
/**
* Clears all active alarms of the selected severities.
*
* This method clears all active alarms for the given list of severities by making bulk update calls. If no severities are selected, it defaults to using all available severities.
* It works by sending a series of update requests for each severity and returns a Promise that resolves with an object indicating if all alarms were resolved immediately.
*
* @param selectedSeverities An array of severities to be cleared. If not provided, all severities will be cleared.
* @param sourceId - Identifier for the source associated with the alarms to be cleared.
*
* @returns A Promise that resolves with an object with a flag `resolvedImmediately`. The flag is true if all alarms for all selected severities were cleared successfully; otherwise false.
*
* **Example**
* ```typescript
* const severitiesToClear: SeverityType[] = [Severity.MAJOR, Severity.MINOR];
*
* clearAllActiveAlarms(severitiesToClear).then(({ resolvedImmediately }) => {
* if (resolvedImmediately) {
* console.log('All selected alarms were cleared successfully.');
* } else {
* console.log('Some alarms could not be cleared.');
* }
* });
* ```
*
* **Note**
* - The method uses the `alarmService.updateBulk` for each severity to clear the active alarms.
* - It may fetch the `sourceId` based on the view (if applicable) and include it as a query parameter in the update calls.
* - The method returns immediately but the returned Promise needs to have a `then` or `catch` method call to handle the result or error respectively.
* - Uses `Promise.all` to wait for all update requests to complete before resolving the final result.
*/
async clearAllActiveAlarms(selectedSeverities, sourceId) {
const severitiesToUpdate = selectedSeverities || Severity;
const promises = Object.values(severitiesToUpdate).map((severity) => {
const commonParams = { resolved: false, severity };
const parameters = sourceId
? {
...commonParams,
source: sourceId,
withSourceAssets: true,
withSourceDevices: true
}
: commonParams;
return this.alarmService.updateBulk({ status: AlarmStatus.CLEARED }, parameters);
});
const responses = await Promise.all(promises);
return {
resolvedImmediately: responses.every(res => res)
};
}
/**
* Returns the correct link based on the provided context data.
* @param contextData The context the navigation was triggered from.
* @param alarm The alarm to navigate to.
* @returns A link to be used as an url navigation.
*/
getRouterLink(contextData, alarm) {
let detailUrl = `/${ALARMS_PATH}`;
if (alarm) {
detailUrl = `/${ALARMS_PATH}/${alarm.id}`;
}
if (!contextData) {
return detailUrl;
}
switch (contextData.context) {
case ViewContext.Device:
return `/device/${contextData.contextData.id}${detailUrl}`;
case ViewContext.Group:
return `/group/${contextData.contextData.id}${detailUrl}`;
case ViewContext.Simulators:
return `/simulators/${contextData.contextData.id}${detailUrl}`;
default:
return detailUrl;
}
}
/**
* Returns the correct array navigation.
* @param contextData The context the navigation was triggered from.
* @param alarm The alarm to navigate to.
* @returns A link to be used as a router.navigation.
*/
getRouterNavigationArray(contextData, alarm) {
return this.getRouterLink(contextData, alarm).split('/').filter(Boolean);
}
/**
* Returns the correct from and to dates based on the selected interval
* @param intervalId the selected interval. E.g. 'none', 'hours', 'custom' ...
* @returns The calculated date context based on the selected interval.
*/
getDateTimeContextByInterval(intervalId) {
const interval = INTERVALS_EXTENDED.find(({ id }) => id === intervalId);
if (interval.id === 'none') {
return [new Date(0), new Date()];
}
const dateTo = new Date();
const dateFrom = new Date(dateTo.valueOf() - interval.timespanInMs);
return [dateFrom, dateTo];
}
/**
* Creates a value for query parameter for filtering alarms by severity based on array of selected severities.
*
* @param severities - An array of alarm severity types to include in the filter.
* If the array is empty or undefined, no severity filter will be applied.
*
* @returns A comma-separated string of selected alarm severities,
* or null if no severities are provided.
*/
getSeverityQueryParameter(severities) {
if (!severities || severities.length === 0) {
return;
}
if (severities.length === Object.keys(Severity).length) {
return;
}
return severities.join(',');
}
/**
* Creates a value for query parameter for filtering alarms by statuses based on showCleared option.
*
* @param showCleared - A flag indicating whether to include cleared statuses.
* If true, all statuses, including 'CLEARED', will be included; if false, 'CLEARED' will be excluded.
*
* @returns A comma-separated string of alarm statuses.
*/
getStatusQueryParameter(showCleared) {
const statuses = Object.keys(ALARM_STATUS_LABELS);
const filteredStatuses = showCleared
? statuses
: statuses.filter(status => status !== 'CLEARED');
return filteredStatuses.join(',');
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsViewService, deps: [{ token: i1.AlarmService }, { token: i2.OptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsViewService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsViewService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.AlarmService }, { type: i2.OptionsService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxhcm1zLXZpZXcuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2FsYXJtcy9hbGFybXMtdmlldy5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUNMLG1CQUFtQixFQUVuQixZQUFZLEVBQ1osV0FBVyxFQUlYLFFBQVEsRUFHVCxNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBSUwsY0FBYyxFQUNkLFdBQVcsRUFDWCxPQUFPLEVBQ1IsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsZUFBZSxFQUFjLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM1RCxPQUFPLEVBQUUsV0FBVyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7QUFHakU7Ozs7Ozs7O0dBUUc7QUFJSCxNQUFNLE9BQU8saUJBQWlCO0lBWTVCLFlBQ1UsWUFBMEIsRUFDMUIsY0FBOEI7UUFEOUIsaUJBQVksR0FBWixZQUFZLENBQWM7UUFDMUIsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBYi9CLDJCQUFzQixHQUE2QixtQkFBbUIsQ0FBQztRQUN2RSwyQkFBc0IsR0FBRyxNQUFNLENBQUM7UUFDaEMsaUNBQTRCLEdBQUcsVUFBVSxDQUFDO1FBQzFDLDRCQUF1QixHQUFHLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ2xFLG1DQUE4QixHQUFHLE9BQU8sQ0FBQyx5Q0FBeUMsQ0FBQyxDQUFDO1FBRzdGLHNCQUFpQixHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7UUFRdEMsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDO1lBQzdCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLGVBQWUsQ0FBVSxJQUFJLENBQUMsQ0FBQztZQUM3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ICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIEFMQVJNX1NUQVRVU19MQUJFTFMsXG4gIEFsYXJtUXVlcnlGaWx0ZXIsXG4gIEFsYXJtU2VydmljZSxcbiAgQWxhcm1TdGF0dXMsXG4gIEFsYXJtU3RhdHVzVHlwZSxcbiAgSUFsYXJtLFxuICBJUmVzdWx0TGlzdCxcbiAgU2V2ZXJpdHksXG4gIFNldmVyaXR5RmlsdGVyLFxuICBTZXZlcml0eVR5cGVcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHtcbiAgQXBwbGljYXRpb25PcHRpb25zLFxuICBDb250ZXh0RGF0YSxcbiAgRGF0ZVRpbWVDb250ZXh0LFxuICBPcHRpb25zU2VydmljZSxcbiAgVmlld0NvbnRleHQsXG4gIGdldHRleHRcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEFMQVJNU19QQVRILCBJTlRFUlZBTFNfRVhURU5ERUQgfSBmcm9tICcuL2FsYXJtcy5tb2RlbCc7XG5pbXBvcnQgeyBBbGFybUZpbHRlckludGVydmFsIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9pbnRlcnZhbC1waWNrZXInO1xuXG4vKipcbiAqIFNlcnZpY2UgZm9yIG1hbmFnaW5nIGFuZCByZXRyaWV2aW5nIGFsYXJtcyBkYXRhIHdpdGhpbiB0aGUgYWxhcm1zIHZpZXcuXG4gKlxuICogVGhlIGBBbGFybXNWaWV3U2VydmljZWAgcHJvdmlkZXMgZnVuY3Rpb25hbGl0eSB0byBpbnRlcmFjdCB3aXRoIGFsYXJtcyxcbiAqIGluY2x1ZGluZyBmaWx0ZXJpbmcsIGNvdW50aW5nLCBhbmQgdHJhbnNsYXRpb24tcmVsYXRlZCBvcGVyYXRpb25zIGluIGFuIGFsYXJtcyB2aWV3LlxuICpcbiAqIFRoaXMgc2VydmljZSByZWxpZXMgb24gdGhlIGBBbGFybVNlcnZpY2VgIGZvciBmZXRjaGluZyBhbGFybSBkYXRhIGFuZCB0aGUgYE9wdGlvbnNTZXJ2aWNlYFxuICogZm9yIGNvbmZpZ3VyaW5nIGFsYXJtcyB2aWV3IG9wdGlvbnMuXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIEFsYXJtc1ZpZXdTZXJ2aWNlIHtcbiAgcmVhZG9ubHkgQUxBUk1fUkVGUkVTSF9UWVBFX0tFWToga2V5b2YgQXBwbGljYXRpb25PcHRpb25zID0gJ2FsYXJtc1JlZnJlc2hUeXBlJztcbiAgcmVhZG9ubHkgREVGQVVMVF9JTlRFUlZBTF9WQUxVRSA9IDMwXzAwMDtcbiAgcmVhZG9ubHkgREVGQVVMVF9SRUZSRVNIX09QVElPTl9WQUxVRSA9ICdpbnRlcnZhbCc7XG4gIHJlYWRvbmx5IERFRkFVTFRfSU5URVJWQUxfVkFMVUVTID0gWzVfMDAwLCAxMF8wMDAsIDE1XzAwMCwgMzBfMDAwLCA2MF8wMDBdO1xuICByZWFkb25seSBSRUFMVElNRV9VUERBVEVfQUxBUk1TX01FU1NBR0UgPSBnZXR0ZXh0KCdUaGUgbGlzdCB3YXMgdXBkYXRlZCwgY2xpY2sgdG8gcmVmcmVzaC4nKTtcblxuICBpc0ludGVydmFsRW5hYmxlZCQ6IE9ic2VydmFibGU8Ym9vbGVhbj47XG4gIHJlbG9hZEFsYXJtc0xpc3QkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBwcml2YXRlIF9pc0ludGVydmFsRW5hYmxlZDogQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYWxhcm1TZXJ2aWNlOiBBbGFybVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBvcHRpb25zU2VydmljZTogT3B0aW9uc1NlcnZpY2VcbiAgKSB7XG4gICAgaWYgKHRoaXMuaXNJbnRlcnZhbFJlZnJlc2goKSkge1xuICAgICAgdGhpcy5faXNJbnRlcnZhbEVuYWJsZWQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KHRydWUpO1xuICAgICAgdGhpcy5pc0ludGVydmFsRW5hYmxlZCQgPSB0aGlzLl9pc0ludGVydmFsRW5hYmxlZC5hc09ic2VydmFibGUoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRW1pdHMgYSBzdWJqZWN0IHRvIGluaXRpYWxpemUgdGhlIGFsYXJtcyByZWxvYWRpbmcuXG4gICAqL1xuICB1cGRhdGVBbGFybUxpc3QoKTogdm9pZCB7XG4gICAgdGhpcy5yZWxvYWRBbGFybXNMaXN0JC5uZXh0KCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIGEgbGlzdCBvZiBhbGFybXMgZmlsdGVyZWQgYnkgc3BlY2lmaWVkIHNldmVyaXRpZXMgYW5kIG90aGVyIG9wdGlvbmFsIHF1ZXJ5IGZpbHRlcnMuXG4gICAqXG4gICAqIEBwYXJhbSBzZXZlcml0aWVzIGFuIGFycmF5IG9mIHNldmVyaXRpZXMgdG8gZmlsdGVyIHRoZSBhbGFybXMuXG4gICAqIEBwYXJhbSBzaG93Q2xlYXJlZCBmbGFnIGluZGljYXRpbmcgd2hldGhlciB0byBzaG93IGNsZWFyZWQgYWxhcm1zLiBEZWZhdWx0cyB0byBmYWxzZS5cbiAgICogQHBhcmFtIHNlbGVjdGVkRGF0ZXMgYW4gYXJyYXkgb2YgdHdvIGRhdGVzIHRvIGZpbHRlciBhbGFybXMgYnkgY3JlYXRpb24gYW5kIGxhc3QgdXBkYXRlIGRhdGVzLlxuICAgKiBAcGFyYW0gZmlsdGVyIGFkZGl0aW9uYWwgcXVlcnkgZmlsdGVycyBmb3IgcmV0cmlldmluZyBhbGFybXMuXG4gICAqXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgbGlzdCBvZiBhbGFybXMgc2F0aXNmeWluZyB0aGUgc3BlY2lmaWVkIGZpbHRlcnMuXG4gICAqL1xuICByZXRyaWV2ZUZpbHRlcmVkQWxhcm1zKFxuICAgIHNldmVyaXRpZXM6IFNldmVyaXR5VHlwZVtdLFxuICAgIHNob3dDbGVhcmVkID0gZmFsc2UsXG4gICAgc2VsZWN0ZWREYXRlcz86IFtEYXRlLCBEYXRlXSxcbiAgICBmaWx0ZXI/OiBBbGFybVF1ZXJ5RmlsdGVyXG4gICk6IFByb21pc2U8SVJlc3VsdExpc3Q8SUFsYXJtPj4ge1xuICAgIGNvbnN0IHNldmVyaXRpZXNRdWVyeSA9IHRoaXMuZ2V0U2V2ZXJpdHlRdWVyeVBhcmFtZXRlcihzZXZlcml0aWVzKTtcbiAgICBjb25zdCBzdGF0dXNlc1F1ZXJ5ID0gdGhpcy5nZXRTdGF0dXNRdWVyeVBhcmFtZXRlcihzaG93Q2xlYXJlZCk7XG5cbiAgICBjb25zdCBfZmlsdGVyOiBBbGFybVF1ZXJ5RmlsdGVyID0ge1xuICAgICAgcGFnZVNpemU6IDUwLFxuICAgICAgd2l0aFRvdGFsUGFnZXM6IHRydWUsXG4gICAgICAuLi4oc2V2ZXJpdGllc1F1ZXJ5ICYmIHsgc2V2ZXJpdHk6IHNldmVyaXRpZXNRdWVyeSB9KSxcbiAgICAgIC4uLihzdGF0dXNlc1F1ZXJ5ICYmIHsgc3RhdHVzOiBzdGF0dXNlc1F1ZXJ5IH0pLFxuICAgICAgLi4uKHNlbGVjdGVkRGF0ZXMgJiYge1xuICAgICAgICBsYXN0VXBkYXRlZEZyb206IHNlbGVjdGVkRGF0ZXNbMF0udG9JU09TdHJpbmcoKSxcbiAgICAgICAgY3JlYXRlZFRvOiBzZWxlY3RlZERhdGVzWzFdLnRvSVNPU3RyaW5nKClcbiAgICAgIH0pLFxuICAgICAgLi4uZmlsdGVyXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5hbGFybVNlcnZpY2UubGlzdChfZmlsdGVyKTtcbiAgfVxuXG4gIHJldHJpZXZlQWxhcm1zQnlEYXRlKGRhdGVzOiBEYXRlVGltZUNvbnRleHQpIHtcbiAgICByZXR1cm4gdGhpcy5hbGFybVNlcnZpY2UubGlzdCh7XG4gICAgICBsYXN0VXBkYXRlZEZyb206IGRhdGVzWzBdLnRvSVNPU3RyaW5nKCksXG4gICAgICBjcmVhdGVkVG86IGRhdGVzWzFdLnRvSVNPU3RyaW5nKCksXG4gICAgICBwYWdlU2l6ZTogNTAsXG4gICAgICB3aXRoVG90YWxQYWdlczogdHJ1ZVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgdGhlIHN0YXRlIHRvIGVuYWJsZSBvciBkaXNhYmxlIGludGVydmFscy5cbiAgICogQHBhcmFtIHZhbHVlIC0gQSBib29sZWFuIHZhbHVlIHRvIGluZGljYXRlIHdoZXRoZXIgdG8gZW5hYmxlIGludGVydmFscy5cbiAgICovXG4gIHVwZGF0ZUludGVydmFsU3RhdGUodmFsdWU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLl9pc0ludGVydmFsRW5hYmxlZD8ubmV4dCh2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogRmV0Y2hlcyB0aGUgY291bnQgb2YgYWxhcm1zIGZpbHRlcmVkIGJ5IHNldmVyaXR5IGFuZCBjbGVhcmFuY2Ugc3RhdHVzLlxuICAgKlxuICAgKiBAcGFyYW0gc2V2ZXJpdHkgLSBUaGUgc2V2ZXJpdHkgbGV2ZWwgdG8gZmlsdGVyIGJ5IChlLmcuLCBDUklUSUNBTCwgTUFKT1IsIGV0Yy4pLlxuICAgKiBAcGFyYW0gc2hvd0NsZWFyZWQgLSBXaGV0aGVyIG9yIG5vdCB0byBpbmNsdWRlIGNsZWFyZWQgYWxhcm1zIGluIHRoZSBjb3VudC5cbiAgICogQHBhcmFtIGZpbHRlciAtIEFkZGl0aW9uYWwgZmlsdGVyIGNyaXRlcmlhIGZvciBhbGFybXMuXG4gICAqXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBudW1iZXIgb2YgYWxhcm1zIHRoYXQgbWF0Y2ggdGhlIGZpbHRlciBjcml0ZXJpYS5cbiAgICpcbiAgICovXG4gIGFzeW5jIGdldEFsYXJtc0NvdW50QnlTZXZlcml0eShcbiAgICBzZXZlcml0eTogU2V2ZXJpdHlUeXBlLFxuICAgIHNob3dDbGVhcmVkOiBib29sZWFuLFxuICAgIGZpbHRlcj86IEFsYXJtUXVlcnlGaWx0ZXJcbiAgKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBzdGF0dXNlc1F1ZXJ5ID0gdGhpcy5nZXRTdGF0dXNRdWVyeVBhcmFtZXRlcihzaG93Q2xlYXJlZCk7XG4gICAgY29uc3QgX2ZpbHRlcjogQWxhcm1RdWVyeUZpbHRlciA9IHtcbiAgICAgIC4uLihzZXZlcml0eSAmJiB7IHNldmVyaXR5OiBzZXZlcml0eSB9KSxcbiAgICAgIC4uLihzdGF0dXNlc1F1ZXJ5ICYmIHsgc3RhdHVzOiBzdGF0dXNlc1F1ZXJ5IH0pLFxuICAgICAgLi4uZmlsdGVyXG4gICAgfTtcbiAgICBjb25zdCB7IGRhdGEgfSA9IGF3YWl0IHRoaXMuYWxhcm1TZXJ2aWNlLmNvdW50KF9maWx0ZXIpO1xuXG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSBjdXJyZW50IGFsYXJtcyByZWZyZXNoIHR5cGUgZnJvbSB0aGUgT3B0aW9uc1NlcnZpY2VcbiAgICogYW5kIGRldGVybWluZXMgd2hldGhlciBpdCBpcyBzZXQgdG8gXCJpbnRlcnZhbFwiLlxuICAgKlxuICAgKiBAcmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGFsYXJtcyByZWZyZXNoIHR5cGUgaXMgXCJpbnRlcnZhbCxcIiBvdGhlcndpc2UgYGZhbHNlYC5cbiAgICovXG4gIGlzSW50ZXJ2YWxSZWZyZXNoKCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5vcHRpb25zU2VydmljZS5nZXQodGhpcy5BTEFSTV9SRUZSRVNIX1RZUEVfS0VZLCAnaW50ZXJ2YWwnKTtcbiAgICByZXR1cm4gdmFsdWUgPT09ICdpbnRlcnZhbCc7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgbGlzdCBvZiBzZWxlY3RlZCBzZXZlcml0aWVzIGJhc2VkIG9uIHRoZSBuZXcgc2V2ZXJpdHkgZmlsdGVyLlxuICAgKlxuICAgKiBAcGFyYW0gc2V2ZXJpdHlVcGRhdGVzIC0gVGhlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHVwZGF0ZXMgdG8gZWFjaCBzZXZlcml0eS5cbiAgICpcbiAgICogQHJldHVybnMgQW4gYXJyYXkgcmVwcmVzZW50aW5nIHRoZSB1cGRhdGVkIHNlbGVjdGVkIHNldmVyaXRpZXMuXG4gICAqL1xuICB1cGRhdGVTZWxlY3RlZFNldmVyaXRpZXMoc2V2ZXJpdHlVcGRhdGVzOiBTZXZlcml0eUZpbHRlcik6IFNldmVyaXR5VHlwZVtdIHtcbiAgICByZXR1cm4gKE9iamVjdC5rZXlzKHNldmVyaXR5VXBkYXRlcykgYXMgU2V2ZXJpdHlUeXBlW10pXG4gICAgICAuZmlsdGVyKGtleSA9PiBzZXZlcml0eVVwZGF0ZXNba2V5XSlcbiAgICAgIC5tYXAoa2V5ID0+IGtleS50b1VwcGVyQ2FzZSgpIGFzIFNldmVyaXR5VHlwZSk7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXJzIGFsbCBhY3RpdmUgYWxhcm1zIG9mIHRoZSBzZWxlY3RlZCBzZXZlcml0aWVzLlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBjbGVhcnMgYWxsIGFjdGl2ZSBhbGFybXMgZm9yIHRoZSBnaXZlbiBsaXN0IG9mIHNldmVyaXRpZXMgYnkgbWFraW5nIGJ1bGsgdXBkYXRlIGNhbGxzLiBJZiBubyBzZXZlcml0aWVzIGFyZSBzZWxlY3RlZCwgaXQgZGVmYXVsdHMgdG8gdXNpbmcgYWxsIGF2YWlsYWJsZSBzZXZlcml0aWVzLlxuICAgKiBJdCB3b3JrcyBieSBzZW5kaW5nIGEgc2VyaWVzIG9mIHVwZGF0ZSByZXF1ZXN0cyBmb3IgZWFjaCBzZXZlcml0eSBhbmQgcmV0dXJucyBhIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIGFuIG9iamVjdCBpbmRpY2F0aW5nIGlmIGFsbCBhbGFybXMgd2VyZSByZXNvbHZlZCBpbW1lZGlhdGVseS5cbiAgICpcbiAgICogQHBhcmFtIHNlbGVjdGVkU2V2ZXJpdGllcyBBbiBhcnJheSBvZiBzZXZlcml0aWVzIHRvIGJlIGNsZWFyZWQuIElmIG5vdCBwcm92aWRlZCwgYWxsIHNldmVyaXRpZXMgd2lsbCBiZSBjbGVhcmVkLlxuICAgKiBAcGFyYW0gc291cmNlSWQgLSBJZGVudGlmaWVyIGZvciB0aGUgc291cmNlIGFzc29jaWF0ZWQgd2l0aCB0aGUgYWxhcm1zIHRvIGJlIGNsZWFyZWQuXG4gICAqXG4gICAqIEByZXR1cm5zIEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggYW4gb2JqZWN0IHdpdGggYSBmbGFnIGByZXNvbHZlZEltbWVkaWF0ZWx5YC4gVGhlIGZsYWcgaXMgdHJ1ZSBpZiBhbGwgYWxhcm1zIGZvciBhbGwgc2VsZWN0ZWQgc2V2ZXJpdGllcyB3ZXJlIGNsZWFyZWQgc3VjY2Vzc2Z1bGx5OyBvdGhlcndpc2UgZmFsc2UuXG4gICAqXG4gICAqICoqRXhhbXBsZSoqXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3Qgc2V2ZXJpdGllc1RvQ2xlYXI6IFNldmVyaXR5VHlwZVtdID0gW1NldmVyaXR5Lk1BSk9SLCBTZXZlcml0eS5NSU5PUl07XG4gICAqXG4gICAqIGNsZWFyQWxsQWN0aXZlQWxhcm1zKHNldmVyaXRpZXNUb0NsZWFyKS50aGVuKCh7IHJlc29sdmVkSW1tZWRpYXRlbHkgfSkgPT4ge1xuICAgKiAgIGlmIChyZXNvbHZlZEltbWVkaWF0ZWx5KSB7XG4gICAqICAgICBjb25zb2xlLmxvZygnQWxsIHNlbGVjdGVkIGFsYXJtcyB3ZXJlIGNsZWFyZWQgc3VjY2Vzc2Z1bGx5LicpO1xuICAgKiAgIH0gZWxzZSB7XG4gICAqICAgICBjb25zb2xlLmxvZygnU29tZSBhbGFybXMgY291bGQgbm90IGJlIGNsZWFyZWQuJyk7XG4gICAqICAgfVxuICAgKiB9KTtcbiAgICogYGBgXG4gICAqXG4gICAqICoqTm90ZSoqXG4gICAqIC0gVGhlIG1ldGhvZCB1c2VzIHRoZSBgYWxhcm1TZXJ2aWNlLnVwZGF0ZUJ1bGtgIGZvciBlYWNoIHNldmVyaXR5IHRvIGNsZWFyIHRoZSBhY3RpdmUgYWxhcm1zLlxuICAgKiAtIEl0IG1heSBmZXRjaCB0aGUgYHNvdXJjZUlkYCBiYXNlZCBvbiB0aGUgdmlldyAoaWYgYXBwbGljYWJsZSkgYW5kIGluY2x1ZGUgaXQgYXMgYSBxdWVyeSBwYXJhbWV0ZXIgaW4gdGhlIHVwZGF0ZSBjYWxscy5cbiAgICogLSBUaGUgbWV0aG9kIHJldHVybnMgaW1tZWRpYXRlbHkgYnV0IHRoZSByZXR1cm5lZCBQcm9taXNlIG5lZWRzIHRvIGhhdmUgYSBgdGhlbmAgb3IgYGNhdGNoYCBtZXRob2QgY2FsbCB0byBoYW5kbGUgdGhlIHJlc3VsdCBvciBlcnJvciByZXNwZWN0aXZlbHkuXG4gICAqIC0gVXNlcyBgUHJvbWlzZS5hbGxgIHRvIHdhaXQgZm9yIGFsbCB1cGRhdGUgcmVxdWVzdHMgdG8gY29tcGxldGUgYmVmb3JlIHJlc29sdmluZyB0aGUgZmluYWwgcmVzdWx0LlxuICAgKi9cbiAgYXN5bmMgY2xlYXJBbGxBY3RpdmVBbGFybXMoXG4gICAgc2VsZWN0ZWRTZXZlcml0aWVzOiBTZXZlcml0eVR5cGVbXSxcbiAgICBzb3VyY2VJZDogc3RyaW5nIHwgbnVtYmVyXG4gICk6IFByb21pc2U8eyByZXNvbHZlZEltbWVkaWF0ZWx5OiBib29sZWFuIH0+IHtcbiAgICBjb25zdCBzZXZlcml0aWVzVG9VcGRhdGUgPSBzZWxlY3RlZFNldmVyaXRpZXMgfHwgU2V2ZXJpdHk7XG5cbiAgICBjb25zdCBwcm9taXNlcyA9IE9iamVjdC52YWx1ZXMoc2V2ZXJpdGllc1RvVXBkYXRlKS5tYXAoKHNldmVyaXR5OiBTZXZlcml0eVR5cGUpID0+IHtcbiAgICAgIGNvbnN0IGNvbW1vblBhcmFtcyA9IHsgcmVzb2x2ZWQ6IGZhbHNlLCBzZXZlcml0eSB9O1xuXG4gICAgICBjb25zdCBwYXJhbWV0ZXJzID0gc291cmNlSWRcbiAgICAgICAgPyB7XG4gICAgICAgICAgICAuLi5jb21tb25QYXJhbXMsXG4gICAgICAgICAgICBzb3VyY2U6IHNvdXJjZUlkLFxuICAgICAgICAgICAgd2l0aFNvdXJjZUFzc2V0czogdHJ1ZSxcbiAgICAgICAgICAgIHdpdGhTb3VyY2VEZXZpY2VzOiB0cnVlXG4gICAgICAgICAgfVxuICAgICAgICA6IGNvbW1vblBhcmFtcztcblxuICAgICAgcmV0dXJuIHRoaXMuYWxhcm1TZXJ2aWNlLnVwZGF0ZUJ1bGsoeyBzdGF0dXM6IEFsYXJtU3RhdHVzLkNMRUFSRUQgfSwgcGFyYW1ldGVycyk7XG4gICAgfSk7XG5cbiAgICBjb25zdCByZXNwb25zZXMgPSBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlc29sdmVkSW1tZWRpYXRlbHk6IHJlc3BvbnNlcy5ldmVyeShyZXMgPT4gcmVzKVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgY29ycmVjdCBsaW5rIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb250ZXh0IGRhdGEuXG4gICAqIEBwYXJhbSBjb250ZXh0RGF0YSBUaGUgY29udGV4dCB0aGUgbmF2aWdhdGlvbiB3YXMgdHJpZ2dlcmVkIGZyb20uXG4gICAqIEBwYXJhbSBhbGFybSBUaGUgYWxhcm0gdG8gbmF2aWdhdGUgdG8uXG4gICAqIEByZXR1cm5zIEEgbGluayB0byBiZSB1c2VkIGFzIGFuIHVybCBuYXZpZ2F0aW9uLlxuICAgKi9cbiAgZ2V0Um91dGVyTGluayhjb250ZXh0RGF0YT86IENvbnRleHREYXRhLCBhbGFybT86IElBbGFybSk6IHN0cmluZyB7XG4gICAgbGV0IGRldGFpbFVybCA9IGAvJHtBTEFSTVNfUEFUSH1gO1xuICAgIGlmIChhbGFybSkge1xuICAgICAgZGV0YWlsVXJsID0gYC8ke0FMQVJNU19QQVRIfS8ke2FsYXJtLmlkfWA7XG4gICAgfVxuICAgIGlmICghY29udGV4dERhdGEpIHtcbiAgICAgIHJldHVybiBkZXRhaWxVcmw7XG4gICAgfVxuXG4gICAgc3dpdGNoIChjb250ZXh0RGF0YS5jb250ZXh0KSB7XG4gICAgICBjYXNlIFZpZXdDb250ZXh0LkRldmljZTpcbiAgICAgICAgcmV0dXJuIGAvZGV2aWNlLyR7Y29udGV4dERhdGEuY29udGV4dERhdGEuaWR9JHtkZXRhaWxVcmx9YDtcbiAgICAgIGNhc2UgVmlld0NvbnRleHQuR3JvdXA6XG4gICAgICAgIHJldHVybiBgL2dyb3VwLyR7Y29udGV4dERhdGEuY29udGV4dERhdGEuaWR9JHtkZXRhaWxVcmx9YDtcbiAgICAgIGNhc2UgVmlld0NvbnRleHQuU2ltdWxhdG9yczpcbiAgICAgICAgcmV0dXJuIGAvc2ltdWxhdG9ycy8ke2NvbnRleHREYXRhLmNvbnRleHREYXRhLmlkfSR7ZGV0YWlsVXJsfWA7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gZGV0YWlsVXJsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBjb3JyZWN0IGFycmF5IG5hdmlnYXRpb24uXG4gICAqIEBwYXJhbSBjb250ZXh0RGF0YSBUaGUgY29udGV4dCB0aGUgbmF2aWdhdGlvbiB3YXMgdHJpZ2dlcmVkIGZyb20uXG4gICAqIEBwYXJhbSBhbGFybSBUaGUgYWxhcm0gdG8gbmF2aWdhdGUgdG8uXG4gICAqIEByZXR1cm5zIEEgbGluayB0byBiZSB1c2VkIGFzIGEgcm91dGVyLm5hdmlnYXRpb24uXG4gICAqL1xuICBnZXRSb3V0ZXJOYXZpZ2F0aW9uQXJyYXkoY29udGV4dERhdGE/OiBDb250ZXh0RGF0YSwgYWxhcm0/OiBJQWxhcm0pOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0Um91dGVyTGluayhjb250ZXh0RGF0YSwgYWxhcm0pLnNwbGl0KCcvJykuZmlsdGVyKEJvb2xlYW4pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGNvcnJlY3QgZnJvbSBhbmQgdG8gZGF0ZXMgYmFzZWQgb24gdGhlIHNlbGVjdGVkIGludGVydmFsXG4gICAqIEBwYXJhbSBpbnRlcnZhbElkIHRoZSBzZWxlY3RlZCBpbnRlcnZhbC4gRS5nLiAnbm9uZScsICdob3VycycsICdjdXN0b20nIC4uLlxuICAgKiBAcmV0dXJucyBUaGUgY2FsY3VsYXRlZCBkYXRlIGNvbnRleHQgYmFzZWQgb24gdGhlIHNlbGVjdGVkIGludGVydmFsLlxuICAgKi9cbiAgZ2V0RGF0ZVRpbWVDb250ZXh0QnlJbnRlcnZhbChpbnRlcnZhbElkOiBBbGFybUZpbHRlckludGVydmFsWydpZCddKTogRGF0ZVRpbWVDb250ZXh0IHtcbiAgICBjb25zdCBpbnRlcnZhbCA9IElOVEVSVkFMU19FWFRFTkRFRC5maW5kKCh7IGlkIH0pID0+IGlkID09PSBpbnRlcnZhbElkKTtcbiAgICBpZiAoaW50ZXJ2YWwuaWQgPT09ICdub25lJykge1xuICAgICAgcmV0dXJuIFtuZXcgRGF0ZSgwKSwgbmV3IERhdGUoKV07XG4gICAgfVxuXG4gICAgY29uc3QgZGF0ZVRvID0gbmV3IERhdGUoKTtcbiAgICBjb25zdCBkYXRlRnJvbSA9IG5ldyBEYXRlKGRhdGVUby52YWx1ZU9mKCkgLSBpbnRlcnZhbC50aW1lc3BhbkluTXMpO1xuICAgIHJldHVybiBbZGF0ZUZyb20sIGRhdGVUb107XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHZhbHVlIGZvciBxdWVyeSBwYXJhbWV0ZXIgZm9yIGZpbHRlcmluZyBhbGFybXMgYnkgc2V2ZXJpdHkgYmFzZWQgb24gYXJyYXkgb2Ygc2VsZWN0ZWQgc2V2ZXJpdGllcy5cbiAgICpcbiAgICogQHBhcmFtIHNldmVyaXRpZXMgLSBBbiBhcnJheSBvZiBhbGFybSBzZXZlcml0eSB0eXBlcyB0byBpbmNsdWRlIGluIHRoZSBmaWx0ZXIuXG4gICAqIElmIHRoZSBhcnJheSBpcyBlbXB0eSBvciB1bmRlZmluZWQsIG5vIHNldmVyaXR5IGZpbHRlciB3aWxsIGJlIGFwcGxpZWQuXG4gICAqXG4gICAqIEByZXR1cm5zIEEgY29tbWEtc2VwYXJhdGVkIHN0cmluZyBvZiBzZWxlY3RlZCBhbGFybSBzZXZlcml0aWVzLFxuICAgKiBvciBudWxsIGlmIG5vIHNldmVyaXRpZXMgYXJlIHByb3ZpZGVkLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRTZXZlcml0eVF1ZXJ5UGFyYW1ldGVyKHNldmVyaXRpZXM6IFNldmVyaXR5VHlwZVtdKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgaWYgKCFzZXZlcml0aWVzIHx8IHNldmVyaXRpZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChzZXZlcml0aWVzLmxlbmd0aCA9PT0gT2JqZWN0LmtleXMoU2V2ZXJpdHkpLmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHJldHVybiBzZXZlcml0aWVzLmpvaW4oJywnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgdmFsdWUgZm9yIHF1ZXJ5IHBhcmFtZXRlciBmb3IgZmlsdGVyaW5nIGFsYXJtcyBieSBzdGF0dXNlcyBiYXNlZCBvbiBzaG93Q2xlYXJlZCBvcHRpb24uXG4gICAqXG4gICAqIEBwYXJhbSBzaG93Q2xlYXJlZCAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgdG8gaW5jbHVkZSBjbGVhcmVkIHN0YXR1c2VzLlxuICAgKiBJZiB0cnVlLCBhbGwgc3RhdHVzZXMsIGluY2x1ZGluZyAnQ0xFQVJFRCcsIHdpbGwgYmUgaW5jbHVkZWQ7IGlmIGZhbHNlLCAnQ0xFQVJFRCcgd2lsbCBiZSBleGNsdWRlZC5cbiAgICpcbiAgICogQHJldHVybnMgQSBjb21tYS1zZXBhcmF0ZWQgc3RyaW5nIG9mIGFsYXJtIHN0YXR1c2VzLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRTdGF0dXNRdWVyeVBhcmFtZXRlcihzaG93Q2xlYXJlZDogYm9vbGVhbik6IHN0cmluZyB7XG4gICAgY29uc3Qgc3RhdHVzZXMgPSBPYmplY3Qua2V5cyhBTEFSTV9TVEFUVVNfTEFCRUxTKSBhcyBBbGFybVN0YXR1c1R5cGVbXTtcbiAgICBjb25zdCBmaWx0ZXJlZFN0YXR1c2VzID0gc2hvd0NsZWFyZWRcbiAgICAgID8gc3RhdHVzZXNcbiAgICAgIDogc3RhdHVzZXMuZmlsdGVyKHN0YXR1cyA9PiBzdGF0dXMgIT09ICdDTEVBUkVEJyk7XG4gICAgcmV0dXJuIGZpbHRlcmVkU3RhdHVzZXMuam9pbignLCcpO1xuICB9XG59XG4iXX0=