UNPKG

@wolsok/thanos

Version:

Wolf Soko's implementation of a cool Thanos snapping vaporizing effect for destroying dom elements

253 lines 44.7 kB
import { Inject, Injectable, NgZone } from '@angular/core'; import { default as html2canvas } from 'html2canvas'; import { animationFrameScheduler, finalize, from, interval, map, switchMap, takeWhile, tap, timeInterval, } from 'rxjs'; import { SimplexNoise } from './simplex-noise'; import { WS_THANOS_OPTIONS_TOKEN } from './ws-thanos-options.token'; import * as i0 from "@angular/core"; const PARTICLE_BYTE_LENGTH = 10; const MIN_PARTICLE_ALPHA = ~~(255 * 0.01); const HEIGHT_SCALE = 5; const WIDTH_SCALE = 2; const FLOW_FIELD_RES = 0.05; class WsThanosService { thanosOptions; ngZone; constructor(thanosOptions, ngZone) { this.thanosOptions = thanosOptions; this.ngZone = ngZone; } static getParticleIndicesForBase(base) { return { x: base, y: base + 1, dx: base + 2, dy: base + 3, ax: base + 4, ay: base + 5, r: base + 6, g: base + 7, b: base + 8, a: base + 9, }; } static getColorIndicesForCoord(x, y, width) { const red = y * (width * 4) + x * 4; return { r: red, g: red + 1, b: red + 2, a: red + 3 }; } static updateParticles({ seed, noise, particlesData, thanosOptions, animationState, }) { const { deltaTSec, animationT, maxWidth, maxHeight } = animationState; const { particleAcceleration } = thanosOptions; const { particles, maxParticleX, minParticleY } = particlesData; // the time is used to calculate the vaporization front. const time = Math.sin(animationT * (Math.PI / 2)) * 1.1; const startAccelerateX = maxParticleX - time * maxParticleX; const startAccelerateY = time * (maxHeight - minParticleY) + minParticleY; const lengthY = maxHeight - startAccelerateY; const accelerateRadiusPow = startAccelerateX * startAccelerateX + lengthY * lengthY; for (let i = 0; i < particles.length; i += PARTICLE_BYTE_LENGTH) { const { x, y, dx, dy, ax, ay, a } = WsThanosService.getParticleIndicesForBase(i); const particleX = particles[x]; const particleY = particles[y]; // only update particles that are inside view and visible if (particleX > maxWidth || particleX < 0 || particleY > maxHeight || particleY < 0 || particles[a] < MIN_PARTICLE_ALPHA) { continue; } if (!(Math.abs(particles[ax]) > 0 || Math.abs(particles[ay]) > 0)) { let pYLength = maxHeight - particleY; let pXLength = particleX; // we calculate some random looking numbers and functions to have nice looking vaporizing front of particles // todo consider to use noise; pXLength += Math.tan((pXLength / 20.12) * time + seed) * 0.5; pXLength += (particleX % deltaTSec) * 0.5; pXLength += Math.sin((pXLength / 30 + 723.394) * time + seed * 12.5) * 11; pYLength += Math.tan((pYLength / 0.45) * time + seed * 1.5) * 0.5; pYLength += Math.cos((pYLength / 100 + 2323.234) * time + seed * 456.1) * 23; const pLength = pXLength * pXLength + pYLength * pYLength; if (pLength > accelerateRadiusPow) { particles[ax] = Math.random(); particles[ay] = Math.random() * -1; } } else { // use noise to flow along velocity field const flowFieldAcc = WsThanosService.getXYFromFlowField(noise, seed, particleX, particleY); const accelerationX = flowFieldAcc[0]; const accelerationY = flowFieldAcc[1]; particles[ax] += accelerationX; particles[ay] += accelerationY; } // * Math.pow(1 + animationT, 4) particles[dx] += particles[ax] * particleAcceleration * deltaTSec; particles[dy] += particles[ay] * particleAcceleration * deltaTSec; particles[x] += particles[dx] * deltaTSec; particles[y] += particles[dy] * deltaTSec; // fade particle out ( very late); particles[a] *= 1 - Math.pow(animationT, 15); // 255 - Math.sqrt(particles[dx] * particles[dx] + particles[dy] * particles[dy]) / 1.2; } } static drawParticles(drawCtx, particles) { const { width, height } = drawCtx.canvas; drawCtx.clearRect(0, 0, width, height); const image = drawCtx.getImageData(0, 0, width, height); const imageData = image.data; for (let i = 0; i < particles.length; i += PARTICLE_BYTE_LENGTH) { const particleX = particles[i]; const particleY = particles[i + 1]; const pI = WsThanosService.getParticleIndicesForBase(i); if (particleX > width || particleX < 0 || particleY > height || particleY < 0 || particles[pI.a] < MIN_PARTICLE_ALPHA) { continue; } const { r, g, b, a } = WsThanosService.getColorIndicesForCoord(~~particles[pI.x], ~~particles[pI.y], width); imageData[r] = ~~particles[pI.r]; imageData[g] = ~~particles[pI.g]; imageData[b] = ~~particles[pI.b]; imageData[a] = ~~particles[pI.a]; } drawCtx.putImageData(image, 0, 0); } static prepareCanvasForVaporize(divCanvas, maxParticleCount) { const { width, height } = divCanvas; // scale result canvas to have more room to draw particles while vaporizing; const resultHeight = height * HEIGHT_SCALE; const resultWidth = width * WIDTH_SCALE; const resultCanvas = document.createElement('canvas'); resultCanvas.height = resultHeight; resultCanvas.width = resultWidth; const imageData = divCanvas.getContext('2d')?.getImageData(0, 0, width, height); if (imageData == null) { throw new Error('Could not get image data from canvas'); } const particlesData = WsThanosService.createParticlesForImageData(imageData, maxParticleCount, resultHeight); return { resultCanvas, particlesData }; } static createParticlesForImageData(imageData, maxParticleCount, resultHeight) { const { width, height } = imageData; let particleCandidates = 0; let particleCount = 0; const particleCandiatesList = []; for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const { a } = WsThanosService.getColorIndicesForCoord(x, y, width); if (imageData.data[a] >= MIN_PARTICLE_ALPHA) { particleCandidates++; particleCandiatesList.push({ x, y }); } } } const maxNumParticles = Math.min(particleCandidates, maxParticleCount); const particles = new Float32Array(Float32Array.BYTES_PER_ELEMENT * maxNumParticles * PARTICLE_BYTE_LENGTH); let maxParticleX = 0; let minParticleY = resultHeight; while (particleCount < maxNumParticles) { // select random index from candiates const index = ~~(Math.random() * particleCandiatesList.length); const { x, y } = particleCandiatesList[index]; // overwrite index with last element to prevent double selection of particles // eslint-disable-next-line @typescript-eslint/no-non-null-assertion particleCandiatesList[index] = particleCandiatesList.pop(); maxParticleX = Math.max(maxParticleX, x); minParticleY = Math.min(minParticleY, y); const { dx, dy, ax, ay, r, g, b, a, ...xy } = WsThanosService.getParticleIndicesForBase(particleCount * PARTICLE_BYTE_LENGTH); particles[xy.x] = x; particles[xy.y] = y + resultHeight - height; particles[dx] = 0; particles[dy] = 0; particles[ax] = 0; particles[ay] = 0; const indicesImage = WsThanosService.getColorIndicesForCoord(x, y, width); particles[r] = imageData.data[indicesImage.r]; particles[g] = imageData.data[indicesImage.g]; particles[b] = imageData.data[indicesImage.b]; particles[a] = imageData.data[indicesImage.a]; particleCount++; } return { particles, maxParticleX, minParticleY }; } static getXYFromFlowField(noise, seed, x, y) { const sampleX = noise.scaled3D(x, y, seed + 33.23, FLOW_FIELD_RES); const sampleY = noise.scaled3D(x, seed / 13.23, y, FLOW_FIELD_RES) * -1; return [sampleX, sampleY]; } /** * start the vaporizeAndScrollIntoView-effect. * * It's running outside the ngZone. */ vaporize(elem) { return this.ngZone.runOutsideAngular(() => this.vaporizeIntern(elem)); } vaporizeIntern(elem) { elem.style.opacity = elem.style.opacity || '1'; elem.style.transition = `opacity ${Math.floor(this.thanosOptions.animationLength * 0.8)}ms ease-out`; const noise = new SimplexNoise({ frequency: 0.01, min: 0 }); const seed = new Date().getDate() * Math.random(); const html2CanvasPromise = html2canvas(elem, { backgroundColor: null, scale: 1, allowTaint: true, windowHeight: window.innerHeight, windowWidth: window.innerWidth, scrollY: -window.scrollY, }); return from(html2CanvasPromise).pipe(map((canvasFromHtmlElem) => { const canvasAndParticles = WsThanosService.prepareCanvasForVaporize(canvasFromHtmlElem, this.thanosOptions.maxParticleCount); const { resultCanvas } = canvasAndParticles; if (elem.parentElement) { elem.parentElement.style.position = elem.parentElement.style.position || 'relative'; } resultCanvas.style.position = 'absolute'; resultCanvas.style.left = 0 + 'px'; resultCanvas.style.top = '-' + elem.getBoundingClientRect().height * (HEIGHT_SCALE - 1) + 'px'; resultCanvas.style.zIndex = '2000'; resultCanvas.style.pointerEvents = 'none'; elem.insertAdjacentElement('beforebegin', resultCanvas); // this should start the transition above defined elem.style.opacity = '0'; return canvasAndParticles; }), switchMap(({ resultCanvas, particlesData }) => { let time = 0; const { animationLength, maxParticleCount, particleAcceleration } = this.thanosOptions; return interval(1000 / 60, animationFrameScheduler).pipe(timeInterval(), tap((deltaT) => (time += deltaT.interval)), map((deltaT) => ({ deltaTSec: deltaT.interval / 1000, animationT: time / animationLength, maxWidth: resultCanvas.width, maxHeight: resultCanvas.height, })), tap((animationState) => { WsThanosService.updateParticles({ particlesData, animationState, thanosOptions: { animationLength, maxParticleCount, particleAcceleration, }, noise, seed, }); const context = resultCanvas.getContext('2d'); if (context) { WsThanosService.drawParticles(context, particlesData.particles); } }), takeWhile((animationState) => animationState.animationT <= 1), finalize(() => resultCanvas.remove())); })); } static ɵfac = function WsThanosService_Factory(t) { return new (t || WsThanosService)(i0.ɵɵinject(WS_THANOS_OPTIONS_TOKEN), i0.ɵɵinject(i0.NgZone)); }; static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: WsThanosService, factory: WsThanosService.ɵfac, providedIn: 'root' }); } export { WsThanosService }; (function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(WsThanosService, [{ type: Injectable, args: [{ providedIn: 'root' }] }], function () { return [{ type: undefined, decorators: [{ type: Inject, args: [WS_THANOS_OPTIONS_TOKEN] }] }, { type: i0.NgZone }]; }, null); })(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3MtdGhhbm9zLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL3B1YmxpYy93cy10aGFub3Mvc3JjL2xpYi93cy10aGFub3Muc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFM0QsT0FBTyxFQUFFLE9BQU8sSUFBSSxXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDckQsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixRQUFRLEVBQ1IsSUFBSSxFQUNKLFFBQVEsRUFDUixHQUFHLEVBRUgsU0FBUyxFQUNULFNBQVMsRUFDVCxHQUFHLEVBQ0gsWUFBWSxHQUNiLE1BQU0sTUFBTSxDQUFDO0FBRWQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDOztBQUdwRSxNQUFNLG9CQUFvQixHQUFHLEVBQUUsQ0FBQztBQUNoQyxNQUFNLGtCQUFrQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsQ0FBQztBQUMxQyxNQUFNLFlBQVksR0FBRyxDQUFDLENBQUM7QUFDdkIsTUFBTSxXQUFXLEdBQUcsQ0FBQyxDQUFDO0FBQ3RCLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQztBQTZCNUIsTUFDYSxlQUFlO0lBR2hCO0lBQ0E7SUFIVixZQUVVLGFBQThCLEVBQzlCLE1BQWM7UUFEZCxrQkFBYSxHQUFiLGFBQWEsQ0FBaUI7UUFDOUIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtJQUNyQixDQUFDO0lBRUksTUFBTSxDQUFDLHlCQUF5QixDQUFDLElBQVk7UUFDbkQsT0FBTztZQUNMLENBQUMsRUFBRSxJQUFJO1lBQ1AsQ0FBQyxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1gsRUFBRSxF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d0JBQ2IsZUFBZTt3QkFDZixnQkFBZ0I7d0JBQ2hCLG9CQUFvQjtxQkFDckI7b0JBQ0QsS0FBSztvQkFDTCxJQUFJO2lCQUNMLENBQUMsQ0FBQztnQkFDSCxNQUFNLE9BQU8sR0FBRyxZQUFZLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUM5QyxJQUFJLE9BQU8sRUFBRTtvQkFDWCxlQUFlLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7aUJBQ2pFO1lBQ0gsQ0FBQyxDQUFDLEVBQ0YsU0FBUyxDQUFDLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQyxjQUFjLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQyxFQUM3RCxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQ3RDLENBQUM7UUFDSixDQUFDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQzt5RUExU1UsZUFBZSxjQUVoQix1QkFBdUI7Z0VBRnRCLGVBQWUsV0FBZixlQUFlLG1CQURGLE1BQU07O1NBQ25CLGVBQWU7dUZBQWYsZUFBZTtjQUQzQixVQUFVO2VBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFOztzQkFHN0IsTUFBTTt1QkFBQyx1QkFBdUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIE5nWm9uZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBkZWZhdWx0IGFzIGh0bWwyY2FudmFzIH0gZnJvbSAnaHRtbDJjYW52YXMnO1xuaW1wb3J0IHtcbiAgYW5pbWF0aW9uRnJhbWVTY2hlZHVsZXIsXG4gIGZpbmFsaXplLFxuICBmcm9tLFxuICBpbnRlcnZhbCxcbiAgbWFwLFxuICBPYnNlcnZhYmxlLFxuICBzd2l0Y2hNYXAsXG4gIHRha2VXaGlsZSxcbiAgdGFwLFxuICB0aW1lSW50ZXJ2YWwsXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQW5pbWF0aW9uU3RhdGUgfSBmcm9tICcuL2FuaW1hdGlvbi5zdGF0ZSc7XG5pbXBvcnQgeyBTaW1wbGV4Tm9pc2UgfSBmcm9tICcuL3NpbXBsZXgtbm9pc2UnO1xuaW1wb3J0IHsgV1NfVEhBTk9TX09QVElPTlNfVE9LRU4gfSBmcm9tICcuL3dzLXRoYW5vcy1vcHRpb25zLnRva2VuJztcbmltcG9ydCB0eXBlIHsgV3NUaGFub3NPcHRpb25zIH0gZnJvbSAnLi93cy10aGFub3Mub3B0aW9ucyc7XG5cbmNvbnN0IFBBUlRJQ0xFX0JZVEVfTEVOR1RIID0gMTA7XG5jb25zdCBNSU5fUEFSVElDTEVfQUxQSEEgPSB+figyNTUgKiAwLjAxKTtcbmNvbnN0IEhFSUdIVF9TQ0FMRSA9IDU7XG5jb25zdCBXSURUSF9TQ0FMRSA9IDI7XG5jb25zdCBGTE9XX0ZJRUxEX1JFUyA9IDAuMDU7XG5cbmludGVyZmFjZSBQYXJ0aWNsZXNEYXRhIHtcbiAgcGFydGljbGVzOiBGbG9hdDMyQXJyYXk7XG4gIG1heFBhcnRpY2xlWDogbnVtYmVyO1xuICBtaW5QYXJ0aWNsZVk6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFVwZGF0ZVBhcnRpY2xlUGFyYW1zIHtcbiAgcGFydGljbGVzRGF0YTogUGFydGljbGVzRGF0YTtcbiAgYW5pbWF0aW9uU3RhdGU6IEFuaW1hdGlvblN0YXRlO1xuICB0aGFub3NPcHRpb25zOiBXc1RoYW5vc09wdGlvbnM7XG4gIG5vaXNlOiBTaW1wbGV4Tm9pc2U7XG4gIHNlZWQ6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFBhcnRpY2xlSW5kaWNlcyB7XG4gIHg6IG51bWJlcjtcbiAgeTogbnVtYmVyO1xuICBkeDogbnVtYmVyO1xuICBkeTogbnVtYmVyO1xuICBheDogbnVtYmVyO1xuICBheTogbnVtYmVyO1xuICByOiBudW1iZXI7XG4gIGc6IG51bWJlcjtcbiAgYjogbnVtYmVyO1xuICBhOiBudW1iZXI7XG59XG5cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgV3NUaGFub3NTZXJ2aWNlIHtcbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChXU19USEFOT1NfT1BUSU9OU19UT0tFTilcbiAgICBwcml2YXRlIHRoYW5vc09wdGlvbnM6IFdzVGhhbm9zT3B0aW9ucyxcbiAgICBwcml2YXRlIG5nWm9uZTogTmdab25lXG4gICkge31cblxuICBwcml2YXRlIHN0YXRpYyBnZXRQYXJ0aWNsZUluZGljZXNGb3JCYXNlKGJhc2U6IG51bWJlcik6IFBhcnRpY2xlSW5kaWNlcyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHg6IGJhc2UsXG4gICAgICB5OiBiYXNlICsgMSxcbiAgICAgIGR4OiBiYXNlICsgMixcbiAgICAgIGR5OiBiYXNlICsgMyxcbiAgICAgIGF4OiBiYXNlICsgNCxcbiAgICAgIGF5OiBiYXNlICsgNSxcbiAgICAgIHI6IGJhc2UgKyA2LFxuICAgICAgZzogYmFzZSArIDcsXG4gICAgICBiOiBiYXNlICsgOCxcbiAgICAgIGE6IGJhc2UgKyA5LFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBnZXRDb2xvckluZGljZXNGb3JDb29yZChcbiAgICB4OiBudW1iZXIsXG4gICAgeTogbnVtYmVyLFxuICAgIHdpZHRoOiBudW1iZXJcbiAgKTogeyBhOiBudW1iZXI7IHI6IG51bWJlcjsgYjogbnVtYmVyOyBnOiBudW1iZXIgfSB7XG4gICAgY29uc3QgcmVkID0geSAqICh3aWR0aCAqIDQpICsgeCAqIDQ7XG4gICAgcmV0dXJuIHsgcjogcmVkLCBnOiByZWQgKyAxLCBiOiByZWQgKyAyLCBhOiByZWQgKyAzIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyB1cGRhdGVQYXJ0aWNsZXMoe1xuICAgIHNlZWQsXG4gICAgbm9pc2UsXG4gICAgcGFydGljbGVzRGF0YSxcbiAgICB0aGFub3NPcHRpb25zLFxuICAgIGFuaW1hdGlvblN0YXRlLFxuICB9OiBVcGRhdGVQYXJ0aWNsZVBhcmFtcyk6IHZvaWQge1xuICAgIGNvbnN0IHsgZGVsdGFUU2VjLCBhbmltYXRpb25ULCBtYXhXaWR0aCwgbWF4SGVpZ2h0IH0gPSBhbmltYXRpb25TdGF0ZTtcbiAgICBjb25zdCB7IHBhcnRpY2xlQWNjZWxlcmF0aW9uIH0gPSB0aGFub3NPcHRpb25zO1xuICAgIGNvbnN0IHsgcGFydGljbGVzLCBtYXhQYXJ0aWNsZVgsIG1pblBhcnRpY2xlWSB9ID0gcGFydGljbGVzRGF0YTtcblxuICAgIC8vIHRoZSB0aW1lIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSB2YXBvcml6YXRpb24gZnJvbnQuXG4gICAgY29uc3QgdGltZSA9IE1hdGguc2luKGFuaW1hdGlvblQgKiAoTWF0aC5QSSAvIDIpKSAqIDEuMTtcblxuICAgIGNvbnN0IHN0YXJ0QWNjZWxlcmF0ZVggPSBtYXhQYXJ0aWNsZVggLSB0aW1lICogbWF4UGFydGljbGVYO1xuICAgIGNvbnN0IHN0YXJ0QWNjZWxlcmF0ZVkgPSB0aW1lICogKG1heEhlaWdodCAtIG1pblBhcnRpY2xlWSkgKyBtaW5QYXJ0aWNsZVk7XG5cbiAgICBjb25zdCBsZW5ndGhZID0gbWF4SGVpZ2h0IC0gc3RhcnRBY2NlbGVyYXRlWTtcbiAgICBjb25zdCBhY2NlbGVyYXRlUmFkaXVzUG93ID0gc3RhcnRBY2NlbGVyYXRlWCAqIHN0YXJ0QWNjZWxlcmF0ZVggKyBsZW5ndGhZICogbGVuZ3RoWTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGFydGljbGVzLmxlbmd0aDsgaSArPSBQQVJUSUNMRV9CWVRFX0xFTkdUSCkge1xuICAgICAgY29uc3QgeyB4LCB5LCBkeCwgZHksIGF4LCBheSwgYSB9ID0gV3NUaGFub3NTZXJ2aWNlLmdldFBhcnRpY2xlSW5kaWNlc0ZvckJhc2UoaSk7XG4gICAgICBjb25zdCBwYXJ0aWNsZVggPSBwYXJ0aWNsZXNbeF07XG4gICAgICBjb25zdCBwYXJ0aWNsZVkgPSBwYXJ0aWNsZXNbeV07XG5cbiAgICAgIC8vIG9ubHkgdXBkYXRlIHBhcnRpY2xlcyB0aGF0IGFyZSBpbnNpZGUgdmlldyBhbmQgdmlzaWJsZVxuICAgICAgaWYgKFxuICAgICAgICBwYXJ0aWNsZVggPiBtYXhXaWR0aCB8fFxuICAgICAgICBwYXJ0aWNsZVggPCAwIHx8XG4gICAgICAgIHBhcnRpY2xlWSA+IG1heEhlaWdodCB8fFxuICAgICAgICBwYXJ0aWNsZVkgPCAwIHx8XG4gICAgICAgIHBhcnRpY2xlc1thXSA8IE1JTl9QQVJUSUNMRV9BTFBIQVxuICAgICAgKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoIShNYXRoLmFicyhwYXJ0aWNsZXNbYXhdKSA+IDAgfHwgTWF0aC5hYnMocGFydGljbGVzW2F5XSkgPiAwKSkge1xuICAgICAgICBsZXQgcFlMZW5ndGggPSBtYXhIZWlnaHQgLSBwYXJ0aWNsZVk7XG4gICAgICAgIGxldCBwWExlbmd0aCA9IHBhcnRpY2xlWDtcblxuICAgICAgICAvLyB3ZSBjYWxjdWxhdGUgc29tZSByYW5kb20gbG9va2luZyBudW1iZXJzIGFuZCBmdW5jdGlvbnMgdG8gaGF2ZSBuaWNlIGxvb2tpbmcgdmFwb3JpemluZyBmcm9udCBvZiBwYXJ0aWNsZXNcbiAgICAgICAgLy8gdG9kbyBjb25zaWRlciB0byB1c2Ugbm9pc2U7XG4gICAgICAgIHBYTGVuZ3RoICs9IE1hdGgudGFuKChwWExlbmd0aCAvIDIwLjEyKSAqIHRpbWUgKyBzZWVkKSAqIDAuNTtcbiAgICAgICAgcFhMZW5ndGggKz0gKHBhcnRpY2xlWCAlIGRlbHRhVFNlYykgKiAwLjU7XG4gICAgICAgIHBYTGVuZ3RoICs9IE1hdGguc2luKChwWExlbmd0aCAvIDMwICsgNzIzLjM5NCkgKiB0aW1lICsgc2VlZCAqIDEyLjUpICogMTE7XG4gICAgICAgIHBZTGVuZ3RoICs9IE1hdGgudGFuKChwWUxlbmd0aCAvIDAuNDUpICogdGltZSArIHNlZWQgKiAxLjUpICogMC41O1xuICAgICAgICBwWUxlbmd0aCArPSBNYXRoLmNvcygocFlMZW5ndGggLyAxMDAgKyAyMzIzLjIzNCkgKiB0aW1lICsgc2VlZCAqIDQ1Ni4xKSAqIDIzO1xuXG4gICAgICAgIGNvbnN0IHBMZW5ndGggPSBwWExlbmd0aCAqIHBYTGVuZ3RoICsgcFlMZW5ndGggKiBwWUxlbmd0aDtcbiAgICAgICAgaWYgKHBMZW5ndGggPiBhY2NlbGVyYXRlUmFkaXVzUG93KSB7XG4gICAgICAgICAgcGFydGljbGVzW2F4XSA9IE1hdGgucmFuZG9tKCk7XG4gICAgICAgICAgcGFydGljbGVzW2F5XSA9IE1hdGgucmFuZG9tKCkgKiAtMTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdXNlIG5vaXNlIHRvIGZsb3cgYWxvbmcgdmVsb2NpdHkgZmllbGRcbiAgICAgICAgY29uc3QgZmxvd0ZpZWxkQWNjID0gV3NUaGFub3NTZXJ2aWNlLmdldFhZRnJvbUZsb3dGaWVsZChub2lzZSwgc2VlZCwgcGFydGljbGVYLCBwYXJ0aWNsZVkpO1xuICAgICAgICBjb25zdCBhY2NlbGVyYXRpb25YID0gZmxvd0ZpZWxkQWNjWzBdO1xuICAgICAgICBjb25zdCBhY2NlbGVyYXRpb25ZID0gZmxvd0ZpZWxkQWNjWzFdO1xuICAgICAgICBwYXJ0aWNsZXNbYXhdICs9IGFjY2VsZXJhdGlvblg7XG4gICAgICAgIHBhcnRpY2xlc1theV0gKz0gYWNjZWxlcmF0aW9uWTtcbiAgICAgIH1cblxuICAgICAgLy8gKiBNYXRoLnBvdygxICsgYW5pbWF0aW9uVCwgNClcbiAgICAgIHBhcnRpY2xlc1tkeF0gKz0gcGFydGljbGVzW2F4XSAqIHBhcnRpY2xlQWNjZWxlcmF0aW9uICogZGVsdGFUU2VjO1xuICAgICAgcGFydGljbGVzW2R5XSArPSBwYXJ0aWNsZXNbYXldICogcGFydGljbGVBY2NlbGVyYXRpb24gKiBkZWx0YVRTZWM7XG4gICAgICBwYXJ0aWNsZXNbeF0gKz0gcGFydGljbGVzW2R4XSAqIGRlbHRhVFNlYztcbiAgICAgIHBhcnRpY2xlc1t5XSArPSBwYXJ0aWNsZXNbZHldICogZGVsdGFUU2VjO1xuICAgICAgLy8gZmFkZSBwYXJ0aWNsZSBvdXQgKCB2ZXJ5IGxhdGUpO1xuICAgICAgcGFydGljbGVzW2FdICo9IDEgLSBNYXRoLnBvdyhhbmltYXRpb25ULCAxNSk7IC8vIDI1NSAtIE1hdGguc3FydChwYXJ0aWNsZXNbZHhdICogcGFydGljbGVzW2R4XSArIHBhcnRpY2xlc1tkeV0gKiBwYXJ0aWNsZXNbZHldKSAvIDEuMjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBkcmF3UGFydGljbGVzKGRyYXdDdHg6IENhbnZhc1JlbmRlcmluZ0NvbnRleHQyRCwgcGFydGljbGVzOiBGbG9hdDMyQXJyYXkpOiB2b2lkIHtcbiAgICBjb25zdCB7IHdpZHRoLCBoZWlnaHQgfSA9IGRyYXdDdHguY2FudmFzO1xuICAgIGRyYXdDdHguY2xlYXJSZWN0KDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xuICAgIGNvbnN0IGltYWdlID0gZHJhd0N0eC5nZXRJbWFnZURhdGEoMCwgMCwgd2lkdGgsIGhlaWdodCk7XG4gICAgY29uc3QgaW1hZ2VEYXRhID0gaW1hZ2UuZGF0YTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcnRpY2xlcy5sZW5ndGg7IGkgKz0gUEFSVElDTEVfQllURV9MRU5HVEgpIHtcbiAgICAgIGNvbnN0IHBhcnRpY2xlWCA9IHBhcnRpY2xlc1tpXTtcbiAgICAgIGNvbnN0IHBhcnRpY2xlWSA9IHBhcnRpY2xlc1tpICsgMV07XG4gICAgICBjb25zdCBwSSA9IFdzVGhhbm9zU2VydmljZS5nZXRQYXJ0aWNsZUluZGljZXNGb3JCYXNlKGkpO1xuICAgICAgaWYgKFxuICAgICAgICBwYXJ0aWNsZVggPiB3aWR0aCB8fFxuICAgICAgICBwYXJ0aWNsZVggPCAwIHx8XG4gICAgICAgIHBhcnRpY2xlWSA+IGhlaWdodCB8fFxuICAgICAgICBwYXJ0aWNsZVkgPCAwIHx8XG4gICAgICAgIHBhcnRpY2xlc1twSS5hXSA8IE1JTl9QQVJUSUNMRV9BTFBIQVxuICAgICAgKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgeyByLCBnLCBiLCBhIH0gPSBXc1RoYW5vc1NlcnZpY2UuZ2V0Q29sb3JJbmRpY2VzRm9yQ29vcmQofn5wYXJ0aWNsZXNbcEkueF0sIH5+cGFydGljbGVzW3BJLnldLCB3aWR0aCk7XG4gICAgICBpbWFnZURhdGFbcl0gPSB+fnBhcnRpY2xlc1twSS5yXTtcbiAgICAgIGltYWdlRGF0YVtnXSA9IH5+cGFydGljbGVzW3BJLmddO1xuICAgICAgaW1hZ2VEYXRhW2JdID0gfn5wYXJ0aWNsZXNbcEkuYl07XG4gICAgICBpbWFnZURhdGFbYV0gPSB+fnBhcnRpY2xlc1twSS5hXTtcbiAgICB9XG4gICAgZHJhd0N0eC5wdXRJbWFnZURhdGEoaW1hZ2UsIDAsIDApO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgcHJlcGFyZUNhbnZhc0ZvclZhcG9yaXplKFxuICAgIGRpdkNhbnZhczogSFRNTENhbnZhc0VsZW1lbnQsXG4gICAgbWF4UGFydGljbGVDb3VudDogbnVtYmVyXG4gICk6IHtcbiAgICBwYXJ0aWNsZXNEYXRhOiBQYXJ0aWNsZXNEYXRhO1xuICAgIHJlc3VsdENhbnZhczogSFRNTENhbnZhc0VsZW1lbnQ7XG4gIH0ge1xuICAgIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gZGl2Q2FudmFzO1xuXG4gICAgLy8gc2NhbGUgcmVzdWx0IGNhbnZhcyB0byBoYXZlIG1vcmUgcm9vbSB0byBkcmF3IHBhcnRpY2xlcyB3aGlsZSB2YXBvcml6aW5nO1xuICAgIGNvbnN0IHJlc3VsdEhlaWdodCA9IGhlaWdodCAqIEhFSUdIVF9TQ0FMRTtcbiAgICBjb25zdCByZXN1bHRXaWR0aCA9IHdpZHRoICogV0lEVEhfU0NBTEU7XG4gICAgY29uc3QgcmVzdWx0Q2FudmFzOiBIVE1MQ2FudmFzRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgIHJlc3VsdENhbnZhcy5oZWlnaHQgPSByZXN1bHRIZWlnaHQ7XG4gICAgcmVzdWx0Q2FudmFzLndpZHRoID0gcmVzdWx0V2lkdGg7XG5cbiAgICBjb25zdCBpbWFnZURhdGEgPSBkaXZDYW52YXMuZ2V0Q29udGV4dCgnMmQnKT8uZ2V0SW1hZ2VEYXRhKDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xuICAgIGlmIChpbWFnZURhdGEgPT0gbnVsbCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgZ2V0IGltYWdlIGRhdGEgZnJvbSBjYW52YXMnKTtcbiAgICB9XG4gICAgY29uc3QgcGFydGljbGVzRGF0YSA9IFdzVGhhbm9zU2VydmljZS5jcmVhdGVQYXJ0aWNsZXNGb3JJbWFnZURhdGEoaW1hZ2VEYXRhLCBtYXhQYXJ0aWNsZUNvdW50LCByZXN1bHRIZWlnaHQpO1xuICAgIHJldHVybiB7IHJlc3VsdENhbnZhcywgcGFydGljbGVzRGF0YSB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlUGFydGljbGVzRm9ySW1hZ2VEYXRhKFxuICAgIGltYWdlRGF0YTogSW1hZ2VEYXRhLFxuICAgIG1heFBhcnRpY2xlQ291bnQ6IG51bWJlcixcbiAgICByZXN1bHRIZWlnaHQ6IG51bWJlclxuICApOiB7IG1pblBhcnRpY2xlWTogbnVtYmVyOyBtYXhQYXJ0aWNsZVg6IG51bWJlcjsgcGFydGljbGVzOiBGbG9hdDMyQXJyYXkgfSB7XG4gICAgY29uc3QgeyB3aWR0aCwgaGVpZ2h0IH0gPSBpbWFnZURhdGE7XG4gICAgbGV0IHBhcnRpY2xlQ2FuZGlkYXRlcyA9IDA7XG4gICAgbGV0IHBhcnRpY2xlQ291bnQgPSAwO1xuXG4gICAgY29uc3QgcGFydGljbGVDYW5kaWF0ZXNMaXN0OiB7IHg6IG51bWJlcjsgeTogbnVtYmVyIH1bXSA9IFtdO1xuICAgIGZvciAobGV0IHkgPSAwOyB5IDwgaGVpZ2h0OyB5KyspIHtcbiAgICAgIGZvciAobGV0IHggPSAwOyB4IDwgd2lkdGg7IHgrKykge1xuICAgICAgICBjb25zdCB7IGEgfSA9IFdzVGhhbm9zU2VydmljZS5nZXRDb2xvckluZGljZXNGb3JDb29yZCh4LCB5LCB3aWR0aCk7XG4gICAgICAgIGlmIChpbWFnZURhdGEuZGF0YVthXSA+PSBNSU5fUEFSVElDTEVfQUxQSEEpIHtcbiAgICAgICAgICBwYXJ0aWNsZUNhbmRpZGF0ZXMrKztcbiAgICAgICAgICBwYXJ0aWNsZUNhbmRpYXRlc0xpc3QucHVzaCh7IHgsIHkgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBtYXhOdW1QYXJ0aWNsZXMgPSBNYXRoLm1pbihwYXJ0aWNsZUNhbmRpZGF0ZXMsIG1heFBhcnRpY2xlQ291bnQpO1xuICAgIGNvbnN0IHBhcnRpY2xlcyA9IG5ldyBGbG9hdDMyQXJyYXkoRmxvYXQzMkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UICogbWF4TnVtUGFydGljbGVzICogUEFSVElDTEVfQllURV9MRU5HVEgpO1xuXG4gICAgbGV0IG1heFBhcnRpY2xlWCA9IDA7XG4gICAgbGV0IG1pblBhcnRpY2xlWSA9IHJlc3VsdEhlaWdodDtcbiAgICB3aGlsZSAocGFydGljbGVDb3VudCA8IG1heE51bVBhcnRpY2xlcykge1xuICAgICAgLy8gc2VsZWN0IHJhbmRvbSBpbmRleCBmcm9tIGNhbmRpYXRlc1xuICAgICAgY29uc3QgaW5kZXggPSB+fihNYXRoLnJhbmRvbSgpICogcGFydGljbGVDYW5kaWF0ZXNMaXN0Lmxlbmd0aCk7XG4gICAgICBjb25zdCB7IHgsIHkgfSA9IHBhcnRpY2xlQ2FuZGlhdGVzTGlzdFtpbmRleF07XG5cbiAgICAgIC8vIG92ZXJ3cml0ZSBpbmRleCB3aXRoIGxhc3QgZWxlbWVudCB0byBwcmV2ZW50IGRvdWJsZSBzZWxlY3Rpb24gb2YgcGFydGljbGVzXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLW5vbi1udWxsLWFzc2VydGlvblxuICAgICAgcGFydGljbGVDYW5kaWF0ZXNMaXN0W2luZGV4XSA9IHBhcnRpY2xlQ2FuZGlhdGVzTGlzdC5wb3AoKSE7XG5cbiAgICAgIG1heFBhcnRpY2xlWCA9IE1hdGgubWF4KG1heFBhcnRpY2xlWCwgeCk7XG4gICAgICBtaW5QYXJ0aWNsZVkgPSBNYXRoLm1pbihtaW5QYXJ0aWNsZVksIHkpO1xuICAgICAgY29uc3QgeyBkeCwgZHksIGF4LCBheSwgciwgZywgYiwgYSwgLi4ueHkgfSA9IFdzVGhhbm9zU2VydmljZS5nZXRQYXJ0aWNsZUluZGljZXNGb3JCYXNlKFxuICAgICAgICBwYXJ0aWNsZUNvdW50ICogUEFSVElDTEVfQllURV9MRU5HVEhcbiAgICAgICk7XG4gICAgICBwYXJ0aWNsZXNbeHkueF0gPSB4O1xuICAgICAgcGFydGljbGVzW3h5LnldID0geSArIHJlc3VsdEhlaWdodCAtIGhlaWdodDtcbiAgICAgIHBhcnRpY2xlc1tkeF0gPSAwO1xuICAgICAgcGFydGljbGVzW2R5XSA9IDA7XG4gICAgICBwYXJ0aWNsZXNbYXhdID0gMDtcbiAgICAgIHBhcnRpY2xlc1theV0gPSAwO1xuXG4gICAgICBjb25zdCBpbmRpY2VzSW1hZ2UgPSBXc1RoYW5vc1NlcnZpY2UuZ2V0Q29sb3JJbmRpY2VzRm9yQ29vcmQoeCwgeSwgd2lkdGgpO1xuXG4gICAgICBwYXJ0aWNsZXNbcl0gPSBpbWFnZURhdGEuZGF0YVtpbmRpY2VzSW1hZ2Uucl07XG4gICAgICBwYXJ0aWNsZXNbZ10gPSBpbWFnZURhdGEuZGF0YVtpbmRpY2VzSW1hZ2UuZ107XG4gICAgICBwYXJ0aWNsZXNbYl0gPSBpbWFnZURhdGEuZGF0YVtpbmRpY2VzSW1hZ2UuYl07XG4gICAgICBwYXJ0aWNsZXNbYV0gPSBpbWFnZURhdGEuZGF0YVtpbmRpY2VzSW1hZ2UuYV07XG4gICAgICBwYXJ0aWNsZUNvdW50Kys7XG4gICAgfVxuICAgIHJldHVybiB7IHBhcnRpY2xlcywgbWF4UGFydGljbGVYLCBtaW5QYXJ0aWNsZVkgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGdldFhZRnJvbUZsb3dGaWVsZChub2lzZTogU2ltcGxleE5vaXNlLCBzZWVkOiBudW1iZXIsIHg6IG51bWJlciwgeTogbnVtYmVyKSB7XG4gICAgY29uc3Qgc2FtcGxlWCA9IG5vaXNlLnNjYWxlZDNEKHgsIHksIHNlZWQgKyAzMy4yMywgRkxPV19GSUVMRF9SRVMpO1xuICAgIGNvbnN0IHNhbXBsZVkgPSBub2lzZS5zY2FsZWQzRCh4LCBzZWVkIC8gMTMuMjMsIHksIEZMT1dfRklFTERfUkVTKSAqIC0xO1xuICAgIHJldHVybiBbc2FtcGxlWCwgc2FtcGxlWV07XG4gIH1cblxuICAvKipcbiAgICogc3RhcnQgdGhlIHZhcG9yaXplQW5kU2Nyb2xsSW50b1ZpZXctZWZmZWN0LlxuICAgKlxuICAgKiBJdCdzIHJ1bm5pbmcgb3V0c2lkZSB0aGUgbmdab25lLlxuICAgKi9cbiAgdmFwb3JpemUoZWxlbTogSFRNTEVsZW1lbnQpOiBPYnNlcnZhYmxlPEFuaW1hdGlvblN0YXRlPiB7XG4gICAgcmV0dXJuIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHRoaXMudmFwb3JpemVJbnRlcm4oZWxlbSkpO1xuICB9XG5cbiAgcHJpdmF0ZSB2YXBvcml6ZUludGVybihlbGVtOiBIVE1MRWxlbWVudCk6IE9ic2VydmFibGU8QW5pbWF0aW9uU3RhdGU+IHtcbiAgICBlbGVtLnN0eWxlLm9wYWNpdHkgPSBlbGVtLnN0eWxlLm9wYWNpdHkgfHwgJzEnO1xuICAgIGVsZW0uc3R5bGUudHJhbnNpdGlvbiA9IGBvcGFjaXR5ICR7TWF0aC5mbG9vcih0aGlzLnRoYW5vc09wdGlvbnMuYW5pbWF0aW9uTGVuZ3RoICogMC44KX1tcyBlYXNlLW91dGA7XG4gICAgY29uc3Qgbm9pc2UgPSBuZXcgU2ltcGxleE5vaXNlKHsgZnJlcXVlbmN5OiAwLjAxLCBtaW46IDAgfSk7XG4gICAgY29uc3Qgc2VlZCA9IG5ldyBEYXRlKCkuZ2V0RGF0ZSgpICogTWF0aC5yYW5kb20oKTtcbiAgICBjb25zdCBodG1sMkNhbnZhc1Byb21pc2U6IFByb21pc2U8SFRNTENhbnZhc0VsZW1lbnQ+ID0gaHRtbDJjYW52YXMoZWxlbSwge1xuICAgICAgYmFja2dyb3VuZENvbG9yOiBudWxsLFxuICAgICAgc2NhbGU6IDEsXG4gICAgICBhbGxvd1RhaW50OiB0cnVlLFxuICAgICAgd2luZG93SGVpZ2h0OiB3aW5kb3cuaW5uZXJIZWlnaHQsXG4gICAgICB3aW5kb3dXaWR0aDogd2luZG93LmlubmVyV2lkdGgsXG4gICAgICBzY3JvbGxZOiAtd2luZG93LnNjcm9sbFksXG4gICAgfSk7XG5cbiAgICByZXR1cm4gZnJvbShodG1sMkNhbnZhc1Byb21pc2UpLnBpcGUoXG4gICAgICBtYXAoKGNhbnZhc0Zyb21IdG1sRWxlbSkgPT4ge1xuICAgICAgICBjb25zdCBjYW52YXNBbmRQYXJ0aWNsZXMgPSBXc1RoYW5vc1NlcnZpY2UucHJlcGFyZUNhbnZhc0ZvclZhcG9yaXplKFxuICAgICAgICAgIGNhbnZhc0Zyb21IdG1sRWxlbSxcbiAgICAgICAgICB0aGlzLnRoYW5vc09wdGlvbnMubWF4UGFydGljbGVDb3VudFxuICAgICAgICApO1xuICAgICAgICBjb25zdCB7IHJlc3VsdENhbnZhcyB9ID0gY2FudmFzQW5kUGFydGljbGVzO1xuICAgICAgICBpZiAoZWxlbS5wYXJlbnRFbGVtZW50KSB7XG4gICAgICAgICAgZWxlbS5wYXJlbnRFbGVtZW50LnN0eWxlLnBvc2l0aW9uID0gZWxlbS5wYXJlbnRFbGVtZW50LnN0eWxlLnBvc2l0aW9uIHx8ICdyZWxhdGl2ZSc7XG4gICAgICAgIH1cbiAgICAgICAgcmVzdWx0Q2FudmFzLnN0eWxlLnBvc2l0aW9uID0gJ2Fic29sdXRlJztcbiAgICAgICAgcmVzdWx0Q2FudmFzLnN0eWxlLmxlZnQgPSAwICsgJ3B4JztcbiAgICAgICAgcmVzdWx0Q2FudmFzLnN0eWxlLnRvcCA9ICctJyArIGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0ICogKEhFSUdIVF9TQ0FMRSAtIDEpICsgJ3B4JztcbiAgICAgICAgcmVzdWx0Q2FudmFzLnN0eWxlLnpJbmRleCA9ICcyMDAwJztcbiAgICAgICAgcmVzdWx0Q2FudmFzLnN0eWxlLnBvaW50ZXJFdmVudHMgPSAnbm9uZSc7XG5cbiAgICAgICAgZWxlbS5pbnNlcnRBZGphY2VudEVsZW1lbnQoJ2JlZm9yZWJlZ2luJywgcmVzdWx0Q2FudmFzKTtcbiAgICAgICAgLy8gdGhpcyBzaG91bGQgc3RhcnQgdGhlIHRyYW5zaXRpb24gYWJvdmUgZGVmaW5lZFxuICAgICAgICBlbGVtLnN0eWxlLm9wYWNpdHkgPSAnMCc7XG4gICAgICAgIHJldHVybiBjYW52YXNBbmRQYXJ0aWNsZXM7XG4gICAgICB9KSxcbiAgICAgIHN3aXRjaE1hcCgoeyByZXN1bHRDYW52YXMsIHBhcnRpY2xlc0RhdGEgfSkgPT4ge1xuICAgICAgICBsZXQgdGltZSA9IDA7XG4gICAgICAgIGNvbnN0IHsgYW5pbWF0aW9uTGVuZ3RoLCBtYXhQYXJ0aWNsZUNvdW50LCBwYXJ0aWNsZUFjY2VsZXJhdGlvbiB9ID0gdGhpcy50aGFub3NPcHRpb25zO1xuICAgICAgICByZXR1cm4gaW50ZXJ2YWwoMTAwMCAvIDYwLCBhbmltYXRpb25GcmFtZVNjaGVkdWxlcikucGlwZShcbiAgICAgICAgICB0aW1lSW50ZXJ2YWwoKSxcbiAgICAgICAgICB0YXAoKGRlbHRhVCkgPT4gKHRpbWUgKz0gZGVsdGFULmludGVydmFsKSksXG4gICAgICAgICAgbWFwKFxuICAgICAgICAgICAgKGRlbHRhVCkgPT5cbiAgICAgICAgICAgICAgKHtcbiAgICAgICAgICAgICAgICBkZWx0YVRTZWM6IGRlbHRhVC5pbnRlcnZhbCAvIDEwMDAsXG4gICAgICAgICAgICAgICAgYW5pbWF0aW9uVDogdGltZSAvIGFuaW1hdGlvbkxlbmd0aCxcbiAgICAgICAgICAgICAgICBtYXhXaWR0aDogcmVzdWx0Q2FudmFzLndpZHRoLFxuICAgICAgICAgICAgICAgIG1heEhlaWdodDogcmVzdWx0Q2FudmFzLmhlaWdodCxcbiAgICAgICAgICAgICAgfSBhcyBBbmltYXRpb25TdGF0ZSlcbiAgICAgICAgICApLFxuICAgICAgICAgIHRhcCgoYW5pbWF0aW9uU3RhdGUpID0+IHtcbiAgICAgICAgICAgIFdzVGhhbm9zU2VydmljZS51cGRhdGVQYXJ0aWNsZXMoe1xuICAgICAgICAgICAgICBwYXJ0aWNsZXNEYXRhLFxuICAgICAgICAgICAgICBhbmltYXRpb25TdGF0ZSxcbiAgICAgICAgICAgICAgdGhhbm9zT3B0aW9uczoge1xuICAgICAgICAgICAgICAgIGFuaW1hdGlvbkxlbmd0aCxcbiAgICAgICAgICAgICAgICBtYXhQYXJ0aWNsZUNvdW50LFxuICAgICAgICAgICAgICAgIHBhcnRpY2xlQWNjZWxlcmF0aW9uLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBub2lzZSxcbiAgICAgICAgICAgICAgc2VlZCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3QgY29udGV4dCA9IHJlc3VsdENhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuICAgICAgICAgICAgaWYgKGNvbnRleHQpIHtcbiAgICAgICAgICAgICAgV3NUaGFub3NTZXJ2aWNlLmRyYXdQYXJ0aWNsZXMoY29udGV4dCwgcGFydGljbGVzRGF0YS5wYXJ0aWNsZXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pLFxuICAgICAgICAgIHRha2VXaGlsZSgoYW5pbWF0aW9uU3RhdGUpID0+IGFuaW1hdGlvblN0YXRlLmFuaW1hdGlvblQgPD0gMSksXG4gICAgICAgICAgZmluYWxpemUoKCkgPT4gcmVzdWx0Q2FudmFzLnJlbW92ZSgpKVxuICAgICAgICApO1xuICAgICAgfSlcbiAgICApO1xuICB9XG59XG4iXX0=