@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
150 lines • 21.4 kB
JavaScript
import { inject, Injectable, RendererFactory2 } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import * as i0 from "@angular/core";
export class ManagedFocusContainerService {
constructor() {
this.rendererFactory = inject(RendererFactory2);
this._containers = [];
// programmatically create a renderer as it can't be injected into a service
this._renderer = this.rendererFactory.createRenderer(null, null);
}
/**
* Create or get an existing object which manages the tabindex of descendants.
* @param element The element containing focusable descendants.
* @param component The component requesting the managed focus container.
*/
register(element, component) {
// Only create a new instance if no other component has created a container on the same element
let containerRef = this._containers.find(ref => ref.container.element.isEqualNode(element));
if (!containerRef) {
containerRef = new ManagedFocusContainerWithReferences(new ManagedFocusContainer(element, this._renderer));
this._containers.push(containerRef);
// Start listening for focus
containerRef.container.register();
}
// Track references to dispose correctly
if (component) {
containerRef.addReference(component);
}
}
/**
* Remove the container object. This will call `unregister` on the container if `component` is the last reference
* to it.
* @param element The element containing focusable descendants.
* @param component The component requesting the managed focus container.
*/
unregister(element, component) {
// Remove the container's reference to the source component
const containerRef = this._containers.find(ref => ref.container.element.isEqualNode(element));
// technically this function can be called before the register function if ngOnDestroy runs before it
// is fully initialized so we should stop here if there is no containRef.
if (!containerRef) {
return;
}
containerRef.removeReference(component);
if (!containerRef.isAlive()) {
// Last reference was removed, so unregister the listeners
containerRef.container.unregister();
// Clean up the reference tracking array
this._containers = this._containers.filter(c => c !== containerRef);
}
}
/**
* Get an observable which can be used to determine when the element or one of its descendants has focus.
* @param element The element containing focusable descendants.
*/
hasFocus(element) {
const container = this.getContainer(element);
return container ? container.hasFocus$.asObservable() : null;
}
getContainer(element) {
const containerRef = this._containers.find(ref => ref.container.element.isEqualNode(element));
return containerRef ? containerRef.container : null;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: ManagedFocusContainerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: ManagedFocusContainerService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: ManagedFocusContainerService, decorators: [{
type: Injectable
}], ctorParameters: () => [] });
class ManagedFocusContainer {
constructor(element, _renderer) {
this.element = element;
this._renderer = _renderer;
/** Whether the container or one of its descendants has focus. */
this.hasFocus$ = new BehaviorSubject(false);
this._modifiedElements = [];
this._unlisten = [];
}
/** Start managing the focus of child elements. */
register() {
this._unlisten.push(this._renderer.listen(this.element, 'focusin', this.onFocusIn.bind(this)));
this._unlisten.push(this._renderer.listen(this.element, 'focusout', this.onFocusOut.bind(this)));
// Check if the container already has focus
setTimeout(() => {
if (!this.element.contains(document.activeElement)) {
this.removeTabFocus();
}
});
}
/** Stop managing the focus of child elements. */
unregister() {
// Dispose the event handlers
this._unlisten.forEach(unlisten => unlisten());
this._unlisten = [];
// Undo any tabindex modifications
this.restoreTabFocus();
}
onFocusIn() {
this.restoreTabFocus();
}
onFocusOut() {
this.removeTabFocus();
}
removeTabFocus() {
this.hasFocus$.next(false);
// Clear the list of affected elements
this._modifiedElements = [];
// Get all focusable children
const focusable = this.element.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
// Remove focusable children from the tab ring
Array.from(focusable).forEach(element => {
const originalTabIndex = element.getAttribute('tabindex');
this._renderer.setAttribute(element, 'tabindex', '-1');
this._modifiedElements.push({
element,
tabindex: originalTabIndex
});
});
}
restoreTabFocus() {
this.hasFocus$.next(true);
// Restore tab focus ability by removing the custom `tabindex` attribute
this._modifiedElements.forEach(elementInfo => {
if (elementInfo.tabindex === null) {
this._renderer.removeAttribute(elementInfo.element, 'tabindex');
}
else {
this._renderer.setAttribute(elementInfo.element, 'tabindex', elementInfo.tabindex);
}
});
// Clear the list of affected elements
this._modifiedElements = [];
}
}
class ManagedFocusContainerWithReferences {
constructor(container) {
this.container = container;
this._components = [];
}
addReference(component) {
this._components.push(component);
}
removeReference(component) {
this._components = this._components.filter(c => c !== component);
}
isAlive() {
return this._components.length > 0;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFuYWdlZC1mb2N1cy1jb250YWluZXIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9kaXJlY3RpdmVzL2FjY2Vzc2liaWxpdHkvbWFuYWdlZC1mb2N1cy1jb250YWluZXIvbWFuYWdlZC1mb2N1cy1jb250YWluZXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBYSxnQkFBZ0IsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNoRixPQUFPLEVBQUUsZUFBZSxFQUFjLE1BQU0sTUFBTSxDQUFDOztBQUduRCxNQUFNLE9BQU8sNEJBQTRCO0lBTXJDO1FBTFMsb0JBQWUsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUU1QyxnQkFBVyxHQUEwQyxFQUFFLENBQUM7UUFJNUQsNEVBQTRFO1FBQzVFLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3JFLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsUUFBUSxDQUFDLE9BQW9CLEVBQUUsU0FBa0I7UUFFN0MsK0ZBQStGO1FBQy9GLElBQUksWUFBWSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDNUYsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ2hCLFlBQVksR0FBRyxJQUFJLG1DQUFtQyxDQUFDLElBQUkscUJBQXFCLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1lBQzNHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBRXBDLDRCQUE0QjtZ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ImltcG9ydCB7IGluamVjdCwgSW5qZWN0YWJsZSwgUmVuZGVyZXIyLCBSZW5kZXJlckZhY3RvcnkyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIE1hbmFnZWRGb2N1c0NvbnRhaW5lclNlcnZpY2Uge1xuICAgIHJlYWRvbmx5IHJlbmRlcmVyRmFjdG9yeSA9IGluamVjdChSZW5kZXJlckZhY3RvcnkyKTtcblxuICAgIHByaXZhdGUgX2NvbnRhaW5lcnM6IE1hbmFnZWRGb2N1c0NvbnRhaW5lcldpdGhSZWZlcmVuY2VzW10gPSBbXTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9yZW5kZXJlcjogUmVuZGVyZXIyO1xuXG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIC8vIHByb2dyYW1tYXRpY2FsbHkgY3JlYXRlIGEgcmVuZGVyZXIgYXMgaXQgY2FuJ3QgYmUgaW5qZWN0ZWQgaW50byBhIHNlcnZpY2VcbiAgICAgICAgdGhpcy5fcmVuZGVyZXIgPSB0aGlzLnJlbmRlcmVyRmFjdG9yeS5jcmVhdGVSZW5kZXJlcihudWxsLCBudWxsKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgb3IgZ2V0IGFuIGV4aXN0aW5nIG9iamVjdCB3aGljaCBtYW5hZ2VzIHRoZSB0YWJpbmRleCBvZiBkZXNjZW5kYW50cy5cbiAgICAgKiBAcGFyYW0gZWxlbWVudCBUaGUgZWxlbWVudCBjb250YWluaW5nIGZvY3VzYWJsZSBkZXNjZW5kYW50cy5cbiAgICAgKiBAcGFyYW0gY29tcG9uZW50IFRoZSBjb21wb25lbnQgcmVxdWVzdGluZyB0aGUgbWFuYWdlZCBmb2N1cyBjb250YWluZXIuXG4gICAgICovXG4gICAgcmVnaXN0ZXIoZWxlbWVudDogSFRNTEVsZW1lbnQsIGNvbXBvbmVudDogdW5rbm93bik6IHZvaWQge1xuXG4gICAgICAgIC8vIE9ubHkgY3JlYXRlIGEgbmV3IGluc3RhbmNlIGlmIG5vIG90aGVyIGNvbXBvbmVudCBoYXMgY3JlYXRlZCBhIGNvbnRhaW5lciBvbiB0aGUgc2FtZSBlbGVtZW50XG4gICAgICAgIGxldCBjb250YWluZXJSZWYgPSB0aGlzLl9jb250YWluZXJzLmZpbmQocmVmID0+IHJlZi5jb250YWluZXIuZWxlbWVudC5pc0VxdWFsTm9kZShlbGVtZW50KSk7XG4gICAgICAgIGlmICghY29udGFpbmVyUmVmKSB7XG4gICAgICAgICAgICBjb250YWluZXJSZWYgPSBuZXcgTWFuYWdlZEZvY3VzQ29udGFpbmVyV2l0aFJlZmVyZW5jZXMobmV3IE1hbmFnZWRGb2N1c0NvbnRhaW5lcihlbGVtZW50LCB0aGlzLl9yZW5kZXJlcikpO1xuICAgICAgICAgICAgdGhpcy5fY29udGFpbmVycy5wdXNoKGNvbnRhaW5lclJlZik7XG5cbiAgICAgICAgICAgIC8vIFN0YXJ0IGxpc3RlbmluZyBmb3IgZm9jdXNcbiAgICAgICAgICAgIGNvbnRhaW5lclJlZi5jb250YWluZXIucmVnaXN0ZXIoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRyYWNrIHJlZmVyZW5jZXMgdG8gZGlzcG9zZSBjb3JyZWN0bHlcbiAgICAgICAgaWYgKGNvbXBvbmVudCkge1xuICAgICAgICAgICAgY29udGFpbmVyUmVmLmFkZFJlZmVyZW5jZShjb21wb25lbnQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIHRoZSBjb250YWluZXIgb2JqZWN0LiBUaGlzIHdpbGwgY2FsbCBgdW5yZWdpc3RlcmAgb24gdGhlIGNvbnRhaW5lciBpZiBgY29tcG9uZW50YCBpcyB0aGUgbGFzdCByZWZlcmVuY2VcbiAgICAgKiB0byBpdC5cbiAgICAgKiBAcGFyYW0gZWxlbWVudCBUaGUgZWxlbWVudCBjb250YWluaW5nIGZvY3VzYWJsZSBkZXNjZW5kYW50cy5cbiAgICAgKiBAcGFyYW0gY29tcG9uZW50IFRoZSBjb21wb25lbnQgcmVxdWVzdGluZyB0aGUgbWFuYWdlZCBmb2N1cyBjb250YWluZXIuXG4gICAgICovXG4gICAgdW5yZWdpc3RlcihlbGVtZW50OiBIVE1MRWxlbWVudCwgY29tcG9uZW50OiB1bmtub3duKTogdm9pZCB7XG5cbiAgICAgICAgLy8gUmVtb3ZlIHRoZSBjb250YWluZXIncyByZWZlcmVuY2UgdG8gdGhlIHNvdXJjZSBjb21wb25lbnRcbiAgICAgICAgY29uc3QgY29udGFpbmVyUmVmID0gdGhpcy5fY29udGFpbmVycy5maW5kKHJlZiA9PiByZWYuY29udGFpbmVyLmVsZW1lbnQuaXNFcXVhbE5vZGUoZWxlbWVudCkpO1xuXG4gICAgICAgIC8vIHRlY2huaWNhbGx5IHRoaXMgZnVuY3Rpb24gY2FuIGJlIGNhbGxlZCBiZWZvcmUgdGhlIHJlZ2lzdGVyIGZ1bmN0aW9uIGlmIG5nT25EZXN0cm95IHJ1bnMgYmVmb3JlIGl0XG4gICAgICAgIC8vIGlzIGZ1bGx5IGluaXRpYWxpemVkIHNvIHdlIHNob3VsZCBzdG9wIGhlcmUgaWYgdGhlcmUgaXMgbm8gY29udGFpblJlZi5cbiAgICAgICAgaWYgKCFjb250YWluZXJSZWYpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnRhaW5lclJlZi5yZW1vdmVSZWZlcmVuY2UoY29tcG9uZW50KTtcblxuICAgICAgICBpZiAoIWNvbnRhaW5lclJlZi5pc0FsaXZlKCkpIHtcblxuICAgICAgICAgICAgLy8gTGFzdCByZWZlcmVuY2Ugd2FzIHJlbW92ZWQsIHNvIHVucmVnaXN0ZXIgdGhlIGxpc3RlbmVyc1xuICAgICAgICAgICAgY29udGFpbmVyUmVmLmNvbnRhaW5lci51bnJlZ2lzdGVyKCk7XG5cbiAgICAgICAgICAgIC8vIENsZWFuIHVwIHRoZSByZWZlcmVuY2UgdHJhY2tpbmcgYXJyYXlcbiAgICAgICAgICAgIHRoaXMuX2NvbnRhaW5lcnMgPSB0aGlzLl9jb250YWluZXJzLmZpbHRlcihjID0+IGMgIT09IGNvbnRhaW5lclJlZik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYW4gb2JzZXJ2YWJsZSB3aGljaCBjYW4gYmUgdXNlZCB0byBkZXRlcm1pbmUgd2hlbiB0aGUgZWxlbWVudCBvciBvbmUgb2YgaXRzIGRlc2NlbmRhbnRzIGhhcyBmb2N1cy5cbiAgICAgKiBAcGFyYW0gZWxlbWVudCBUaGUgZWxlbWVudCBjb250YWluaW5nIGZvY3VzYWJsZSBkZXNjZW5kYW50cy5cbiAgICAgKi9cbiAgICBoYXNGb2N1cyhlbGVtZW50OiBIVE1MRWxlbWVudCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmdldENvbnRhaW5lcihlbGVtZW50KTtcbiAgICAgICAgcmV0dXJuIGNvbnRhaW5lciA/IGNvbnRhaW5lci5oYXNGb2N1cyQuYXNPYnNlcnZhYmxlKCkgOiBudWxsO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0Q29udGFpbmVyKGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogTWFuYWdlZEZvY3VzQ29udGFpbmVyIHtcbiAgICAgICAgY29uc3QgY29udGFpbmVyUmVmID0gdGhpcy5fY29udGFpbmVycy5maW5kKHJlZiA9PiByZWYuY29udGFpbmVyLmVsZW1lbnQuaXNFcXVhbE5vZGUoZWxlbWVudCkpO1xuICAgICAgICByZXR1cm4gY29udGFpbmVyUmVmID8gY29udGFpbmVyUmVmLmNvbnRhaW5lciA6IG51bGw7XG4gICAgfVxufVxuXG5jbGFzcyBNYW5hZ2VkRm9jdXNDb250YWluZXIge1xuXG4gICAgLyoqIFdoZXRoZXIgdGhlIGNvbnRhaW5lciBvciBvbmUgb2YgaXRzIGRlc2NlbmRhbnRzIGhhcyBmb2N1cy4gKi9cbiAgICByZWFkb25seSBoYXNGb2N1cyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcblxuICAgIHByaXZhdGUgX21vZGlmaWVkRWxlbWVudHM6IE1hbmFnZWRGb2N1c0VsZW1lbnRJbmZvW10gPSBbXTtcbiAgICBwcml2YXRlIF91bmxpc3RlbjogKCgpID0+IHZvaWQpW10gPSBbXTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwdWJsaWMgcmVhZG9ubHkgZWxlbWVudDogSFRNTEVsZW1lbnQsXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgX3JlbmRlcmVyOiBSZW5kZXJlcjJcbiAgICApIHsgfVxuXG4gICAgLyoqIFN0YXJ0IG1hbmFnaW5nIHRoZSBmb2N1cyBvZiBjaGlsZCBlbGVtZW50cy4gKi9cbiAgICByZWdpc3RlcigpOiB2b2lkIHtcblxuICAgICAgICB0aGlzLl91bmxpc3Rlbi5wdXNoKHRoaXMuX3JlbmRlcmVyLmxpc3Rlbih0aGlzLmVsZW1lbnQsICdmb2N1c2luJywgdGhpcy5vbkZvY3VzSW4uYmluZCh0aGlzKSkpO1xuICAgICAgICB0aGlzLl91bmxpc3Rlbi5wdXNoKHRoaXMuX3JlbmRlcmVyLmxpc3Rlbih0aGlzLmVsZW1lbnQsICdmb2N1c291dCcsIHRoaXMub25Gb2N1c091dC5iaW5kKHRoaXMpKSk7XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGNvbnRhaW5lciBhbHJlYWR5IGhhcyBmb2N1c1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIGlmICghdGhpcy5lbGVtZW50LmNvbnRhaW5zKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVUYWJGb2N1cygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogU3RvcCBtYW5hZ2luZyB0aGUgZm9jdXMgb2YgY2hpbGQgZWxlbWVudHMuICovXG4gICAgdW5yZWdpc3RlcigpOiB2b2lkIHtcblxuICAgICAgICAvLyBEaXNwb3NlIHRoZSBldmVudCBoYW5kbGVyc1xuICAgICAgICB0aGlzLl91bmxpc3Rlbi5mb3JFYWNoKHVubGlzdGVuID0+IHVubGlzdGVuKCkpO1xuICAgICAgICB0aGlzLl91bmxpc3RlbiA9IFtdO1xuXG4gICAgICAgIC8vIFVuZG8gYW55IHRhYmluZGV4IG1vZGlmaWNhdGlvbnNcbiAgICAgICAgdGhpcy5yZXN0b3JlVGFiRm9jdXMoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uRm9jdXNJbigpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5yZXN0b3JlVGFiRm9jdXMoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uRm9jdXNPdXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMucmVtb3ZlVGFiRm9jdXMoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbW92ZVRhYkZvY3VzKCk6IHZvaWQge1xuXG4gICAgICAgIHRoaXMuaGFzRm9jdXMkLm5leHQoZmFsc2UpO1xuXG4gICAgICAgIC8vIENsZWFyIHRoZSBsaXN0IG9mIGFmZmVjdGVkIGVsZW1lbnRzXG4gICAgICAgIHRoaXMuX21vZGlmaWVkRWxlbWVudHMgPSBbXTtcblxuICAgICAgICAvLyBHZXQgYWxsIGZvY3VzYWJsZSBjaGlsZHJlblxuICAgICAgICBjb25zdCBmb2N1c2FibGUgPSB0aGlzLmVsZW1lbnQucXVlcnlTZWxlY3RvckFsbChcbiAgICAgICAgICAgICdidXR0b24sIFtocmVmXSwgaW5wdXQsIHNlbGVjdCwgdGV4dGFyZWEsIFt0YWJpbmRleF06bm90KFt0YWJpbmRleD1cIi0xXCJdKSdcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBSZW1vdmUgZm9jdXNhYmxlIGNoaWxkcmVuIGZyb20gdGhlIHRhYiByaW5nXG4gICAgICAgIEFycmF5LmZyb20oZm9jdXNhYmxlKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgY29uc3Qgb3JpZ2luYWxUYWJJbmRleCA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCd0YWJpbmRleCcpO1xuICAgICAgICAgICAgdGhpcy5fcmVuZGVyZXIuc2V0QXR0cmlidXRlKGVsZW1lbnQsICd0YWJpbmRleCcsICctMScpO1xuICAgICAgICAgICAgdGhpcy5fbW9kaWZpZWRFbGVtZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgICBlbGVtZW50LFxuICAgICAgICAgICAgICAgIHRhYmluZGV4OiBvcmlnaW5hbFRhYkluZGV4XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZXN0b3JlVGFiRm9jdXMoKTogdm9pZCB7XG5cbiAgICAgICAgdGhpcy5oYXNGb2N1cyQubmV4dCh0cnVlKTtcblxuICAgICAgICAvLyBSZXN0b3JlIHRhYiBmb2N1cyBhYmlsaXR5IGJ5IHJlbW92aW5nIHRoZSBjdXN0b20gYHRhYmluZGV4YCBhdHRyaWJ1dGVcbiAgICAgICAgdGhpcy5fbW9kaWZpZWRFbGVtZW50cy5mb3JFYWNoKGVsZW1lbnRJbmZvID0+IHtcbiAgICAgICAgICAgIGlmIChlbGVtZW50SW5mby50YWJpbmRleCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuX3JlbmRlcmVyLnJlbW92ZUF0dHJpYnV0ZShlbGVtZW50SW5mby5lbGVtZW50LCAndGFiaW5kZXgnKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fcmVuZGVyZXIuc2V0QXR0cmlidXRlKGVsZW1lbnRJbmZvLmVsZW1lbnQsICd0YWJpbmRleCcsIGVsZW1lbnRJbmZvLnRhYmluZGV4KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQ2xlYXIgdGhlIGxpc3Qgb2YgYWZmZWN0ZWQgZWxlbWVudHNcbiAgICAgICAgdGhpcy5fbW9kaWZpZWRFbGVtZW50cyA9IFtdO1xuICAgIH1cbn1cblxuaW50ZXJmYWNlIE1hbmFnZWRGb2N1c0VsZW1lbnRJbmZvIHtcbiAgICBlbGVtZW50OiBFbGVtZW50O1xuICAgIHRhYmluZGV4OiBzdHJpbmc7XG59XG5cbmNsYXNzIE1hbmFnZWRGb2N1c0NvbnRhaW5lcldpdGhSZWZlcmVuY2VzIHtcblxuICAgIHByaXZhdGUgX2NvbXBvbmVudHM6IHVua25vd25bXSA9IFtdO1xuXG4gICAgY29uc3RydWN0b3IocHVibGljIGNvbnRhaW5lcjogTWFuYWdlZEZvY3VzQ29udGFpbmVyKSB7IH1cblxuICAgIGFkZFJlZmVyZW5jZShjb21wb25lbnQ6IHVua25vd24pOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fY29tcG9uZW50cy5wdXNoKGNvbXBvbmVudCk7XG4gICAgfVxuXG4gICAgcmVtb3ZlUmVmZXJlbmNlKGNvbXBvbmVudDogdW5rbm93bik6IHZvaWQge1xuICAgICAgICB0aGlzLl9jb21wb25lbnRzID0gdGhpcy5fY29tcG9uZW50cy5maWx0ZXIoYyA9PiBjICE9PSBjb21wb25lbnQpO1xuICAgIH1cblxuICAgIGlzQWxpdmUoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9jb21wb25lbnRzLmxlbmd0aCA+IDA7XG4gICAgfVxufSJdfQ==