@nakedobjects/gemini
Version:
Single Page Application client for a Naked Objects application.
95 lines • 20.7 kB
JavaScript
import { Component, Input, ViewChildren } from '@angular/core';
import difference from 'lodash-es/difference';
import findIndex from 'lodash-es/findIndex';
import first from 'lodash-es/first';
import map from 'lodash-es/map';
import some from 'lodash-es/some';
import { ActionComponent } from '../action/action.component';
import { wrapAction } from '../action/action.component';
import { safeUnsubscribe } from '../helpers-components';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "../action/action.component";
export class ActionListComponent {
previousActionChildrenNames = [];
holder;
sub;
actionChildren;
set menuHolder(mh) {
this.holder = mh;
this.actionHolders = []; // clear cache;
}
get menuHolder() {
return this.holder;
}
get items() {
return this.menuHolder.menuItems;
}
actionHolders = [];
getActionHolders(menuItem) {
return map(menuItem.actions, a => wrapAction(a));
}
hasActions = (menuItem) => {
const actions = menuItem.actions;
return actions && actions.length > 0;
};
hasItems = (menuItem) => {
const items = menuItem.menuItems;
return items && items.length > 0;
};
menuName = (menuItem) => menuItem.name;
menuItems = (menuItem) => menuItem.menuItems;
menuActions = (menuItem, index) => {
if (!this.actionHolders[index]) {
this.actionHolders[index] = this.getActionHolders(menuItem);
}
return this.actionHolders[index];
};
toggleCollapsed = (menuItem) => menuItem.toggleCollapsed();
navCollapsed = (menuItem) => menuItem.navCollapsed;
displayClass = (menuItem) => ({ collapsed: menuItem.navCollapsed, open: !menuItem.navCollapsed, rootMenu: !menuItem.name });
classes(action) {
const hint = action.presentationHint ?? '';
return hint.trim();
}
focusFromIndex(actions, index = 0) {
const toFocus = actions.toArray().slice(index);
if (toFocus && toFocus.length > 0) {
// until first element returns true
some(toFocus, i => i.focus());
}
}
focus(actions) {
if (actions && actions.length > 0) {
const actionChildrenNames = map(actions.toArray(), a => a.action.value);
const newActions = difference(actionChildrenNames, this.previousActionChildrenNames);
let index = 0;
if (newActions && newActions.length > 0) {
const firstAction = first(newActions);
index = findIndex(actions.toArray(), a => a.action.value === firstAction);
index = index < 0 ? 0 : index;
}
this.previousActionChildrenNames = actionChildrenNames;
this.focusFromIndex(actions, index);
}
}
ngAfterViewInit() {
this.focus(this.actionChildren);
this.sub = this.actionChildren?.changes.subscribe((ql) => this.focus(ql));
}
ngOnDestroy() {
safeUnsubscribe(this.sub);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ActionListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: ActionListComponent, selector: "nof-action-list", inputs: { menuHolder: "menuHolder" }, viewQueries: [{ propertyName: "actionChildren", predicate: ActionComponent, descendants: true }], ngImport: i0, template: "<ng-container *ngFor=\"let menu of items; let i = index\">\n\n <div *ngIf=\"menuName(menu)\" (click)=\"toggleCollapsed(menu)\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"submenu\" [ngSwitch]=\"navCollapsed(menu)\" tabindex=\"0\">\n {{menuName(menu)}}\n <div *ngSwitchCase=\"true\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"icon-expand\" tabindex=\"0\"></div>\n <div *ngSwitchCase=\"false\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"icon-collapse\" tabindex=\"0\"></div>\n </div>\n <div *ngIf=\"!navCollapsed(menu)\" class=\"menuitem\" [ngClass]=\"displayClass(menu)\">\n <ng-container *ngIf=\"hasActions(menu)\">\n <ng-container *ngFor=\"let action of menuActions(menu, i)\">\n <nof-action [ngClass]=\"classes(action)\" [action]=\"action\"></nof-action>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"hasItems(menu)\">\n <nof-action-list [menuHolder]=\"menu\"></nof-action-list>\n </ng-container>\n </div>\n</ng-container>\n", styles: [":host{float:left;margin-bottom:var(--space-5);display:block;margin-right:var(--space-4);background-color:var(--menu-background-color)}nof-action,.submenu{display:block;cursor:pointer;outline:none;margin-right:var(--space-5);width:var(--action-width)}.submenu{padding:var(--space-3);color:var(--menu-text-color)}.submenu:hover{outline-style:solid;outline-width:1px;outline-color:var(--default-contrast-color)}.collapsed{display:none}.open{margin-left:var(--space-4)}.open.rootMenu{margin-left:0}.icon-expand:before{content:var(--submenu-expand-icon)}.icon-collapse:before{content:var(--submenu-collapse-icon)}.icon-expand,.icon-collapse{font-size:var(--font-size-1)}.icon-expand:hover,.icon-collapse:hover{outline-color:var(--contrast-outline-color);outline-width:1px}[class^=icon-],[class*=\" icon-\"]{font-family:iconFont;font-weight:var(--font-weight-1);font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;display:inline-block;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0;position:relative}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: ActionListComponent, selector: "nof-action-list", inputs: ["menuHolder"] }, { kind: "component", type: i2.ActionComponent, selector: "nof-action", inputs: ["action"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ActionListComponent, decorators: [{
type: Component,
args: [{ selector: 'nof-action-list', template: "<ng-container *ngFor=\"let menu of items; let i = index\">\n\n <div *ngIf=\"menuName(menu)\" (click)=\"toggleCollapsed(menu)\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"submenu\" [ngSwitch]=\"navCollapsed(menu)\" tabindex=\"0\">\n {{menuName(menu)}}\n <div *ngSwitchCase=\"true\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"icon-expand\" tabindex=\"0\"></div>\n <div *ngSwitchCase=\"false\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"icon-collapse\" tabindex=\"0\"></div>\n </div>\n <div *ngIf=\"!navCollapsed(menu)\" class=\"menuitem\" [ngClass]=\"displayClass(menu)\">\n <ng-container *ngIf=\"hasActions(menu)\">\n <ng-container *ngFor=\"let action of menuActions(menu, i)\">\n <nof-action [ngClass]=\"classes(action)\" [action]=\"action\"></nof-action>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"hasItems(menu)\">\n <nof-action-list [menuHolder]=\"menu\"></nof-action-list>\n </ng-container>\n </div>\n</ng-container>\n", styles: [":host{float:left;margin-bottom:var(--space-5);display:block;margin-right:var(--space-4);background-color:var(--menu-background-color)}nof-action,.submenu{display:block;cursor:pointer;outline:none;margin-right:var(--space-5);width:var(--action-width)}.submenu{padding:var(--space-3);color:var(--menu-text-color)}.submenu:hover{outline-style:solid;outline-width:1px;outline-color:var(--default-contrast-color)}.collapsed{display:none}.open{margin-left:var(--space-4)}.open.rootMenu{margin-left:0}.icon-expand:before{content:var(--submenu-expand-icon)}.icon-collapse:before{content:var(--submenu-collapse-icon)}.icon-expand,.icon-collapse{font-size:var(--font-size-1)}.icon-expand:hover,.icon-collapse:hover{outline-color:var(--contrast-outline-color);outline-width:1px}[class^=icon-],[class*=\" icon-\"]{font-family:iconFont;font-weight:var(--font-weight-1);font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;display:inline-block;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0;position:relative}\n"] }]
}], propDecorators: { actionChildren: [{
type: ViewChildren,
args: [ActionComponent]
}], menuHolder: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLWxpc3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vZ2VtaW5pL3NyYy9hY3Rpb24tbGlzdC9hY3Rpb24tbGlzdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9nZW1pbmkvc3JjL2FjdGlvbi1saXN0L2FjdGlvbi1saXN0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBaUIsU0FBUyxFQUFFLEtBQUssRUFBd0IsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXBHLE9BQU8sVUFBVSxNQUFNLHNCQUFzQixDQUFDO0FBQzlDLE9BQU8sU0FBUyxNQUFNLHFCQUFxQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxNQUFNLGlCQUFpQixDQUFDO0FBQ3BDLE9BQU8sR0FBRyxNQUFNLGVBQWUsQ0FBQztBQUNoQyxPQUFPLElBQUksTUFBTSxnQkFBZ0IsQ0FBQztBQUVsQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0QsT0FBTyxFQUFpQixVQUFVLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN2RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7Ozs7QUFPeEQsTUFBTSxPQUFPLG1CQUFtQjtJQUVwQiwyQkFBMkIsR0FBYSxFQUFFLENBQUM7SUFDM0MsTUFBTSxDQUF3QjtJQUM5QixHQUFHLENBQWlCO0lBRzVCLGNBQWMsQ0FBOEI7SUFFNUMsSUFDSSxVQUFVLENBQUMsRUFBd0I7UUFDbkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxFQUFFLENBQUM7UUFDakIsSUFBSSxDQUFDLGFBQWEsR0FBRyxFQUFFLENBQUMsQ0FBQyxlQUFlO0lBQzVDLENBQUM7SUFFRCxJQUFJLFVBQVU7UUFDVixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVELElBQUksS0FBSztRQUNMLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUM7SUFDckMsQ0FBQztJQUVPLGFBQWEsR0FBc0IsRUFBRSxDQUFDO0lBRXRDLGdCQUFnQixDQUFDLFFBQTJCO1FBQ2hELE9BQU8sR0FBRyxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQsVUFBVSxHQUFHLENBQUMsUUFBMkIsRUFBRSxFQUFFO1FBQ3pDLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUM7UUFDakMsT0FBTyxPQUFPLElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDekMsQ0FBQyxDQUFDO0lBRUYsUUFBUSxHQUFHLENBQUMsUUFBMkIsRUFBRSxFQUFFO1FBQ3ZDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUM7UUFDakMsT0FBTyxLQUFLLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDckMsQ0FBQyxDQUFDO0lBRUYsUUFBUSxHQUFHLENBQUMsUUFBMkIsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQztJQUUxRCxTQUFTLEdBQUcsQ0FBQyxRQUEyQixFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDO0lBRWhFLFdBQVcsR0FBRyxDQUFDLFFBQTJCLEVBQUUsS0FBYSxFQUFFLEVBQUU7UUFDekQsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUM3QixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3JDLENBQUMsQ0FBQztJQUVGLGVBQWUsR0FBRyxDQUFDLFFBQTJCLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUU5RSxZQUFZLEdBQUcsQ0FBQyxRQUEyQixFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDO0lBRXRFLFlBQVksR0FBRyxDQUFDLFFBQTJCLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsUUFBUSxDQUFDLFlBQVksRUFBRSxJQUFJLEVBQUUsQ0FBQyxRQUFRLENBQUMsWUFBWSxFQUFFLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBRS9JLE9BQU8sQ0FBQyxNQUF1QztRQUMzQyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsZ0JBQWdCLElBQUksRUFBRSxDQUFDO1FBQzNDLE9BQU8sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxjQUFjLENBQUMsT0FBbUMsRUFBRSxLQUFLLEdBQUcsQ0FBQztRQUV6RCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRS9DLElBQUksT0FBTyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDaEMsbUNBQW1DO1lBQ25DLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUNsQyxDQUFDO0lBQ0wsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFvQztRQUN0QyxJQUFJLE9BQU8sSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2hDLE1BQU0sbUJBQW1CLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDeEUsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLG1CQUFtQixFQUFFLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1lBQ3JGLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztZQUVkLElBQUksVUFBVSxJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RDLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDdEMsS0FBSyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssS0FBSyxXQUFXLENBQUMsQ0FBQztnQkFDMUUsS0FBSyxHQUFHLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1lBQ2xDLENBQUM7WUFDRCxJQUFJLENBQUMsMkJBQTJCLEdBQUcsbUJBQW1CLENBQUM7WUFDdkQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDeEMsQ0FBQztJQUNMLENBQUM7SUFFRCxlQUFlO1FBQ1gsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUE4QixFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDMUcsQ0FBQztJQUVELFdBQVc7UUFDUCxlQUFlLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzlCLENBQUM7dUdBOUZRLG1CQUFtQjsyRkFBbkIsbUJBQW1CLGdJQU1kLGVBQWUsZ0RDdkJqQyxrakNBa0JBLDJwREREYSxtQkFBbUI7OzJGQUFuQixtQkFBbUI7a0JBTC9CLFNBQVM7K0JBQ0ksaUJBQWlCOzhCQVczQixjQUFjO3NCQURiLFlBQVk7dUJBQUMsZUFBZTtnQkFJekIsVUFBVTtzQkFEYixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQWZ0ZXJWaWV3SW5pdCwgQ29tcG9uZW50LCBJbnB1dCwgT25EZXN0cm95LCBRdWVyeUxpc3QsIFZpZXdDaGlsZHJlbiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWN0aW9uVmlld01vZGVsLCBJTWVudUhvbGRlclZpZXdNb2RlbCwgTWVudUl0ZW1WaWV3TW9kZWwgfSBmcm9tICdAbmFrZWRvYmplY3RzL3ZpZXctbW9kZWxzJztcbmltcG9ydCBkaWZmZXJlbmNlIGZyb20gJ2xvZGFzaC1lcy9kaWZmZXJlbmNlJztcbmltcG9ydCBmaW5kSW5kZXggZnJvbSAnbG9kYXNoLWVzL2ZpbmRJbmRleCc7XG5pbXBvcnQgZmlyc3QgZnJvbSAnbG9kYXNoLWVzL2ZpcnN0JztcbmltcG9ydCBtYXAgZnJvbSAnbG9kYXNoLWVzL21hcCc7XG5pbXBvcnQgc29tZSBmcm9tICdsb2Rhc2gtZXMvc29tZSc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb25MaWtlIGFzIElTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEFjdGlvbkNvbXBvbmVudCB9IGZyb20gJy4uL2FjdGlvbi9hY3Rpb24uY29tcG9uZW50JztcbmltcG9ydCB7IElBY3Rpb25Ib2xkZXIsIHdyYXBBY3Rpb24gfSBmcm9tICcuLi9hY3Rpb24vYWN0aW9uLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBzYWZlVW5zdWJzY3JpYmUgfSBmcm9tICcuLi9oZWxwZXJzLWNvbXBvbmVudHMnO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ25vZi1hY3Rpb24tbGlzdCcsXG4gICAgdGVtcGxhdGVVcmw6ICdhY3Rpb24tbGlzdC5jb21wb25lbnQuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJ2FjdGlvbi1saXN0LmNvbXBvbmVudC5jc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBBY3Rpb25MaXN0Q29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcblxuICAgIHByaXZhdGUgcHJldmlvdXNBY3Rpb25DaGlsZHJlbk5hbWVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIHByaXZhdGUgaG9sZGVyITogSU1lbnVIb2xkZXJWaWV3TW9kZWw7XG4gICAgcHJpdmF0ZSBzdWI/OiBJU3Vic2NyaXB0aW9uO1xuXG4gICAgQFZpZXdDaGlsZHJlbihBY3Rpb25Db21wb25lbnQpXG4gICAgYWN0aW9uQ2hpbGRyZW4/OiBRdWVyeUxpc3Q8QWN0aW9uQ29tcG9uZW50PjtcblxuICAgIEBJbnB1dCgpXG4gICAgc2V0IG1lbnVIb2xkZXIobWg6IElNZW51SG9sZGVyVmlld01vZGVsKSB7XG4gICAgICAgIHRoaXMuaG9sZGVyID0gbWg7XG4gICAgICAgIHRoaXMuYWN0aW9uSG9sZGVycyA9IFtdOyAvLyBjbGVhciBjYWNoZTtcbiAgICB9XG5cbiAgICBnZXQgbWVudUhvbGRlcigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaG9sZGVyO1xuICAgIH1cblxuICAgIGdldCBpdGVtcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWVudUhvbGRlci5tZW51SXRlbXM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhY3Rpb25Ib2xkZXJzOiBJQWN0aW9uSG9sZGVyW11bXSA9IFtdO1xuXG4gICAgcHJpdmF0ZSBnZXRBY3Rpb25Ib2xkZXJzKG1lbnVJdGVtOiBNZW51SXRlbVZpZXdNb2RlbCkge1xuICAgICAgICByZXR1cm4gbWFwKG1lbnVJdGVtLmFjdGlvbnMsIGEgPT4gd3JhcEFjdGlvbihhKSk7XG4gICAgfVxuXG4gICAgaGFzQWN0aW9ucyA9IChtZW51SXRlbTogTWVudUl0ZW1WaWV3TW9kZWwpID0+IHtcbiAgICAgICAgY29uc3QgYWN0aW9ucyA9IG1lbnVJdGVtLmFjdGlvbnM7XG4gICAgICAgIHJldHVybiBhY3Rpb25zICYmIGFjdGlvbnMubGVuZ3RoID4gMDtcbiAgICB9O1xuXG4gICAgaGFzSXRlbXMgPSAobWVudUl0ZW06IE1lbnVJdGVtVmlld01vZGVsKSA9PiB7XG4gICAgICAgIGNvbnN0IGl0ZW1zID0gbWVudUl0ZW0ubWVudUl0ZW1zO1xuICAgICAgICByZXR1cm4gaXRlbXMgJiYgaXRlbXMubGVuZ3RoID4gMDtcbiAgICB9O1xuXG4gICAgbWVudU5hbWUgPSAobWVudUl0ZW06IE1lbnVJdGVtVmlld01vZGVsKSA9PiBtZW51SXRlbS5uYW1lO1xuXG4gICAgbWVudUl0ZW1zID0gKG1lbnVJdGVtOiBNZW51SXRlbVZpZXdNb2RlbCkgPT4gbWVudUl0ZW0ubWVudUl0ZW1zO1xuXG4gICAgbWVudUFjdGlvbnMgPSAobWVudUl0ZW06IE1lbnVJdGVtVmlld01vZGVsLCBpbmRleDogbnVtYmVyKSA9PiB7XG4gICAgICAgIGlmICghdGhpcy5hY3Rpb25Ib2xkZXJzW2luZGV4XSkge1xuICAgICAgICAgICAgdGhpcy5hY3Rpb25Ib2xkZXJzW2luZGV4XSA9IHRoaXMuZ2V0QWN0aW9uSG9sZGVycyhtZW51SXRlbSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuYWN0aW9uSG9sZGVyc1tpbmRleF07XG4gICAgfTtcblxuICAgIHRvZ2dsZUNvbGxhcHNlZCA9IChtZW51SXRlbTogTWVudUl0ZW1WaWV3TW9kZWwpID0+IG1lbnVJdGVtLnRvZ2dsZUNvbGxhcHNlZCgpO1xuXG4gICAgbmF2Q29sbGFwc2VkID0gKG1lbnVJdGVtOiBNZW51SXRlbVZpZXdNb2RlbCkgPT4gbWVudUl0ZW0ubmF2Q29sbGFwc2VkO1xuXG4gICAgZGlzcGxheUNsYXNzID0gKG1lbnVJdGVtOiBNZW51SXRlbVZpZXdNb2RlbCkgPT4gKHsgY29sbGFwc2VkOiBtZW51SXRlbS5uYXZDb2xsYXBzZWQsIG9wZW46ICFtZW51SXRlbS5uYXZDb2xsYXBzZWQsIHJvb3RNZW51OiAhbWVudUl0ZW0ubmFtZSB9KTtcblxuICAgIGNsYXNzZXMoYWN0aW9uOiBBY3Rpb25WaWV3TW9kZWwgfCBJQWN0aW9uSG9sZGVyICkge1xuICAgICAgICBjb25zdCBoaW50ID0gYWN0aW9uLnByZXNlbnRhdGlvbkhpbnQgPz8gJyc7XG4gICAgICAgIHJldHVybiBoaW50LnRyaW0oKTtcbiAgICB9XG5cbiAgICBmb2N1c0Zyb21JbmRleChhY3Rpb25zOiBRdWVyeUxpc3Q8QWN0aW9uQ29tcG9uZW50PiwgaW5kZXggPSAwKSB7XG5cbiAgICAgICAgY29uc3QgdG9Gb2N1cyA9IGFjdGlvbnMudG9BcnJheSgpLnNsaWNlKGluZGV4KTtcblxuICAgICAgICBpZiAodG9Gb2N1cyAmJiB0b0ZvY3VzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIC8vIHVudGlsIGZpcnN0IGVsZW1lbnQgcmV0dXJucyB0cnVlXG4gICAgICAgICAgICBzb21lKHRvRm9jdXMsIGkgPT4gaS5mb2N1cygpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZvY3VzKGFjdGlvbnM/OiBRdWVyeUxpc3Q8QWN0aW9uQ29tcG9uZW50Pikge1xuICAgICAgICBpZiAoYWN0aW9ucyAmJiBhY3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGFjdGlvbkNoaWxkcmVuTmFtZXMgPSBtYXAoYWN0aW9ucy50b0FycmF5KCksIGEgPT4gYS5hY3Rpb24udmFsdWUpO1xuICAgICAgICAgICAgY29uc3QgbmV3QWN0aW9ucyA9IGRpZmZlcmVuY2UoYWN0aW9uQ2hpbGRyZW5OYW1lcywgdGhpcy5wcmV2aW91c0FjdGlvbkNoaWxkcmVuTmFtZXMpO1xuICAgICAgICAgICAgbGV0IGluZGV4ID0gMDtcblxuICAgICAgICAgICAgaWYgKG5ld0FjdGlvbnMgJiYgbmV3QWN0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlyc3RBY3Rpb24gPSBmaXJzdChuZXdBY3Rpb25zKTtcbiAgICAgICAgICAgICAgICBpbmRleCA9IGZpbmRJbmRleChhY3Rpb25zLnRvQXJyYXkoKSwgYSA9PiBhLmFjdGlvbi52YWx1ZSA9PT0gZmlyc3RBY3Rpb24pO1xuICAgICAgICAgICAgICAgIGluZGV4ID0gaW5kZXggPCAwID8gMCA6IGluZGV4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5wcmV2aW91c0FjdGlvbkNoaWxkcmVuTmFtZXMgPSBhY3Rpb25DaGlsZHJlbk5hbWVzO1xuICAgICAgICAgICAgdGhpcy5mb2N1c0Zyb21JbmRleChhY3Rpb25zLCBpbmRleCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZm9jdXModGhpcy5hY3Rpb25DaGlsZHJlbik7XG4gICAgICAgIHRoaXMuc3ViID0gdGhpcy5hY3Rpb25DaGlsZHJlbj8uY2hhbmdlcy5zdWJzY3JpYmUoKHFsOiBRdWVyeUxpc3Q8QWN0aW9uQ29tcG9uZW50PikgPT4gdGhpcy5mb2N1cyhxbCkpO1xuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICBzYWZlVW5zdWJzY3JpYmUodGhpcy5zdWIpO1xuICAgIH1cbn1cbiIsIjxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IG1lbnUgb2YgaXRlbXM7IGxldCBpID0gaW5kZXhcIj5cblxuICAgIDxkaXYgKm5nSWY9XCJtZW51TmFtZShtZW51KVwiIChjbGljayk9XCJ0b2dnbGVDb2xsYXBzZWQobWVudSlcIiAoa2V5ZG93bi5lbnRlcik9XCJ0b2dnbGVDb2xsYXBzZWQobWVudSlcIiBjbGFzcz1cInN1Ym1lbnVcIiBbbmdTd2l0Y2hdPVwibmF2Q29sbGFwc2VkKG1lbnUpXCIgdGFiaW5kZXg9XCIwXCI+XG4gICAgICAgIHt7bWVudU5hbWUobWVudSl9fVxuICAgICAgICA8ZGl2ICpuZ1N3aXRjaENhc2U9XCJ0cnVlXCIgKGtleWRvd24uZW50ZXIpPVwidG9nZ2xlQ29sbGFwc2VkKG1lbnUpXCIgY2xhc3M9XCJpY29uLWV4cGFuZFwiIHRhYmluZGV4PVwiMFwiPjwvZGl2PlxuICAgICAgICA8ZGl2ICpuZ1N3aXRjaENhc2U9XCJmYWxzZVwiIChrZXlkb3duLmVudGVyKT1cInRvZ2dsZUNvbGxhcHNlZChtZW51KVwiIGNsYXNzPVwiaWNvbi1jb2xsYXBzZVwiIHRhYmluZGV4PVwiMFwiPjwvZGl2PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgICpuZ0lmPVwiIW5hdkNvbGxhcHNlZChtZW51KVwiICBjbGFzcz1cIm1lbnVpdGVtXCIgW25nQ2xhc3NdPVwiZGlzcGxheUNsYXNzKG1lbnUpXCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJoYXNBY3Rpb25zKG1lbnUpXCI+XG4gICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBhY3Rpb24gb2YgbWVudUFjdGlvbnMobWVudSwgaSlcIj5cbiAgICAgICAgICAgICAgICA8bm9mLWFjdGlvbiBbbmdDbGFzc109XCJjbGFzc2VzKGFjdGlvbilcIiBbYWN0aW9uXT1cImFjdGlvblwiPjwvbm9mLWFjdGlvbj5cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAgKm5nSWY9XCJoYXNJdGVtcyhtZW51KVwiPlxuICAgICAgICAgICAgPG5vZi1hY3Rpb24tbGlzdCBbbWVudUhvbGRlcl09XCJtZW51XCI+PC9ub2YtYWN0aW9uLWxpc3Q+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgIDwvZGl2PlxuPC9uZy1jb250YWluZXI+XG4iXX0=