ng-cw-v12
Version:
Angular UI Component Library
349 lines (332 loc) • 41.4 kB
JavaScript
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==