UNPKG

ngx-acuw

Version:

Angular components using WEBGL (threejs)

486 lines (484 loc) 69.1 kB
import { animate, query, stagger, state, style, transition, trigger } from '@angular/animations'; import { Component, ContentChildren, Directive, EventEmitter, HostListener, Input, Output, ViewChild } from '@angular/core'; import { Subscription } from 'rxjs'; import { Euler, Group, Object3D, PerspectiveCamera, Quaternion, Scene } from 'three'; import { Vector3 } from 'three'; import { CSS3DObject, CSS3DRenderer } from 'three/examples/jsm/renderers/CSS3DRenderer'; import { ObjectControls } from '../controls/object-controls'; import { RxjsTween } from '../tween/rxjs-tween'; import * as i0 from "@angular/core"; import * as i1 from "@angular/animations"; import * as i2 from "../performance-monitor/performance-monitor.component"; import * as i3 from "@angular/common"; export class CarouselItem { constructor(el) { this.el = el; this.htmlElement = this.el.nativeElement; } } CarouselItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: CarouselItem, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); CarouselItem.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: CarouselItem, selector: "acuw-carousel-item", host: { classAttribute: "acuw-carousel-item" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: CarouselItem, decorators: [{ type: Directive, args: [{ selector: `acuw-carousel-item`, host: { 'class': 'acuw-carousel-item', } }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; } }); export class CarouselComponent { constructor(ngZone, animationBuilder) { this.ngZone = ngZone; this.animationBuilder = animationBuilder; this.showDots = true; this.dotColor = '#fff'; this.activeDotColor = '#3f51b5'; this.dotAnimationCircleColor = '#fff'; this.activeCarouselElement = 0; this.initAnimation = true; this.radius = 200; this.yPosition = 0; this.cameraFov = 65; this.cameraDistance = 600; this.autoPlay = false; this.autoPlayInterval = 5000; this.rotationDuration = 500; this.showPerformanceMonitor = false; this.activeElementChanged = new EventEmitter(); this.css3dRenderer = new CSS3DRenderer(); this.scene = new Scene(); this.carouselGroup = new Group(); this.carouselObjSubsciptions = new Array(); this.rotationSubscription = new Subscription(); this.animation = true; this.userMove = false; } ngAfterViewInit() { // Init camera this.camera = new PerspectiveCamera(this.cameraFov, window.innerWidth / window.innerHeight, 0.1, 1000); this.camera.position.set(0.0, 0.0, this.cameraDistance); // Get the with and heigth of the threejs renderer const divWidth = this.threejsContainer.nativeElement.clientWidth; const divHeight = this.threejsContainer.nativeElement.clientHeight; // Create CSS3D Renderer this.css3dRenderer = new CSS3DRenderer(); this.css3dRenderer.setSize(divWidth, divHeight); this.css3dRenderer.domElement.style.position = 'absolute'; this.css3dRenderer.domElement.style.top = '0'; this.threejsContainer.nativeElement.appendChild(this.css3dRenderer.domElement); // Init carousel elements this.initCarouselObjects(); // Object-Controls this.objectControls = new ObjectControls(this.css3dRenderer.domElement, this.carouselGroup, this.threejsContainer.nativeElement); this.objectControls.userInteracted$.subscribe({ next: val => { this.userMove = val; // Cancel the rotation, if running this.rotationSubscription.unsubscribe(); } }); // Initialize the animation of the inidcation dots if (this.autoPlay) { this.startDotAnimation(this.activeCarouselElement); } // Animate this.animate(); } ngOnChanges(changes) { let change = changes['activeCarouselElement']; if (change && !change.firstChange && this.carouselGroup) { this.rotateTo(change.currentValue, true); } change = changes['radius']; if (change && !change.firstChange && this.carouselGroup) { this.updateRadius(); } change = changes['cameraFov']; if (change && !change.firstChange && this.camera) { this.camera.fov = this.cameraFov; this.camera.updateProjectionMatrix(); } change = changes['cameraDistance']; if (change && !change.firstChange && this.camera) { this.camera.position.set(0, 0, this.cameraDistance); this.camera.updateProjectionMatrix(); } change = changes['autoPlay']; if (change && this.carouselGroup) { if (change.currentValue === true) { this.startDotAnimation(this.activeCarouselElement); } else { this.resetDotAnimation(); } } } ngOnDestroy() { // Cancel Animation cancelAnimationFrame(this.animationFrameId); // Unsubscribe Subscriptions this.rotationSubscription.unsubscribe(); // Remove threejs container from DOM this.threejsContainer.nativeElement.removeChild(this.css3dRenderer.domElement); // Clear scene this.scene.clear(); } /** * Resizes the canvas and updates the texture resulution information of the images */ resize() { // Get width and heigh of the threejs dom element after window resize const divWidth = this.threejsContainer.nativeElement.clientWidth; const divHeight = this.threejsContainer.nativeElement.clientHeight; // Define aspect ratio this.camera.aspect = divWidth / divHeight; this.camera.updateProjectionMatrix(); this.css3dRenderer.setSize(divWidth, divHeight); } /** * Animation */ animate() { // Only render if the animation flat is true if (this.animation == true) { this.css3dRenderer.render(this.scene, this.camera); } if (this.performanceMonitor && this.showPerformanceMonitor) { this.performanceMonitor.end(); } this.ngZone.runOutsideAngular(() => { this.animationFrameId = window.requestAnimationFrame(() => this.animate()); }); } /** * starts the animation of the indication dots * @param index index number for which dot the animation should be started * @returns */ startDotAnimation(index) { if (this.dotAnimationPlayer || !this.dots) { // Animation is already ongoing return; } // Define the animation let autoPlayAnimation; if (this.showDots) { autoPlayAnimation = this.animationBuilder.build([ style({ strokeDasharray: '0,250.2', visibility: 'visible' }), animate(this.autoPlayInterval, style({ strokeDasharray: '250.2,250.2', visibility: 'hidden' })) ]); } else { autoPlayAnimation = this.animationBuilder.build([ style({ strokeDasharray: '0,250.2', visibility: 'hidden' }), animate(this.autoPlayInterval, style({ strokeDasharray: '250.2,250.2', visibility: 'hidden' })) ]); } // Get the element for, which the animation should be applied const path = this.dots.nativeElement.children[index].getElementsByTagName('path')[0]; this.dotAnimationPlayer = autoPlayAnimation.create(path); // Start the animation this.dotAnimationPlayer.play(); // Switch to the next carousel, as soon as the animation is finished this.dotAnimationPlayer.onDone(() => { this.dotAnimationPlayer = null; this.next(); }); } /** * Resets the dot animation */ resetDotAnimation() { if (this.dotAnimationPlayer && this.dotAnimationPlayer.hasStarted()) { this.dotAnimationPlayer.reset(); this.dotAnimationPlayer = null; } } /** * Initialize the carousel objects */ initCarouselObjects(animation = true) { this.carouselElements = new Array(); for (let idx = 0; idx < this.carouselItemTemplates.length; idx++) { let copiedElement = (this.carouselItemTemplates.get(idx)?.htmlElement); if (copiedElement) { var object = new CSS3DObject(copiedElement); object.element.style.pointerEvents = 'none'; // Add element to global variable this.carouselElements.push(object); // Create subscription for tween animation this.carouselObjSubsciptions.push(new Subscription()); } } // Clear the carousel group this.carouselGroup.clear(); var yOrientation = -((this.activeCarouselElement) * Math.PI * 2 / this.carouselElements.length); this.carouselGroup.rotation.set(0, yOrientation, 0); var index = 0; const elementsCnt = this.carouselElements.length; this.carouselElements.forEach(obj => { // Unsubscribe previously subscription this.carouselObjSubsciptions[index].unsubscribe(); // Define final position let tweenObj = new Object3D(); let theta = index * 2 * (Math.PI / elementsCnt); tweenObj.position.setFromCylindricalCoords(this.radius, theta, this.yPosition); let vector = new Vector3(tweenObj.position.x * 2, tweenObj.position.y, tweenObj.position.z * 2); tweenObj.lookAt(vector); // Set roattion obj.rotation.x = tweenObj.rotation.x; obj.rotation.y = tweenObj.rotation.y; obj.rotation.z = tweenObj.rotation.z; if (this.initAnimation === true && animation === true) { // Set random position obj.position.x = Math.random() * 2000 - 1000; obj.position.y = Math.random() * 500; obj.position.z = Math.random() * 500; // Add the objects to the portfolio group this.carouselGroup.add(obj); // Tween to final position this.ngZone.runOutsideAngular(() => { this.carouselObjSubsciptions[index] = RxjsTween.createTween(RxjsTween.easeInOutQuad, [obj.position.x, obj.position.y, obj.position.z], [tweenObj.position.x, tweenObj.position.y, tweenObj.position.z], 2000).subscribe({ next: tweenPos => { obj.position.set(tweenPos[0], tweenPos[1], tweenPos[2]); } }); }); } else { obj.position.x = tweenObj.position.x; obj.position.y = tweenObj.position.y; obj.position.z = tweenObj.position.z; // Add the objects to the portfolio group this.carouselGroup.add(obj); } index = index + 1; }); //add the group to the scene this.scene.add(this.carouselGroup); } /** * Rotate to next carousel item * @returns Promise with the new active element number */ next() { let nextElement = this.activeCarouselElement >= this.carouselElements.length - 1 ? 0 : this.activeCarouselElement + 1; return this.rotateTo(nextElement); } /** * Rotate to previous carousel item# * @returns Promise with the new active element number */ previous() { let nextElement = this.activeCarouselElement == 0 ? this.carouselElements.length - 1 : this.activeCarouselElement - 1; return this.rotateTo(nextElement); } /** * Rotates to a sepcific carousel item * @param targetIndex index of the carousel item */ rotateTo(targetIndex, skipAnimation = false) { return new Promise((resolve, reject) => { if (targetIndex > this.carouselElements.length - 1) { console.error('target index is greater than available carousel items'); reject('target index is greater than available carousel items'); } this.resetDotAnimation(); if (targetIndex > this.activeCarouselElement) { // In case the current elment is the first again, reset the orientation if (this.activeCarouselElement == 0 && (this.carouselGroup.rotation.y != 0 && this.carouselGroup.rotation.x == 0 && this.carouselGroup.rotation.z == 0)) { this.carouselGroup.rotation.set(0, 0, 0); } } else if (targetIndex == this.carouselElements.length - 1) { // Set position of the first element to y = -2*PI if (this.activeCarouselElement == 0 && (this.carouselGroup.rotation.y == 0 && this.carouselGroup.rotation.x == 0 && this.carouselGroup.rotation.z == 0)) { this.carouselGroup.rotation.set(0, -2 * Math.PI, 0); } } const startQuaternion = this.carouselGroup.quaternion.clone(); // Calculate the orientation of the target item const yOrientation = -((targetIndex) * Math.PI * 2 / this.carouselElements.length); let targetQuaternion = new Quaternion().setFromEuler(new Euler(0, yOrientation, 0, 'XYZ')); if (skipAnimation) { this.carouselGroup.quaternion.slerpQuaternions(startQuaternion, targetQuaternion, 1); this.rotationCompleted(targetIndex); resolve(this.activeCarouselElement); } else { this.rotationSubscription.unsubscribe(); // Run rotation animation outsie zgZone this.ngZone.runOutsideAngular(() => { this.rotationSubscription = RxjsTween.createTween(RxjsTween.easeInOutQuad, 0, 1, this.rotationDuration).subscribe({ next: x => { this.carouselGroup.quaternion.slerpQuaternions(startQuaternion, targetQuaternion, x); }, complete: () => { this.carouselGroup.quaternion.slerpQuaternions(startQuaternion, targetQuaternion, 1); this.ngZone.run(() => { this.rotationCompleted(targetIndex); resolve(this.activeCarouselElement); }); } }); }); } }); } /** * things to do when rotation is completed * @param targetIndex */ rotationCompleted(targetIndex) { this.activeCarouselElement = targetIndex; this.activeElementChanged.emit(this.activeCarouselElement); this.objectControls.resetUserInteractionFlag(); if (this.autoPlay) { this.startDotAnimation(this.activeCarouselElement); } } /** * Updates and reinits the carousel items */ updateCarouselItems() { this.initCarouselObjects(false); } /** * Updates the radius of the carousel items */ updateRadius() { for (let idx = 0; idx < this.carouselGroup.children.length; idx++) { let theta = idx * 2 * (Math.PI / this.carouselGroup.children.length); this.carouselGroup.children[idx].position.setFromCylindricalCoords(this.radius, theta, this.yPosition); } } } CarouselComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: CarouselComponent, deps: [{ token: i0.NgZone }, { token: i1.AnimationBuilder }], target: i0.ɵɵFactoryTarget.Component }); CarouselComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: CarouselComponent, selector: "acuw-carousel", inputs: { showDots: "showDots", dotColor: "dotColor", activeDotColor: "activeDotColor", dotAnimationCircleColor: "dotAnimationCircleColor", activeCarouselElement: "activeCarouselElement", initAnimation: "initAnimation", radius: "radius", yPosition: "yPosition", cameraFov: "cameraFov", cameraDistance: "cameraDistance", autoPlay: "autoPlay", autoPlayInterval: "autoPlayInterval", rotationDuration: "rotationDuration", showPerformanceMonitor: "showPerformanceMonitor" }, outputs: { activeElementChanged: "activeElementChanged" }, host: { listeners: { "window:resize": "resize()" } }, queries: [{ propertyName: "carouselItemTemplates", predicate: CarouselItem }], viewQueries: [{ propertyName: "threejsContainer", first: true, predicate: ["threejsContainer"], descendants: true }, { propertyName: "dots", first: true, predicate: ["indicationDots"], descendants: true }, { propertyName: "performanceMonitor", first: true, predicate: ["performanceMonitor"], descendants: true }], usesOnChanges: true, ngImport: i0, template: ` <div class="carousel-container"> <div #threejsContainer class="threejs-container"></div> <!-- dots --> <div #indicationDots class="dots" [ngStyle]="{'visibility': showDots ? 'visible' : 'hidden'}"> <svg *ngFor="let carouselTemplate of carouselItemTemplates; index as i" viewBox="0 0 100 100"> <circle cx="50" cy="50" r="45" [ngStyle]="{'fill': activeCarouselElement===i ? activeDotColor : dotColor}"/> <path id="{{i}}" fill="none" stroke-linecap="round" stroke-width="20" [ngStyle]="{'stroke': dotAnimationCircleColor, 'visibility': activeCarouselElement===i && autoPlay ? 'visible' : 'hidden'}" d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80"/> </svg> </div> <acuw-performance-monitor *ngIf="showPerformanceMonitor" #performanceMonitor></acuw-performance-monitor> </div> `, isInline: true, styles: [".carousel-container{position:relative;width:100%;height:100%;background-color:inherit}.threejs-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%;background-color:inherit}.dots{position:absolute;bottom:0%;display:flex;flex-direction:row;justify-content:center;flex-wrap:wrap;width:100%;overflow:hidden}.dots svg{width:28px;height:28px;margin:0 5px 24px}\n"], components: [{ type: i2.PerformanceMonitorComponent, selector: "acuw-performance-monitor" }], directives: [{ type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [ trigger('dotsAnimation', [ transition(':enter', [ query('svg', [ style({ opacity: 0, transform: 'translateY(200%)' }), stagger(100, [ animate('300ms ease-in', style({ opacity: 1, transform: 'none' })) ]) ], { optional: true }) ]), transition(':leave', [ query('svg', [ stagger(100, [ animate('300ms ease-in', style({ opacity: 0, transform: 'translateY(200%)' })) ]) ], { optional: true }) ]) ]), trigger('autoPlayAnimation', [ state('false', style({ strokeDasharray: '0,250.2' })), state('true', style({ strokeDasharray: '250.2,250.2' })), transition('false => true', animate(5000)) ]) ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: CarouselComponent, decorators: [{ type: Component, args: [{ selector: 'acuw-carousel', template: ` <div class="carousel-container"> <div #threejsContainer class="threejs-container"></div> <!-- dots --> <div #indicationDots class="dots" [ngStyle]="{'visibility': showDots ? 'visible' : 'hidden'}"> <svg *ngFor="let carouselTemplate of carouselItemTemplates; index as i" viewBox="0 0 100 100"> <circle cx="50" cy="50" r="45" [ngStyle]="{'fill': activeCarouselElement===i ? activeDotColor : dotColor}"/> <path id="{{i}}" fill="none" stroke-linecap="round" stroke-width="20" [ngStyle]="{'stroke': dotAnimationCircleColor, 'visibility': activeCarouselElement===i && autoPlay ? 'visible' : 'hidden'}" d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80"/> </svg> </div> <acuw-performance-monitor *ngIf="showPerformanceMonitor" #performanceMonitor></acuw-performance-monitor> </div> `, animations: [ trigger('dotsAnimation', [ transition(':enter', [ query('svg', [ style({ opacity: 0, transform: 'translateY(200%)' }), stagger(100, [ animate('300ms ease-in', style({ opacity: 1, transform: 'none' })) ]) ], { optional: true }) ]), transition(':leave', [ query('svg', [ stagger(100, [ animate('300ms ease-in', style({ opacity: 0, transform: 'translateY(200%)' })) ]) ], { optional: true }) ]) ]), trigger('autoPlayAnimation', [ state('false', style({ strokeDasharray: '0,250.2' })), state('true', style({ strokeDasharray: '250.2,250.2' })), transition('false => true', animate(5000)) ]) ], styles: [".carousel-container{position:relative;width:100%;height:100%;background-color:inherit}.threejs-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%;background-color:inherit}.dots{position:absolute;bottom:0%;display:flex;flex-direction:row;justify-content:center;flex-wrap:wrap;width:100%;overflow:hidden}.dots svg{width:28px;height:28px;margin:0 5px 24px}\n"] }] }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i1.AnimationBuilder }]; }, propDecorators: { showDots: [{ type: Input }], dotColor: [{ type: Input }], activeDotColor: [{ type: Input }], dotAnimationCircleColor: [{ type: Input }], activeCarouselElement: [{ type: Input }], initAnimation: [{ type: Input }], radius: [{ type: Input }], yPosition: [{ type: Input }], cameraFov: [{ type: Input }], cameraDistance: [{ type: Input }], autoPlay: [{ type: Input }], autoPlayInterval: [{ type: Input }], rotationDuration: [{ type: Input }], showPerformanceMonitor: [{ type: Input }], activeElementChanged: [{ type: Output }], threejsContainer: [{ type: ViewChild, args: ['threejsContainer'] }], dots: [{ type: ViewChild, args: ['indicationDots'] }], performanceMonitor: [{ type: ViewChild, args: ['performanceMonitor'] }], carouselItemTemplates: [{ type: ContentChildren, args: [CarouselItem] }], resize: [{ type: HostListener, args: ['window:resize'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Fyb3VzZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWFjdXcvc3JjL2xpYi9jYXJvdXNlbC9jYXJvdXNlbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBcUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNwSSxPQUFPLEVBQWlCLFNBQVMsRUFBRSxlQUFlLEVBQUUsU0FBUyxFQUFjLFlBQVksRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFnQyxNQUFNLEVBQTRCLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvTSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxpQkFBaUIsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLE1BQU0sT0FBTyxDQUFDO0FBQ3JGLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxPQUFPLENBQUM7QUFDaEMsT0FBTyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUN4RixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFN0QsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7OztBQVFoRCxNQUFNLE9BQU8sWUFBWTtJQUl2QixZQUFvQixFQUFjO1FBQWQsT0FBRSxHQUFGLEVBQUUsQ0FBWTtRQUNoQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDO0lBQzNDLENBQUM7O3lHQU5VLFlBQVk7NkZBQVosWUFBWTsyRkFBWixZQUFZO2tCQU54QixTQUFTO21CQUFDO29CQUNULFFBQVEsRUFB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T0FBTyxDQUFDLG1CQUFtQixFQUFFOzRCQUMzQixLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDOzRCQUNyRCxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDOzRCQUN4RCxVQUFVLENBQUMsZUFBZSxFQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQzt5QkFDM0MsQ0FBQztxQkFDSDs0SEFJUSxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csY0FBYztzQkFBdEIsS0FBSztnQkFDRyx1QkFBdUI7c0JBQS9CLEtBQUs7Z0JBQ0cscUJBQXFCO3NCQUE3QixLQUFLO2dCQUNHLGFBQWE7c0JBQXJCLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxjQUFjO3NCQUF0QixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUNHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxzQkFBc0I7c0JBQTlCLEtBQUs7Z0JBRUksb0JBQW9CO3NCQUE3QixNQUFNO2dCQUV3QixnQkFBZ0I7c0JBQTlDLFNBQVM7dUJBQUMsa0JBQWtCO2dCQUNBLElBQUk7c0JBQWhDLFNBQVM7dUJBQUMsZ0JBQWdCO2dCQUNNLGtCQUFrQjtzQkFBbEQsU0FBUzt1QkFBQyxvQkFBb0I7Z0JBRUEscUJBQXFCO3NCQUFuRCxlQUFlO3VCQUFDLFlBQVk7Z0JBa0dFLE1BQU07c0JBQXBDLFlBQVk7dUJBQUMsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGFuaW1hdGUsIEFuaW1hdGlvbkJ1aWxkZXIsIEFuaW1hdGlvblBsYXllciwgcXVlcnksIHN0YWdnZXIsIHN0YXRlLCBzdHlsZSwgdHJhbnNpdGlvbiwgdHJpZ2dlciB9IGZyb20gJ0Bhbmd1bGFyL2FuaW1hdGlvbnMnO1xyXG5pbXBvcnQgeyBBZnRlclZpZXdJbml0LCBDb21wb25lbnQsIENvbnRlbnRDaGlsZHJlbiwgRGlyZWN0aXZlLCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgSW5wdXQsIE5nWm9uZSwgT25DaGFuZ2VzLCBPbkRlc3Ryb3ksIE91dHB1dCwgUXVlcnlMaXN0LCBTaW1wbGVDaGFuZ2VzLCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IEV1bGVyLCBHcm91cCwgT2JqZWN0M0QsIFBlcnNwZWN0aXZlQ2FtZXJhLCBRdWF0ZXJuaW9uLCBTY2VuZSB9IGZyb20gJ3RocmVlJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJ3RocmVlJztcclxuaW1wb3J0IHsgQ1NTM0RPYmplY3QsIENTUzNEUmVuZGVyZXIgfSBmcm9tICd0aHJlZS9leGFtcGxlcy9qc20vcmVuZGVyZXJzL0NTUzNEUmVuZGVyZXInO1xyXG5pbXBvcnQgeyBPYmplY3RDb250cm9scyB9IGZyb20gJy4uL2NvbnRyb2xzL29iamVjdC1jb250cm9scyc7XHJcbmltcG9ydCB7IFBlcmZvcm1hbmNlTW9uaXRvckNvbXBvbmVudCB9IGZyb20gJy4uL3BlcmZvcm1hbmNlLW1vbml0b3IvcGVyZm9ybWFuY2UtbW9uaXRvci5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBSeGpzVHdlZW4gfSBmcm9tICcuLi90d2Vlbi9yeGpzLXR3ZWVuJztcclxuXHJcbkBEaXJlY3RpdmUoe1xyXG4gIHNlbGVjdG9yOiBgYWN1dy1jYXJvdXNlbC1pdGVtYCxcclxuICBob3N0OiB7XHJcbiAgICAnY2xhc3MnOiAnYWN1dy1jYXJvdXNlbC1pdGVtJyxcclxuICB9XHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBDYXJvdXNlbEl0ZW0ge1xyXG5cclxuICBodG1sRWxlbWVudDogSFRNTEVsZW1lbnQ7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZWw6IEVsZW1lbnRSZWYpIHtcclxuICAgIHRoaXMuaHRtbEVsZW1lbnQgPSB0aGlzLmVsLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgfVxyXG59XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2FjdXctY2Fyb3VzZWwnLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2IGNsYXNzPVwiY2Fyb3VzZWwtY29udGFpbmVyXCI+XHJcbiAgICAgIDxkaXYgI3RocmVlanNDb250YWluZXIgY2xhc3M9XCJ0aHJlZWpzLWNvbnRhaW5lclwiPjwvZGl2PlxyXG4gICAgICA8IS0tIGRvdHMgLS0+XHJcbiAgICAgIDxkaXYgI2luZGljYXRpb25Eb3RzIGNsYXNzPVwiZG90c1wiIFtuZ1N0eWxlXT1cInsndmlzaWJpbGl0eSc6IHNob3dEb3RzID8gJ3Zpc2libGUnIDogJ2hpZGRlbid9XCI+XHJcbiAgICAgICAgPHN2ZyAqbmdGb3I9XCJsZXQgY2Fyb3VzZWxUZW1wbGF0ZSBvZiBjYXJvdXNlbEl0ZW1UZW1wbGF0ZXM7IGluZGV4IGFzIGlcIiB2aWV3Qm94PVwiMCAwIDEwMCAxMDBcIj5cclxuICAgICAgICAgICAgPGNpcmNsZSBjeD1cIjUwXCIgY3k9XCI1MFwiIHI9XCI0NVwiIFtuZ1N0eWxlXT1cInsnZmlsbCc6IGFjdGl2ZUNhcm91c2VsRWxlbWVudD09PWkgPyBhY3RpdmVEb3RDb2xvciA6IGRvdENvbG9yfVwiLz5cclxuICAgICAgICAgICAgPHBhdGggaWQ9XCJ7e2l9fVwiIGZpbGw9XCJub25lXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS13aWR0aD1cIjIwXCIgXHJcbiAgICAgICAgICAgIFtuZ1N0eWxlXT1cInsnc3Ryb2tlJzogZG90QW5pbWF0aW9uQ2lyY2xlQ29sb3IsICd2aXNpYmlsaXR5JzogYWN0aXZlQ2Fyb3VzZWxFbGVtZW50PT09aSAmJiBhdXRvUGxheSA/ICd2aXNpYmxlJyA6ICdoaWRkZW4nfVwiXHJcbiAgICAgICAgICAgICAgICAgIGQ9XCJNNTAgMTAgYSA0MCA0MCAwIDAgMSAwIDgwIGEgNDAgNDAgMCAwIDEgMCAtODBcIi8+XHJcbiAgICAgICAgICA8L3N2Zz5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgPGFjdXctcGVyZm9ybWFuY2UtbW9uaXRvciAqbmdJZj1cInNob3dQZXJmb3JtYW5jZU1vbml0b3JcIiAjcGVyZm9ybWFuY2VNb25pdG9yPjwvYWN1dy1wZXJmb3JtYW5jZS1tb25pdG9yPlxyXG4gICAgPC9kaXY+XHJcbiAgICBcclxuICBgLFxyXG4gIHN0eWxlVXJsczogWycuL2Nhcm91c2VsLmNvbXBvbmVudC5jc3MnXSxcclxuICBhbmltYXRpb25zOiBbXHJcbiAgICB0cmlnZ2VyKCdkb3RzQW5pbWF0aW9uJywgW1xyXG4gICAgICB0cmFuc2l0aW9uKCc6ZW50ZXInLCBbXHJcbiAgICAgICAgcXVlcnkoJ3N2ZycsIFtcclxuICAgICAgICAgIHN0eWxlKHsgb3BhY2l0eTogMCwgdHJhbnNmb3JtOiAndHJhbnNsYXRlWSgyMDAlKScgfSksXHJcbiAgICAgICAgICBzdGFnZ2VyKDEwMCwgW1xyXG4gICAgICAgICAgICBhbmltYXRlKCczMDBtcyBlYXNlLWluJywgc3R5bGUoeyBvcGFjaXR5OiAxLCB0cmFuc2Zvcm06ICdub25lJyB9KSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgXSwgeyBvcHRpb25hbDogdHJ1ZSB9KVxyXG4gICAgICBdKSxcclxuICAgICAgdHJhbnNpdGlvbignOmxlYXZlJywgW1xyXG4gICAgICAgIHF1ZXJ5KCdzdmcnLCBbXHJcbiAgICAgICAgICBzdGFnZ2VyKDEwMCwgW1xyXG4gICAgICAgICAgICBhbmltYXRlKCczMDBtcyBlYXNlLWluJywgc3R5bGUoeyBvcGFjaXR5OiAwLCB0cmFuc2Zvcm06ICd0cmFuc2xhdGVZKDIwMCUpJyB9KSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgXSwgeyBvcHRpb25hbDogdHJ1ZSB9KVxyXG4gICAgICBdKVxyXG4gICAgXSksXHJcbiAgICB0cmlnZ2VyKCdhdXRvUGxheUFuaW1hdGlvbicsIFtcclxuICAgICAgc3RhdGUoJ2ZhbHNlJywgc3R5bGUoeyBzdHJva2VEYXNoYXJyYXk6ICcwLDI1MC4yJyB9KSksXHJcbiAgICAgIHN0YXRlKCd0cnVlJywgc3R5bGUoeyBzdHJva2VEYXNoYXJyYXk6ICcyNTAuMiwyNTAuMicgfSkpLFxyXG4gICAgICB0cmFuc2l0aW9uKCdmYWxzZSA9PiB0cnVlJywgYW5pbWF0ZSg1MDAwKSlcclxuICAgIF0pXHJcbiAgXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgQ2Fyb3VzZWxDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XHJcblxyXG4gIEBJbnB1dCgpIHNob3dEb3RzID0gdHJ1ZTtcclxuICBASW5wdXQoKSBkb3RDb2xvciA9ICcjZmZmJztcclxuICBASW5wdXQoKSBhY3RpdmVEb3RDb2xvciA9ICcjM2Y1MWI1JztcclxuICBASW5wdXQoKSBkb3RBbmltYXRpb25DaXJjbGVDb2xvciA9ICcjZmZmJztcclxuICBASW5wdXQoKSBhY3RpdmVDYXJvdXNlbEVsZW1lbnQ6IG51bWJlciA9IDA7XHJcbiAgQElucHV0KCkgaW5pdEFuaW1hdGlvbiA9IHRydWU7XHJcbiAgQElucHV0KCkgcmFkaXVzID0gMjAwO1xyXG4gIEBJbnB1dCgpIHlQb3NpdGlvbiA9IDA7XHJcbiAgQElucHV0KCkgY2FtZXJhRm92ID0gNjU7XHJcbiAgQElucHV0KCkgY2FtZXJhRGlzdGFuY2UgP