ngx-acuw
Version:
Angular components using WEBGL (threejs)
486 lines (484 loc) • 69.1 kB
JavaScript
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