@fireng/core
Version:
Core utilities for Fireng Angular responsive library.
164 lines • 24.4 kB
JavaScript
import { DOCUMENT } from '@angular/common';
import { computed, inject, Injectable, signal, } from '@angular/core';
import { FIRENG_BREAKPOINTS } from './fireng.token';
import { auditTime, fromEvent } from 'rxjs';
import * as i0 from "@angular/core";
export class FirengScreenService {
document = inject(DOCUMENT);
window = this.document.defaultView || undefined;
// signal to store the current window width
_windowWidth = signal(0);
windowWidth = this._windowWidth.asReadonly();
// signal to store the current window height
_windowHeight = signal(0);
windowHeight = this._windowHeight.asReadonly();
// Signal to store breakpoint and this allows for runtime updates to breakpoints
_breakpoint;
// Computed signal to get sorted breakpoints
_sortedBreakpoints = computed(() => {
const breakpointsEntries = Object.entries(this._breakpoint() || {}).sort((a, b) => a[1] - b[1]);
return Object.fromEntries(breakpointsEntries);
});
// Computed signal for current breakpoint
currentBreakpoint = computed(() => {
const width = this._windowWidth();
const breakpoints = this._sortedBreakpoints();
// taking first first key of breakpoints as default active breakpoint
let activeBreakpointKey = Object.keys(breakpoints)[0];
for (const [breakpointKey, breakpointValue] of Object.entries(breakpoints)) {
if (width >= breakpointValue) {
activeBreakpointKey = breakpointKey;
}
else {
break; // Exit loop once we find the first breakpoint that is larger than the width
}
}
return activeBreakpointKey;
});
// Computed signal for cascading breakpoints
activeBreakpoints = computed(() => {
const currentBreakpoint = this.currentBreakpoint();
const breakpoints = this._sortedBreakpoints();
const activeNames = [];
for (const [breakpointKey, breakpointValue] of Object.entries(breakpoints)) {
activeNames.push(breakpointKey);
if (breakpointKey === currentBreakpoint) {
break;
}
}
return activeNames;
});
constructor() {
this._breakpoint = signal(inject(FIRENG_BREAKPOINTS));
if (this.window) {
this._windowWidth.set(this.window.innerWidth);
this._windowHeight.set(this.window.innerHeight);
fromEvent(this.window, 'resize')
.pipe(auditTime(100))
.subscribe(() => {
this._windowWidth.set(this.window?.innerWidth || 0);
this._windowHeight.set(this.window?.innerHeight || 0);
});
}
else {
console.warn('FirengScreenService: No window object found. Screen service may not work as expected.');
}
}
/**
* Checks if the current screen width matches the specified breakpoint.
* @param breakpointName The name of the breakpoint (e.g., 'xs', 'md').
* @returns A signal indicating if the current screen width matches the specified breakpoint.
*/
isBreakpoint(breakpointName) {
return computed(() => breakpointName === this.currentBreakpoint());
}
/**
* Checks if the current screen size is at or above a specific breakpoint.
* @param breakpointName The name of the breakpoint (e.g., 'sm', 'md').
* @returns A signal indicating if the current screen is at or above the breakpoint.
*/
isBreakpointUp(breakpointName) {
return computed(() => {
const breakpoints = this._sortedBreakpoints();
const targetIndex = Object.keys(breakpoints).indexOf(breakpointName);
const currentIndex = Object.keys(breakpoints).indexOf(this.currentBreakpoint());
return (targetIndex >= currentIndex && targetIndex >= 0 && currentIndex >= 0);
});
}
/**
* Checks if the current screen size is below a specific breakpoint.
* @param breakpointName The name of the breakpoint (e.g., 'sm', 'md').
* @returns A signal indicating if the current screen is below the breakpoint.
*/
isBreakpointDown(breakpointName) {
return computed(() => {
const breakpoints = this._sortedBreakpoints();
const targetIndex = Object.keys(breakpoints).indexOf(breakpointName);
const currentIndex = Object.keys(breakpoints).indexOf(this.currentBreakpoint());
return (currentIndex < targetIndex && targetIndex >= 0 && currentIndex >= 0);
});
}
/**
* Allows users to update breakpoints dynamically at runtime.
* This will immediately update the `currentBreakpoint` and `activeBreakpoints` signals.
* @param newBreakpoints An array of new breakpoint definitions.
*/
setBreakpoints(newBreakpoints) {
const keys = new Set();
for (const [key, value] of Object.entries(newBreakpoints)) {
if (typeof value !== 'number' || isNaN(value) || value < 0) {
console.warn(`Invalid breakpoint value for "${key}": ${value}`);
return;
}
else if (keys.has(key)) {
console.warn(`Duplicate breakpoint key found: "${key}"`);
return;
}
keys.add(key);
}
this._breakpoint.set(newBreakpoints);
console.log('FirengScreenService: Breakpoints updated successfully.');
}
isPortrait = computed(() => {
return this._windowHeight() > this._windowWidth();
});
/**
* Resolves a responsive value from a map based on current active breakpoints.
*
* It applies cascading logic: the value for the largest active breakpoint in `valueMap` is returned.
* If no match is found, the `fallback` value is returned.
*
* @template T The type of the value (e.g., `number`, `string`).
* @param valueMap An object mapping breakpoint names to values (e.g., `{ xs: 5, md: 10 }`).
* @param fallback An optional default value if no matching breakpoint is found.
* @returns A signal emitting the resolved value, or `fallback`, or `undefined`.
*
* @example
* // Get items per page: 5 for xs, 10 for md and up, default 5
* const itemsPerPage = this.screenService.resolveBreakpointValue({ xs: 5, md: 10 }, 5);
*/
resolveBreakpointValue(valueMap, fallback) {
return computed(() => {
const activeBreakpoints = this.activeBreakpoints();
let selectedValue;
for (const breakpoint of activeBreakpoints) {
if (valueMap.hasOwnProperty(breakpoint)) {
selectedValue = valueMap[breakpoint];
}
}
if (selectedValue === undefined) {
return fallback;
}
return selectedValue;
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FirengScreenService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FirengScreenService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FirengScreenService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlyZW5nLXNjcmVlbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvY29yZS9zcmMvbGliL2ZpcmVuZy1zY3JlZW4uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUNMLFFBQVEsRUFDUixNQUFNLEVBQ04sVUFBVSxFQUVWLE1BQU0sR0FFUCxNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQzs7QUFLNUMsTUFBTSxPQUFPLG1CQUFtQjtJQUNiLFFBQVEsR0FBYSxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDdEMsTUFBTSxHQUNyQixJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsSUFBSSxTQUFTLENBQUM7SUFFekMsMkNBQTJDO0lBQ25DLFlBQVksR0FBMkIsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFdBQVcsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBRTdELDRDQUE0QztJQUNwQyxhQUFhLEdBQTJCLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQyxZQUFZLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUUvRCxnRkFBZ0Y7SUFDL0QsV0FBVyxDQUFvQztJQUVoRSw0Q0FBNEM7SUFDM0Isa0JBQWtCLEdBQThCLFFBQVEsQ0FDdkUsR0FBRyxFQUFFO1FBQ0gsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQ3RFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFB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b0JBQ3hDLGFBQWEsR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7Z0JBQ3ZDLENBQUM7WUFDSCxDQUFDO1lBRUQsSUFBSSxhQUFhLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ2hDLE9BQU8sUUFBUSxDQUFDO1lBQ2xCLENBQUM7WUFFRCxPQUFPLGFBQWEsQ0FBQztRQUN2QixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7d0dBL0xVLG1CQUFtQjs0R0FBbkIsbUJBQW1CLGNBRmxCLE1BQU07OzRGQUVQLG1CQUFtQjtrQkFIL0IsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7XHJcbiAgY29tcHV0ZWQsXHJcbiAgaW5qZWN0LFxyXG4gIEluamVjdGFibGUsXHJcbiAgU2lnbmFsLFxyXG4gIHNpZ25hbCxcclxuICBXcml0YWJsZVNpZ25hbCxcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgRmlyZW5nQnJlYWtwb2ludHMsIEZpcmVuZ1Jlc3BvbnNpdmVNYXAgfSBmcm9tICcuL2ZpcmVuZy50eXBlcyc7XHJcbmltcG9ydCB7IEZJUkVOR19CUkVBS1BPSU5UUyB9IGZyb20gJy4vZmlyZW5nLnRva2VuJztcclxuaW1wb3J0IHsgYXVkaXRUaW1lLCBmcm9tRXZlbnQgfSBmcm9tICdyeGpzJztcclxuXHJcbkBJbmplY3RhYmxlKHtcclxuICBwcm92aWRlZEluOiAncm9vdCcsXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBGaXJlbmdTY3JlZW5TZXJ2aWNlIHtcclxuICBwcml2YXRlIHJlYWRvbmx5IGRvY3VtZW50OiBEb2N1bWVudCA9IGluamVjdChET0NVTUVOVCk7XHJcbiAgcHJpdmF0ZSByZWFkb25seSB3aW5kb3c6IFdpbmRvdyB8IHVuZGVmaW5lZCA9XHJcbiAgICB0aGlzLmRvY3VtZW50LmRlZmF1bHRWaWV3IHx8IHVuZGVmaW5lZDtcclxuXHJcbiAgLy8gc2lnbmFsIHRvIHN0b3JlIHRoZSBjdXJyZW50IHdpbmRvdyB3aWR0aFxyXG4gIHByaXZhdGUgX3dpbmRvd1dpZHRoOiBXcml0YWJsZVNpZ25hbDxudW1iZXI+ID0gc2lnbmFsKDApO1xyXG4gIHB1YmxpYyByZWFkb25seSB3aW5kb3dXaWR0aCA9IHRoaXMuX3dpbmRvd1dpZHRoLmFzUmVhZG9ubHkoKTtcclxuXHJcbiAgLy8gc2lnbmFsIHRvIHN0b3JlIHRoZSBjdXJyZW50IHdpbmRvdyBoZWlnaHRcclxuICBwcml2YXRlIF93aW5kb3dIZWlnaHQ6IFdyaXRhYmxlU2lnbmFsPG51bWJlcj4gPSBzaWduYWwoMCk7XHJcbiAgcHVibGljIHJlYWRvbmx5IHdpbmRvd0hlaWdodCA9IHRoaXMuX3dpbmRvd0hlaWdodC5hc1JlYWRvbmx5KCk7XHJcblxyXG4gIC8vIFNpZ25hbCB0byBzdG9yZSBicmVha3BvaW50IGFuZCB0aGlzIGFsbG93cyBmb3IgcnVudGltZSB1cGRhdGVzIHRvIGJyZWFrcG9pbnRzXHJcbiAgcHJpdmF0ZSByZWFkb25seSBfYnJlYWtwb2ludDogV3JpdGFibGVTaWduYWw8RmlyZW5nQnJlYWtwb2ludHM+O1xyXG5cclxuICAvLyBDb21wdXRlZCBzaWduYWwgdG8gZ2V0IHNvcnRlZCBicmVha3BvaW50c1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgX3NvcnRlZEJyZWFrcG9pbnRzOiBTaWduYWw8RmlyZW5nQnJlYWtwb2ludHM+ID0gY29tcHV0ZWQoXHJcbiAgICAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IGJyZWFrcG9pbnRzRW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHRoaXMuX2JyZWFrcG9pbnQoKSB8fCB7fSkuc29ydChcclxuICAgICAgICAoYSwgYikgPT4gYVsxXSAtIGJbMV1cclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhicmVha3BvaW50c0VudHJpZXMpO1xyXG4gICAgfVxyXG4gICk7XHJcbiAgLy8gQ29tcHV0ZWQgc2lnbmFsIGZvciBjdXJyZW50IGJyZWFrcG9pbnRcclxuICBwdWJsaWMgcmVhZG9ubHkgY3VycmVudEJyZWFrcG9pbnQ6IFNpZ25hbDxzdHJpbmc+ID0gY29tcHV0ZWQoKCkgPT4ge1xyXG4gICAgY29uc3Qgd2lkdGggPSB0aGlzLl93aW5kb3dXaWR0aCgpO1xyXG4gICAgY29uc3QgYnJlYWtwb2ludHMgPSB0aGlzLl9zb3J0ZWRCcmVha3BvaW50cygpO1xyXG5cclxuICAgIC8vIHRha2luZyBmaXJzdCBmaXJzdCBrZXkgb2YgYnJlYWtwb2ludHMgYXMgZGVmYXVsdCBhY3RpdmUgYnJlYWtwb2ludFxyXG4gICAgbGV0IGFjdGl2ZUJyZWFrcG9pbnRLZXkgPSBPYmplY3Qua2V5cyhicmVha3BvaW50cylbMF07XHJcblxyXG4gICAgZm9yIChjb25zdCBbYnJlYWtwb2ludEtleSwgYnJlYWtwb2ludFZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhcclxuICAgICAgYnJlYWtwb2ludHNcclxuICAgICkpIHtcclxuICAgICAgaWYgKHdpZHRoID49IGJyZWFrcG9pbnRWYWx1ZSkge1xyXG4gICAgICAgIGFjdGl2ZUJyZWFrcG9pbnRLZXkgPSBicmVha3BvaW50S2V5O1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGJyZWFrOyAvLyBFeGl0IGxvb3Agb25jZSB3ZSBmaW5kIHRoZSBmaXJzdCBicmVha3BvaW50IHRoYXQgaXMgbGFyZ2VyIHRoYW4gdGhlIHdpZHRoXHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gYWN0aXZlQnJlYWtwb2ludEtleTtcclxuICB9KTtcclxuXHJcbiAgLy8gQ29tcHV0ZWQgc2lnbmFsIGZvciBjYXNjYWRpbmcgYnJlYWtwb2ludHNcclxuICBwdWJsaWMgcmVhZG9ubHkgYWN0aXZlQnJlYWtwb2ludHM6IFNpZ25hbDxzdHJpbmdbXT4gPSBjb21wdXRlZCgoKSA9PiB7XHJcbiAgICBjb25zdCBjdXJyZW50QnJlYWtwb2ludCA9IHRoaXMuY3VycmVudEJyZWFrcG9pbnQoKTtcclxuICAgIGNvbnN0IGJyZWFrcG9pbnRzID0gdGhpcy5fc29ydGVkQnJlYWtwb2ludHMoKTtcclxuXHJcbiAgICBjb25zdCBhY3RpdmVOYW1lczogc3RyaW5nW10gPSBbXTtcclxuICAgIGZvciAoY29uc3QgW2JyZWFrcG9pbnRLZXksIGJyZWFrcG9pbnRWYWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoXHJcbiAgICAgIGJyZWFrcG9pbnRzXHJcbiAgICApKSB7XHJcbiAgICAgIGFjdGl2ZU5hbWVzLnB1c2goYnJlYWtwb2ludEtleSk7XHJcbiAgICAgIGlmIChicmVha3BvaW50S2V5ID09PSBjdXJyZW50QnJlYWtwb2ludCkge1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gYWN0aXZlTmFtZXM7XHJcbiAgfSk7XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgdGhpcy5fYnJlYWtwb2ludCA9IHNpZ25hbChpbmplY3QoRklSRU5HX0JSRUFLUE9JTlRTKSk7XHJcblxyXG4gICAgaWYgKHRoaXMud2luZG93KSB7XHJcbiAgICAgIHRoaXMuX3dpbmRvd1dpZHRoLnNldCh0aGlzLndpbmRvdy5pbm5lcldpZHRoKTtcclxuICAgICAgdGhpcy5fd2luZG93SGVpZ2h0LnNldCh0aGlzLndpbmRvdy5pbm5lckhlaWdodCk7XHJcblxyXG4gICAgICBmcm9tRXZlbnQodGhpcy53aW5kb3csICdyZXNpemUnKVxyXG4gICAgICAgIC5waXBlKGF1ZGl0VGltZSgxMDApKVxyXG4gICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgICAgICAgdGhpcy5fd2luZG93V2lkdGguc2V0KHRoaXMud2luZG93Py5pbm5lcldpZHRoIHx8IDApO1xyXG4gICAgICAgICAgdGhpcy5fd2luZG93SGVpZ2h0LnNldCh0aGlzLndpbmRvdz8uaW5uZXJIZWlnaHQgfHwgMCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zb2xlLndhcm4oXHJcbiAgICAgICAgJ0ZpcmVuZ1NjcmVlblNlcnZpY2U6IE5vIHdpbmRvdyBvYmplY3QgZm91bmQuIFNjcmVlbiBzZXJ2aWNlIG1heSBub3Qgd29yayBhcyBleHBlY3RlZC4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDaGVja3MgaWYgdGhlIGN1cnJlbnQgc2NyZWVuIHdpZHRoIG1hdGNoZXMgdGhlIHNwZWNpZmllZCBicmVha3BvaW50LlxyXG4gICAqIEBwYXJhbSBicmVha3BvaW50TmFtZSBUaGUgbmFtZSBvZiB0aGUgYnJlYWtwb2ludCAoZS5nLiwgJ3hzJywgJ21kJykuXHJcbiAgICogQHJldHVybnMgQSBzaWduYWwgaW5kaWNhdGluZyBpZiB0aGUgY3VycmVudCBzY3JlZW4gd2lkdGggbWF0Y2hlcyB0aGUgc3BlY2lmaWVkIGJyZWFrcG9pbnQuXHJcbiAgICovXHJcbiAgcHVibGljIGlzQnJlYWtwb2ludChicmVha3BvaW50TmFtZTogc3RyaW5nKTogU2lnbmFsPGJvb2xlYW4+IHtcclxuICAgIHJldHVybiBjb21wdXRlZCgoKSA9PiBicmVha3BvaW50TmFtZSA9PT0gdGhpcy5jdXJyZW50QnJlYWtwb2ludCgpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrcyBpZiB0aGUgY3VycmVudCBzY3JlZW4gc2l6ZSBpcyBhdCBvciBhYm92ZSBhIHNwZWNpZmljIGJyZWFrcG9pbnQuXHJcbiAgICogQHBhcmFtIGJyZWFrcG9pbnROYW1lIFRoZSBuYW1lIG9mIHRoZSBicmVha3BvaW50IChlLmcuLCAnc20nLCAnbWQnKS5cclxuICAgKiBAcmV0dXJucyBBIHNpZ25hbCBpbmRpY2F0aW5nIGlmIHRoZSBjdXJyZW50IHNjcmVlbiBpcyBhdCBvciBhYm92ZSB0aGUgYnJlYWtwb2ludC5cclxuICAgKi9cclxuICBwdWJsaWMgaXNCcmVha3BvaW50VXAoYnJlYWtwb2ludE5hbWU6IHN0cmluZyk6IFNpZ25hbDxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gY29tcHV0ZWQoKCkgPT4ge1xyXG4gICAgICBjb25zdCBicmVha3BvaW50cyA9IHRoaXMuX3NvcnRlZEJyZWFrcG9pbnRzKCk7XHJcbiAgICAgIGNvbnN0IHRhcmdldEluZGV4ID0gT2JqZWN0LmtleXMoYnJlYWtwb2ludHMpLmluZGV4T2YoYnJlYWtwb2ludE5hbWUpO1xyXG4gICAgICBjb25zdCBjdXJyZW50SW5kZXggPSBPYmplY3Qua2V5cyhicmVha3BvaW50cykuaW5kZXhPZihcclxuICAgICAgICB0aGlzLmN1cnJlbnRCcmVha3BvaW50KClcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHJldHVybiAoXHJcbiAgICAgICAgdGFyZ2V0SW5kZXggPj0gY3VycmVudEluZGV4ICYmIHRhcmdldEluZGV4ID49IDAgJiYgY3VycmVudEluZGV4ID49IDBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2hlY2tzIGlmIHRoZSBjdXJyZW50IHNjcmVlbiBzaXplIGlzIGJlbG93IGEgc3BlY2lmaWMgYnJlYWtwb2ludC5cclxuICAgKiBAcGFyYW0gYnJlYWtwb2ludE5hbWUgVGhlIG5hbWUgb2YgdGhlIGJyZWFrcG9pbnQgKGUuZy4sICdzbScsICdtZCcpLlxyXG4gICAqIEByZXR1cm5zIEEgc2lnbmFsIGluZGljYXRpbmcgaWYgdGhlIGN1cnJlbnQgc2NyZWVuIGlzIGJlbG93IHRoZSBicmVha3BvaW50LlxyXG4gICAqL1xyXG4gIHB1YmxpYyBpc0JyZWFrcG9pbnREb3duKGJyZWFrcG9pbnROYW1lOiBzdHJpbmcpOiBTaWduYWw8Ym9vbGVhbj4ge1xyXG4gICAgcmV0dXJuIGNvbXB1dGVkKCgpID0+IHtcclxuICAgICAgY29uc3QgYnJlYWtwb2ludHMgPSB0aGlzLl9zb3J0ZWRCcmVha3BvaW50cygpO1xyXG4gICAgICBjb25zdCB0YXJnZXRJbmRleCA9IE9iamVjdC5rZXlzKGJyZWFrcG9pbnRzKS5pbmRleE9mKGJyZWFrcG9pbnROYW1lKTtcclxuICAgICAgY29uc3QgY3VycmVudEluZGV4ID0gT2JqZWN0LmtleXMoYnJlYWtwb2ludHMpLmluZGV4T2YoXHJcbiAgICAgICAgdGhpcy5jdXJyZW50QnJlYWtwb2ludCgpXHJcbiAgICAgICk7XHJcblxyXG4gICAgICByZXR1cm4gKFxyXG4gICAgICAgIGN1cnJlbnRJbmRleCA8IHRhcmdldEluZGV4ICYmIHRhcmdldEluZGV4ID49IDAgJiYgY3VycmVudEluZGV4ID49IDBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQWxsb3dzIHVzZXJzIHRvIHVwZGF0ZSBicmVha3BvaW50cyBkeW5hbWljYWxseSBhdCBydW50aW1lLlxyXG4gICAqIFRoaXMgd2lsbCBpbW1lZGlhdGVseSB1cGRhdGUgdGhlIGBjdXJyZW50QnJlYWtwb2ludGAgYW5kIGBhY3RpdmVCcmVha3BvaW50c2Agc2lnbmFscy5cclxuICAgKiBAcGFyYW0gbmV3QnJlYWtwb2ludHMgQW4gYXJyYXkgb2YgbmV3IGJyZWFrcG9pbnQgZGVmaW5pdGlvbnMuXHJcbiAgICovXHJcbiAgcHVibGljIHNldEJyZWFrcG9pbnRzKG5ld0JyZWFrcG9pbnRzOiBGaXJlbmdCcmVha3BvaW50cyk6IHZvaWQge1xyXG4gICAgY29uc3Qga2V5cyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xyXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3QnJlYWtwb2ludHMpKSB7XHJcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdudW1iZXInIHx8IGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA8IDApIHtcclxuICAgICAgICBjb25zb2xlLndhcm4oYEludmFsaWQgYnJlYWtwb2ludCB2YWx1ZSBmb3IgXCIke2tleX1cIjogJHt2YWx1ZX1gKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH0gZWxzZSBpZiAoa2V5cy5oYXMoa2V5KSkge1xyXG4gICAgICAgIGNvbnNvbGUud2FybihgRHVwbGljYXRlIGJyZWFrcG9pbnQga2V5IGZvdW5kOiBcIiR7a2V5fVwiYCk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcbiAgICAgIGtleXMuYWRkKGtleSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fYnJlYWtwb2ludC5zZXQobmV3QnJlYWtwb2ludHMpO1xyXG4gICAgY29uc29sZS5sb2coJ0ZpcmVuZ1NjcmVlblNlcnZpY2U6IEJyZWFrcG9pbnRzIHVwZGF0ZWQgc3VjY2Vzc2Z1bGx5LicpO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHJlYWRvbmx5IGlzUG9ydHJhaXQ6IFNpZ25hbDxib29sZWFuPiA9IGNvbXB1dGVkKCgpID0+IHtcclxuICAgIHJldHVybiB0aGlzLl93aW5kb3dIZWlnaHQoKSA+IHRoaXMuX3dpbmRvd1dpZHRoKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlc29sdmVzIGEgcmVzcG9uc2l2ZSB2YWx1ZSBmcm9tIGEgbWFwIGJhc2VkIG9uIGN1cnJlbnQgYWN0aXZlIGJyZWFrcG9pbnRzLlxyXG4gICAqXHJcbiAgICogSXQgYXBwbGllcyBjYXNjYWRpbmcgbG9naWM6IHRoZSB2YWx1ZSBmb3IgdGhlIGxhcmdlc3QgYWN0aXZlIGJyZWFrcG9pbnQgaW4gYHZhbHVlTWFwYCBpcyByZXR1cm5lZC5cclxuICAgKiBJZiBubyBtYXRjaCBpcyBmb3VuZCwgdGhlIGBmYWxsYmFja2AgdmFsdWUgaXMgcmV0dXJuZWQuXHJcbiAgICpcclxuICAgKiBAdGVtcGxhdGUgVCBUaGUgdHlwZSBvZiB0aGUgdmFsdWUgKGUuZy4sIGBudW1iZXJgLCBgc3RyaW5nYCkuXHJcbiAgICogQHBhcmFtIHZhbHVlTWFwIEFuIG9iamVjdCBtYXBwaW5nIGJyZWFrcG9pbnQgbmFtZXMgdG8gdmFsdWVzIChlLmcuLCBgeyB4czogNSwgbWQ6IDEwIH1gKS5cclxuICAgKiBAcGFyYW0gZmFsbGJhY2sgQW4gb3B0aW9uYWwgZGVmYXVsdCB2YWx1ZSBpZiBubyBtYXRjaGluZyBicmVha3BvaW50IGlzIGZvdW5kLlxyXG4gICAqIEByZXR1cm5zIEEgc2lnbmFsIGVtaXR0aW5nIHRoZSByZXNvbHZlZCB2YWx1ZSwgb3IgYGZhbGxiYWNrYCwgb3IgYHVuZGVmaW5lZGAuXHJcbiAgICpcclxuICAgKiBAZXhhbXBsZVxyXG4gICAqIC8vIEdldCBpdGVtcyBwZXIgcGFnZTogNSBmb3IgeHMsIDEwIGZvciBtZCBhbmQgdXAsIGRlZmF1bHQgNVxyXG4gICAqIGNvbnN0IGl0ZW1zUGVyUGFnZSA9IHRoaXMuc2NyZWVuU2VydmljZS5yZXNvbHZlQnJlYWtwb2ludFZhbHVlKHsgeHM6IDUsIG1kOiAxMCB9LCA1KTtcclxuICAgKi9cclxuICBwdWJsaWMgcmVzb2x2ZUJyZWFrcG9pbnRWYWx1ZTxUPihcclxuICAgIHZhbHVlTWFwOiBGaXJlbmdSZXNwb25zaXZlTWFwPFQ+LFxyXG4gICAgZmFsbGJhY2s/OiBUXHJcbiAgKTogU2lnbmFsPFQgfCB1bmRlZmluZWQ+IHtcclxuICAgIHJldHVybiBjb21wdXRlZCgoKSA9PiB7XHJcbiAgICAgIGNvbnN0IGFjdGl2ZUJyZWFrcG9pbnRzID0gdGhpcy5hY3RpdmVCcmVha3BvaW50cygpO1xyXG5cclxuICAgICAgbGV0IHNlbGVjdGVkVmFsdWU6IFQgfCB1bmRlZmluZWQ7XHJcbiAgICAgIGZvciAoY29uc3QgYnJlYWtwb2ludCBvZiBhY3RpdmVCcmVha3BvaW50cykge1xyXG4gICAgICAgIGlmICh2YWx1ZU1hcC5oYXNPd25Qcm9wZXJ0eShicmVha3BvaW50KSkge1xyXG4gICAgICAgICAgc2VsZWN0ZWRWYWx1ZSA9IHZhbHVlTWFwW2JyZWFrcG9pbnRdO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHNlbGVjdGVkVmFsdWUgPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIHJldHVybiBmYWxsYmFjaztcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHNlbGVjdGVkVmFsdWU7XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuIl19