UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

261 lines 34.5 kB
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=