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