UNPKG

ngx-acuw

Version:

Angular components using WEBGL (threejs)

613 lines (611 loc) 75.7 kB
import { Component, ViewChild, Input, HostListener, } from '@angular/core'; import { BufferAttribute, Clock, InstancedBufferAttribute, InstancedBufferGeometry, LinearFilter, Mesh, MeshBasicMaterial, PerspectiveCamera, PlaneGeometry, Raycaster, RGBAFormat, Scene, TextureLoader, Vector2, WebGLRenderer, } from 'three'; import { Object3D, RawShaderMaterial, Texture } from 'three'; import { TouchTexture } from './scripts/touch-texture'; import { Shaders } from './scripts/shaders'; import { RxjsTween } from '../tween/rxjs-tween'; import { interval, Subscription } from 'rxjs'; import { animate, style, transition, trigger } from '@angular/animations'; import * as i0 from "@angular/core"; import * as i1 from "../performance-monitor/performance-monitor.component"; import * as i2 from "@angular/common"; export class ImageAsParticlesComponent { constructor(ngZone) { this.ngZone = ngZone; // Declare variables this.renderer = new WebGLRenderer({ antialias: true, alpha: true, }); this.scene = new Scene(); this.clock = new Clock(true); this.texture = new Texture(); this.width = 0; this.height = 0; this.touch = new TouchTexture(); this.mouse = new Vector2(); this.raycaster = new Raycaster(); this.pImageUrl = ''; this.pImageChanging = false; this.gestureInfo$ = interval(2000); this.gestureInfoSubscription = new Subscription(); this.showTouchGestureInfo = false; this.justifyContent = 'center'; this.alignItems = 'center'; this.backgroundColor = '#000000'; this.imageWidth = '100%'; this.imageHeight = '100%'; this.animationEnabled = true; this.showPerformanceMonitor = false; } // Inputs set imageUrl(imageUrl) { this.pImageUrl = imageUrl; if (this.pImageChanging === true) { return; } if (this.mesh != null) { this.pImageChanging = true; this.triggerImageChange(); } } get imageUrl() { return this.pImageUrl; } set horizontalAlignment(horizontalAlignment) { switch (horizontalAlignment) { case 'start': this.justifyContent = 'flex-start'; break; case 'center': this.justifyContent = 'center'; break; case 'end': this.justifyContent = 'flex-end'; break; default: this.justifyContent = 'center'; break; } } get horizontalAlignment() { return this.justifyContent; } set verticalAlignment(verticalAlignment) { switch (verticalAlignment) { case 'top': this.alignItems = 'flex-start'; break; case 'center': this.alignItems = 'center'; break; case 'bottom': this.alignItems = 'flex-end'; break; default: this.alignItems = 'center'; break; } } get verticalAlignment() { return this.alignItems; } ngAfterViewInit() { if (this.pImageUrl === '') { return; } const canvasWidth = this.canvasRef.nativeElement.clientWidth; const canvasHeight = this.canvasRef.nativeElement.clientHeight; // Set camera this.camera = new PerspectiveCamera(50, canvasWidth / canvasHeight, 1, 10000); this.camera.position.z = 300; // Init particles this.initParticles(this.pImageUrl); // Init renderer this.renderer.setSize(canvasWidth - 1, canvasHeight); this.canvasRef.nativeElement.appendChild(this.renderer.domElement); // Start animation this.animate(); } ngOnDestroy() { this.scene.clear(); this.renderer.clear(); this.texture.dispose(); this.renderer.dispose(); } /** * Creates the particles depending on the image and initializes the touch canvas * @param url url of the image */ initParticles(url) { const loader = new TextureLoader(); loader.load(url, (texture) => { this.texture = texture; this.texture.minFilter = LinearFilter; this.texture.magFilter = LinearFilter; this.texture.format = RGBAFormat; this.width = texture.image.width; this.height = texture.image.height; this.initPoints(true); this.initHitArea(); this.initTouch(); this.resize(); this.show(); }); } /** * Initializes the points * @param discard discard pixels darker than threshold #22 */ initPoints(discard) { const numPoints = this.width * this.height; let numVisible = numPoints; let threshold = 0; let originalColors = new Float32Array(); if (discard) { // discard pixels darker than threshold #22 numVisible = 0; threshold = 34; const img = this.texture.image; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = this.width; canvas.height = this.height; if (ctx != null) { ctx.scale(1, -1); ctx.drawImage(img, 0, 0, this.width, this.height * -1); const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); originalColors = Float32Array.from(imgData.data); for (let i = 0; i < numPoints; i++) { if (originalColors[i * 4 + 0] > threshold) { numVisible++; } } } } const uniforms = { uTime: { value: 0 }, uRandom: { value: 1.0 }, uDepth: { value: 2.0 }, uSize: { value: 0.0 }, uTextureSize: { value: new Vector2(this.width, this.height) }, uTexture: { value: this.texture }, uTouch: { value: null }, }; const shaders = new Shaders(); const material = new RawShaderMaterial({ uniforms, vertexShader: shaders.particleVertex, fragmentShader: shaders.particleFragment, depthTest: false, transparent: true, // blending: THREE.AdditiveBlending }); const geometry = new InstancedBufferGeometry(); // positions const positions = new BufferAttribute(new Float32Array(4 * 3), 3); positions.setXYZ(0, -0.5, 0.5, 0.0); positions.setXYZ(1, 0.5, 0.5, 0.0); positions.setXYZ(2, -0.5, -0.5, 0.0); positions.setXYZ(3, 0.5, -0.5, 0.0); geometry.setAttribute('position', positions); // uvs const uvs = new BufferAttribute(new Float32Array(4 * 2), 2); uvs.setXY(0, 0.0, 0.0); uvs.setXY(1, 1.0, 0.0); uvs.setXY(2, 0.0, 1.0); uvs.setXY(3, 1.0, 1.0); geometry.setAttribute('uv', uvs); // index geometry.setIndex(new BufferAttribute(new Uint16Array([0, 2, 1, 2, 3, 1]), 1)); const indices = new Uint16Array(numVisible); const offsets = new Float32Array(numVisible * 3); const angles = new Float32Array(numVisible); for (let i = 0, j = 0; i < numPoints; i++) { if (discard && originalColors[i * 4 + 0] <= threshold) { continue; } offsets[j * 3 + 0] = i % this.width; offsets[j * 3 + 1] = Math.floor(i / this.width); indices[j] = i; angles[j] = Math.random() * Math.PI; j++; } geometry.setAttribute('pindex', new InstancedBufferAttribute(indices, 1, false)); geometry.setAttribute('offset', new InstancedBufferAttribute(offsets, 3, false)); geometry.setAttribute('angle', new InstancedBufferAttribute(angles, 1, false)); this.mesh = new Mesh(geometry, material); const object3d = new Object3D(); object3d.add(this.mesh); this.scene.add(object3d); } /** * Initializes the touch area */ initTouch() { this.mesh.material.uniforms.uTouch.value = this.touch.texture; } /** * Initializes the hit area */ initHitArea() { const geometry = new PlaneGeometry(this.width, this.height, 1, 1); const material = new MeshBasicMaterial({ color: 0xffffff, wireframe: true, depthTest: false, }); material.visible = false; this.hitArea = new Mesh(geometry, material); this.mesh.add(this.hitArea); } /** * animation for showing the particles * @param time time of animation in ms */ show(time = 1000) { // Tween in this.ngZone.runOutsideAngular(() => { RxjsTween.createTween(RxjsTween.easeInOutQuad, [0.5, 0.0, 70.0], [1.5, 2.0, 4.0], time).subscribe((val) => { this.mesh.material.uniforms.uSize.value = val[0]; this.mesh.material.uniforms.uRandom.value = val[1]; this.mesh.material.uniforms.uDepth.value = val[2]; }, () => { }, () => { this.pImageChanging = false; }); }); } /** * animation for tween out the particles and destroy everything * @param time time of animation in ms */ triggerImageChange(time = 1000) { const uSizeStart = this.mesh.material.uniforms.uSize .value; const uRandomStart = this.mesh.material.uniforms .uRandom.value; const uDepth = this.mesh.material.uniforms.uDepth .value; this.ngZone.runOutsideAngular(() => { // Tween out RxjsTween.createTween(RxjsTween.easeInOutQuad, [uSizeStart, uRandomStart, uDepth], [0.0, 5.0, -20.0], time).subscribe((val) => { this.mesh.material.uniforms.uSize.value = val[0]; this.mesh.material.uniforms.uRandom.value = val[1]; this.mesh.material.uniforms.uDepth.value = val[2]; }, () => { }, () => { if (this.mesh != null) { if (this.mesh.parent != null) { this.mesh.parent.remove(this.mesh); } this.mesh.geometry.dispose(); this.mesh.material.dispose(); } if (this.hitArea != null) { if (this.hitArea.parent != null) { this.hitArea.parent.remove(this.hitArea); } this.hitArea.geometry.dispose(); this.hitArea.material.dispose(); } this.initParticles(this.pImageUrl); this.pImageChanging = false; }); }); } /** * Method for triggering the animation */ animate() { this.ngZone.runOutsideAngular(() => { window.requestAnimationFrame(() => this.animate()); if (this.animationEnabled === true) { const delta = this.clock.getDelta(); if (this.mesh != null) { if (this.touch) { this.touch.update(); } this.mesh.material.uniforms.uTime.value += delta; } this.renderer.render(this.scene, this.camera); } if (this.performanceMonitor && this.showPerformanceMonitor) { this.performanceMonitor.end(); } }); } /** * Handle mouse move event * @param event mouse event */ onMouseMove(event) { // getBoundingClientRect retruns the distance in pixels of the top left corner of the element // to the top left corner of the viewport const domRect = this.canvasRef.nativeElement.getBoundingClientRect(); // get the offset distance between the canvas, which contains the particles, to the outer container element const canvasEl = this.canvasRef.nativeElement .children[0]; // Calculate the relative mouse position this.mouse.x = ((event.clientX - domRect.left - canvasEl.offsetLeft) / canvasEl.clientWidth) * 2 - 1; this.mouse.y = (-(event.clientY - domRect.top - canvasEl.offsetTop) / canvasEl.clientHeight) * 2 + 1; // console.info('raw: x= ' + event.clientX + ' , y= ' + event.clientY); // console.info('normalized: x= ' + this.mouse.x + ' , y= ' + this.mouse.y); this.raycaster.setFromCamera(this.mouse, this.camera); if (this.hitArea === undefined) { return; } const intersects = this.raycaster.intersectObject(this.hitArea); if (intersects !== undefined && intersects.length > 0 && this.touch && intersects[0].uv !== undefined) { this.touch.addTouch(intersects[0].uv.x, intersects[0].uv.y); } } /** * Handle touch move envent * @param event mouse event */ onTouchMove(event) { if (event.touches.length < 2) { this.showTouchGestureInfo = true; this.gestureInfoSubscription.unsubscribe(); this.gestureInfoSubscription = this.gestureInfo$.subscribe({ next: () => { this.showTouchGestureInfo = false; this.gestureInfoSubscription.unsubscribe(); }, }); return; } event.preventDefault(); // getBoundingClientRect retruns the distance in pixels of the top left corner of the element // to the top left corner of the viewport const domRect = this.canvasRef.nativeElement.getBoundingClientRect(); // get the offset distance between the canvas, which contains the particles, to the outer container element const canvasEl = this.canvasRef.nativeElement .children[0]; // Calculate the relative mouse position this.mouse.x = ((event.touches[0].clientX - domRect.left - canvasEl.offsetLeft) / canvasEl.clientWidth) * 2 - 1; this.mouse.y = (-(event.touches[0].clientY - domRect.top - canvasEl.offsetTop) / canvasEl.clientHeight) * 2 + 1; this.raycaster.setFromCamera(this.mouse, this.camera); const intersects = this.raycaster.intersectObject(this.hitArea); if (intersects !== undefined && intersects.length > 0 && this.touch && intersects[0].uv !== undefined) { this.touch.addTouch(intersects[0].uv.x, intersects[0].uv.y); } } resize() { if (this.height !== undefined) { this.camera.aspect = this.canvasRef.nativeElement.clientWidth / this.canvasRef.nativeElement.clientHeight; this.camera.updateProjectionMatrix(); const fovHeight = 2 * Math.tan((this.camera.fov * Math.PI) / 180 / 2) * this.camera.position.z; const scale = fovHeight / this.height; this.mesh.scale.set(scale, scale, 1); // this.hitArea.scale.set(scale, scale, 1); if (this.renderer !== undefined) { const width = this.imageWidth == null ? this.canvasRef.nativeElement.clientWidth : this.distanceAsNumber(this.imageWidth, this.canvasRef.nativeElement.clientWidth); const height = this.imageHeight == null ? this.canvasRef.nativeElement.clientHeight : this.distanceAsNumber(this.imageHeight, this.canvasRef.nativeElement.clientHeight); this.renderer.setSize(width, height); } } } distanceAsNumber(distance, parentDistance) { let returnVal = 0; if (distance.includes('px')) { returnVal = Number.parseInt(distance.replace('px', ''), 10); } else if (distance.includes('%')) { returnVal = (Number.parseInt(distance.replace('%', ''), 10) / 100) * parentDistance; } else { returnVal = Number.parseInt(distance, 10); } return returnVal; } } ImageAsParticlesComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ImageAsParticlesComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); ImageAsParticlesComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: ImageAsParticlesComponent, selector: "lib-image-as-particles", inputs: { imageUrl: "imageUrl", backgroundColor: "backgroundColor", imageWidth: "imageWidth", imageHeight: "imageHeight", horizontalAlignment: "horizontalAlignment", verticalAlignment: "verticalAlignment", animationEnabled: "animationEnabled", showPerformanceMonitor: "showPerformanceMonitor" }, host: { listeners: { "window:resize": "resize()" } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["container"], descendants: true }, { propertyName: "performanceMonitor", first: true, predicate: ["performanceMonitor"], descendants: true }], ngImport: i0, template: ` <div #container class="threejs-container" [style.background-color]="backgroundColor" [style.justify-content]="justifyContent" [style.align-items]="alignItems" (mousemove)="onMouseMove($event)" (touchmove)="onTouchMove($event)" ></div> <div *ngIf="showTouchGestureInfo == true" class="touch-gesture-info" [@showHideGestureInformation] > <div> <span>Use two fingers for touch animation</span> <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" viewBox="0 0 24 24" fill="white" width="18px" height="18px" > <g><rect fill="none" height="24" width="24" x="0" /></g> <g> <g> <g> <path d="M9,11.24V7.5C9,6.12,10.12,5,11.5,5S14,6.12,14,7.5v3.74c1.21-0.81,2-2.18,2-3.74C16,5.01,13.99,3,11.5,3S7,5.01,7,7.5 C7,9.06,7.79,10.43,9,11.24z M18.84,15.87l-4.54-2.26c-0.17-0.07-0.35-0.11-0.54-0.11H13v-6C13,6.67,12.33,6,11.5,6 S10,6.67,10,7.5v10.74c-3.6-0.76-3.54-0.75-3.67-0.75c-0.31,0-0.59,0.13-0.79,0.33l-0.79,0.8l4.94,4.94 C9.96,23.83,10.34,24,10.75,24h6.79c0.75,0,1.33-0.55,1.44-1.28l0.75-5.27c0.01-0.07,0.02-0.14,0.02-0.2 C19.75,16.63,19.37,16.09,18.84,15.87z" /> </g> </g> </g> </svg> </div> </div> <acuw-performance-monitor *ngIf="showPerformanceMonitor" #performanceMonitor ></acuw-performance-monitor> `, isInline: true, styles: [".threejs-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%;background-color:#222}.touch-gesture-info{position:absolute;width:100%;display:flex;flex-direction:row;justify-content:center;top:20px;color:#fff}.touch-gesture-info div{background-color:#0000004d;display:flex;flex-direction:row;padding:6px 10px;border-radius:5px}\n"], components: [{ type: i1.PerformanceMonitorComponent, selector: "acuw-performance-monitor" }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [ trigger('showHideGestureInformation', [ transition(':enter', [ style({ opacity: '0' }), animate('300ms ease-in', style({ opacity: '1' })), ]), transition(':leave', [ style({ opacity: '1' }), animate('300ms ease-in', style({ opacity: '0' })), ]), ]), ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ImageAsParticlesComponent, decorators: [{ type: Component, args: [{ selector: 'lib-image-as-particles', template: ` <div #container class="threejs-container" [style.background-color]="backgroundColor" [style.justify-content]="justifyContent" [style.align-items]="alignItems" (mousemove)="onMouseMove($event)" (touchmove)="onTouchMove($event)" ></div> <div *ngIf="showTouchGestureInfo == true" class="touch-gesture-info" [@showHideGestureInformation] > <div> <span>Use two fingers for touch animation</span> <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" viewBox="0 0 24 24" fill="white" width="18px" height="18px" > <g><rect fill="none" height="24" width="24" x="0" /></g> <g> <g> <g> <path d="M9,11.24V7.5C9,6.12,10.12,5,11.5,5S14,6.12,14,7.5v3.74c1.21-0.81,2-2.18,2-3.74C16,5.01,13.99,3,11.5,3S7,5.01,7,7.5 C7,9.06,7.79,10.43,9,11.24z M18.84,15.87l-4.54-2.26c-0.17-0.07-0.35-0.11-0.54-0.11H13v-6C13,6.67,12.33,6,11.5,6 S10,6.67,10,7.5v10.74c-3.6-0.76-3.54-0.75-3.67-0.75c-0.31,0-0.59,0.13-0.79,0.33l-0.79,0.8l4.94,4.94 C9.96,23.83,10.34,24,10.75,24h6.79c0.75,0,1.33-0.55,1.44-1.28l0.75-5.27c0.01-0.07,0.02-0.14,0.02-0.2 C19.75,16.63,19.37,16.09,18.84,15.87z" /> </g> </g> </g> </svg> </div> </div> <acuw-performance-monitor *ngIf="showPerformanceMonitor" #performanceMonitor ></acuw-performance-monitor> `, styles: [ ` .threejs-container { position: relative; display: flex; justify-content: center; align-items: center; width: 100%; height: 100%; background-color: #222222; } .touch-gesture-info { position: absolute; width: 100%; display: flex; flex-direction: row; justify-content: center; top: 20px; color: white; } .touch-gesture-info div { background-color: rgba(0, 0, 0, 0.3); display: flex; flex-direction: row; padding: 6px 10px 6px 10px; border-radius: 5px; } `, ], animations: [ trigger('showHideGestureInformation', [ transition(':enter', [ style({ opacity: '0' }), animate('300ms ease-in', style({ opacity: '1' })), ]), transition(':leave', [ style({ opacity: '1' }), animate('300ms ease-in', style({ opacity: '0' })), ]), ]), ], }] }], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { imageUrl: [{ type: Input }], backgroundColor: [{ type: Input }], imageWidth: [{ type: Input }], imageHeight: [{ type: Input }], horizontalAlignment: [{ type: Input }], verticalAlignment: [{ type: Input }], animationEnabled: [{ type: Input }], showPerformanceMonitor: [{ type: Input }], canvasRef: [{ type: ViewChild, args: ['container'] }], performanceMonitor: [{ type: ViewChild, args: ['performanceMonitor'] }], resize: [{ type: HostListener, args: ['window:resize'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtYXMtcGFydGljbGVzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1hY3V3L3NyYy9saWIvaW1hZ2UtYXMtcGFydGljbGVzL2ltYWdlLWFzLXBhcnRpY2xlcy5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxTQUFTLEVBR1QsS0FBSyxFQUVMLFlBQVksR0FFYixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQ0wsZUFBZSxFQUNmLEtBQUssRUFDTCx3QkFBd0IsRUFDeEIsdUJBQXVCLEVBQ3ZCLFlBQVksRUFDWixJQUFJLEVBQ0osaUJBQWlCLEVBQ2pCLGlCQUFpQixFQUNqQixhQUFhLEVBQ2IsU0FBUyxFQUNULFVBQVUsRUFDVixLQUFLLEVBQ0wsYUFBYSxFQUNiLE9BQU8sRUFDUCxhQUFhLEdBQ2QsTUFBTSxPQUFPLENBQUM7QUFDZixPQUFPLEVBQUUsUUFBUSxFQUFFLGlCQUFpQixFQUFFLE9BQU8sRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUM3RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsUUFBUSxFQUFjLFlBQVksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMxRCxPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7Ozs7QUE0RjFFLE1BQU0sT0FBTyx5QkFBeUI7SUEwRnBDLFlBQW9CLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBekZsQyxvQkFBb0I7UUFDWixhQUFRLEdBQWtCLElBQUksYUFBYSxDQUFDO1lBQ2xELFNB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SyxDQUFDLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDO2dDQUN2QixPQUFPLENBQUMsZUFBZSxFQUFFLEtBQUssQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDOzZCQUNsRCxDQUFDOzRCQUNGLFVBQVUsQ0FBQyxRQUFRLEVBQUU7Z0NBQ25CLEtBQUssQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQztnQ0FDdkIsT0FBTyxDQUFDLGVBQWUsRUFBRSxLQUFLLENBQUMsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQzs2QkFDbEQsQ0FBQzt5QkFDSCxDQUFDO3FCQUNIO2lCQUNGOzZGQTRCSyxRQUFRO3NCQURYLEtBQUs7Z0JBY0csZUFBZTtzQkFBdkIsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBRUYsbUJBQW1CO3NCQUR0QixLQUFLO2dCQXFCRixpQkFBaUI7c0JBRHBCLEtBQUs7Z0JBb0JHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxzQkFBc0I7c0JBQTlCLEtBQUs7Z0JBRWtCLFNBQVM7c0JBQWhDLFNBQVM7dUJBQUMsV0FBVztnQkFFdEIsa0JBQWtCO3NCQURqQixTQUFTO3VCQUFDLG9CQUFvQjtnQkF5WUEsTUFBTTtzQkFBcEMsWUFBWTt1QkFBQyxlQUFlIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgVmlld0NoaWxkLFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgQWZ0ZXJWaWV3SW5pdCxcclxuICBJbnB1dCxcclxuICBPbkRlc3Ryb3ksXHJcbiAgSG9zdExpc3RlbmVyLFxyXG4gIE5nWm9uZSxcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtcclxuICBCdWZmZXJBdHRyaWJ1dGUsXHJcbiAgQ2xvY2ssXHJcbiAgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlLFxyXG4gIEluc3RhbmNlZEJ1ZmZlckdlb21ldHJ5LFxyXG4gIExpbmVhckZpbHRlcixcclxuICBNZXNoLFxyXG4gIE1lc2hCYXNpY01hdGVyaWFsLFxyXG4gIFBlcnNwZWN0aXZlQ2FtZXJhLFxyXG4gIFBsYW5lR2VvbWV0cnksXHJcbiAgUmF5Y2FzdGVyLFxyXG4gIFJHQkFGb3JtYXQsXHJcbiAgU2NlbmUsXHJcbiAgVGV4dHVyZUxvYWRlcixcclxuICBWZWN0b3IyLFxyXG4gIFdlYkdMUmVuZGVyZXIsXHJcbn0gZnJvbSAndGhyZWUnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCwgUmF3U2hhZGVyTWF0ZXJpYWwsIFRleHR1cmUgfSBmcm9tICd0aHJlZSc7XHJcbmltcG9ydCB7IFRvdWNoVGV4dHVyZSB9IGZyb20gJy4vc2NyaXB0cy90b3VjaC10ZXh0dXJlJztcclxuaW1wb3J0IHsgU2hhZGVycyB9IGZyb20gJy4vc2NyaXB0cy9zaGFkZXJzJztcclxuaW1wb3J0IHsgUnhqc1R3ZWVuIH0gZnJvbSAnLi4vdHdlZW4vcnhqcy10d2Vlbic7XHJcbmltcG9ydCB7IGludGVydmFsLCBPYnNlcnZhYmxlLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgYW5pbWF0ZSwgc3R5bGUsIHRyYW5zaXRpb24sIHRyaWdnZXIgfSBmcm9tICdAYW5ndWxhci9hbmltYXRpb25zJztcclxuaW1wb3J0IHsgUGVyZm9ybWFuY2VNb25pdG9yQ29tcG9uZW50IH0gZnJvbSAnLi4vcGVyZm9ybWFuY2UtbW9uaXRvci9wZXJmb3JtYW5jZS1tb25pdG9yLmNvbXBvbmVudCc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2xpYi1pbWFnZS1hcy1wYXJ0aWNsZXMnLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2XHJcbiAgICAgICNjb250YWluZXJcclxuICAgICAgY2xhc3M9XCJ0aHJlZWpzLWNvbnRhaW5lclwiXHJcbiAgICAgIFtzdHlsZS5iYWNrZ3JvdW5kLWNvbG9yXT1cImJhY2tncm91bmRDb2xvclwiXHJcbiAgICAgIFtzdHlsZS5qdXN0aWZ5LWNvbnRlbnRdPVwianVzdGlmeUNvbnRlbnRcIlxyXG4gICAgICBbc3R5bGUuYWxpZ24taXRlbXNdPVwiYWxpZ25JdGVtc1wiXHJcbiAgICAgIChtb3VzZW1vdmUpPVwib25Nb3VzZU1vdmUoJGV2ZW50KVwiXHJcbiAgICAgICh0b3VjaG1vdmUpPVwib25Ub3VjaE1vdmUoJGV2ZW50KVwiXHJcbiAgICA+PC9kaXY+XHJcbiAgICA8ZGl2XHJcbiAgICAgICpuZ0lmPVwic2hvd1RvdWNoR2VzdHVyZUluZm8gPT0gdHJ1ZVwiXHJcbiAgICAgIGNsYXNzPVwidG91Y2gtZ2VzdHVyZS1pbmZvXCJcclxuICAgICAgW0BzaG93SGlkZUdlc3R1cmVJbmZvcm1hdGlvbl1cclxuICAgID5cclxuICAgICAgPGRpdj5cclxuICAgICAgICA8c3Bhbj5Vc2UgdHdvIGZpbmdlcnMgZm9yIHRvdWNoIGFuaW1hdGlvbjwvc3Bhbj5cclxuICAgICAgICA8c3ZnXHJcbiAgICAgICAgICB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCJcclxuICAgICAgICAgIGVuYWJsZS1iYWNrZ3JvdW5kPVwibmV3IDAgMCAyNCAyNFwiXHJcbiAgICAgICAgICB2aWV3Qm94PVwiMCAwIDI0IDI0XCJcclxuICAgICAgICAgIGZpbGw9XCJ3a