UNPKG

gentics-ui-core

Version:

This is the common core framework for the Gentics CMS and Mesh UI, and other Angular applications.

268 lines 37 kB
import { ChangeDetectionStrategy, Component, Directive, ElementRef, EventEmitter, HostBinding, Input, Output, ViewChild } from '@angular/core'; import { animate, animateChild, AnimationBuilder, keyframes, query, state, style, transition, trigger } from '@angular/animations'; import { UserAgentRef } from '../modal/user-agent-ref'; import * as i0 from "@angular/core"; import * as i1 from "@angular/animations"; import * as i2 from "../modal/user-agent-ref"; import * as i3 from "@angular/common"; // must export and be a function (not arrow function expression) to prevent ngc errors export function animateCubicBezier(millis) { return animate(`${millis}ms cubic-bezier(0.215, 0.61, 0.355, 1)`); } /** * The SideMenu component is an off-canvas menu with a toggle button which can be * used to toggle the state. The component itself is stateless, and relies on the value passed in as * the `opened` prop to set its state. Toggling must also be handled by the host component. * * The toggle button must be placed within a `<gtx-side-menu-toggle>` element. All other content will be projected * into the main body of the menu. * * **Note**: For the side menu to be positioned correctly, its container must have the `position` CSS attribute set. * * ```html * <gtx-side-menu [opened]="displayMenu" (toggle)="displayMenu = $event"> * <gtx-side-menu-toggle> * <button>Toggle</button> * </gtx-side-menu-toggle> * <div class="my-menu-content"> * <ul> * <li>Menu item 1</li> * <li>Menu item 2</li> * <li>Menu item 3</li> * <li>Menu item 4</li> * <li>Menu item 5</li> * </ul> * </div> * </gtx-side-menu> * ``` */ export class SideMenu { constructor(animationBuilder, elementRef, userAgentRef) { this.animationBuilder = animationBuilder; this.elementRef = elementRef; this.userAgentRef = userAgentRef; /** * Sets the state of the menu: true = opened, false = closed. */ this.opened = false; /** * Sets whether the menu should appear to the left or the right of the screen. Defaults to 'left'. */ this.position = 'left'; /** * Sets the width of the menu. Should be a valid CSS width value, e.g. '400px', '20vw', '30em'. **Note** that * percentage values should be avoided, since they will produce unexpected results. */ this.width = '300px'; /** * The distance in pixels between the edge of the container and the toggle button when the menu is closed. */ this.toggleButtonOffset = 20; /** * Fired when the toggle button is clicked. The value is equal to * the value of the `opened` */ this.toggle = new EventEmitter(); } get alignmentClassLeft() { return this.position === 'left'; } get alignmentClassRight() { return this.position === 'right'; } get animationParams() { const buttonWidth = parseInt(this.toggleButton.nativeElement.offsetWidth); let transform = this.position === 'left' ? `translateX(${this.toggleButtonOffset}px)` : `translateX(-${this.toggleButtonOffset}px)`; if (this.opened) { // IE11 cannot use `calc()` with transform properties, so instead we can just use multiple separate // translateX() statements. transform = this.position === 'left' ? `translateX(${this.responsiveWidth}) translateX(-${buttonWidth}px) translateX(-${this.toggleButtonOffset}px)` : `translateX(-${this.responsiveWidth}) translateX(+${buttonWidth}px) translateX(+${this.toggleButtonOffset}px)`; } return { value: this.opened ? 'open' : 'closed', params: { transform } }; } get menuAnimationState() { // There seems to be an open Angular bug with leaving animations on IE and Edge, // so we only play that animation if we are not on IE or Edge. // https://github.com/angular/angular/issues/29463 // https://jira.gentics.com/browse/SUP-8106 const openState = !this.userAgentRef.isEdge && !this.userAgentRef.isIE11 ? 'open' : 'openIE'; return this.opened ? openState : 'void'; } /** * Returns the width of the menu, taking into account screen width */ get responsiveWidth() { const screenWidth = window.innerWidth; if (screenWidth < 600) { return `${this.ancestorWithWidth.offsetWidth}px`; } return this.width; } get menuParams() { return this.opened ? 'open' : 'closed'; } /** * We need to know the width of the element in which the SideMenu is nested. Here we traverse the DOM tree * looking for the first ancestor element with a non-zero offsetWidth. */ ngAfterViewInit() { let ancestorWithWidth; let currentElement = this.elementRef.nativeElement; const maxLevels = 10; let i = 0; while (!ancestorWithWidth && i < maxLevels) { const parent = currentElement.parentElement; if (0 < parent.offsetWidth) { ancestorWithWidth = parent; } currentElement = parent; i++; } this.ancestorWithWidth = ancestorWithWidth; } /** * The AnimationBuilder is used here because the desired animation result could not be achieved using the * metadata-based approach alone. This issue describes the problem: https://github.com/angular/angular/issues/20796 * * If that issue gets resolved then this could be simplified and we may be able to drop the AnimationBuilder * and move this logic into the animationParams getter. */ animationStarted(event) { const menu = this.elementRef.nativeElement.querySelector('.menu'); if (menu) { if (this.player) { this.player.destroy(); } const sign = this.position === 'right' ? '' : '-'; let startX = '0'; let endX = `${sign}${this.responsiveWidth}`; if (event.toState === 'open') { [startX, endX] = [endX, startX]; } const factory = this.animationBuilder.build([ animate('0.3s', keyframes([ style({ transform: `translateX(${startX})`, offset: 0 }), style({ transform: `translateX(${endX})`, offset: 0.7 }) ])) ]); this.player = factory.create(menu, {}); this.player.play(); } } toggleState() { this.toggle.emit(!this.opened); } close() { if (this.opened === true) { this.toggleState(); } } } /** @nocollapse */ SideMenu.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SideMenu, deps: [{ token: i1.AnimationBuilder }, { token: i0.ElementRef }, { token: i2.UserAgentRef }], target: i0.ɵɵFactoryTarget.Component }); /** @nocollapse */ SideMenu.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SideMenu, selector: "gtx-side-menu", inputs: { opened: "opened", position: "position", width: "width", toggleButtonOffset: "toggleButtonOffset" }, outputs: { toggle: "toggle" }, host: { properties: { "class.opened": "this.opened", "class.align-left": "this.alignmentClassLeft", "class.align-right": "this.alignmentClassRight" } }, viewQueries: [{ propertyName: "toggleButton", first: true, predicate: ["toggleButton"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"side-menu-overlay\"\n [@overlayState]=\"animationParams\"\n (click)=\"close()\"></div>\n\n<div #toggleButton\n [@toggleState]=\"animationParams\"\n (@toggleState.start)=\"animationStarted($event)\"\n class=\"toggle-button\"\n (click)=\"toggleState()\">\n <ng-content select=\"gtx-side-menu-toggle\"></ng-content>\n</div>\n\n<div class=\"menu\"\n [@menuState]=\"menuAnimationState\"\n [style.width]=\"responsiveWidth\"\n *ngIf=\"opened\">\n <div [@contentState]=\"animationParams\"\n class=\"menu-content\">\n <ng-content></ng-content>\n </div>\n</div>\n", directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [ trigger('menuState', [ // There seems to be an open Angular bug with leaving animations on IE and Edge, // so we only play that animation if we are not on IE or Edge. // https://github.com/angular/angular/issues/29463 // https://jira.gentics.com/browse/SUP-8106 state('void', style('*')), state('open', style('*')), state('openIE', style('*')), transition('void => *', [ query('@contentState', [animateChild({ delay: 100 })]), animateCubicBezier(300) ]), transition('void => *', animateCubicBezier(300)), transition('open => *', animateCubicBezier(300)), ]), trigger('toggleState', [ state('closed', style({ transform: '{{ transform }}' }), { params: { transform: 'translateX(0)' } }), state('open', style({ transform: '{{ transform }}' }), { params: { transform: 'translateX(0)' } }), transition('* => *', animateCubicBezier(300)) ]), trigger('overlayState', [ state('closed', style({ opacity: 0 })), state('open', style({ opacity: 1 })), transition('* => *', animateCubicBezier(600)) ]), trigger('contentState', [ state('void', style('*')), state('*', style({ opacity: 1, transform: 'translateX(0)' })), transition('* => *', animateCubicBezier(400)) ]) ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SideMenu, decorators: [{ type: Component, args: [{ selector: 'gtx-side-menu', animations: [ trigger('menuState', [ // There seems to be an open Angular bug with leaving animations on IE and Edge, // so we only play that animation if we are not on IE or Edge. // https://github.com/angular/angular/issues/29463 // https://jira.gentics.com/browse/SUP-8106 state('void', style('*')), state('open', style('*')), state('openIE', style('*')), transition('void => *', [ query('@contentState', [animateChild({ delay: 100 })]), animateCubicBezier(300) ]), transition('void => *', animateCubicBezier(300)), transition('open => *', animateCubicBezier(300)), ]), trigger('toggleState', [ state('closed', style({ transform: '{{ transform }}' }), { params: { transform: 'translateX(0)' } }), state('open', style({ transform: '{{ transform }}' }), { params: { transform: 'translateX(0)' } }), transition('* => *', animateCubicBezier(300)) ]), trigger('overlayState', [ state('closed', style({ opacity: 0 })), state('open', style({ opacity: 1 })), transition('* => *', animateCubicBezier(600)) ]), trigger('contentState', [ state('void', style('*')), state('*', style({ opacity: 1, transform: 'translateX(0)' })), transition('* => *', animateCubicBezier(400)) ]) ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"side-menu-overlay\"\n [@overlayState]=\"animationParams\"\n (click)=\"close()\"></div>\n\n<div #toggleButton\n [@toggleState]=\"animationParams\"\n (@toggleState.start)=\"animationStarted($event)\"\n class=\"toggle-button\"\n (click)=\"toggleState()\">\n <ng-content select=\"gtx-side-menu-toggle\"></ng-content>\n</div>\n\n<div class=\"menu\"\n [@menuState]=\"menuAnimationState\"\n [style.width]=\"responsiveWidth\"\n *ngIf=\"opened\">\n <div [@contentState]=\"animationParams\"\n class=\"menu-content\">\n <ng-content></ng-content>\n </div>\n</div>\n" }] }], ctorParameters: function () { return [{ type: i1.AnimationBuilder }, { type: i0.ElementRef }, { type: i2.UserAgentRef }]; }, propDecorators: { opened: [{ type: HostBinding, args: ['class.opened'] }, { type: Input }], position: [{ type: Input }], width: [{ type: Input }], toggleButtonOffset: [{ type: Input }], alignmentClassLeft: [{ type: HostBinding, args: ['class.align-left'] }], alignmentClassRight: [{ type: HostBinding, args: ['class.align-right'] }], toggleButton: [{ type: ViewChild, args: ['toggleButton', { static: true }] }], toggle: [{ type: Output }] } }); export class SideMenuToggle { } /** @nocollapse */ SideMenuToggle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SideMenuToggle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ SideMenuToggle.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: SideMenuToggle, selector: "gtx-side-menu-toggle", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SideMenuToggle, decorators: [{ type: Directive, args: [{ selector: 'gtx-side-menu-toggle' }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lkZS1tZW51LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3NpZGUtbWVudS9zaWRlLW1lbnUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvc2lkZS1tZW51L3NpZGUtbWVudS50cGwuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixXQUFXLEVBQ1gsS0FBSyxFQUNMLE1BQU0sRUFDTixTQUFTLEVBQ1osTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUNILE9BQU8sRUFDUCxZQUFZLEVBQ1osZ0JBQWdCLEVBRWhCLFNBQVMsRUFDVCxLQUFLLEVBQ0wsS0FBSyxFQUNMLEtBQUssRUFDTCxVQUFVLEVBQ1YsT0FBTyxFQUNWLE1BQU0scUJBQXFCLENBQUM7QUFFN0IsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLHlCQUF5QixDQUFDOzs7OztBQUVyRCxzRkFBc0Y7QUFDdEYsTUFBTSxVQUFVLGtCQUFrQixDQUFDLE1BQWM7SUFDN0MsT0FBTyxPQUFPLENBQUMsR0FBRyxNQUFNLHdDQUF3QyxDQUFDLENBQUM7QUFDdEUsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTBCRztBQXNDSCxNQUFNLE9BQU8sUUFBUTtJQW9GakIsWUFDWSxnQkFBa0MsRUFDbEMsVUFBc0IsRUFDdEIsWUFBMEI7UUFGMUIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQUNsQyxlQUFVLEdBQVYsVUFBVSxDQUFZO1FBQ3RCLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBckZ0Qzs7V0FFRztRQUVNLFdBQU0sR0FBWSxLQUFLLENBQUM7UUFDakM7O1dBRUc7UUFDTSxhQUFRLEdBQXFCLE1BQU0sQ0FBQztRQUM3Qzs7O1dBR0c7UUFD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LGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxDQUFDO3lCQUNoRCxDQUFDO3dCQUNGLE9BQU8sQ0FBQyxjQUFjLEVBQUU7NEJBQ3BCLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDOzRCQUN6QixLQUFLLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsU0FBUyxFQUFFLGVBQWUsRUFBRSxDQUFDLENBQUM7NEJBQzdELFVBQVUsQ0FBQyxRQUFRLEVBQUUsa0JBQWtCLENBQUMsR0FBRyxDQUFDLENBQUM7eUJBQ2hELENBQUM7cUJBQ0wsbUJBQ2dCLHVCQUF1QixDQUFDLE1BQU07MkpBUXRDLE1BQU07c0JBRGQsV0FBVzt1QkFBQyxjQUFjOztzQkFDMUIsS0FBSztnQkFJRyxRQUFRO3NCQUFoQixLQUFLO2dCQUtHLEtBQUs7c0JBQWIsS0FBSztnQkFJRyxrQkFBa0I7c0JBQTFCLEtBQUs7Z0JBR0Ysa0JBQWtCO3NCQURyQixXQUFXO3VCQUFDLGtCQUFrQjtnQkFNM0IsbUJBQW1CO3NCQUR0QixXQUFXO3VCQUFDLG1CQUFtQjtnQkFnQ2EsWUFBWTtzQkFBeEQsU0FBUzt1QkFBQyxjQUFjLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQU1qQyxNQUFNO3NCQUFmLE1BQU07O0FBMkZYLE1BQU0sT0FBTyxjQUFjOzs4SEFBZCxjQUFjO2tIQUFkLGNBQWM7MkZBQWQsY0FBYztrQkFIMUIsU0FBUzttQkFBQztvQkFDUCxRQUFRLEVBQUUsc0JBQXNCO2lCQUNuQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gICAgQ29tcG9uZW50LFxuICAgIERpcmVjdGl2ZSxcbiAgICBFbGVtZW50UmVmLFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBIb3N0QmluZGluZyxcbiAgICBJbnB1dCxcbiAgICBPdXRwdXQsXG4gICAgVmlld0NoaWxkXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgICBhbmltYXRlLFxuICAgIGFuaW1hdGVDaGlsZCxcbiAgICBBbmltYXRpb25CdWlsZGVyLFxuICAgIEFuaW1hdGlvblBsYXllcixcbiAgICBrZXlmcmFtZXMsXG4gICAgcXVlcnksXG4gICAgc3RhdGUsXG4gICAgc3R5bGUsXG4gICAgdHJhbnNpdGlvbixcbiAgICB0cmlnZ2VyXG59IGZyb20gJ0Bhbmd1bGFyL2FuaW1hdGlvbnMnO1xuXG5pbXBvcnQge1VzZXJBZ2VudFJlZn0gZnJvbSAnLi4vbW9kYWwvdXNlci1hZ2VudC1yZWYnO1xuXG4vLyBtdXN0IGV4cG9ydCBhbmQgYmUgYSBmdW5jdGlvbiAobm90IGFycm93IGZ1bmN0aW9uIGV4cHJlc3Npb24pIHRvIHByZXZlbnQgbmdjIGVycm9yc1xuZXhwb3J0IGZ1bmN0aW9uIGFuaW1hdGVDdWJpY0JlemllcihtaWxsaXM6IG51bWJlcik6IGFueSB7XG4gICAgcmV0dXJuIGFuaW1hdGUoYCR7bWlsbGlzfW1zIGN1YmljLWJlemllcigwLjIxNSwgMC42MSwgMC4zNTUsIDEpYCk7XG59XG5cbi8qKlxuICogVGhlIFNpZGVNZW51IGNvbXBvbmVudCBpcyBhbiBvZmYtY2FudmFzIG1lbnUgd2l0aCBhIHRvZ2dsZSBidXR0b24gd2hpY2ggY2FuIGJlXG4gKiB1c2VkIHRvIHRvZ2dsZSB0aGUgc3RhdGUuIFRoZSBjb21wb25lbnQgaXRzZWxmIGlzIHN0YXRlbGVzcywgYW5kIHJlbGllcyBvbiB0aGUgdmFsdWUgcGFzc2VkIGluIGFzXG4gKiB0aGUgYG9wZW5lZGAgcHJvcCB0byBzZXQgaXRzIHN0YXRlLiBUb2dnbGluZyBtdXN0IGFsc28gYmUgaGFuZGxlZCBieSB0aGUgaG9zdCBjb21wb25lbnQuXG4gKlxuICogVGhlIHRvZ2dsZSBidXR0b24gbXVzdCBiZSBwbGFjZWQgd2l0aGluIGEgYDxndHgtc2lkZS1tZW51LXRvZ2dsZT5gIGVsZW1lbnQuIEFsbCBvdGhlciBjb250ZW50IHdpbGwgYmUgcHJvamVjdGVkXG4gKiBpbnRvIHRoZSBtYWluIGJvZHkgb2YgdGhlIG1lbnUuXG4gKlxuICogKipOb3RlKio6IEZvciB0aGUgc2lkZSBtZW51IHRvIGJlIHBvc2l0aW9uZWQgY29ycmVjdGx5LCBpdHMgY29udGFpbmVyIG11c3QgaGF2ZSB0aGUgYHBvc2l0aW9uYCBDU1MgYXR0cmlidXRlIHNldC5cbiAqXG4gKiBgYGBodG1sXG4gKiA8Z3R4LXNpZGUtbWVudSBbb3BlbmVkXT1cImRpc3BsYXlNZW51XCIgKHRvZ2dsZSk9XCJkaXNwbGF5TWVudSA9ICRldmVudFwiPlxuICogICAgIDxndHgtc2lkZS1tZW51LXRvZ2dsZT5cbiAqICAgICAgICAgPGJ1dHRvbj5Ub2dnbGU8L2J1dHRvbj5cbiAqICAgICA8L2d0eC1zaWRlLW1lbnUtdG9nZ2xlPlxuICogICAgIDxkaXYgY2xhc3M9XCJteS1tZW51LWNvbnRlbnRcIj5cbiAqICAgICAgICAgPHVsPlxuICogICAgICAgICAgICAgPGxpPk1lbnUgaXRlbSAxPC9saT5cbiAqICAgICAgICAgICAgIDxsaT5NZW51IGl0ZW0gMjwvbGk+XG4gKiAgICAgICAgICAgICA8bGk+TWVudSBpdGVtIDM8L2xpPlxuICogICAgICAgICAgICAgPGxpPk1lbnUgaXRlbSA0PC9saT5cbiAqICAgICAgICAgICAgIDxsaT5NZW51IGl0ZW0gNTwvbGk+XG4gKiAgICAgICAgIDwvdWw+XG4gKiAgICAgPC9kaXY+XG4gKiA8L2d0eC1zaWRlLW1lbnU+XG4gKiBgYGBcbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdndHgtc2lkZS1tZW51JyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vc2lkZS1tZW51LnRwbC5odG1sJyxcbiAgICBhbmltYXRpb25zOiBbXG4gICAgICAgIHRyaWdnZXIoJ21lbnVTdGF0ZScsIFtcbiAgICAgICAgICAgIC8vIFRoZXJlIHNlZW1zIHRvIGJlIGFuIG9wZW4gQW5ndWxhciBidWcgd2l0aCBsZWF2aW5nIGFuaW1hdGlvbnMgb24gSUUgYW5kIEVkZ2UsXG4gICAgICAgICAgICAvLyBzbyB3ZSBvbmx5IHBsYXkgdGhhdCBhbmltYXRpb24gaWYgd2UgYXJlIG5vdCBvbiBJRSBvciBFZGdlLlxuICAgICAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2FuZ3VsYXIvYW5ndWxhci9pc3N1ZXMvMjk0NjNcbiAgICAgICAgICAgIC8vIGh0dHBzOi8vamlyYS5nZW50aWNzLmNvbS9icm93c2UvU1VQLTgxMDZcbiAgICAgICAgICAgIHN0YXRlKCd2b2lkJywgc3R5bGUoJyonKSksXG4gICAgICAgICAgICBzdGF0ZSgnb3BlbicsIHN0eWxlKCcqJykpLFxuICAgICAgICAgICAgc3RhdGUoJ29wZW5JRScsIHN0eWxlKCcqJykpLFxuICAgICAgICAgICAgdHJhbnNpdGlvbigndm9pZCA9PiAqJywgW1xuICAgICAgICAgICAgICAgIHF1ZXJ5KCdAY29udGVudFN0YXRlJywgW2FuaW1hdGVDaGlsZCh7IGRlbGF5OiAxMDAgfSldKSxcbiAgICAgICAgICAgICAgICBhbmltYXRlQ3ViaWNCZXppZXIoMzAwKVxuICAgICAgICAgICAgXSksXG4gICAgICAgICAgICB0cmFuc2l0aW9uKCd2b2lkID0+IConLCBhbmltYXRlQ3ViaWNCZXppZXIoMzAwKSksXG4gICAgICAgICAgICB0cmFuc2l0aW9uKCdvcGVuID0+IConLCBhbmltYXRlQ3ViaWNCZXppZXIoMzAwKSksXG4gICAgICAgIF0pLFxuICAgICAgICB0cmlnZ2VyKCd0b2dnbGVTdGF0ZScsIFtcbiAgICAgICAgICAgIHN0YXRlKCdjbG9zZWQnLCBzdHlsZSh7IHRyYW5zZm9ybTogJ3t7IHRyYW5zZm9ybSB9fScgfSksIHsgcGFyYW1zOiB7IHRyYW5zZm9ybTogJ3RyYW5zbGF0ZVgoMCknIH0gfSksXG4gICAgICAgICAgICBzdGF0ZSgnb3BlbicsIHN0eWxlKHsgdHJhbnNmb3JtOiAne3sgdHJhbnNmb3JtIH19JyB9KSwgeyBwYXJhbXM6IHsgdHJhbnNmb3JtOiAndHJhbnNsYXRlWCgwKScgfSB9KSxcbiAgICAgICAgICAgIHRyYW5zaXRpb24oJyogPT4gKicsIGFuaW1hdGVDdWJpY0JlemllcigzMDApKVxuICAgICAgICBdKSxcbiAgICAgICAgdHJpZ2dlcignb3ZlcmxheVN0YXRlJywgW1xuICAgICAgICAgICAgc3RhdGUoJ2Nsb3NlZCcsIHN0eWxlKHsgb3BhY2l0eTogMCB9KSksXG4gICAgICAgICAgICBzdGF0ZSgnb3BlbicsIHN0eWxlKHsgb3BhY2l0eTogMSB9KSksXG4gICAgICAgICAgICB0cmFuc2l0aW9uKCcqID0+IConLCBhbmltYXRlQ3ViaWNCZXppZXIoNjAwKSlcbiAgICAgICAgXSksXG4gICAgICAgIHRyaWdnZXIoJ2NvbnRlbnRTdGF0ZScsIFtcbiAgICAgICAgICAgIHN0YXRlKCd2b2lkJywgc3R5bGUoJyonKSksXG4gICAgICAgICAgICBzdGF0ZSgnKicsIHN0eWxlKHsgb3BhY2l0eTogMSwgdHJhbnNmb3JtOiAndHJhbnNsYXRlWCgwKScgfSkpLFxuICAgICAgICAgICAgdHJhbnNpdGlvbignKiA9PiAqJywgYW5pbWF0ZUN1YmljQmV6aWVyKDQwMCkpXG4gICAgICAgIF0pXG4gICAgXSxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaFxufSlcbmV4cG9ydCBjbGFzcyBTaWRlTWVudSB7XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdGF0ZSBvZiB0aGUgbWVudTogdHJ1ZSA9IG9wZW5lZCwgZmFsc2UgPSBjbG9zZWQuXG4gICAgICovXG4gICAgQEhvc3RCaW5kaW5nKCdjbGFzcy5vcGVuZWQnKVxuICAgIEBJbnB1dCgpIG9wZW5lZDogYm9vbGVhbiA9IGZhbHNlO1xuICAgIC8qKlxuICAgICAqIFNldHMgd2hldGhlciB0aGUgbWVudSBzaG91bGQgYXBwZWFyIHRvIHRoZSBsZWZ0IG9yIHRoZSByaWdodCBvZiB0aGUgc2NyZWVuLiBEZWZhdWx0cyB0byAnbGVmdCcuXG4gICAgICovXG4gICAgQElucHV0KCkgcG9zaXRpb246ICdsZWZ0JyB8ICdyaWdodCcgPSAnbGVmdCc7XG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgd2lkdGggb2YgdGhlIG1lbnUuIFNob3VsZCBiZSBhIHZhbGlkIENTUyB3aWR0aCB2YWx1ZSwgZS5nLiAnNDAwcHgnLCAnMjB2dycsICczMGVtJy4gKipOb3RlKiogdGhhdFxuICAgICAqIHBlcmNlbnRhZ2UgdmFsdWVzIHNob3VsZCBiZSBhdm9pZGVkLCBzaW5jZSB0aGV5IHdpbGwgcHJvZHVjZSB1bmV4cGVjdGVkIHJlc3VsdHMuXG4gICAgICovXG4gICAgQElucHV0KCkgd2lkdGg6IHN0cmluZyA9ICczMDBweCc7XG4gICAgLyoqXG4gICAgICogVGhlIGRpc3RhbmNlIGluIHBpeGVscyBiZXR3ZWVuIHRoZSBlZGdlIG9mIHRoZSBjb250YWluZXIgYW5kIHRoZSB0b2dnbGUgYnV0dG9uIHdoZW4gdGhlIG1lbnUgaXMgY2xvc2VkLlxuICAgICAqL1xuICAgIEBJbnB1dCgpIHRvZ2dsZUJ1dHRvbk9mZnNldDogbnVtYmVyID0gMjA7XG5cbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLmFsaWduLWxlZnQnKVxuICAgIGdldCBhbGlnbm1lbnRDbGFzc0xlZnQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnBvc2l0aW9uID09PSAnbGVmdCc7XG4gICAgfVxuXG4gICAgQEhvc3RCaW5kaW5nKCdjbGFzcy5hbGlnbi1yaWdodCcpXG4gICAgZ2V0IGFsaWdubWVudENsYXNzUmlnaHQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnBvc2l0aW9uID09PSAncmlnaHQnO1xuICAgIH1cblxuICAgIGdldCBhbmltYXRpb25QYXJhbXMoKTogYW55IHtcbiAgICAgICAgY29uc3QgYnV0dG9uV2lkdGggPSBwYXJzZUludCh0aGlzLnRvZ2dsZUJ1dHRvbi5uYXRpdmVFbGVtZW50Lm9mZnNldFdpZHRoKTtcbiAgICAgICAgbGV0IHRyYW5zZm9ybSA9IHRoaXMucG9zaXRpb24gPT09ICdsZWZ0JyA/XG4gICAgICAgICAgICBgdHJhbnNsYXRlWCgke3RoaXMudG9nZ2xlQnV0dG9uT2Zmc2V0fXB4KWAgOlxuICAgICAgICAgICAgYHRyYW5zbGF0ZVgoLSR7dGhpcy50b2dnbGVCdXR0b25PZmZzZXR9cHgpYDtcbiAgICAgICAgaWYgKHRoaXMub3BlbmVkKSB7XG4gICAgICAgICAgICAvLyBJRTExIGNhbm5vdCB1c2UgYGNhbGMoKWAgd2l0aCB0cmFuc2Zvcm0gcHJvcGVydGllcywgc28gaW5zdGVhZCB3ZSBjYW4ganVzdCB1c2UgbXVsdGlwbGUgc2VwYXJhdGVcbiAgICAgICAgICAgIC8vIHRyYW5zbGF0ZVgoKSBzdGF0ZW1lbnRzLlxuICAgICAgICAgICAgdHJhbnNmb3JtID0gdGhpcy5wb3NpdGlvbiA9PT0gJ2xlZnQnID9cbiAgICAgICAgICAgICAgICBgdHJhbnNsYXRlWCgke3RoaXMucmVzcG9uc2l2ZVdpZHRofSkgdHJhbnNsYXRlWCgtJHtidXR0b25XaWR0aH1weCkgdHJhbnNsYXRlWCgtJHt0aGlzLnRvZ2dsZUJ1dHRvbk9mZnNldH1weClgIDpcbiAgICAgICAgICAgICAgICBgdHJhbnNsYXRlWCgtJHt0aGlzLnJlc3BvbnNpdmVXaWR0aH0pIHRyYW5zbGF0ZVgoKyR7YnV0dG9uV2lkdGh9cHgpIHRyYW5zbGF0ZVgoKyR7dGhpcy50b2dnbGVCdXR0b25PZmZzZXR9cHgpYDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdmFsdWU6IHRoaXMub3BlbmVkID8gJ29wZW4nIDogJ2Nsb3NlZCcsXG4gICAgICAgICAgICBwYXJhbXM6IHsgdHJhbnNmb3JtIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBnZXQgbWVudUFuaW1hdGlvblN0YXRlKCk6IGFueSB7XG4gICAgICAgIC8vIFRoZXJlIHNlZW1zIHRvIGJlIGFuIG9wZW4gQW5ndWxhciBidWcgd2l0aCBsZWF2aW5nIGFuaW1hdGlvbnMgb24gSUUgYW5kIEVkZ2UsXG4gICAgICAgIC8vIHNvIHdlIG9ubHkgcGxheSB0aGF0IGFuaW1hdGlvbiBpZiB3ZSBhcmUgbm90IG9uIElFIG9yIEVkZ2UuXG4gICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvaXNzdWVzLzI5NDYzXG4gICAgICAgIC8vIGh0dHBzOi8vamlyYS5nZW50aWNzLmNvbS9icm93c2UvU1VQLTgxMDZcbiAgICAgICAgY29uc3Qgb3BlblN0YXRlID0gIXRoaXMudXNlckFnZW50UmVmLmlzRWRnZSAmJiAhdGhpcy51c2VyQWdlbnRSZWYuaXNJRTExID8gJ29wZW4nIDogJ29wZW5JRSc7XG4gICAgICAgIHJldHVybiB0aGlzLm9wZW5lZCA/IG9wZW5TdGF0ZSA6ICd2b2lkJztcbiAgICB9XG5cbiAgICBAVmlld0NoaWxkKCd0b2dnbGVCdXR0b24nLCB7IHN0YXRpYzogdHJ1ZSB9KSB0b2dnbGVCdXR0b246IEVsZW1lbnRSZWY7XG5cbiAgICAvKipcbiAgICAgKiBGaXJlZCB3aGVuIHRoZSB0b2dnbGUgYnV0dG9uIGlzIGNsaWNrZWQuIFRoZSB2YWx1ZSBpcyBlcXVhbCB0b1xuICAgICAqIHRoZSB2YWx1ZSBvZiB0aGUgYG9wZW5lZGBcbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgdG9nZ2xlID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuXG4gICAgcHVibGljIHBsYXllcjogQW5pbWF0aW9uUGxheWVyO1xuICAgIHByaXZhdGUgYW5jZXN0b3JXaXRoV2lkdGg6IEhUTUxFbGVtZW50O1xuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgd2lkdGggb2YgdGhlIG1lbnUsIHRha2luZyBpbnRvIGFjY291bnQgc2NyZWVuIHdpZHRoXG4gICAgICovXG4gICAgZ2V0IHJlc3BvbnNpdmVXaWR0aCgpOiBzdHJpbmcge1xuICAgICAgICBjb25zdCBzY3JlZW5XaWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoO1xuICAgICAgICBpZiAoc2NyZWVuV2lkdGggPCA2MDApIHtcbiAgICAgICAgICAgIHJldHVybiBgJHt0aGlzLmFuY2VzdG9yV2l0aFdpZHRoLm9mZnNldFdpZHRofXB4YDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy53aWR0aDtcbiAgICB9XG5cbiAgICBnZXQgbWVudVBhcmFtcygpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5vcGVuZWQgPyAnb3BlbicgOiAnY2xvc2VkJztcbiAgICB9XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJpdmF0ZSBhbmltYXRpb25CdWlsZGVyOiBBbmltYXRpb25CdWlsZGVyLFxuICAgICAgICBwcml2YXRlIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWYsXG4gICAgICAgIHByaXZhdGUgdXNlckFnZW50UmVmOiBVc2VyQWdlbnRSZWZcbiAgICApIHt9XG5cbiAgICAvKipcbiAgICAgKiBXZSBuZWVkIHRvIGtub3cgdGhlIHdpZHRoIG9mIHRoZSBlbGVtZW50IGluIHdoaWNoIHRoZSBTaWRlTWVudSBpcyBuZXN0ZWQuIEhlcmUgd2UgdHJhdmVyc2UgdGhlIERPTSB0cmVlXG4gICAgICogbG9va2luZyBmb3IgdGhlIGZpcnN0IGFuY2VzdG9yIGVsZW1lbnQgd2l0aCBhIG5vbi16ZXJvIG9mZnNldFdpZHRoLlxuICAgICAqL1xuICAgIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICAgICAgbGV0IGFuY2VzdG9yV2l0aFdpZHRoOiBIVE1MRWxlbWVudCB8IG51bGw7XG4gICAgICAgIGxldCBjdXJyZW50RWxlbWVudCA9IHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50O1xuICAgICAgICBjb25zdCBtYXhMZXZlbHMgPSAxMDtcbiAgICAgICAgbGV0IGkgPSAwO1xuICAgICAgICB3aGlsZSAoIWFuY2VzdG9yV2l0aFdpZHRoICYmIGkgPCBtYXhMZXZlbHMpIHtcbiAgICAgICAgICAgIGNvbnN0IHBhcmVudCA9IGN1cnJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQ7XG4gICAgICAgICAgICBpZiAoMCA8IHBhcmVudC5vZmZzZXRXaWR0aCkge1xuICAgICAgICAgICAgICAgIGFuY2VzdG9yV2l0aFdpZHRoID0gcGFyZW50O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY3VycmVudEVsZW1lbnQgPSBwYXJlbnQ7XG4gICAgICAgICAgICBpKys7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5hbmNlc3RvcldpdGhXaWR0aCA9IGFuY2VzdG9yV2l0aFdpZHRoO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBBbmltYXRpb25CdWlsZGVyIGlzIHVzZWQgaGVyZSBiZWNhdXNlIHRoZSBkZXNpcmVkIGFuaW1hdGlvbiByZXN1bHQgY291bGQgbm90IGJlIGFjaGlldmVkIHVzaW5nIHRoZVxuICAgICAqIG1ldGFkYXRhLWJhc2VkIGFwcHJvYWNoIGFsb25lLiBUaGlzIGlzc3VlIGRlc2NyaWJlcyB0aGUgcHJvYmxlbTogaHR0cHM6Ly9naXRodWIuY29tL2FuZ3VsYXIvYW5ndWxhci9pc3N1ZXMvMjA3OTZcbiAgICAgKlxuICAgICAqIElmIHRoYXQgaXNzdWUgZ2V0cyByZXNvbHZlZCB0aGVuIHRoaXMgY291bGQgYmUgc2ltcGxpZmllZCBhbmQgd2UgbWF5IGJlIGFibGUgdG8gZHJvcCB0aGUgQW5pbWF0aW9uQnVpbGRlclxuICAgICAqIGFuZCBtb3ZlIHRoaXMgbG9naWMgaW50byB0aGUgYW5pbWF0aW9uUGFyYW1zIGdldHRlci5cbiAgICAgKi9cbiAgICBhbmltYXRpb25TdGFydGVkKGV2ZW50OiBhbnkpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgbWVudSA9IHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3IoJy5tZW51Jyk7XG5cbiAgICAgICAgaWYgKG1lbnUpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnBsYXllcikge1xuICAgICAgICAgICAgICAgIHRoaXMucGxheWVyLmRlc3Ryb3koKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNpZ24gPSB0aGlzLnBvc2l0aW9uID09PSAncmlnaHQnID8gJycgOiAnLSc7XG4gICAgICAgICAgICBsZXQgc3RhcnRYID0gJzAnO1xuICAgICAgICAgICAgbGV0IGVuZFggPSBgJHtzaWdufSR7dGhpcy5yZXNwb25zaXZlV2lkdGh9YDtcbiAgICAgICAgICAgIGlmIChldmVudC50b1N0YXRlID09PSAnb3BlbicpIHtcbiAgICAgICAgICAgICAgICBbc3RhcnRYLCBlbmRYXSA9IFtlbmRYLCBzdGFydFhdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuYW5pbWF0aW9uQnVpbGRlci5idWlsZChbXG4gICAgICAgICAgICAgICAgYW5pbWF0ZSgnMC4zcycsIGtleWZyYW1lcyhbXG4gICAgICAgICAgICAgICAgICAgIHN0eWxlKHt0cmFuc2Zvcm06IGB0cmFuc2xhdGVYKCR7c3RhcnRYfSlgLCBvZmZzZXQ6IDAgfSksXG4gICAgICAgICAgICAgICAgICAgIHN0eWxlKHt0cmFuc2Zvcm06IGB0cmFuc2xhdGVYKCR7ZW5kWH0pYCwgb2Zmc2V0OiAwLjcgfSlcbiAgICAgICAgICAgICAgICBdKSlcbiAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgdGhpcy5wbGF5ZXIgPSBmYWN0b3J5LmNyZWF0ZShtZW51LCB7fSk7XG4gICAgICAgICAgICB0aGlzLnBsYXllci5wbGF5KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0b2dnbGVTdGF0ZSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50b2dnbGUuZW1pdCghdGhpcy5vcGVuZWQpO1xuICAgIH1cblxuICAgIGNsb3NlKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5vcGVuZWQgPT09IHRydWUpIHtcbiAgICAgICAgICAgIHRoaXMudG9nZ2xlU3RhdGUoKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuQERpcmVjdGl2ZSh7XG4gICAgc2VsZWN0b3I6ICdndHgtc2lkZS1tZW51LXRvZ2dsZSdcbn0pXG5leHBvcnQgY2xhc3MgU2lkZU1lbnVUb2dnbGUge31cbiIsIjxkaXYgY2xhc3M9XCJzaWRlLW1lbnUtb3ZlcmxheVwiXG4gICAgIFtAb3ZlcmxheVN0YXRlXT1cImFuaW1hdGlvblBhcmFtc1wiXG4gICAgIChjbGljayk9XCJjbG9zZSgpXCI+PC9kaXY+XG5cbjxkaXYgI3RvZ2dsZUJ1dHRvblxuICAgICBbQHRvZ2dsZVN0YXRlXT1cImFuaW1hdGlvblBhcmFtc1wiXG4gICAgIChAdG9nZ2xlU3RhdGUuc3RhcnQpPVwiYW5pbWF0aW9uU3RhcnRlZCgkZXZlbnQpXCJcbiAgICAgY2xhc3M9XCJ0b2dnbGUtYnV0dG9uXCJcbiAgICAgKGNsaWNrKT1cInRvZ2dsZVN0YXRlKClcIj5cbiAgICA8bmctY29udGVudCBzZWxlY3Q9XCJndHgtc2lkZS1tZW51LXRvZ2dsZVwiPjwvbmctY29udGVudD5cbjwvZGl2PlxuXG48ZGl2IGNsYXNzPVwibWVudVwiXG4gICAgIFtAbWVudVN0YXRlXT1cIm1lbnVBbmltYXRpb25TdGF0ZVwiXG4gICAgIFtzdHlsZS53aWR0aF09XCJyZXNwb25zaXZlV2lkdGhcIlxuICAgICAqbmdJZj1cIm9wZW5lZFwiPlxuICAgIDxkaXYgW0Bjb250ZW50U3RhdGVdPVwiYW5pbWF0aW9uUGFyYW1zXCJcbiAgICAgICAgY2xhc3M9XCJtZW51LWNvbnRlbnRcIj5cbiAgICAgICAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuICAgIDwvZGl2PlxuPC9kaXY+XG4iXX0=