@jsonforms/angular-material
Version:
Material Renderer Set for Angular module of JSON Forms
254 lines (250 loc) • 31.6 kB
JavaScript
/*
The MIT License
Copyright (c) 2017-2019 EclipseSource Munich
https://github.com/eclipsesource/jsonforms
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
import some from 'lodash/some';
import get from 'lodash/get';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, } from '@angular/core';
import { JsonFormsAngularService, JsonFormsArrayControl, } from '@jsonforms/angular';
import { arrayDefaultTranslations, createDefaultValue, decode, defaultJsonFormsI18nState, findUISchema, getArrayTranslations, getFirstPrimitiveProp, mapDispatchToArrayControlProps, mapStateToArrayControlProps, rankWith, setReadonly, uiTypeIs, } from '@jsonforms/core';
import * as i0 from "@angular/core";
import * as i1 from "@jsonforms/angular";
import * as i2 from "@angular/common";
import * as i3 from "@angular/material/sidenav";
import * as i4 from "@angular/material/list";
import * as i5 from "@angular/material/button";
import * as i6 from "@angular/material/icon";
import * as i7 from "./detail";
const keywords = ['#', 'properties', 'items'];
export const removeSchemaKeywords = (path) => {
return decode(path
.split('/')
.filter((s) => !some(keywords, (key) => key === s))
.join('.'));
};
export class MasterListComponent extends JsonFormsArrayControl {
changeDetectorRef;
masterItems;
selectedItem;
selectedItemIdx;
addItem;
removeItems;
highlightedIdx;
translations;
constructor(jsonformsService, changeDetectorRef) {
super(jsonformsService);
this.changeDetectorRef = changeDetectorRef;
}
onListItemHover(idx) {
this.highlightedIdx = idx;
}
trackElement(_index, element) {
return element ? element.label : null;
}
ngOnInit() {
super.ngOnInit();
const dispatch = this.jsonFormsService.updateCore.bind(this.jsonFormsService);
const { addItem, removeItems } = mapDispatchToArrayControlProps(dispatch);
this.addItem = addItem;
this.removeItems = removeItems;
}
mapAdditionalProps(props) {
const { data, path, schema, uischema } = props;
const controlElement = uischema;
this.propsPath = props.path;
const detailUISchema = findUISchema(props.uischemas, schema, `${controlElement.scope}/items`, props.path, 'VerticalLayout', controlElement, props.rootSchema);
if (!this.isEnabled()) {
setReadonly(detailUISchema);
}
this.translations = props.translations;
const masterItems = (data || []).map((d, index) => {
const labelRefInstancePath = controlElement.options?.labelRef &&
removeSchemaKeywords(controlElement.options.labelRef);
const isPrimitive = d !== undefined && typeof d !== 'object';
const masterItem = {
label: isPrimitive
? d.toString()
: get(d, labelRefInstancePath ?? getFirstPrimitiveProp(schema)),
data: d,
path: `${path}.${index}`,
schema,
uischema: detailUISchema,
};
return masterItem;
});
this.masterItems = masterItems;
let newSelectedIdx = -1;
let newSelectedItem;
if (this.masterItems.length === 0) {
// unset select if no elements anymore
this.selectedItem = undefined;
this.selectedItemIdx = -1;
}
else if (this.selectedItemIdx >= this.masterItems.length) {
// the previous index is to high, reduce it to the maximal possible
newSelectedIdx = this.masterItems.length - 1;
newSelectedItem = this.masterItems[newSelectedIdx];
}
else if (this.selectedItemIdx !== -1 &&
this.selectedItemIdx < this.masterItems.length) {
newSelectedIdx = this.selectedItemIdx;
newSelectedItem = this.masterItems[this.selectedItemIdx];
}
if (newSelectedItem !== undefined &&
this.selectedItem !== undefined &&
(newSelectedItem.label === this.selectedItem.label ||
newSelectedItem.path === this.selectedItem.path)) {
// after checking that we are on the same path, set selection
this.selectedItem = newSelectedItem;
this.selectedItemIdx = newSelectedIdx;
}
else if (this.masterItems.length > 0) {
// pre-select 1st entry if the previous selected element as fallback
this.selectedItem = this.masterItems[0];
this.selectedItemIdx = 0;
}
this.changeDetectorRef.markForCheck();
}
onSelect(item, idx) {
this.selectedItem = item;
this.selectedItemIdx = idx;
}
onAddClick() {
this.addItem(this.propsPath, createDefaultValue(this.scopedSchema, this.rootSchema))();
}
onDeleteClick(item) {
this.removeItems(this.propsPath, [item])();
}
mapToProps(state) {
const props = mapStateToArrayControlProps(state, this.getOwnProps());
const t = state.jsonforms.i18n?.translate ?? defaultJsonFormsI18nState.translate;
const translations = getArrayTranslations(t, arrayDefaultTranslations, props.i18nKeyPrefix, props.label);
return { ...props, translations };
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: MasterListComponent, deps: [{ token: i1.JsonFormsAngularService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.10", type: MasterListComponent, selector: "jsonforms-list-with-detail-master", usesInheritance: true, ngImport: i0, template: `
<mat-sidenav-container
[ngStyle]="{ display: hidden ? 'none' : '' }"
autosize="true"
class="container"
>
<mat-sidenav mode="side" opened>
<mat-nav-list>
<mat-list-item *ngIf="masterItems.length === 0">{{
translations.noDataMessage
}}</mat-list-item>
<mat-list-item
*ngFor="
let item of masterItems;
let i = index;
trackBy: trackElement
"
[class.selected]="item === selectedItem"
(click)="onSelect(item, i)"
(mouseover)="onListItemHover(i)"
(mouseout)="onListItemHover(undefined)"
>
<a matLine>{{ item.label || 'No label set' }}</a>
<button
mat-icon-button
class="button item-button hide"
(click)="onDeleteClick(i)"
[ngClass]="{ show: highlightedIdx == i }"
*ngIf="isEnabled()"
>
<mat-icon mat-list-icon>delete</mat-icon>
</button>
</mat-list-item>
</mat-nav-list>
<button
mat-fab
color="primary"
class="add-button"
(click)="onAddClick()"
*ngIf="isEnabled()"
>
<mat-icon [attr.aria-label]="translations.addAriaLabel">add</mat-icon>
</button>
</mat-sidenav>
<mat-sidenav-content class="content">
<jsonforms-detail
*ngIf="selectedItem"
[item]="selectedItem"
></jsonforms-detail>
</mat-sidenav-content>
</mat-sidenav-container>
`, isInline: true, styles: ["mat-list-item.selected{background:#0000000a}.container{height:100vh}.content{padding:15px;background-color:#fff}.add-button{float:right;margin-top:.5em;margin-right:.25em}.button{float:right;margin-right:.25em}.item-button{position:absolute;top:0;right:0}.hide{display:none}.show{display:inline-block}mat-sidenav{width:20%}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i3.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i3.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i3.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "component", type: i4.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i4.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i5.MatFabButton, selector: "button[mat-fab]", inputs: ["extended"], exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i7.JsonFormsDetailComponent, selector: "jsonforms-detail", inputs: ["item"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: MasterListComponent, decorators: [{
type: Component,
args: [{ selector: 'jsonforms-list-with-detail-master', template: `
<mat-sidenav-container
[ngStyle]="{ display: hidden ? 'none' : '' }"
autosize="true"
class="container"
>
<mat-sidenav mode="side" opened>
<mat-nav-list>
<mat-list-item *ngIf="masterItems.length === 0">{{
translations.noDataMessage
}}</mat-list-item>
<mat-list-item
*ngFor="
let item of masterItems;
let i = index;
trackBy: trackElement
"
[class.selected]="item === selectedItem"
(click)="onSelect(item, i)"
(mouseover)="onListItemHover(i)"
(mouseout)="onListItemHover(undefined)"
>
<a matLine>{{ item.label || 'No label set' }}</a>
<button
mat-icon-button
class="button item-button hide"
(click)="onDeleteClick(i)"
[ngClass]="{ show: highlightedIdx == i }"
*ngIf="isEnabled()"
>
<mat-icon mat-list-icon>delete</mat-icon>
</button>
</mat-list-item>
</mat-nav-list>
<button
mat-fab
color="primary"
class="add-button"
(click)="onAddClick()"
*ngIf="isEnabled()"
>
<mat-icon [attr.aria-label]="translations.addAriaLabel">add</mat-icon>
</button>
</mat-sidenav>
<mat-sidenav-content class="content">
<jsonforms-detail
*ngIf="selectedItem"
[item]="selectedItem"
></jsonforms-detail>
</mat-sidenav-content>
</mat-sidenav-container>
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["mat-list-item.selected{background:#0000000a}.container{height:100vh}.content{padding:15px;background-color:#fff}.add-button{float:right;margin-top:.5em;margin-right:.25em}.button{float:right;margin-right:.25em}.item-button{position:absolute;top:0;right:0}.hide{display:none}.show{display:inline-block}mat-sidenav{width:20%}\n"] }]
}], ctorParameters: () => [{ type: i1.JsonFormsAngularService }, { type: i0.ChangeDetectorRef }] });
export const masterDetailTester = rankWith(4, uiTypeIs('ListWithDetail'));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFzdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYnJhcnkvb3RoZXIvbWFzdGVyLWRldGFpbC9tYXN0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBdUJFO0FBQ0YsT0FBTyxJQUFJLE1BQU0sYUFBYSxDQUFDO0FBQy9CLE9BQU8sR0FBRyxNQUFNLFlBQVksQ0FBQztBQUM3QixPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEdBRVYsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixxQkFBcUIsR0FDdEIsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBRUwsd0JBQXdCLEVBR3hCLGtCQUFrQixFQUNsQixNQUFNLEVBQ04seUJBQXlCLEVBQ3pCLFlBQVksRUFDWixvQkFBb0IsRUFDcEIscUJBQXFCLEVBRXJCLDhCQUE4QixFQUM5QiwyQkFBMkIsRUFFM0IsUUFBUSxFQUNSLFdBQVcsRUFFWCxRQUFRLEdBQ1QsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7Ozs7O0FBRXpCLE1BQU0sUUFBUSxHQUFHLENBQUMsR0FBRyxFQUFFLFlBQVksRUFBRSxPQUFPLENBQUMsQ0FBQztBQUU5QyxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLElBQVksRUFBRSxFQUFFO0lBQ25ELE9BQU8sTUFBTSxDQUNYLElBQUk7U0FDRCxLQUFLLENBQUMsR0FBRyxDQUFDO1NBQ1YsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUNsRCxJQUFJLENBQUMsR0FBRyxDQUFDLENBQ2IsQ0FBQztBQUNKLENBQUMsQ0FBQztBQWdHRixNQUFNLE9BQU8sbUJBQ1gsU0FB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O0dBbURUOzs0RkF5Q1UsbUJBQW1CO2tCQTlGL0IsU0FBUzsrQkFDRSxtQ0FBbUMsWUFDbkM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1EVCxtQkF1Q2dCLHVCQUF1QixDQUFDLE1BQU07O0FBaUpqRCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBaUIsUUFBUSxDQUN0RCxDQUFDLEVBQ0QsUUFBUSxDQUFDLGdCQUFnQixDQUFDLENBQzNCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICBUaGUgTUlUIExpY2Vuc2VcbiAgXG4gIENvcHlyaWdodCAoYykgMjAxNy0yMDE5IEVjbGlwc2VTb3VyY2UgTXVuaWNoXG4gIGh0dHBzOi8vZ2l0aHViLmNvbS9lY2xpcHNlc291cmNlL2pzb25mb3Jtc1xuICBcbiAgUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4gIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbiAgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuICBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbiAgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbiAgXG4gIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4gIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuICBcbiAgVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuICBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbiAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbiAgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbiAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuICBUSEUgU09GVFdBUkUuXG4qL1xuaW1wb3J0IHNvbWUgZnJvbSAnbG9kYXNoL3NvbWUnO1xuaW1wb3J0IGdldCBmcm9tICdsb2Rhc2gvZ2V0JztcbmltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBPbkluaXQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgSnNvbkZvcm1zQW5ndWxhclNlcnZpY2UsXG4gIEpzb25Gb3Jtc0FycmF5Q29udHJvbCxcbn0gZnJvbSAnQGpzb25mb3Jtcy9hbmd1bGFyJztcbmltcG9ydCB7XG4gIEFycmF5Q29udHJvbFByb3BzLFxuICBhcnJheURlZmF1bHRUcmFuc2xhdGlvbnMsXG4gIEFycmF5VHJhbnNsYXRpb25zLFxuICBDb250cm9sRWxlbWVudCxcbiAgY3JlYXRlRGVmYXVsdFZhbHVlLFxuICBkZWNvZGUsXG4gIGRlZmF1bHRKc29uRm9ybXNJMThuU3RhdGUsXG4gIGZpbmRVSVNjaGVtYSxcbiAgZ2V0QXJyYXlUcmFuc2xhdGlvbnMsXG4gIGdldEZpcnN0UHJpbWl0aXZlUHJvcCxcbiAgSnNvbkZvcm1zU3RhdGUsXG4gIG1hcERpc3BhdGNoVG9BcnJheUNvbnRyb2xQcm9wcyxcbiAgbWFwU3RhdGVUb0FycmF5Q29udHJvbFByb3BzLFxuICBSYW5rZWRUZXN0ZXIsXG4gIHJhbmtXaXRoLFxuICBzZXRSZWFkb25seSxcbiAgU3RhdGVQcm9wc09mQXJyYXlDb250cm9sLFxuICB1aVR5cGVJcyxcbn0gZnJvbSAnQGpzb25mb3Jtcy9jb3JlJztcblxuY29uc3Qga2V5d29yZHMgPSBbJyMnLCAncHJvcGVydGllcycsICdpdGVtcyddO1xuXG5leHBvcnQgY29uc3QgcmVtb3ZlU2NoZW1hS2V5d29yZHMgPSAocGF0aDogc3RyaW5nKSA9PiB7XG4gIHJldHVybiBkZWNvZGUoXG4gICAgcGF0aFxuICAgICAgLnNwbGl0KCcvJylcbiAgICAgIC5maWx0ZXIoKHMpID0+ICFzb21lKGtleXdvcmRzLCAoa2V5KSA9PiBrZXkgPT09IHMpKVxuICAgICAgLmpvaW4oJy4nKVxuICApO1xufTtcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnanNvbmZvcm1zLWxpc3Qtd2l0aC1kZXRhaWwtbWFzdGVyJyxcbiAgdGVtcGxhdGU6IGBcbiAgICA8bWF0LXNpZGVuYXYtY29udGFpbmVyXG4gICAgICBbbmdTdHlsZV09XCJ7IGRpc3BsYXk6IGhpZGRlbiA/ICdub25lJyA6ICcnIH1cIlxuICAgICAgYXV0b3NpemU9XCJ0cnVlXCJcbiAgICAgIGNsYXNzPVwiY29udGFpbmVyXCJcbiAgICA+XG4gICAgICA8bWF0LXNpZGVuYXYgbW9kZT1cInNpZGVcIiBvcGVuZWQ+XG4gICAgICAgIDxtYXQtbmF2LWxpc3Q+XG4gICAgICAgICAgPG1hdC1saXN0LWl0ZW0gKm5nSWY9XCJtYXN0ZXJJdGVtcy5sZW5ndGggPT09IDBcIj57e1xuICAgICAgICAgICAgdHJhbnNsYXRpb25zLm5vRGF0YU1lc3NhZ2VcbiAgICAgICAgICB9fTwvbWF0LWxpc3QtaXRlbT5cbiAgICAgICAgICA8bWF0LWxpc3QtaXRlbVxuICAgICAgICAgICAgKm5nRm9yPVwiXG4gICAgICAgICAgICAgIGxldCBpdGVtIG9mIG1hc3Rlckl0ZW1zO1xuICAgICAgICAgICAgICBsZXQgaSA9IGluZGV4O1xuICAgICAgICAgICAgICB0cmFja0J5OiB0cmFja0VsZW1lbnRcbiAgICAgICAgICAgIFwiXG4gICAgICAgICAgICBbY2xhc3Muc2VsZWN0ZWRdPVwiaXRlbSA9PT0gc2VsZWN0ZWRJdGVtXCJcbiAgICAgICAgICAgIChjbGljayk9XCJvblNlbGVjdChpdGVtLCBpKVwiXG4gICAgICAgICAgICAobW91c2VvdmVyKT1cIm9uTGlzdEl0ZW1Ib3ZlcihpKVwiXG4gICAgICAgICAgICAobW91c2VvdXQpPVwib25MaXN0SXRlbUhvdmVyKHVuZGVmaW5lZClcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxhIG1hdExpbmU+e3sgaXRlbS5sYWJlbCB8fCAnTm8gbGFiZWwgc2V0JyB9fTwvYT5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICAgICAgIGNsYXNzPVwiYnV0dG9uIGl0ZW0tYnV0dG9uIGhpZGVcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwib25EZWxldGVDbGljayhpKVwiXG4gICAgICAgICAgICAgIFtuZ0NsYXNzXT1cInsgc2hvdzogaGlnaGxpZ2h0ZWRJZHggPT0gaSB9XCJcbiAgICAgICAgICAgICAgKm5nSWY9XCJpc0VuYWJsZWQoKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxtYXQtaWNvbiBtYXQtbGlzdC1pY29uPmRlbGV0ZTwvbWF0LWljb24+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L21hdC1saXN0LWl0ZW0+XG4gICAgICAgIDwvbWF0LW5hdi1saXN0PlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgbWF0LWZhYlxuICAgICAgICAgIGNvbG9yPVwicHJpbWFyeVwiXG4gICAgICAgICAgY2xhc3M9XCJhZGQtYnV0dG9uXCJcbiAgICAgICAgICAoY2xpY2spPVwib25BZGRDbGljaygpXCJcbiAgICAgICAgICAqbmdJZj1cImlzRW5hYmxlZCgpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxtYXQtaWNvbiBbYXR0ci5hcmlhLWxhYmVsXT1cInRyYW5zbGF0aW9ucy5hZGRBcmlhTGFiZWxcIj5hZGQ8L21hdC1pY29uPlxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvbWF0LXNpZGVuYXY+XG4gICAgICA8bWF0LXNpZGVuYXYtY29udGVudCBjbGFzcz1cImNvbnRlbnRcIj5cbiAgICAgICAgPGpzb25mb3Jtcy1kZXRhaWxcbiAgICAgICAgICAqbmdJZj1cInNlbGVjdGVkSXRlbVwiXG4gICAgICAgICAgW2l0ZW1dPVwic2VsZWN0ZWRJdGVtXCJcbiAgICAgICAgPjwvanNvbmZvcm1zLWRldGFpbD5cbiAgICAgIDwvbWF0LXNpZGVuYXYtY29udGVudD5cbiAgICA8L21hdC1zaWRlbmF2LWNvbnRhaW5lcj5cbiAgYCxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgLyogVE9ETyhtZGMtbWlncmF0aW9uKTogVGhlIGZvbGxvd2luZyBydWxlIHRhcmdldHMgaW50ZXJuYWwgY2xhc3NlcyBvZiBsaXN0IHRoYXQgbWF5IG5vIGxvbmdlciBhcHBseSBmb3IgdGhlIE1EQyB2ZXJzaW9uLiAqL1xuICAgICAgbWF0LWxpc3QtaXRlbS5zZWxlY3RlZCB7XG4gICAgICAgIGJhY2tncm91bmQ6IHJnYmEoMCwgMCwgMCwgMC4wNCk7XG4gICAgICB9XG4gICAgICAuY29udGFpbmVyIHtcbiAgICAgICAgaGVpZ2h0OiAxMDB2aDtcbiAgICAgIH1cbiAgICAgIC5jb250ZW50IHtcbiAgICAgICAgcGFkZGluZzogMTVweDtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZjtcbiAgICAgIH1cbiAgICAgIC5hZGQtYnV0dG9uIHtcbiAgICAgICAgZmxvYXQ6IHJpZ2h0O1xuICAgICAgICBtYXJnaW4tdG9wOiAwLjVlbTtcbiAgICAgICAgbWFyZ2luLXJpZ2h0OiAwLjI1ZW07XG4gICAgICB9XG4gICAgICAuYnV0dG9uIHtcbiAgICAgICAgZmxvYXQ6IHJpZ2h0O1xuICAgICAgICBtYXJnaW4tcmlnaHQ6IDAuMjVlbTtcbiAgICAgIH1cbiAgICAgIC5pdGVtLWJ1dHRvbiB7XG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgdG9wOiAwO1xuICAgICAgICByaWdodDogMDtcbiAgICAgIH1cbiAgICAgIC5oaWRlIHtcbiAgICAgICAgZGlzcGxheTogbm9uZTtcbiAgICAgIH1cbiAgICAgIC5zaG93IHtcbiAgICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICAgICAgfVxuICAgICAgbWF0LXNpZGVuYXYge1xuICAgICAgICB3aWR0aDogMjAlO1xuICAgICAgfVxuICAgIGAsXG4gIF0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBNYXN0ZXJMaXN0Q29tcG9uZW50XG4gIGV4dGVuZHMgSnNvbkZvcm1zQXJyYXlDb250cm9sXG4gIGltcGxlbWVudHMgT25Jbml0XG57XG4gIG1hc3Rlckl0ZW1zOiBhbnlbXTtcbiAgc2VsZWN0ZWRJdGVtOiBhbnk7XG4gIHNlbGVjdGVkSXRlbUlkeDogbnVtYmVyO1xuICBhZGRJdGVtOiAocGF0aDogc3RyaW5nLCB2YWx1ZTogYW55KSA9PiAoKSA9PiB2b2lkO1xuICByZW1vdmVJdGVtczogKHBhdGg6IHN0cmluZywgdG9EZWxldGU6IG51bWJlcltdKSA9PiAoKSA9PiB2b2lkO1xuICBoaWdobGlnaHRlZElkeDogbnVtYmVyO1xuICB0cmFuc2xhdGlvbnM6IEFycmF5VHJhbnNsYXRpb25zO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGpzb25mb3Jtc1NlcnZpY2U6IEpzb25Gb3Jtc0FuZ3VsYXJTZXJ2aWNlLFxuICAgIHByaXZhdGUgY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmXG4gICkge1xuICAgIHN1cGVyKGpzb25mb3Jtc1NlcnZpY2UpO1xuICB9XG5cbiAgb25MaXN0SXRlbUhvdmVyKGlkeDogbnVtYmVyKSB7XG4gICAgdGhpcy5oaWdobGlnaHRlZElkeCA9IGlkeDtcbiAgfVxuXG4gIHRyYWNrRWxlbWVudChfaW5kZXg6IG51bWJlciwgZWxlbWVudDogYW55KSB7XG4gICAgcmV0dXJuIGVsZW1lbnQgPyBlbGVtZW50LmxhYmVsIDogbnVsbDtcbiAgfVxuXG4gIG5nT25Jbml0KCkge1xuICAgIHN1cGVyLm5nT25Jbml0KCk7XG4gICAgY29uc3QgZGlzcGF0Y2ggPSB0aGlzLmpzb25Gb3Jtc1NlcnZpY2UudXBkYXRlQ29yZS5iaW5kKFxuICAgICAgdGhpcy5qc29uRm9ybXNTZXJ2aWNlXG4gICAgKTtcbiAgICBjb25zdCB7IGFkZEl0ZW0sIHJlbW92ZUl0ZW1zIH0gPSBtYXBEaXNwYXRjaFRvQXJyYXlDb250cm9sUHJvcHMoZGlzcGF0Y2gpO1xuICAgIHRoaXMuYWRkSXRlbSA9IGFkZEl0ZW07XG4gICAgdGhpcy5yZW1vdmVJdGVtcyA9IHJlbW92ZUl0ZW1zO1xuICB9XG5cbiAgbWFwQWRkaXRpb25hbFByb3BzKFxuICAgIHByb3BzOiBBcnJheUNvbnRyb2xQcm9wcyAmIHsgdHJhbnNsYXRpb25zOiBBcnJheVRyYW5zbGF0aW9ucyB9XG4gICkge1xuICAgIGNvbnN0IHsgZGF0YSwgcGF0aCwgc2NoZW1hLCB1aXNjaGVtYSB9ID0gcHJvcHM7XG4gICAgY29uc3QgY29udHJvbEVsZW1lbnQgPSB1aXNjaGVtYSBhcyBDb250cm9sRWxlbWVudDtcbiAgICB0aGlzLnByb3BzUGF0aCA9IHByb3BzLnBhdGg7XG4gICAgY29uc3QgZGV0YWlsVUlTY2hlbWEgPSBmaW5kVUlTY2hlbWEoXG4gICAgICBwcm9wcy51aXNjaGVtYXMsXG4gICAgICBzY2hlbWEsXG4gICAgICBgJHtjb250cm9sRWxlbWVudC5zY29wZX0vaXRlbXNgLFxuICAgICAgcHJvcHMucGF0aCxcbiAgICAgICdWZXJ0aWNhbExheW91dCcsXG4gICAgICBjb250cm9sRWxlbWVudCxcbiAgICAgIHByb3BzLnJvb3RTY2hlbWFcbiAgICApO1xuXG4gICAgaWYgKCF0aGlzLmlzRW5hYmxlZCgpKSB7XG4gICAgICBzZXRSZWFkb25seShkZXRhaWxVSVNjaGVtYSk7XG4gICAgfVxuXG4gICAgdGhpcy50cmFuc2xhdGlvbnMgPSBwcm9wcy50cmFuc2xhdGlvbnM7XG5cbiAgICBjb25zdCBtYXN0ZXJJdGVtcyA9IChkYXRhIHx8IFtdKS5tYXAoKGQ6IGFueSwgaW5kZXg6IG51bWJlcikgPT4ge1xuICAgICAgY29uc3QgbGFiZWxSZWZJbnN0YW5jZVBhdGggPVxuICAgICAgICBjb250cm9sRWxlbWVudC5vcHRpb25zPy5sYWJlbFJlZiAmJlxuICAgICAgICByZW1vdmVTY2hlbWFLZXl3b3Jkcyhjb250cm9sRWxlbWVudC5vcHRpb25zLmxhYmVsUmVmKTtcbiAgICAgIGNvbnN0IGlzUHJpbWl0aXZlID0gZCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiBkICE9PSAnb2JqZWN0JztcbiAgICAgIGNvbnN0IG1hc3Rlckl0ZW0gPSB7XG4gICAgICAgIGxhYmVsOiBpc1ByaW1pdGl2ZVxuICAgICAgICAgID8gZC50b1N0cmluZygpXG4gICAgICAgICAgOiBnZXQoZCwgbGFiZWxSZWZJbnN0YW5jZVBhdGggPz8gZ2V0Rmlyc3RQcmltaXRpdmVQcm9wKHNjaGVtYSkpLFxuICAgICAgICBkYXRhOiBkLFxuICAgICAgICBwYXRoOiBgJHtwYXRofS4ke2luZGV4fWAsXG4gICAgICAgIHNjaGVtYSxcbiAgICAgICAgdWlzY2hlbWE6IGRldGFpbFVJU2NoZW1hLFxuICAgICAgfTtcbiAgICAgIHJldHVybiBtYXN0ZXJJdGVtO1xuICAgIH0pO1xuICAgIHRoaXMubWFzdGVySXRlbXMgPSBtYXN0ZXJJdGVtcztcbiAgICBsZXQgbmV3U2VsZWN0ZWRJZHggPSAtMTtcbiAgICBsZXQgbmV3U2VsZWN0ZWRJdGVtO1xuICAgIGlmICh0aGlzLm1hc3Rlckl0ZW1zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgLy8gdW5zZXQgc2VsZWN0IGlmIG5vIGVsZW1lbnRzIGFueW1vcmVcbiAgICAgIHRoaXMuc2VsZWN0ZWRJdGVtID0gdW5kZWZpbmVkO1xuICAgICAgdGhpcy5zZWxlY3RlZEl0ZW1JZHggPSAtMTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuc2VsZWN0ZWRJdGVtSWR4ID49IHRoaXMubWFzdGVySXRlbXMubGVuZ3RoKSB7XG4gICAgICAvLyB0aGUgcHJldmlvdXMgaW5kZXggaXMgdG8gaGlnaCwgcmVkdWNlIGl0IHRvIHRoZSBtYXhpbWFsIHBvc3NpYmxlXG4gICAgICBuZXdTZWxlY3RlZElkeCA9IHRoaXMubWFzdGVySXRlbXMubGVuZ3RoIC0gMTtcbiAgICAgIG5ld1NlbGVjdGVkSXRlbSA9IHRoaXMubWFzdGVySXRlbXNbbmV3U2VsZWN0ZWRJZHhdO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICB0aGlzLnNlbGVjdGVkSXRlbUlkeCAhPT0gLTEgJiZcbiAgICAgIHRoaXMuc2VsZWN0ZWRJdGVtSWR4IDwgdGhpcy5tYXN0ZXJJdGVtcy5sZW5ndGhcbiAgICApIHtcbiAgICAgIG5ld1NlbGVjdGVkSWR4ID0gdGhpcy5zZWxlY3RlZEl0ZW1JZHg7XG4gICAgICBuZXdTZWxlY3RlZEl0ZW0gPSB0aGlzLm1hc3Rlckl0ZW1zW3RoaXMuc2VsZWN0ZWRJdGVtSWR4XTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBuZXdTZWxlY3RlZEl0ZW0gIT09IHVuZGVmaW5lZCAmJlxuICAgICAgdGhpcy5zZWxlY3RlZEl0ZW0gIT09IHVuZGVmaW5lZCAmJlxuICAgICAgKG5ld1NlbGVjdGVkSXRlbS5sYWJlbCA9PT0gdGhpcy5zZWxlY3RlZEl0ZW0ubGFiZWwgfHxcbiAgICAgICAgbmV3U2VsZWN0ZWRJdGVtLnBhdGggPT09IHRoaXMuc2VsZWN0ZWRJdGVtLnBhdGgpXG4gICAgKSB7XG4gICAgICAvLyBhZnRlciBjaGVja2luZyB0aGF0IHdlIGFyZSBvbiB0aGUgc2FtZSBwYXRoLCBzZXQgc2VsZWN0aW9uXG4gICAgICB0aGlzLnNlbGVjdGVkSXRlbSA9IG5ld1NlbGVjdGVkSXRlbTtcbiAgICAgIHRoaXMuc2VsZWN0ZWRJdGVtSWR4ID0gbmV3U2VsZWN0ZWRJZHg7XG4gICAgfSBlbHNlIGlmICh0aGlzLm1hc3Rlckl0ZW1zLmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIHByZS1zZWxlY3QgMXN0IGVudHJ5IGlmIHRoZSBwcmV2aW91cyBzZWxlY3RlZCBlbGVtZW50IGFzIGZhbGxiYWNrXG4gICAgICB0aGlzLnNlbGVjdGVkSXRlbSA9IHRoaXMubWFzdGVySXRlbXNbMF07XG4gICAgICB0aGlzLnNlbGVjdGVkSXRlbUlkeCA9IDA7XG4gICAgfVxuICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBvblNlbGVjdChpdGVtOiBhbnksIGlkeDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5zZWxlY3RlZEl0ZW0gPSBpdGVtO1xuICAgIHRoaXMuc2VsZWN0ZWRJdGVtSWR4ID0gaWR4O1xuICB9XG5cbiAgb25BZGRDbGljaygpIHtcbiAgICB0aGlzLmFkZEl0ZW0oXG4gICAgICB0aGlzLnByb3BzUGF0aCxcbiAgICAgIGNyZWF0ZURlZmF1bHRWYWx1ZSh0aGlzLnNjb3BlZFNjaGVtYSwgdGhpcy5yb290U2NoZW1hKVxuICAgICkoKTtcbiAgfVxuXG4gIG9uRGVsZXRlQ2xpY2soaXRlbTogbnVtYmVyKSB7XG4gICAgdGhpcy5yZW1vdmVJdGVtcyh0aGlzLnByb3BzUGF0aCwgW2l0ZW1dKSgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG1hcFRvUHJvcHMoXG4gICAgc3RhdGU6IEpzb25Gb3Jtc1N0YXRlXG4gICk6IFN0YXRlUHJvcHNPZkFycmF5Q29udHJvbCAmIHsgdHJhbnNsYXRpb25zOiBBcnJheVRyYW5zbGF0aW9ucyB9IHtcbiAgICBjb25zdCBwcm9wcyA9IG1hcFN0YXRlVG9BcnJheUNvbnRyb2xQcm9wcyhzdGF0ZSwgdGhpcy5nZXRPd25Qcm9wcygpKTtcbiAgICBjb25zdCB0ID1cbiAgICAgIHN0YXRlLmpzb25mb3Jtcy5pMThuPy50cmFuc2xhdGUgPz8gZGVmYXVsdEpzb25Gb3Jtc0kxOG5TdGF0ZS50cmFuc2xhdGU7XG4gICAgY29uc3QgdHJhbnNsYXRpb25zID0gZ2V0QXJyYXlUcmFuc2xhdGlvbnMoXG4gICAgICB0LFxuICAgICAgYXJyYXlEZWZhdWx0VHJhbnNsYXRpb25zLFxuICAgICAgcHJvcHMuaTE4bktleVByZWZpeCxcbiAgICAgIHByb3BzLmxhYmVsXG4gICAgKTtcbiAgICByZXR1cm4geyAuLi5wcm9wcywgdHJhbnNsYXRpb25zIH07XG4gIH1cbn1cblxuZXhwb3J0IGNvbnN0IG1hc3RlckRldGFpbFRlc3RlcjogUmFua2VkVGVzdGVyID0gcmFua1dpdGgoXG4gIDQsXG4gIHVpVHlwZUlzKCdMaXN0V2l0aERldGFpbCcpXG4pO1xuIl19