UNPKG

ng-cw-v12

Version:

Angular UI Component Library

349 lines (332 loc) 41.4 kB
import { Component, ViewChild, Input, HostListener } from '@angular/core'; import * as THREE from 'three'; import * as i0 from "@angular/core"; const vertexShader = ` varying vec2 vUv; void main() { vUv = uv; gl_Position = vec4(position, 1.0); } `; const fragmentShader = ` precision highp float; uniform float iTime; uniform vec3 iResolution; uniform vec3 uColor; uniform float uAmplitude; uniform float uDistance; uniform vec2 uMouse; #define PI 3.1415926538 const int u_line_count = 40; const float u_line_width = 7.0; const float u_line_blur = 10.0; float Perlin2D(vec2 P) { vec2 Pi = floor(P); vec4 Pf_Pfmin1 = P.xyxy - vec4(Pi, Pi + 1.0); vec4 Pt = vec4(Pi.xy, Pi.xy + 1.0); Pt = Pt - floor(Pt * (1.0 / 71.0)) * 71.0; Pt += vec2(26.0, 161.0).xyxy; Pt *= Pt; Pt = Pt.xzxz * Pt.yyww; vec4 hash_x = fract(Pt * (1.0 / 951.135664)); vec4 hash_y = fract(Pt * (1.0 / 642.949883)); vec4 grad_x = hash_x - 0.49999; vec4 grad_y = hash_y - 0.49999; vec4 grad_results = inversesqrt(grad_x * grad_x + grad_y * grad_y) * (grad_x * Pf_Pfmin1.xzxz + grad_y * Pf_Pfmin1.yyww); grad_results *= 1.4142135623730950; vec2 blend = Pf_Pfmin1.xy * Pf_Pfmin1.xy * Pf_Pfmin1.xy * (Pf_Pfmin1.xy * (Pf_Pfmin1.xy * 6.0 - 15.0) + 10.0); vec4 blend2 = vec4(blend, vec2(1.0 - blend)); return dot(grad_results, blend2.zxzx * blend2.wwyy); } float pixel(float count, vec2 resolution) { return (1.0 / max(resolution.x, resolution.y)) * count; } float lineFn(vec2 st, float width, float perc, float offset, vec2 mouse, float time, float amplitude, float distance) { float split_offset = (perc * 0.4); float split_point = 0.1 + split_offset; float amplitude_normal = smoothstep(split_point, 0.7, st.x); float amplitude_strength = 0.5; float finalAmplitude = amplitude_normal * amplitude_strength * amplitude * (1.0 + (mouse.y - 0.5) * 0.2); float time_scaled = time / 10.0 + (mouse.x - 0.5) * 1.0; float blur = smoothstep(split_point, split_point + 0.05, st.x) * perc; float xnoise = mix( Perlin2D(vec2(time_scaled, st.x + perc) * 2.5), Perlin2D(vec2(time_scaled, st.x + time_scaled) * 3.5) / 1.5, st.x * 0.3 ); float y = 0.5 + (perc - 0.5) * distance + xnoise / 2.0 * finalAmplitude; float line_start = smoothstep( y + (width / 2.0) + (u_line_blur * pixel(1.0, iResolution.xy) * blur), y, st.y ); float line_end = smoothstep( y, y - (width / 2.0) - (u_line_blur * pixel(1.0, iResolution.xy) * blur), st.y ); return clamp( (line_start - line_end) * (1.0 - smoothstep(0.0, 1.0, pow(perc, 0.3))), 0.0, 1.0 ); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = fragCoord / iResolution.xy; float line_strength = 1.0; for (int i = 0; i < u_line_count; i++) { float p = float(i) / float(u_line_count); line_strength *= (1.0 - lineFn( uv, u_line_width * pixel(1.0, iResolution.xy) * (1.0 - p), p, (PI * 1.0) * p, uMouse, iTime, uAmplitude, uDistance )); } float colorVal = 1.0 - line_strength; fragColor = vec4(uColor * colorVal, colorVal); } void main() { mainImage(gl_FragColor, gl_FragCoord.xy); } `; export class ThreadsBackgroundComponent { constructor(ngZone) { this.ngZone = ngZone; /** 颜色 [r, g, b] 数组(0-1) */ this.ncColor = [1, 1, 1]; /** 振幅大小(0-5) */ this.ncAmplitude = 1; /** 线条距离(0-2) */ this.ncDistance = 0; /** 背景颜色 */ this.ncBgColor = 'black'; /** 是否启用鼠标交互 */ this._enableMouseInteraction = false; this.animationFrameId = null; this.isVisible = true; this.isRunning = false; this.currentMouse = new THREE.Vector2(0.5, 0.5); this.targetMouse = new THREE.Vector2(0.5, 0.5); this.onVisibilityChange = () => { if (document.hidden) { this.pause(); } else if (this.isVisible) { this.ngZone.runOutsideAngular(() => { this.start(); }); } }; this.update = (t) => { if (!this.isRunning) return; if (this.ncEnableMouseInteraction) { const smoothing = 0.05; this.currentMouse.x += smoothing * (this.targetMouse.x - this.currentMouse.x); this.currentMouse.y += smoothing * (this.targetMouse.y - this.currentMouse.y); this.material.uniforms['uMouse'].value.copy(this.currentMouse); } else { this.material.uniforms['uMouse'].value.set(0.5, 0.5); } this.material.uniforms['iTime'].value = t * 0.001; this.renderer.render(this.scene, this.camera); this.animationFrameId = requestAnimationFrame(this.update); }; } set ncEnableMouseInteraction(val) { this._enableMouseInteraction = val !== null && val !== undefined && val !== false && val !== 'false'; } get ncEnableMouseInteraction() { return this._enableMouseInteraction; } ngOnInit() { } ngAfterViewInit() { this.ngZone.runOutsideAngular(() => { this.initWebGL(); }); } ngOnDestroy() { this.cleanup(); } ngOnChanges(changes) { if (this.material) { if (changes['ncColor']) { this.material.uniforms['uColor'].value.copy(this.getThreeColor(this.ncColor)); } if (changes['ncAmplitude']) { this.material.uniforms['uAmplitude'].value = this.ncAmplitude; } if (changes['ncDistance']) { this.material.uniforms['uDistance'].value = this.ncDistance; } } } getThreeColor(color) { if (Array.isArray(color)) { return new THREE.Color(color[0], color[1], color[2]); } return new THREE.Color(color); } initWebGL() { const container = this.containerRef.nativeElement; // 初始化渲染器 this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: false }); this.renderer.setClearColor(0x000000, 0); // 采用与 Threads.jsx 中 blendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA) 一致的默认混合方式 container.appendChild(this.renderer.domElement); this.scene = new THREE.Scene(); this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); this.geometry = new THREE.PlaneGeometry(2, 2); // 初始分辨率设定,后续由 resize 更新 const canvasWidth = container.clientWidth || 1; const canvasHeight = container.clientHeight || 1; this.material = new THREE.ShaderMaterial({ vertexShader, fragmentShader, transparent: true, uniforms: { iTime: { value: 0 }, iResolution: { value: new THREE.Vector3(canvasWidth, canvasHeight, canvasWidth / canvasHeight) }, uColor: { value: this.getThreeColor(this.ncColor) }, uAmplitude: { value: this.ncAmplitude }, uDistance: { value: this.ncDistance }, uMouse: { value: new THREE.Vector2(0.5, 0.5) } } }); this.mesh = new THREE.Mesh(this.geometry, this.material); this.scene.add(this.mesh); this.setupResizeObserver(container); this.setupIntersectionObserver(container); this.resize(); this.start(); } setupResizeObserver(container) { this.resizeObserver = new ResizeObserver(() => { this.ngZone.runOutsideAngular(() => { this.resize(); }); }); this.resizeObserver.observe(container); } setupIntersectionObserver(container) { this.intersectionObserver = new IntersectionObserver(entries => { const entry = entries[0]; this.isVisible = entry.isIntersecting && entry.intersectionRatio > 0; if (this.isVisible && !document.hidden) { this.ngZone.runOutsideAngular(() => { this.start(); }); } else { this.pause(); } }, { threshold: [0, 0.01, 0.1] }); this.intersectionObserver.observe(container); document.addEventListener('visibilitychange', this.onVisibilityChange); } resize() { if (!this.containerRef || !this.renderer) return; const container = this.containerRef.nativeElement; const width = container.clientWidth; const height = container.clientHeight; this.renderer.setSize(width, height); // 可选设置 pixelRatio,如不需要极高精度可保留 1 提高性能 // this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); this.material.uniforms['iResolution'].value.set(width, height, (width / Math.max(height, 1))); } start() { if (this.isRunning) return; this.isRunning = true; this.animationFrameId = requestAnimationFrame(this.update); } pause() { this.isRunning = false; if (this.animationFrameId !== null) { cancelAnimationFrame(this.animationFrameId); this.animationFrameId = null; } } cleanup() { var _a, _b; this.pause(); try { (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect(); } catch (e) { void 0; } try { (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect(); } catch (e) { void 0; } document.removeEventListener('visibilitychange', this.onVisibilityChange); if (this.renderer) { const canvas = this.renderer.domElement; if (canvas && canvas.parentNode) canvas.parentNode.removeChild(canvas); this.renderer.dispose(); this.renderer.forceContextLoss(); } if (this.geometry) this.geometry.dispose(); if (this.material) this.material.dispose(); } onMouseMove(event) { if (!this.ncEnableMouseInteraction || !this.containerRef) return; const container = this.containerRef.nativeElement; const rect = container.getBoundingClientRect(); const x = (event.clientX - rect.left) / rect.width; const y = 1.0 - (event.clientY - rect.top) / rect.height; this.targetMouse.set(x, y); } onMouseLeave() { if (!this.ncEnableMouseInteraction) return; this.targetMouse.set(0.5, 0.5); } } ThreadsBackgroundComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: ThreadsBackgroundComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); ThreadsBackgroundComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: ThreadsBackgroundComponent, selector: "nc-threads-background", inputs: { ncColor: "ncColor", ncAmplitude: "ncAmplitude", ncDistance: "ncDistance", ncBgColor: "ncBgColor", ncEnableMouseInteraction: "ncEnableMouseInteraction" }, host: { listeners: { "mousemove": "onMouseMove($event)", "mouseleave": "onMouseLeave()" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #container class=\"nc-threads-canvas-container\" [style.background-color]=\"ncBgColor\"></div>\r\n<div class=\"nc-content-wrapper\">\r\n <ng-content></ng-content>\r\n</div>", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden}.nc-threads-canvas-container{position:absolute;inset:0;z-index:0;pointer-events:none}.nc-content-wrapper{position:relative;z-index:1;width:100%;height:100%}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: ThreadsBackgroundComponent, decorators: [{ type: Component, args: [{ selector: 'nc-threads-background', templateUrl: './threads-background.component.html', styleUrls: ['./threads-background.component.less'] }] }], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { containerRef: [{ type: ViewChild, args: ['container', { static: true }] }], ncColor: [{ type: Input }], ncAmplitude: [{ type: Input }], ncDistance: [{ type: Input }], ncBgColor: [{ type: Input }], ncEnableMouseInteraction: [{ type: Input }], onMouseMove: [{ type: HostListener, args: ['mousemove', ['$event']] }], onMouseLeave: [{ type: HostListener, args: ['mouseleave'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyZWFkcy1iYWNrZ3JvdW5kLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbXBvbmVudHMvdGhyZWFkcy1iYWNrZ3JvdW5kL3RocmVhZHMtYmFja2dyb3VuZC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9jb21wb25lbnRzL3RocmVhZHMtYmFja2dyb3VuZC90aHJlYWRzLWJhY2tncm91bmQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFJVCxTQUFTLEVBRVQsS0FBSyxFQUdMLFlBQVksRUFFYixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEtBQUssS0FBSyxNQUFNLE9BQU8sQ0FBQzs7QUFFL0IsTUFBTSxZQUFZLEdBQUc7Ozs7OztDQU1wQixDQUFDO0FBRUYsTUFBTSxjQUFjLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQXlHdEIsQ0FBQztBQU9GLE1BQU0sT0FBTywwQkFBMEI7SUFzQ3JDLFlBQW9CLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBbkNsQywyQkFBMkI7UUFDbEIsWUFBTyxHQUFhLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUN2QyxnQkFBZ0I7UUFDUCxnQkFBVyxHQUFXLENBQUMsQ0FBQztRQUNqQyxnQkFBZ0I7UUFDUCxlQUFVLEdBQVcsQ0FBQyxDQUFDO1FBQ2hDLFdBQVc7UUFDRixjQUFTLEdBQVcsT0FBTyxDQUFDO1FBRXJDLGVBQWU7UUFDUCw0QkFBdUIsR0FBWSxLQUFLLENBQUM7UUFrQnpDLHFCQUFnQixHQUFrQixJQUFJLENBQUM7UUFDdkMsY0FBUyxHQUFHLElBQUksQ0FBQztR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SztnQkFFRyxTQUFTO3NCQUFqQixLQUFLO2dCQUtGLHdCQUF3QjtzQkFEM0IsS0FBSztnQkEyTU4sV0FBVztzQkFEVixZQUFZO3VCQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFXckMsWUFBWTtzQkFEWCxZQUFZO3VCQUFDLFlBQVkiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIENvbXBvbmVudCxcclxuICBPbkluaXQsXHJcbiAgT25EZXN0cm95LFxyXG4gIEFmdGVyVmlld0luaXQsXHJcbiAgVmlld0NoaWxkLFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgSW5wdXQsXHJcbiAgT25DaGFuZ2VzLFxyXG4gIFNpbXBsZUNoYW5nZXMsXHJcbiAgSG9zdExpc3RlbmVyLFxyXG4gIE5nWm9uZVxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgKiBhcyBUSFJFRSBmcm9tICd0aHJlZSc7XHJcblxyXG5jb25zdCB2ZXJ0ZXhTaGFkZXIgPSBgXHJcbnZhcnlpbmcgdmVjMiB2VXY7XHJcbnZvaWQgbWFpbigpIHtcclxuICB2VXYgPSB1djtcclxuICBnbF9Qb3NpdGlvbiA9IHZlYzQocG9zaXRpb24sIDEuMCk7XHJcbn1cclxuYDtcclxuXHJcbmNvbnN0IGZyYWdtZW50U2hhZGVyID0gYFxyXG5wcmVjaXNpb24gaGlnaHAgZmxvYXQ7XHJcblxyXG51bmlmb3JtIGZsb2F0IGlUaW1lO1xyXG51bmlmb3JtIHZlYzMgaVJlc29sdXRpb247XHJcbnVuaWZvcm0gdmVjMyB1Q29sb3I7XHJcbnVuaWZvcm0gZmxvYXQgdUFtcGxpdHVkZTtcclxudW5pZm9ybSBmbG9hdCB1RGlzdGFuY2U7XHJcbnVuaWZvcm0gdmVjMiB1TW91c2U7XHJcblxyXG4jZGVmaW5lIFBJIDMuMTQxNTkyNjUzOFxyXG5cclxuY29uc3QgaW50IHVfbGluZV9jb3VudCA9IDQwO1xyXG5jb25zdCBmbG9hdCB1X2xpbmVfd2lkdGggPSA3LjA7XHJcbmNvbnN0IGZsb2F0IHVfbGluZV9ibHVyID0gMTAuMDtcclxuXHJcbmZsb2F0IFBlcmxpbjJEKHZlYzIgUCkge1xyXG4gICAgdmVjMiBQaSA9IGZsb29yKFApO1xyXG4gICAgdmVjNCBQZl9QZm1pbjEgPSBQLnh5eHkgLSB2ZWM0KFBpLCBQaSArIDEuMCk7XHJcbiAgICB2ZWM0IFB0ID0gdmVjNChQaS54eSwgUGkueHkgKyAxLjApO1xyXG4gICAgUHQgPSBQdCAtIGZsb29yKFB0ICogKDEuMCAvIDcxLjApKSAqIDcxLjA7XHJcbiAgICBQdCArPSB2ZWMyKDI2LjAsIDE2MS4wKS54eXh5O1xyXG4gICAgUHQgKj0gUHQ7XHJcbiAgICBQdCA9IFB0Lnh6eHogKiBQdC55eXd3O1xyXG4gICAgdmVjNCBoYXNoX3ggPSBmcmFjdChQdCAqICgxLjAgLyA5NTEuMTM1NjY0KSk7XHJcbiAgICB2ZWM0IGhhc2hfeSA9IGZyYWN0KFB0ICogKDEuMCAvIDY0Mi45NDk4ODMpKTtcclxuICAgIHZlYzQgZ3JhZF94ID0gaGFzaF94IC0gMC40OTk5OTtcclxuICAgIHZlYzQgZ3JhZF95ID0gaGFzaF95IC0gMC40OTk5OTtcclxuICAgIHZlYzQgZ3JhZF9yZXN1bHRzID0gaW52ZXJzZXNxcnQoZ3JhZF94ICogZ3JhZF94ICsgZ3JhZF95ICogZ3JhZF95KVxyXG4gICAgICAgICogKGdyYWRfeCAqIFBmX1BmbWluMS54enh6ICsgZ3JhZF95ICogUGZfUGZtaW4xLnl5d3cpO1xyXG4gICAgZ3JhZF9yZXN1bHRzICo9IDEuNDE0MjEzNTYyMzczMDk1MDtcclxuICAgIHZlYzIgYmxlbmQgPSBQZl9QZm1pbjEueHkgKiBQZl9QZm1pbjEueHkgKiBQZl9QZm1pbjEueHlcclxuICAgICAgICAgICAgICAgKiAoUGZfUGZtaW4xLnh5ICogKFBmX1BmbWluMS54eSAqIDYuMCAtIDE1LjApICsgMTAuMCk7XHJcbiAgICB2ZWM0IGJsZW5kMiA9IHZlYzQoYmxlbmQsIHZlYzIoMS4wIC0gYmxlbmQpKTtcclxuICAgIHJldHVybiBkb3QoZ3JhZF9yZXN1bHRzLCBibGVuZDIuenh6eCAqIGJsZW5kMi53d3l5KTtcclxufVxyXG5cclxuZmxvYXQgcGl4ZWwoZmxvYXQgY291bnQsIHZlYzIgcmVzb2x1dGlvbikge1xyXG4gICAgcmV0dXJuICgxLjAgLyBtYXgocmVzb2x1dGlvbi54LCByZXNvbHV0aW9uLnkpKSAqIGNvdW50O1xyXG59XHJcblxyXG5mbG9hdCBsaW5lRm4odmVjMiBzdCwgZmxvYXQgd2lkdGgsIGZsb2F0IHBlcmMsIGZsb2F0IG9mZnNldCwgdmVjMiBtb3VzZSwgZmxvYXQgdGltZSwgZmxvYXQgYW1wbGl0dWRlLCBmbG9hdCBkaXN0YW5jZSkge1xyXG4gICAgZmxvYXQgc3BsaXRfb2Zmc2V0ID0gKHBlcmMgKiAwLjQpO1xyXG4gICAgZmxvYXQgc3BsaXRfcG9pbnQgPSAwLjEgKyBzcGxpdF9vZmZzZXQ7XHJcblxyXG4gICAgZmxvYXQgYW1wbGl0dWRlX25vcm1hbCA9IHNtb290aHN0ZXAoc3BsaXRfcG9pbnQsIDAuNywgc3QueCk7XHJcbiAgICBmbG9hdCBhbXBsaXR1ZGVfc3RyZW5ndGggPSAwLjU7XHJcbiAgICBmbG9hdCBmaW5hbEFtcGxpdHVkZSA9IGFtcGxpdHVkZV9ub3JtYWwgKiBhbXBsaXR1ZGVfc3RyZW5ndGhcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgKiBhbXBsaXR1ZGUgKiAoMS4wICsgKG1vdXNlLnkgLSAwLjUpICogMC4yKTtcclxuXHJcbiAgICBmbG9hdCB0aW1lX3NjYWxlZCA9IHRpbWUgLyAxMC4wICsgKG1vdXNlLnggLSAwLjUpICogMS4wO1xyXG4gICAgZmxvYXQgYmx1ciA9IHNtb290aHN0ZXAoc3BsaXRfcG9pbnQsIHNwbGl0X3BvaW50ICsgMC4wNSwgc3QueCkgKiBwZXJjO1xyXG5cclxuICAgIGZsb2F0IHhub2lzZSA9IG1peChcclxuICAgICAgICBQZXJsaW4yRCh2ZWMyKHRpbWVfc2NhbGVkLCBzdC54ICsgcGVyYykgKiAyLjUpLFxyXG4gICAgICAgIFBlcmxpbjJEKHZlYzIodGltZV9zY2FsZWQsIHN0LnggKyB0aW1lX3NjYWxlZCkgKiAzLjUpIC8gMS41LFxyXG4gICAgICAgIHN0LnggKiAwLjNcclxuICAgICk7XHJcblxyXG4gICAgZmxvYXQgeSA9IDAuNSArIChwZXJjIC0gMC41KSAqIGRpc3RhbmNlICsgeG5vaXNlIC8gMi4wICogZmluYWxBbXBsaXR1ZGU7XHJcblxyXG4gICAgZmxvYXQgbGluZV9zdGFydCA9IHNtb290aHN0ZXAoXHJcbiAgICAgICAgeSArICh3aWR0aCAvIDIuMCkgKyAodV9saW5lX2JsdXIgKiBwaXhlbCgxLjAsIGlSZXNvbHV0aW9uLnh5KSAqIGJsdXIpLFxyXG4gICAgICAgIHksXHJcbiAgICAgICAgc3QueVxyXG4gICAgKTtcclxuXHJcbiAgICBmbG9hdCBsaW5lX2VuZCA9IHNtb290aHN0ZXAoXHJcbiAgICAgICAgeSxcclxuICAgICAgICB5IC0gKHdpZHRoIC8gMi4wKSAtICh1X2xpbmVfYmx1ciAqIHBpeGVsKDEuMCwgaVJlc29sdXRpb24ueHkpICogYmx1ciksXHJcbiAgICAgICAgc3QueVxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4gY2xhbXAoXHJcbiAgICAgICAgKGxpbmVfc3RhcnQgLSBsaW5lX2VuZCkgKiAoMS4wIC0gc21vb3Roc3RlcCgwLjAsIDEuMCwgcG93KHBlcmMsIDAuMykpKSxcclxuICAgICAgICAwLjAsXHJcbiAgICAgICAgMS4wXHJcbiAgICApO1xyXG59XHJcblxyXG52b2lkIG1haW5JbWFnZShvdXQgdmVjNCBmcmFnQ29sb3IsIGluIHZlYzIgZnJhZ0Nvb3JkKSB7XHJcbiAgICB2ZWMyIHV2ID0gZnJhZ0Nvb3JkIC8gaVJlc29sdXRpb24ueHk7XHJcblxyXG4gICAgZmxvYXQgbGluZV9zdHJlbmd0aCA9IDEuMDtcclxuICAgIGZvciAoaW50IGkgPSAwOyBpIDwgdV9saW5lX2NvdW50OyBpKyspIHtcclxuICAgICAgICBmbG9hdCBwID0gZmxvYXQoaSkgLyBmbG9hdCh1X2xpbmVfY291bnQpO1xyXG4gICAgICAgIGxpbmVfc3RyZW5ndGggKj0gKDEuMCAtIGxpbmVGbihcclxuICAgICAgICAgICAgdXYsXHJcbiAgICAgICAgICAgIHVfbGluZV93aWR0aCAqIHBpeGVsKDEuMCwgaVJlc29sdXRpb24ueHkpICogKDEuMCAtIHApLFxyXG4gICAgICAgICAgICBwLFxyXG4gICAgICAgICAgICAoUEkgKiAxLjApICogcCxcclxuICAgICAgICAgICAgdU1vdXNlLFxyXG4gICAgICAgICAgICBpVGltZSxcclxuICAgICAgICAgICAgdUFtcGxpdHVkZSxcclxuICAgICAgICAgICAgdURpc3RhbmNlXHJcbiAgICAgICAgKSk7XHJcbiAgICB9XHJcblxyXG4gICAgZmxvYXQgY29sb3JWYWwgPSAxLjAgLSBsaW5lX3N0cmVuZ3RoO1xyXG4gICAgZnJhZ0NvbG9yID0gdmVjNCh1Q29sb3IgKiBjb2xvclZhbCwgY29sb3JWYWwpO1xyXG59XHJcblxyXG52b2lkIG1haW4oKSB7XHJcbiAgICBtYWluSW1hZ2UoZ2xfRnJhZ0NvbG9yLCBnbF9GcmFnQ29vcmQueHkpO1xyXG59XHJcbmA7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ25jLXRocmVhZHMtYmFja2dyb3VuZCcsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL3RocmVhZHMtYmFja2dyb3VuZC5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vdGhyZWFkcy1iYWNrZ3JvdW5kLmNvbXBvbmVudC5sZXNzJ11cclxufSlcclxuZXhwb3J0IGNsYXNzIFRocmVhZHNCYWNrZ3JvdW5kQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XHJcbiAgQFZpZXdDaGlsZCgnY29udGFpbmVyJywgeyBzdGF0aWM6IHRydWUgfSkgY29udGFpbmVyUmVmITogRWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD47XHJcblxyXG4gIC8qKiDpopzoibIgW3IsIGcsIGJdIOaVsOe7hO+8iDAtMe+8iSAqL1xyXG4gIEBJbnB1dCgpIG5jQ29sb3I6IG51bWJlcltdID0gWzEsIDEsIDFdO1xyXG4gIC8qKiDmjK/luYXlpKflsI/vvIgwLTXvvIkgKi9cclxuICBASW5wdXQoKSBuY0FtcGxpdHVkZTogbnVtYmVyID0gMTtcclxuICAvKiog57q/5p2h6Led56a777yIMC0y77yJICovXHJcbiAgQElucHV0KCkgbmNEaXN0YW5jZTogbnVtYmVyID0gMDtcclxuICAvKiog6IOM5pmv6aKc6ImyICovXHJcbiAgQElucHV0KCkgbmNCZ0NvbG9yOiBzdHJpbmcgPSAnYmxhY2snO1xyXG5cclxuICAvKiog5piv5ZCm5ZCv55So6byg5qCH5Lqk5LqSICovXHJcbiAgcHJpdmF0ZSBfZW5hYmxlTW91c2VJbnRlcmFjdGlvbjogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpXHJcbiAgc2V0IG5jRW5hYmxlTW91c2VJbnRlcmFjdGlvbih2YWw6IGJvb2xlYW4gfCBzdHJpbmcpIHtcclxuICAgIHRoaXMuX2VuYWJsZU1vdXNlSW50ZXJhY3Rpb24gPSB2YWwgIT09IG51bGwgJiYgdmFsICE9PSB1bmRlZmluZWQgJiYgdmFsICE9PSBmYWxzZSAmJiB2YWwgIT09ICdmYWxzZSc7XHJcbiAgfVxyXG4gIGdldCBuY0VuYWJsZU1vdXNlSW50ZXJhY3Rpb24oKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5fZW5hYmxlTW91c2VJbnRlcmFjdGlvbjtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcmVuZGVyZXIhOiBUSFJFRS5XZWJHTFJlbmRlcmVyO1xyXG4gIHByaXZhdGUgc2NlbmUhOiBUSFJFRS5TY2VuZTtcclxuICBwcml2YXRlIGNhbWVyYSE6IFRIUkVFLk9ydGhvZ3JhcGhpY0NhbWVyYTtcclxuICBwcml2YXRlIG1hdGVyaWFsITogVEhSRUUuU2hhZGVyTWF0ZXJpYWw7XHJcbiAgcHJpdmF0ZSBnZW9tZXRyeSE6IFRIUkVFLlBsYW5lR2VvbWV0cnk7XHJcbiAgcHJpdmF0ZSBtZXNoITogVEhSRUUuTWVzaDtcclxuXHJcbiAgcHJpdmF0ZSByZXNpemVPYnNlcnZlciE6IFJlc2l6ZU9ic2VydmVyO1xyXG4gIHByaXZhdGUgaW50ZXJzZWN0aW9uT2JzZXJ2ZXIhOiBJbnRlcnNlY3Rpb25PYnNlcnZlcjtcclxuICBwcml2YXRlIGFuaW1hdGlvbkZyYW1lSWQ6IG51bWJlciB8IG51bGwgPSBudWxsO1xyXG4gIHByaXZhdGUgaXNWaXNpYmxlID0gdHJ1ZTtcclxuICBwcml2YXRlIGlzUnVubmluZyA9IGZhbHNlO1xyXG5cclxuICBwcml2YXRlIGN1cnJlbnRNb3VzZSA9IG5ldyBUSFJFRS5WZWN0b3IyKDAuNSwgMC41KTtcclxuICBwcml2YXRlIHRhcmdldE1vdXNlID0gbmV3IFRIUkVFLlZlY3RvcjIoMC41LCAwLjUpO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIG5nWm9uZTogTmdab25lKSB7IH1cclxuXHJcbiAgbmdPbkluaXQoKTogdm9pZCB7IH1cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICB0aGlzLmluaXRXZWJHTCgpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIHRoaXMuY2xlYW51cCgpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMubWF0ZXJpYWwpIHtcclxuICAgICAgaWYgKGNoYW5nZXNbJ25jQ29sb3InXSkge1xyXG4gICAgICAgIHRoaXMubWF0ZXJpYWwudW5pZm9ybXNbJ3VDb2xvciddLnZhbHVlLmNvcHkodGhpcy5nZXRUaHJlZUNvbG9yKHRoaXMubmNDb2xvcikpO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChjaGFuZ2VzWyduY0FtcGxpdHVkZSddKSB7XHJcbiAgICAgICAgdGhpcy5tYXRlcmlhbC51bmlmb3Jtc1sndUFtcGxpdHVkZSddLnZhbHVlID0gdGhpcy5uY0FtcGxpdHVkZTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoY2hhbmdlc1snbmNEaXN0YW5jZSddKSB7XHJcbiAgICAgICAgdGhpcy5tYXRlcmlhbC51bmlmb3Jtc1sndURpc3RhbmNlJ10udmFsdWUgPSB0aGlzLm5jRGlzdGFuY2U7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0VGhyZWVDb2xvcihjb2xvcjogbnVtYmVyW10pOiBUSFJFRS5Db2xvciB7XHJcbiAgICBpZiAoQXJyYXkuaXNBcnJheShjb2xvcikpIHtcclxuICAgICAgcmV0dXJuIG5ldyBUSFJFRS5Db2xvcihjb2xvclswXSwgY29sb3JbMV0sIGNvbG9yWzJdKTtcclxuICAgIH1cclxuICAgIHJldHVybiBuZXcgVEhSRUUuQ29sb3IoY29sb3IpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0V2ViR0woKTogdm9pZCB7XHJcbiAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmNvbnRhaW5lclJlZi5uYXRpdmVFbGVtZW50O1xyXG5cclxuICAgIC8vIOWIneWni+WMlua4suafk+WZqFxyXG4gICAgdGhpcy5yZW5kZXJlciA9IG5ldyBUSFJFRS5XZWJHTFJlbmRlcmVyKHsgYWxwaGE6IHRydWUsIGFudGlhbGlhczogZmFsc2UgfSk7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldENsZWFyQ29sb3IoMHgwMDAwMDAsIDApO1xyXG4gICAgLy8g6YeH55So5LiOIFRocmVhZHMuanN4IOS4rSBibGVuZEZ1bmMoU1JDX0FMUEhBLCBPTkVfTUlOVVNfU1JDX0FMUEhBKSDkuIDoh7TnmoTpu5jorqTmt7flkIjmlrnlvI9cclxuICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLnJlbmRlcmVyLmRvbUVsZW1lbnQpO1xyXG5cclxuICAgIHRoaXMuc2NlbmUgPSBuZXcgVEhSRUUuU2NlbmUoKTtcclxuICAgIHRoaXMuY2FtZXJhID0gbmV3IFRIUkVFLk9ydGhvZ3JhcGhpY0NhbWVyYSgtMSwgMSwgMSwgLTEsIDAsIDEpO1xyXG5cclxuICAgIHRoaXMuZ2VvbWV0cnkgPSBuZXcgVEhSRUUuUGxhbmVHZW9tZXRyeSgyLCAyKTtcclxuXHJcbiAgICAvLyDliJ3lp4vliIbovqjnjoforr7lrprvvIzlkI7nu63nlLEgcmVzaXplIOabtOaWsFxyXG4gICAgY29uc3QgY2FudmFzV2lkdGggPSBjb250YWluZXIuY2xpZW50V2lkdGggfHwgMTtcclxuICAgIGNvbnN0IGNhbnZhc0hlaWdodCA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQgfHwgMTtcclxuXHJcbiAgICB0aGlzLm1hdGVyaWFsID0gbmV3IFRIUkVFLlNoYWRlck1hdGVyaWFsKHtcclxuICAgICAgdmVydGV4U2hhZGVyLFxyXG4gICAgICBmcmFnbWVudFNoYWRlcixcclxuICAgICAgdHJhbnNwYXJlbnQ6IHRydWUsXHJcbiAgICAgIHVuaWZvcm1zOiB7XHJcbiAgICAgICAgaVRpbWU6IHsgdmFsdWU6IDAgfSxcclxuICAgICAgICBpUmVzb2x1dGlvbjogeyB2YWx1ZTogbmV3IFRIUkVFLlZlY3RvcjMoY2FudmFzV2lkdGgsIGNhbnZhc0hlaWdodCwgY2FudmFzV2lkdGggLyBjYW52YXNIZWlnaHQpIH0sXHJcbiAgICAgICAgdUNvbG9yOiB7IHZhbHVlOiB0aGlzLmdldFRocmVlQ29sb3IodGhpcy5uY0NvbG9yKSB9LFxyXG4gICAgICAgIHVBbXBsaXR1ZGU6IHsgdmFsdWU6IHRoaXMubmNBbXBsaXR1ZGUgfSxcclxuICAgICAgICB1RGlzdGFuY2U6IHsgdmFsdWU6IHRoaXMubmNEaXN0YW5jZSB9LFxyXG4gICAgICAgIHVNb3VzZTogeyB2YWx1ZTogbmV3IFRIUkVFLlZlY3RvcjIoMC41LCAwLjUpIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5tZXNoID0gbmV3IFRIUkVFLk1lc2godGhpcy5nZW9tZXRyeSwgdGhpcy5tYXRlcmlhbCk7XHJcbiAgICB0aGlzLnNjZW5lLmFkZCh0aGlzLm1lc2gpO1xyXG5cclxuICAgIHRoaXMuc2V0dXBSZXNpemVPYnNlcnZlcihjb250YWluZXIpO1xyXG4gICAgdGhpcy5zZXR1cEludGVyc2VjdGlvbk9ic2VydmVyKGNvbnRhaW5lcik7XHJcblxyXG4gICAgdGhpcy5yZXNpemUoKTtcclxuICAgIHRoaXMuc3RhcnQoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgc2V0dXBSZXNpemVPYnNlcnZlcihjb250YWluZXI6IEhUTUxFbGVtZW50KTogdm9pZCB7XHJcbiAgICB0aGlzLnJlc2l6ZU9ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKCgpID0+IHtcclxuICAgICAgdGhpcy5uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICAgIHRoaXMucmVzaXplKCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfSk7XHJcbiAgICB0aGlzLnJlc2l6ZU9ic2VydmVyLm9ic2VydmUoY29udGFpbmVyKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgc2V0dXBJbnRlcnNlY3Rpb25PYnNlcnZlcihjb250YWluZXI6IEhUTUxFbGVtZW50KTogdm9pZCB7XHJcbiAgICB0aGlzLmludGVyc2VjdGlvbk9ic2VydmVyID0gbmV3IEludGVyc2VjdGlvbk9ic2VydmVyKGVudHJpZXMgPT4ge1xyXG4gICAgICBjb25zdCBlbnRyeSA9IGVudHJpZXNbMF07XHJcbiAgICAgIHRoaXMuaXNWaXNpYmxlID0gZW50cnkuaXNJbnRlcnNlY3RpbmcgJiYgZW50cnkuaW50ZXJzZWN0aW9uUmF0aW8gPiAwO1xyXG4gICAgICBpZiAodGhpcy5pc1Zpc2libGUgJiYgIWRvY3VtZW50LmhpZGRlbikge1xyXG4gICAgICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcclxuICAgICAgICAgIHRoaXMuc3RhcnQoKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLnBhdXNlKCk7XHJcbiAgICAgIH1cclxuICAgIH0sIHsgdGhyZXNob2xkOiBbMCwgMC4wMSwgMC4xXSB9KTtcclxuICAgIHRoaXMuaW50ZXJzZWN0aW9uT2JzZXJ2ZXIub2JzZXJ2ZShjb250YWluZXIpO1xyXG5cclxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3Zpc2liaWxpdHljaGFuZ2UnLCB0aGlzLm9uVmlzaWJpbGl0eUNoYW5nZSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIG9uVmlzaWJpbGl0eUNoYW5nZSA9ICgpID0+IHtcclxuICAgIGlmIChkb2N1bWVudC5oaWRkZW4pIHtcclxuICAgICAgdGhpcy5wYXVzZSgpO1xyXG4gICAgfSBlbHNlIGlmICh0aGlzLmlzVmlzaWJsZSkge1xyXG4gICAgICB0aGlzLm5nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XHJcbiAgICAgICAgdGhpcy5zdGFydCgpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9O1xyXG5cclxuICBwcml2YXRlIHJlc2l6ZSgpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5jb250YWluZXJSZWYgfHwgIXRoaXMucmVuZGVyZXIpIHJldHVybjtcclxuICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuY29udGFpbmVyUmVmLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICBjb25zdCB3aWR0aCA9IGNvbnRhaW5lci5jbGllbnRXaWR0aDtcclxuICAgIGNvbnN0IGhlaWdodCA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQ7XHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTaXplKHdpZHRoLCBoZWlnaHQpO1xyXG4gICAgLy8g5Y+v6YCJ6K6+572uIHBpeGVsUmF0aW/vvIzlpoLkuI3pnIDopoHmnoHpq5jnsr7luqblj6/kv53nlZkgMSDmj5Dpq5jmgKfog71cclxuICAgIC8vIHRoaXMucmVuZGVyZXIuc2V0UGl4ZWxSYXRpbyhNYXRoLm1pbih3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbywgMikpO1xyXG5cclxuICAgIHRoaXMubWF0ZXJpYWwudW5pZm9ybXNbJ2lSZXNvbHV0aW9uJ10udmFsdWUuc2V0KFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0LFxyXG4gICAgICAod2lkdGggLyBNYXRoLm1heChoZWlnaHQsIDEpKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlID0gKHQ6IG51bWJlcik6IHZvaWQgPT4ge1xyXG4gICAgaWYgKCF0aGlzLmlzUnVubmluZykgcmV0dXJuO1xyXG5cclxuICAgIGlmICh0aGlzLm5jRW5hYmxlTW91c2VJbnRlcmFjdGlvbikge1xyXG4gICAgICBjb25zdCBzbW9vdGhpbmcgPSAwLjA1O1xyXG4gICAgICB0aGlzLmN1cnJlbnRNb3VzZS54ICs9IHNtb290aGluZyAqICh0aGlzLnRhcmdldE1vdXNlLnggLSB0aGlzLmN1cnJlbnRNb3VzZS54KTtcclxuICAgICAgdGhpcy5jdXJyZW50TW91c2UueSArPSBzbW9vdGhpbmcgKiAodGhpcy50YXJnZXRNb3VzZS55IC0gdGhpcy5jdXJyZW50TW91c2UueSk7XHJcbiAgICAgIHRoaXMubWF0ZXJpYWwudW5pZm9ybXNbJ3VNb3VzZSddLnZhbHVlLmNvcHkodGhpcy5jdXJyZW50TW91c2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5tYXRlcmlhbC51bmlmb3Jtc1sndU1vdXNlJ10udmFsdWUuc2V0KDAuNSwgMC41KTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLm1hdGVyaWFsLnVuaWZvcm1zWydpVGltZSddLnZhbHVlID0gdCAqIDAuMDAxO1xyXG5cclxuICAgIHRoaXMucmVuZGVyZXIucmVuZGVyKHRoaXMuc2NlbmUsIHRoaXMuY2FtZXJhKTtcclxuICAgIHRoaXMuYW5pbWF0aW9uRnJhbWVJZCA9IHJlcXVlc3RBbmltYXRpb25GcmFtZSh0aGlzLnVwZGF0ZSk7XHJcbiAgfTtcclxuXHJcbiAgcHJpdmF0ZSBzdGFydCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmlzUnVubmluZykgcmV0dXJuO1xyXG4gICAgdGhpcy5pc1J1bm5pbmcgPSB0cnVlO1xyXG4gICAgdGhpcy5hbmltYXRpb25GcmFtZUlkID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRoaXMudXBkYXRlKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcGF1c2UoKTogdm9pZCB7XHJcbiAgICB0aGlzLmlzUnVubmluZyA9IGZhbHNlO1xyXG4gICAgaWYgKHRoaXMuYW5pbWF0aW9uRnJhbWVJZCAhPT0gbnVsbCkge1xyXG4gICAgICBjYW5jZWxBbmltYXRpb25GcmFtZSh0aGlzLmFuaW1hdGlvbkZyYW1lSWQpO1xyXG4gICAgICB0aGlzLmFuaW1hdGlvbkZyYW1lSWQgPSBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjbGVhbnVwKCk6IHZvaWQge1xyXG4gICAgdGhpcy5wYXVzZSgpO1xyXG4gICAgdHJ5IHsgdGhpcy5yZXNpemVPYnNlcnZlcj8uZGlzY29ubmVjdCgpOyB9IGNhdGNoIChlKSB7IHZvaWQgMDsgfVxyXG4gICAgdHJ5IHsgdGhpcy5pbnRlcnNlY3Rpb25PYnNlcnZlcj8uZGlzY29ubmVjdCgpOyB9IGNhdGNoIChlKSB7IHZvaWQgMDsgfVxyXG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigndmlzaWJpbGl0eWNoYW5nZScsIHRoaXMub25WaXNpYmlsaXR5Q2hhbmdlKTtcclxuXHJcbiAgICBpZiAodGhpcy5yZW5kZXJlcikge1xyXG4gICAgICBjb25zdCBjYW52YXMgPSB0aGlzLnJlbmRlcmVyLmRvbUVsZW1lbnQ7XHJcbiAgICAgIGlmIChjYW52YXMgJiYgY2FudmFzLnBhcmVudE5vZGUpIGNhbnZhcy5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGNhbnZhcyk7XHJcbiAgICAgIHRoaXMucmVuZGVyZXIuZGlzcG9zZSgpO1xyXG4gICAgICB0aGlzLnJlbmRlcmVyLmZvcmNlQ29udGV4dExvc3MoKTtcclxuICAgIH1cclxuICAgIGlmICh0aGlzLmdlb21ldHJ5KSB0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuICAgIGlmICh0aGlzLm1hdGVyaWFsKSB0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuICB9XHJcblxyXG4gIEBIb3N0TGlzdGVuZXIoJ21vdXNlbW92ZScsIFsnJGV2ZW50J10pXHJcbiAgb25Nb3VzZU1vdmUoZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5uY0VuYWJsZU1vdXNlSW50ZXJhY3Rpb24gfHwgIXRoaXMuY29udGFpbmVyUmVmKSByZXR1cm47XHJcbiAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmNvbnRhaW5lclJlZi5uYXRpdmVFbGVtZW50O1xyXG4gICAgY29uc3QgcmVjdCA9IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIGNvbnN0IHggPSAoZXZlbnQuY2xpZW50WCAtIHJlY3QubGVmdCkgLyByZWN0LndpZHRoO1xyXG4gICAgY29uc3QgeSA9IDEuMCAtIChldmVudC5jbGllbnRZIC0gcmVjdC50b3ApIC8gcmVjdC5oZWlnaHQ7XHJcbiAgICB0aGlzLnRhcmdldE1vdXNlLnNldCh4LCB5KTtcclxuICB9XHJcblxyXG4gIEBIb3N0TGlzdGVuZXIoJ21vdXNlbGVhdmUnKVxyXG4gIG9uTW91c2VMZWF2ZSgpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5uY0VuYWJsZU1vdXNlSW50ZXJhY3Rpb24pIHJldHVybjtcclxuICAgIHRoaXMudGFyZ2V0TW91c2Uuc2V0KDAuNSwgMC41KTtcclxuICB9XHJcbn1cclxuIiwiPGRpdiAjY29udGFpbmVyIGNsYXNzPVwibmMtdGhyZWFkcy1jYW52YXMtY29udGFpbmVyXCIgW3N0eWxlLmJhY2tncm91bmQtY29sb3JdPVwibmNCZ0NvbG9yXCI+PC9kaXY+XHJcbjxkaXYgY2xhc3M9XCJuYy1jb250ZW50LXdyYXBwZXJcIj5cclxuICA8bmctY29udGVudD48L25nLWNvbnRlbnQ+XHJcbjwvZGl2PiJdfQ==