ng-cw-v12
Version:
Angular UI Component Library
440 lines (412 loc) • 52 kB
JavaScript
import { Component, ViewChild, Input, HostListener } from '@angular/core';
import * as THREE from 'three';
import * as i0 from "@angular/core";
const vertexShader = `
precision highp float;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 1.0);
}
`;
const fragmentShader = `
precision highp float;
uniform float uTime;
uniform vec3 uResolution;
uniform vec2 uFocal;
uniform vec2 uRotation;
uniform float uStarSpeed;
uniform float uDensity;
uniform float uHueShift;
uniform float uSpeed;
uniform vec2 uMouse;
uniform float uGlowIntensity;
uniform float uSaturation;
uniform bool uMouseRepulsion;
uniform float uTwinkleIntensity;
uniform float uRotationSpeed;
uniform float uRepulsionStrength;
uniform float uMouseActiveFactor;
uniform float uAutoCenterRepulsion;
varying vec2 vUv;
#define NUM_LAYER 4.0
#define STAR_COLOR_CUTOFF 0.2
#define MAT45 mat2(0.7071, -0.7071, 0.7071, 0.7071)
#define PERIOD 3.0
float Hash21(vec2 p) {
p = fract(p * vec2(123.34, 456.21));
p += dot(p, p + 45.32);
return fract(p.x * p.y);
}
float tri(float x) {
return abs(fract(x) * 2.0 - 1.0);
}
float tris(float x) {
float t = fract(x);
return 1.0 - smoothstep(0.0, 1.0, abs(2.0 * t - 1.0));
}
float trisn(float x) {
float t = fract(x);
return 2.0 * (1.0 - smoothstep(0.0, 1.0, abs(2.0 * t - 1.0))) - 1.0;
}
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
float Star(vec2 uv, float flare) {
float d = length(uv);
float m = (0.05 * uGlowIntensity) / d;
float rays = smoothstep(0.0, 1.0, 1.0 - abs(uv.x * uv.y * 1000.0));
m += rays * flare * uGlowIntensity;
uv *= MAT45;
rays = smoothstep(0.0, 1.0, 1.0 - abs(uv.x * uv.y * 1000.0));
m += rays * 0.3 * flare * uGlowIntensity;
m *= smoothstep(1.0, 0.2, d);
return m;
}
vec3 StarLayer(vec2 uv) {
vec3 col = vec3(0.0);
vec2 gv = fract(uv) - 0.5;
vec2 id = floor(uv);
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 offset = vec2(float(x), float(y));
vec2 si = id + vec2(float(x), float(y));
float seed = Hash21(si);
float size = fract(seed * 345.32);
float glossLocal = tri(uStarSpeed / (PERIOD * seed + 1.0));
float flareSize = smoothstep(0.9, 1.0, size) * glossLocal;
float red = smoothstep(STAR_COLOR_CUTOFF, 1.0, Hash21(si + 1.0)) + STAR_COLOR_CUTOFF;
float blu = smoothstep(STAR_COLOR_CUTOFF, 1.0, Hash21(si + 3.0)) + STAR_COLOR_CUTOFF;
float grn = min(red, blu) * seed;
vec3 base = vec3(red, grn, blu);
float hue = atan(base.g - base.r, base.b - base.r) / (2.0 * 3.14159) + 0.5;
hue = fract(hue + uHueShift / 360.0);
float sat = length(base - vec3(dot(base, vec3(0.299, 0.587, 0.114)))) * uSaturation;
float val = max(max(base.r, base.g), base.b);
base = hsv2rgb(vec3(hue, sat, val));
vec2 pad = vec2(tris(seed * 34.0 + uTime * uSpeed / 10.0), tris(seed * 38.0 + uTime * uSpeed / 30.0)) - 0.5;
float star = Star(gv - offset - pad, flareSize);
vec3 color = base;
float twinkle = trisn(uTime * uSpeed + seed * 6.2831) * 0.5 + 1.0;
twinkle = mix(1.0, twinkle, uTwinkleIntensity);
star *= twinkle;
col += star * size * color;
}
}
return col;
}
void main() {
vec2 focalPx = uFocal * uResolution.xy;
vec2 uv = (vUv * uResolution.xy - focalPx) / uResolution.y;
vec2 mouseNorm = uMouse - vec2(0.5);
if (uAutoCenterRepulsion > 0.0) {
vec2 centerUV = vec2(0.0, 0.0);
float centerDist = length(uv - centerUV);
vec2 repulsion = normalize(uv - centerUV) * (uAutoCenterRepulsion / (centerDist + 0.1));
uv += repulsion * 0.05;
} else if (uMouseRepulsion) {
vec2 mousePosUV = (uMouse * uResolution.xy - focalPx) / uResolution.y;
float mouseDist = length(uv - mousePosUV);
vec2 repulsion = normalize(uv - mousePosUV) * (uRepulsionStrength / (mouseDist + 0.1));
uv += repulsion * 0.05 * uMouseActiveFactor;
} else {
vec2 mouseOffset = mouseNorm * 0.1 * uMouseActiveFactor;
uv += mouseOffset;
}
float autoRotAngle = uTime * uRotationSpeed;
mat2 autoRot = mat2(cos(autoRotAngle), -sin(autoRotAngle), sin(autoRotAngle), cos(autoRotAngle));
uv = autoRot * uv;
uv = mat2(uRotation.x, -uRotation.y, uRotation.y, uRotation.x) * uv;
vec3 col = vec3(0.0);
for (float i = 0.0; i < 1.0; i += 1.0 / NUM_LAYER) {
float depth = fract(i + uStarSpeed * uSpeed);
float scale = mix(20.0 * uDensity, 0.5 * uDensity, depth);
float fade = depth * smoothstep(1.0, 0.9, depth);
col += StarLayer(uv * scale + i * 453.32) * fade;
}
float alpha = length(col);
alpha = smoothstep(0.0, 0.3, alpha);
alpha = min(alpha, 1.0);
gl_FragColor = vec4(col, alpha);
}
`;
export class GalaxyBackgroundComponent {
constructor(ngZone) {
this.ngZone = ngZone;
/** 将星系效应的焦点设置为 [x, y] 坐标(0-1) */
this.ncFocal = [0.5, 0.5];
/** 控制星系的旋转矩阵,其旋转值为[x, y] */
this.ncRotation = [1.0, 0.0];
/** 控制星星的移动速度和动画效果(0.1-2) */
this.ncStarSpeed = 0.5;
/** 控制星星的密度(0.1-3) */
this.ncDensity = 1;
/** 将所有星星的色调按指定的角度(0-360度)进行调整(在ncSaturation不为0时生效)*/
this.ncHueShift = 140;
/** 为真时,停止所有基于时间的动画 */
this._disableAnimation = false;
/** 所有动画的全局速度倍率(0.1-3) */
this.ncSpeed = 1.0;
/** 是否启用鼠标交互 */
this._mouseInteraction = true;
/** 控制星光效果的强度(0-1) */
this.ncGlowIntensity = 0.3;
/** 控制星星的颜色饱和度(0-1,0:灰度 1:全彩) */
this.ncSaturation = 0.0;
/** 是否启用鼠标排斥效果 */
this._mouseRepulsion = true;
/** 鼠标排斥力度(0-10) */
this.ncRepulsionStrength = 2;
/** 控制星星闪烁的程度(0-1,0:不闪烁 1:最大闪烁) */
this.ncTwinkleIntensity = 0.3;
/** 星系自动旋转的速度(0-0.5) */
this.ncRotationSpeed = 0.1;
/** 自动向中心排斥的强度(0-20,如果大于0则不使用鼠标位置) */
this.ncAutoCenterRepulsion = 0;
this.animationId = null;
this.targetMousePos = { x: 0.5, y: 0.5 };
this.smoothMousePos = { x: 0.5, y: 0.5 };
this.targetMouseActive = 0.0;
this.smoothMouseActive = 0.0;
this.animate = (t) => {
this.animationId = requestAnimationFrame(this.animate);
if (!this.ncDisableAnimation) {
this.uniforms.uTime.value = t * 0.001;
this.uniforms.uStarSpeed.value = (t * 0.001 * this.ncStarSpeed) / 10.0;
}
const lerpFactor = 0.05;
this.smoothMousePos.x += (this.targetMousePos.x - this.smoothMousePos.x) * lerpFactor;
this.smoothMousePos.y += (this.targetMousePos.y - this.smoothMousePos.y) * lerpFactor;
this.smoothMouseActive += (this.targetMouseActive - this.smoothMouseActive) * lerpFactor;
this.uniforms.uMouse.value[0] = this.smoothMousePos.x;
this.uniforms.uMouse.value[1] = this.smoothMousePos.y;
this.uniforms.uMouseActiveFactor.value = this.smoothMouseActive;
this.renderer.render(this.scene, this.camera);
};
this.handleMouseLeave = () => {
this.targetMouseActive = 0.0;
};
}
set ncDisableAnimation(val) {
this._disableAnimation = val !== null && val !== undefined && val !== false && val !== 'false';
}
get ncDisableAnimation() {
return this._disableAnimation;
}
set ncMouseInteraction(val) {
this._mouseInteraction = val !== null && val !== undefined && val !== false && val !== 'false';
}
get ncMouseInteraction() {
return this._mouseInteraction;
}
set ncMouseRepulsion(val) {
this._mouseRepulsion = val !== null && val !== undefined && val !== false && val !== 'false';
}
get ncMouseRepulsion() {
return this._mouseRepulsion;
}
ngOnInit() { }
ngAfterViewInit() {
this.initWebGL();
}
ngOnDestroy() {
this.cleanup();
}
ngOnChanges(changes) {
if (!this.uniforms)
return;
this.updateUniforms();
}
initWebGL() {
const container = this.containerRef.nativeElement;
this.renderer = new THREE.WebGLRenderer({
alpha: true,
premultipliedAlpha: false,
antialias: false
});
this.renderer.setClearColor(0x000000, 0);
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
container.appendChild(this.renderer.domElement);
this.scene = new THREE.Scene();
this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
this.uniforms = {
uTime: { value: 0 },
uResolution: { value: new THREE.Vector3() },
uFocal: { value: new THREE.Vector2() },
uRotation: { value: new THREE.Vector2() },
uStarSpeed: { value: this.ncStarSpeed },
uDensity: { value: this.ncDensity },
uHueShift: { value: this.ncHueShift },
uSpeed: { value: this.ncSpeed },
uMouse: { value: [this.smoothMousePos.x, this.smoothMousePos.y] },
uGlowIntensity: { value: this.ncGlowIntensity },
uSaturation: { value: this.ncSaturation },
uMouseRepulsion: { value: this.ncMouseRepulsion },
uTwinkleIntensity: { value: this.ncTwinkleIntensity },
uRotationSpeed: { value: this.ncRotationSpeed },
uRepulsionStrength: { value: this.ncRepulsionStrength },
uMouseActiveFactor: { value: 0.0 },
uAutoCenterRepulsion: { value: this.ncAutoCenterRepulsion }
};
this.updateUniforms();
const geometry = new THREE.PlaneGeometry(2, 2);
this.material = new THREE.RawShaderMaterial({
vertexShader,
fragmentShader,
uniforms: this.uniforms,
transparent: true,
blending: THREE.NormalBlending
});
const mesh = new THREE.Mesh(geometry, this.material);
this.scene.add(mesh);
this.resizeObserver = new ResizeObserver(() => this.resize());
this.resizeObserver.observe(container);
this.resize();
this.ngZone.runOutsideAngular(() => {
this.animate(0);
});
}
updateUniforms() {
if (!this.uniforms || !this.renderer)
return;
this.renderer.setClearColor(0x000000, 0);
this.material && (this.material.transparent = true);
this.uniforms.uFocal.value.set(this.ncFocal[0], this.ncFocal[1]);
this.uniforms.uRotation.value.set(this.ncRotation[0], this.ncRotation[1]);
this.uniforms.uStarSpeed.value = this.ncStarSpeed;
this.uniforms.uDensity.value = this.ncDensity;
this.uniforms.uHueShift.value = this.ncHueShift;
this.uniforms.uSpeed.value = this.ncSpeed;
this.uniforms.uGlowIntensity.value = this.ncGlowIntensity;
this.uniforms.uSaturation.value = this.ncSaturation;
this.uniforms.uMouseRepulsion.value = this.ncMouseRepulsion;
this.uniforms.uTwinkleIntensity.value = this.ncTwinkleIntensity;
this.uniforms.uRotationSpeed.value = this.ncRotationSpeed;
this.uniforms.uRepulsionStrength.value = this.ncRepulsionStrength;
this.uniforms.uAutoCenterRepulsion.value = this.ncAutoCenterRepulsion;
}
resize() {
if (!this.containerRef || !this.renderer)
return;
const container = this.containerRef.nativeElement;
const width = container.offsetWidth;
const height = container.offsetHeight;
this.renderer.setSize(width, height);
if (this.uniforms) {
this.uniforms.uResolution.value.set(width, height, width / height);
}
}
onMouseMove(e) {
if (!this.ncMouseInteraction)
return;
this.updateMousePos(e.clientX, e.clientY);
}
onMouseLeave() {
this.handleMouseLeave();
}
onTouchMove(e) {
if (!this.ncMouseInteraction || e.touches.length === 0)
return;
this.updateMousePos(e.touches[0].clientX, e.touches[0].clientY);
}
onTouchEnd() {
this.handleMouseLeave();
}
updateMousePos(clientX, clientY) {
if (!this.containerRef)
return;
const rect = this.containerRef.nativeElement.getBoundingClientRect();
const x = (clientX - rect.left) / rect.width;
const y = 1.0 - (clientY - rect.top) / rect.height;
this.targetMousePos = { x, y };
this.targetMouseActive = 1.0;
}
cleanup() {
var _a;
if (this.animationId !== null) {
cancelAnimationFrame(this.animationId);
this.animationId = null;
}
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
const container = (_a = this.containerRef) === null || _a === void 0 ? void 0 : _a.nativeElement;
if (container) {
if (this.renderer && container.contains(this.renderer.domElement)) {
container.removeChild(this.renderer.domElement);
}
}
if (this.renderer) {
this.renderer.dispose();
}
if (this.material) {
this.material.dispose();
}
if (this.scene) {
this.scene.clear();
}
}
}
GalaxyBackgroundComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: GalaxyBackgroundComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
GalaxyBackgroundComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: GalaxyBackgroundComponent, selector: "nc-galaxy-background", inputs: { ncFocal: "ncFocal", ncRotation: "ncRotation", ncStarSpeed: "ncStarSpeed", ncDensity: "ncDensity", ncHueShift: "ncHueShift", ncDisableAnimation: "ncDisableAnimation", ncSpeed: "ncSpeed", ncMouseInteraction: "ncMouseInteraction", ncGlowIntensity: "ncGlowIntensity", ncSaturation: "ncSaturation", ncMouseRepulsion: "ncMouseRepulsion", ncRepulsionStrength: "ncRepulsionStrength", ncTwinkleIntensity: "ncTwinkleIntensity", ncRotationSpeed: "ncRotationSpeed", ncAutoCenterRepulsion: "ncAutoCenterRepulsion" }, host: { listeners: { "mousemove": "onMouseMove($event)", "mouseleave": "onMouseLeave()", "touchstart": "onTouchMove($event)", "touchmove": "onTouchMove($event)", "touchend": "onTouchEnd()" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #container class=\"nc-galaxy-canvas-container\"></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-galaxy-canvas-container{position:absolute;inset:0;z-index:0;background-color:#000}.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: GalaxyBackgroundComponent, decorators: [{
type: Component,
args: [{
selector: 'nc-galaxy-background',
templateUrl: './galaxy-background.component.html',
styleUrls: ['./galaxy-background.component.less']
}]
}], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { containerRef: [{
type: ViewChild,
args: ['container', { static: true }]
}], ncFocal: [{
type: Input
}], ncRotation: [{
type: Input
}], ncStarSpeed: [{
type: Input
}], ncDensity: [{
type: Input
}], ncHueShift: [{
type: Input
}], ncDisableAnimation: [{
type: Input
}], ncSpeed: [{
type: Input
}], ncMouseInteraction: [{
type: Input
}], ncGlowIntensity: [{
type: Input
}], ncSaturation: [{
type: Input
}], ncMouseRepulsion: [{
type: Input
}], ncRepulsionStrength: [{
type: Input
}], ncTwinkleIntensity: [{
type: Input
}], ncRotationSpeed: [{
type: Input
}], ncAutoCenterRepulsion: [{
type: Input
}], onMouseMove: [{
type: HostListener,
args: ['mousemove', ['$event']]
}], onMouseLeave: [{
type: HostListener,
args: ['mouseleave']
}], onTouchMove: [{
type: HostListener,
args: ['touchstart', ['$event']]
}, {
type: HostListener,
args: ['touchmove', ['$event']]
}], onTouchEnd: [{
type: HostListener,
args: ['touchend']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2FsYXh5LWJhY2tncm91bmQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvY29tcG9uZW50cy9nYWxheHktYmFja2dyb3VuZC9nYWxheHktYmFja2dyb3VuZC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9jb21wb25lbnRzL2dhbGF4eS1iYWNrZ3JvdW5kL2dhbGF4eS1iYWNrZ3JvdW5kLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBSVQsU0FBUyxFQUVULEtBQUssRUFJTCxZQUFZLEVBQ2IsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxLQUFLLEtBQUssTUFBTSxPQUFPLENBQUM7O0FBRS9CLE1BQU0sWUFBWSxHQUFHOzs7Ozs7Ozs7Q0FTcEIsQ0FBQztBQUVGLE1BQU0sY0FBYyxHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0FzSnRCLENBQUM7QUFPRixNQUFNLE9BQU8seUJBQXlCO0lBcUVwQyxZQUFvQixNQUFjO1FBQWQsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQWxFbEMsaUNBQWlDO1FBQ3hCLFlBQU8sR0FBcUIsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDaEQsNEJBQTRCO1FBQ25CLGVBQVUsR0FBcUIsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDbkQsNEJBQTRCO1FBQ25CLGdCQUFXLEdBQVcsR0FBRyxDQUFDO1FBQ25DLHFCQUFxQjtRQUNaLGNBQVMsR0FBVyxDQUFDLENBQUM7UUFDL0IscURBQXFEO1FBQzVDLGVBQVUsR0FBVyxHQUFHLENB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QUF5QjswR0FBekIseUJBQXlCLDg0QkN2THRDLDhJQUdNOzJGRG9MTyx5QkFBeUI7a0JBTHJDLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLHNCQUFzQjtvQkFDaEMsV0FBVyxFQUFFLG9DQUFvQztvQkFDakQsU0FBUyxFQUFFLENBQUMsb0NBQW9DLENBQUM7aUJBQ2xEOzZGQUUyQyxZQUFZO3NCQUFyRCxTQUFTO3VCQUFDLFdBQVcsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7Z0JBRy9CLE9BQU87c0JBQWYsS0FBSztnQkFFRyxVQUFVO3NCQUFsQixLQUFLO2dCQUVHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBRUcsU0FBUztzQkFBakIsS0FBSztnQkFFRyxVQUFVO3NCQUFsQixLQUFLO2dCQUlGLGtCQUFrQjtzQkFEckIsS0FBSztnQkFRRyxPQUFPO3NCQUFmLEtBQUs7Z0JBSUYsa0JBQWtCO3NCQURyQixLQUFLO2dCQVFHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBRUcsWUFBWTtzQkFBcEIsS0FBSztnQkFJRixnQkFBZ0I7c0JBRG5CLEtBQUs7Z0JBUUcsbUJBQW1CO3NCQUEzQixLQUFLO2dCQUVHLGtCQUFrQjtzQkFBMUIsS0FBSztnQkFFRyxlQUFlO3NCQUF2QixLQUFLO2dCQUVHLHFCQUFxQjtzQkFBN0IsS0FBSztnQkFvSk4sV0FBVztzQkFEVixZQUFZO3VCQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFPckMsWUFBWTtzQkFEWCxZQUFZO3VCQUFDLFlBQVk7Z0JBTzFCLFdBQVc7c0JBRlYsWUFBWTt1QkFBQyxZQUFZLEVBQUUsQ0FBQyxRQUFRLENBQUM7O3NCQUNyQyxZQUFZO3VCQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFPckMsVUFBVTtzQkFEVCxZQUFZO3VCQUFDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIENvbXBvbmVudCxcclxuICBPbkluaXQsXHJcbiAgT25EZXN0cm95LFxyXG4gIEFmdGVyVmlld0luaXQsXHJcbiAgVmlld0NoaWxkLFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgSW5wdXQsXHJcbiAgT25DaGFuZ2VzLFxyXG4gIFNpbXBsZUNoYW5nZXMsXHJcbiAgTmdab25lLFxyXG4gIEhvc3RMaXN0ZW5lclxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgKiBhcyBUSFJFRSBmcm9tICd0aHJlZSc7XHJcblxyXG5jb25zdCB2ZXJ0ZXhTaGFkZXIgPSBgXHJcbnByZWNpc2lvbiBoaWdocCBmbG9hdDtcclxuYXR0cmlidXRlIHZlYzMgcG9zaXRpb247XHJcbmF0dHJpYnV0ZSB2ZWMyIHV2O1xyXG52YXJ5aW5nIHZlYzIgdlV2O1xyXG52b2lkIG1haW4oKSB7XHJcbiAgdlV2ID0gdXY7XHJcbiAgZ2xfUG9zaXRpb24gPSB2ZWM0KHBvc2l0aW9uLCAxLjApO1xyXG59XHJcbmA7XHJcblxyXG5jb25zdCBmcmFnbWVudFNoYWRlciA9IGBcclxucHJlY2lzaW9uIGhpZ2hwIGZsb2F0O1xyXG5cclxudW5pZm9ybSBmbG9hdCB1VGltZTtcclxudW5pZm9ybSB2ZWMzIHVSZXNvbHV0aW9uO1xyXG51bmlmb3JtIHZlYzIgdUZvY2FsO1xyXG51bmlmb3JtIHZlYzIgdVJvdGF0aW9uO1xyXG51bmlmb3JtIGZsb2F0IHVTdGFyU3BlZWQ7XHJcbnVuaWZvcm0gZmxvYXQgdURlbnNpdHk7XHJcbnVuaWZvcm0gZmxvYXQgdUh1ZVNoaWZ0O1xyXG51bmlmb3JtIGZsb2F0IHVTcGVlZDtcclxudW5pZm9ybSB2ZWMyIHVNb3VzZTtcclxudW5pZm9ybSBmbG9hdCB1R2xvd0ludGVuc2l0eTtcclxudW5pZm9ybSBmbG9hdCB1U2F0dXJhdGlvbjtcclxudW5pZm9ybSBib29sIHVNb3VzZVJlcHVsc2lvbjtcclxudW5pZm9ybSBmbG9hdCB1VHdpbmtsZUludGVuc2l0eTtcclxudW5pZm9ybSBmbG9hdCB1Um90YXRpb25TcGVlZDtcclxudW5pZm9ybSBmbG9hdCB1UmVwdWxzaW9uU3RyZW5ndGg7XHJcbnVuaWZvcm0gZmxvYXQgdU1vdXNlQWN0aXZlRmFjdG9yO1xyXG51bmlmb3JtIGZsb2F0IHVBdXRvQ2VudGVyUmVwdWxzaW9uO1xyXG5cclxuXHJcbnZhcnlpbmcgdmVjMiB2VXY7XHJcblxyXG4jZGVmaW5lIE5VTV9MQVlFUiA0LjBcclxuI2RlZmluZSBTVEFSX0NPTE9SX0NVVE9GRiAwLjJcclxuI2RlZmluZSBNQVQ0NSBtYXQyKDAuNzA3MSwgLTAuNzA3MSwgMC43MDcxLCAwLjcwNzEpXHJcbiNkZWZpbmUgUEVSSU9EIDMuMFxyXG5cclxuZmxvYXQgSGFzaDIxKHZlYzIgcCkge1xyXG4gIHAgPSBmcmFjdChwICogdmVjMigxMjMuMzQsIDQ1Ni4yMSkpO1xyXG4gIHAgKz0gZG90KHAsIHAgKyA0NS4zMik7XHJcbiAgcmV0dXJuIGZyYWN0KHAueCAqIHAueSk7XHJcbn1cclxuXHJcbmZsb2F0IHRyaShmbG9hdCB4KSB7XHJcbiAgcmV0dXJuIGFicyhmcmFjdCh4KSAqIDIuMCAtIDEuMCk7XHJcbn1cclxuXHJcbmZsb2F0IHRyaXMoZmxvYXQgeCkge1xyXG4gIGZsb2F0IHQgPSBmcmFjdCh4KTtcclxuICByZXR1cm4gMS4wIC0gc21vb3Roc3RlcCgwLjAsIDEuMCwgYWJzKDIuMCAqIHQgLSAxLjApKTtcclxufVxyXG5cclxuZmxvYXQgdHJpc24oZmxvYXQgeCkge1xyXG4gIGZsb2F0IHQgPSBmcmFjdCh4KTtcclxuICByZXR1cm4gMi4wICogKDEuMCAtIHNtb290aHN0ZXAoMC4wLCAxLjAsIGFicygyLjAgKiB0IC0gMS4wKSkpIC0gMS4wO1xyXG59XHJcblxyXG52ZWMzIGhzdjJyZ2IodmVjMyBjKSB7XHJcbiAgdmVjNCBLID0gdmVjNCgxLjAsIDIuMCAvIDMuMCwgMS4wIC8gMy4wLCAzLjApO1xyXG4gIHZlYzMgcCA9IGFicyhmcmFjdChjLnh4eCArIEsueHl6KSAqIDYuMCAtIEsud3d3KTtcclxuICByZXR1cm4gYy56ICogbWl4KEsueHh4LCBjbGFtcChwIC0gSy54eHgsIDAuMCwgMS4wKSwgYy55KTtcclxufVxyXG5cclxuZmxvYXQgU3Rhcih2ZWMyIHV2LCBmbG9hdCBmbGFyZSkge1xyXG4gIGZsb2F0IGQgPSBsZW5ndGgodXYpO1xyXG4gIGZsb2F0IG0gPSAoMC4wNSAqIHVHbG93SW50ZW5zaXR5KSAvIGQ7XHJcbiAgZmxvYXQgcmF5cyA9IHNtb290aHN0ZXAoMC4wLCAxLjAsIDEuMCAtIGFicyh1di54ICogdXYueSAqIDEwMDAuMCkpO1xyXG4gIG0gKz0gcmF5cyAqIGZsYXJlICogdUdsb3dJbnRlbnNpdHk7XHJcbiAgdXYgKj0gTUFUNDU7XHJcbiAgcmF5cyA9IHNtb290aHN0ZXAoMC4wLCAxLjAsIDEuMCAtIGFicyh1di54ICogdXYueSAqIDEwMDAuMCkpO1xyXG4gIG0gKz0gcmF5cyAqIDAuMyAqIGZsYXJlICogdUdsb3dJbnRlbnNpdHk7XHJcbiAgbSAqPSBzbW9vdGhzdGVwKDEuMCwgMC4yLCBkKTtcclxuICByZXR1cm4gbTtcclxufVxyXG5cclxudmVjMyBTdGFyTGF5ZXIodmVjMiB1dikge1xyXG4gIHZlYzMgY29sID0gdmVjMygwLjApO1xyXG5cclxuICB2ZWMyIGd2ID0gZnJhY3QodXYpIC0gMC41OyBcclxuICB2ZWMyIGlkID0gZmxvb3IodXYpO1xyXG5cclxuICBmb3IgKGludCB5ID0gLTE7IHkgPD0gMTsgeSsrKSB7XHJcbiAgICBmb3IgKGludCB4ID0gLTE7IHggPD0gMTsgeCsrKSB7XHJcbiAgICAgIHZlYzIgb2Zmc2V0ID0gdmVjMihmbG9hdCh4KSwgZmxvYXQoeSkpO1xyXG4gICAgICB2ZWMyIHNpID0gaWQgKyB2ZWMyKGZsb2F0KHgpLCBmbG9hdCh5KSk7XHJcbiAgICAgIGZsb2F0IHNlZWQgPSBIYXNoMjEoc2kpO1xyXG4gICAgICBmbG9hdCBzaXplID0gZnJhY3Qoc2VlZCAqIDM0NS4zMik7XHJcbiAgICAgIGZsb2F0IGdsb3NzTG9jYWwgPSB0cmkodVN0YXJTcGVlZCAvIChQRVJJT0QgKiBzZWVkICsgMS4wKSk7XHJcbiAgICAgIGZsb2F0IGZsYXJlU2l6ZSA9IHNtb290aHN0ZXAoMC45LCAxLjAsIHNpemUpICogZ2xvc3NMb2NhbDtcclxuXHJcbiAgICAgIGZsb2F0IHJlZCA9IHNtb290aHN0ZXAoU1RBUl9DT0xPUl9DVVRPRkYsIDEuMCwgSGFzaDIxKHNpICsgMS4wKSkgKyBTVEFSX0NPTE9SX0NVVE9GRjtcclxuICAgICAgZmxvYXQgYmx1ID0gc21vb3Roc3RlcChTVEFSX0NPTE9SX0NVVE9GRiwgMS4wLCBIYXNoMjEoc2kgKyAzLjApKSArIFNUQVJfQ09MT1JfQ1VUT0ZGO1xyXG4gICAgICBmbG9hdCBncm4gPSBtaW4ocmVkLCBibHUpICogc2VlZDtcclxuICAgICAgdmVjMyBiYXNlID0gdmVjMyhyZWQsIGdybiwgYmx1KTtcclxuICAgICAgXHJcbiAgICAgIGZsb2F0IGh1ZSA9IGF0YW4oYmFzZS5nIC0gYmFzZS5yLCBiYXNlLmIgLSBiYXNlLnIpIC8gKDIuMCAqIDMuMTQxNTkpICsgMC41O1xyXG4gICAgICBodWUgPSBmcmFjdChodWUgKyB1SHVlU2hpZnQgLyAzNjAuMCk7XHJcbiAgICAgIGZsb2F0IHNhdCA9IGxlbmd0aChiYXNlIC0gdmVjMyhkb3QoYmFzZSwgdmVjMygwLjI5OSwgMC41ODcsIDAuMTE0KSkpKSAqIHVTYXR1cmF0aW9uO1xyXG4gICAgICBmbG9hdCB2YWwgPSBtYXgobWF4KGJhc2UuciwgYmFzZS5nKSwgYmFzZS5iKTtcclxuICAgICAgYmFzZSA9IGhzdjJyZ2IodmVjMyhodWUsIHNhdCwgdmFsKSk7XHJcblxyXG4gICAgICB2ZWMyIHBhZCA9IHZlYzIodHJpcyhzZWVkICogMzQuMCArIHVUaW1lICogdVNwZWVkIC8gMTAuMCksIHRyaXMoc2VlZCAqIDM4LjAgKyB1VGltZSAqIHVTcGVlZCAvIDMwLjApKSAtIDAuNTtcclxuXHJcbiAgICAgIGZsb2F0IHN0YXIgPSBTdGFyKGd2IC0gb2Zmc2V0IC0gcGFkLCBmbGFyZVNpemUpO1xyXG4gICAgICB2ZWMzIGNvbG9yID0gYmFzZTtcclxuXHJcbiAgICAgIGZsb2F0IHR3aW5rbGUgPSB0cmlzbih1VGltZSAqIHVTcGVlZCArIHNlZWQgKiA2LjI4MzEpICogMC41ICsgMS4wO1xyXG4gICAgICB0d2lua2xlID0gbWl4KDEuMCwgdHdpbmtsZSwgdVR3aW5rbGVJbnRlbnNpdHkpO1xyXG4gICAgICBzdGFyICo9IHR3aW5rbGU7XHJcbiAgICAgIFxyXG4gICAgICBjb2wgKz0gc3RhciAqIHNpemUgKiBjb2xvcjtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJldHVybiBjb2w7XHJcbn1cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuICB2ZWMyIGZvY2FsUHggPSB1Rm9jYWwgKiB1UmVzb2x1dGlvbi54eTtcclxuICB2ZWMyIHV2ID0gKHZVdiAqIHVSZXNvbHV0aW9uLnh5IC0gZm9jYWxQeCkgLyB1UmVzb2x1dGlvbi55O1xyXG5cclxuICB2ZWMyIG1vdXNlTm9ybSA9IHVNb3VzZSAtIHZlYzIoMC41KTtcclxuICBcclxuICBpZiAodUF1dG9DZW50ZXJSZXB1bHNpb24gPiAwLjApIHtcclxuICAgIHZlYzIgY2VudGVyVVYgPSB2ZWMyKDAuMCwgMC4wKTtcclxuICAgIGZsb2F0IGNlbnRlckRpc3QgPSBsZW5ndGgodXYgLSBjZW50ZXJVVik7XHJcbiAgICB2ZWMyIHJlcHVsc2lvbiA9IG5vcm1hbGl6ZSh1diAtIGNlbnRlclVWKSAqICh1QXV0b0NlbnRlclJlcHVsc2lvbiAvIChjZW50ZXJEaXN0ICsgMC4xKSk7XHJcbiAgICB1diArPSByZXB1bHNpb24gKiAwLjA1O1xyXG4gIH0gZWxzZSBpZiAodU1vdXNlUmVwdWxzaW9uKSB7XHJcbiAgICB2ZWMyIG1vdXNlUG9zVVYgPSAodU1vdXNlICogdVJlc29sdXRpb24ueHkgLSBmb2NhbFB4KSAvIHVSZXNvbHV0aW9uLnk7XHJcbiAgICBmbG9hdCBtb3VzZURpc3QgPSBsZW5ndGgodXYgLSBtb3VzZVBvc1VWKTtcclxuICAgIHZlYzIgcmVwdWxzaW9uID0gbm9ybWFsaXplKHV2IC0gbW91c2VQb3NVVikgKiAodVJlcHVsc2lvblN0cmVuZ3RoIC8gKG1vdXNlRGlzdCArIDAuMSkpO1xyXG4gICAgdXYgKz0gcmVwdWxzaW9uICogMC4wNSAqIHVNb3VzZUFjdGl2ZUZhY3RvcjtcclxuICB9IGVsc2Uge1xyXG4gICAgdmVjMiBtb3VzZU9mZnNldCA9IG1vdXNlTm9ybSAqIDAuMSAqIHVNb3VzZUFjdGl2ZUZhY3RvcjtcclxuICAgIHV2ICs9IG1vdXNlT2Zmc2V0O1xyXG4gIH1cclxuXHJcbiAgZmxvYXQgYXV0b1JvdEFuZ2xlID0gdVRpbWUgKiB1Um90YXRpb25TcGVlZDtcclxuICBtYXQyIGF1dG9Sb3QgPSBtYXQyKGNvcyhhdXRvUm90QW5nbGUpLCAtc2luKGF1dG9Sb3RBbmdsZSksIHNpbihhdXRvUm90QW5nbGUpLCBjb3MoYXV0b1JvdEFuZ2xlKSk7XHJcbiAgdXYgPSBhdXRvUm90ICogdXY7XHJcblxyXG4gIHV2ID0gbWF0Mih1Um90YXRpb24ueCwgLXVSb3RhdGlvbi55LCB1Um90YXRpb24ueSwgdVJvdGF0aW9uLngpICogdXY7XHJcblxyXG4gIHZlYzMgY29sID0gdmVjMygwLjApO1xyXG5cclxuICBmb3IgKGZsb2F0IGkgPSAwLjA7IGkgPCAxLjA7IGkgKz0gMS4wIC8gTlVNX0xBWUVSKSB7XHJcbiAgICBmbG9hdCBkZXB0aCA9IGZyYWN0KGkgKyB1U3RhclNwZWVkICogdVNwZWVkKTtcclxuICAgIGZsb2F0IHNjYWxlID0gbWl4KDIwLjAgKiB1RGVuc2l0eSwgMC41ICogdURlbnNpdHksIGRlcHRoKTtcclxuICAgIGZsb2F0IGZhZGUgPSBkZXB0aCAqIHNtb290aHN0ZXAoMS4wLCAwLjksIGRlcHRoKTtcclxuICAgIGNvbCArPSBTdGFyTGF5ZXIodXYgKiBzY2FsZSArIGkgKiA0NTMuMzIpICogZmFkZTtcclxuICB9XHJcblxyXG4gIGZsb2F0IGFscGhhID0gbGVuZ3RoKGNvbCk7XHJcbiAgYWxwaGEgPSBzbW9vdGhzdGVwKDAuMCwgMC4zLCBhbHBoYSk7XHJcbiAgYWxwaGEgPSBtaW4oYWxwaGEsIDEuMCk7XHJcbiAgZ2xfRnJhZ0NvbG9yID0gdmVjNChjb2wsIGFscGhhKTtcclxufVxyXG5gO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduYy1nYWxheHktYmFja2dyb3VuZCcsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL2dhbGF4eS1iYWNrZ3JvdW5kLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9nYWxheHktYmFja2dyb3VuZC5jb21wb25lbnQubGVzcyddXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBHYWxheHlCYWNrZ3JvdW5kQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XHJcbiAgQFZpZXdDaGlsZCgnY29udGFpbmVyJywgeyBzdGF0aWM6IHRydWUgfSkgY29udGFpbmVyUmVmITogRWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD47XHJcblxyXG4gIC8qKiDlsIbmmJ/ns7vmlYjlupTnmoTnhKbngrnorr7nva7kuLogW3gsIHldIOWdkOagh++8iDAtMe+8iSAqL1xyXG4gIEBJbnB1dCgpIG5jRm9jYWw6IFtudW1iZXIsIG51bWJlcl0gPSBbMC41LCAwLjVdO1xyXG4gIC8qKiDmjqfliLbmmJ/ns7vnmoTml4vovaznn6npmLXvvIzlhbbml4vovazlgLzkuLpbeCwgeV0gKi9cclxuICBASW5wdXQoKSBuY1JvdGF0aW9uOiBbbnVtYmVyLCBudW1iZXJdID0gWzEuMCwgMC4wXTtcclxuICAvKiog5o6n5Yi25pif5pif55qE56e75Yqo6YCf5bqm5ZKM5Yqo55S75pWI5p6c77yIMC4xLTLvvIkgKi9cclxuICBASW5wdXQoKSBuY1N0YXJTcGVlZDogbnVtYmVyID0gMC41O1xyXG4gIC8qKiDmjqfliLbmmJ/mmJ/nmoTlr4bluqbvvIgwLjEtM++8iSAqL1xyXG4gIEBJbnB1dCgpIG5jRGVuc2l0eTogbnVtYmVyID0gMTtcclxuICAvKiog5bCG5omA5pyJ5pif5pif55qE6Imy6LCD5oyJ5oyH5a6a55qE6KeS5bqm77yIMC0zNjDluqbvvInov5vooYzosIPmlbTvvIjlnKhuY1NhdHVyYXRpb27kuI3kuLow5pe255Sf5pWI77yJKi9cclxuICBASW5wdXQoKSBuY0h1ZVNoaWZ0OiBudW1iZXIgPSAxNDA7XHJcbiAgLyoqIOS4uuecn+aXtu+8jOWBnOatouaJgOacieWfuuS6juaXtumXtOeahOWKqOeUuyAqL1xyXG4gIHByaXZhdGUgX2Rpc2FibGVBbmltYXRpb246IGJvb2xlYW4gPSBmYWxzZTtcclxuICBASW5wdXQoKVxyXG4gIHNldCBuY0Rpc2FibGVBbmltYXRpb24odmFsOiBib29sZWFuIHwgc3RyaW5nKSB7XHJcbiAgICB0aGlzLl9kaXNhYmxlQW5pbWF0aW9uID0gdmFsICE9PSBudWxsICYmIHZhbCAhPT0gdW5kZWZpbmVkICYmIHZhbCAhPT0gZmFsc2UgJiYgdmFsICE9PSAnZmFsc2UnO1xyXG4gIH1cclxuICBnZXQgbmNEaXNhYmxlQW5pbWF0aW9uKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2Rpc2FibGVBbmltYXRpb247XHJcbiAgfVxyXG4gIC8qKiDmiYDmnInliqjnlLvnmoTlhajlsYDpgJ/luqblgI3njofvvIgwLjEtM++8iSAqL1xyXG4gIEBJbnB1dCgpIG5jU3BlZWQ6IG51bWJlciA9IDEuMDtcclxuICAvKiog5piv5ZCm5ZCv55So6byg5qCH5Lqk5LqSICovXHJcbiAgcHJpdmF0ZSBfbW91c2VJbnRlcmFjdGlvbjogYm9vbGVhbiA9IHRydWU7XHJcbiAgQElucHV0KClcclxuICBzZXQgbmNNb3VzZUludGVyYWN0aW9uKHZhbDogYm9vbGVhbiB8IHN0cmluZykge1xyXG4gICAgdGhpcy5fbW91c2VJbnRlcmFjdGlvbiA9IHZhbCAhPT0gbnVsbCAmJiB2YWwgIT09IHVuZGVmaW5lZCAmJiB2YWwgIT09IGZhbHNlICYmIHZhbCAhPT0gJ2ZhbHNlJztcclxuICB9XHJcbiAgZ2V0IG5jTW91c2VJbnRlcmFjdGlvbigpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLl9tb3VzZUludGVyYWN0aW9uO1xyXG4gIH1cclxuICAvKiog5o6n5Yi25pif5YWJ5pWI5p6c55qE5by65bqm77yIMC0x77yJICovXHJcbiAgQElucHV0KCkgbmNHbG93SW50ZW5zaXR5OiBudW1iZXIgPSAwLjM7XHJcbiAgLyoqIOaOp+WItuaYn+aYn+eahOminOiJsumlseWSjOW6pu+8iDAtMe+8jDDvvJrngbDluqYgMe+8muWFqOW9qe+8iSAqL1xyXG4gIEBJbnB1dCgpIG5jU2F0dXJhdGlvbjogbnVtYmVyID0gMC4wO1xyXG4gIC8qKiDmmK/lkKblkK/nlKjpvKDmoIfmjpLmlqXmlYjmnpwgKi9cclxuICBwcml2YXRlIF9tb3VzZVJlcHVsc2lvbjogYm9vbGVhbiA9IHRydWU7XHJcbiAgQElucHV0KClcclxuICBzZXQgbmNNb3VzZVJlcHVsc2lvbih2YWw6IGJvb2xlYW4gfCBzdHJpbmcpIHtcclxuICAgIHRoaXMuX21vdXNlUmVwdWxzaW9uID0gdmFsICE9PSBudWxsICYmIHZhbCAhPT0gdW5kZWZpbmVkICYmIHZhbCAhPT0gZmFsc2UgJiYgdmFsICE9PSAnZmFsc2UnO1xyXG4gIH1cclxuICBnZXQgbmNNb3VzZVJlcHVsc2lvbigpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLl9tb3VzZVJlcHVsc2lvbjtcclxuICB9XHJcbiAgLyoqIOm8oOagh+aOkuaWpeWKm+W6pu+8iDAtMTDvvIkgKi9cclxuICBASW5wdXQoKSBuY1JlcHVsc2lvblN0cmVuZ3RoOiBudW1iZXIgPSAyO1xyXG4gIC8qKiDmjqfliLbmmJ/mmJ/pl6rng4HnmoTnqIvluqbvvIgwLTHvvIww77ya5LiN6Zeq54OBIDHvvJrmnIDlpKfpl6rng4HvvIkgKi9cclxuICBASW5wdXQoKSBuY1R3aW5rbGVJbnRlbnNpdHk6IG51bWJlciA9IDAuMztcclxuICAvKiog5pif57O76Ieq5Yqo5peL6L2s55qE6YCf5bqm77yIMC0wLjXvvIkgKi9cclxuICBASW5wdXQoKSBuY1JvdGF0aW9uU3BlZWQ6IG51bWJlciA9IDAuMTtcclxuICAvKiog6Ieq5Yqo5ZCR5Lit5b+D5o6S5pal55qE5by65bqm77yIMC0yMO+8jOWmguaenOWkp+S6jjDliJnkuI3kvb/nlKjpvKDmoIfkvY3nva7vvIkgKi9cclxuICBASW5wdXQoKSBuY0F1dG9DZW50ZXJSZXB1bHNpb246IG51bWJlciA9IDA7XHJcblxyXG5cclxuICBwcml2YXRlIHJlbmRlcmVyITogVEhSRUUuV2ViR0xSZW5kZXJlcjtcclxuICBwcml2YXRlIHNjZW5lITogVEhSRUUuU2NlbmU7XHJcbiAgcHJpdmF0ZSBjYW1lcmEhOiBUSFJFRS5PcnRob2dyYXBoaWNDYW1lcmE7XHJcbiAgcHJpdmF0ZSBtYXRlcmlhbCE6IFRIUkVFLlJhd1NoYWRlck1hdGVyaWFsO1xyXG4gIHByaXZhdGUgcmVzaXplT2JzZXJ2ZXIhOiBSZXNpemVPYnNlcnZlcjtcclxuICBwcml2YXRlIGFuaW1hdGlvbklkOiBudW1iZXIgfCBudWxsID0gbnVsbDtcclxuICBwcml2YXRlIHVuaWZvcm1zOiBhbnk7XHJcblxyXG4gIHByaXZhdGUgdGFyZ2V0TW91c2VQb3MgPSB7IHg6IDAuNSwgeTogMC41IH07XHJcbiAgcHJpdmF0ZSBzbW9vdGhNb3VzZVBvcyA9IHsgeDogMC41LCB5OiAwLjUgfTtcclxuICBwcml2YXRlIHRhcmdldE1vdXNlQWN0aXZlID0gMC4wO1xyXG4gIHByaXZhdGUgc21vb3RoTW91c2VBY3RpdmUgPSAwLjA7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgbmdab25lOiBOZ1pvbmUpIHsgfVxyXG5cclxuICBuZ09uSW5pdCgpOiB2b2lkIHsgfVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmluaXRXZWJHTCgpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICB0aGlzLmNsZWFudXAoKTtcclxuICB9XHJcblxyXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy51bmlmb3JtcykgcmV0dXJuO1xyXG4gICAgdGhpcy51cGRhdGVVbmlmb3JtcygpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0V2ViR0woKTogdm9pZCB7XHJcbiAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmNvbnRhaW5lclJlZi5uYXRpdmVFbGVtZW50O1xyXG5cclxuICAgIHRoaXMucmVuZGVyZXIgPSBuZXcgVEhSRUUuV2ViR0xSZW5kZXJlcih7XHJcbiAgICAgIGFscGhhOiB0cnVlLFxyXG4gICAgICBwcmVtdWx0aXBsaWVkQWxwaGE6IGZhbHNlLFxyXG4gICAgICBhbnRpYWxpYXM6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldENsZWFyQ29sb3IoMHgwMDAwMDAsIDApO1xyXG5cclxuICAgIHRoaXMucmVuZGVyZXIuc2V0UGl4ZWxSYXRpbyhNYXRoLm1pbih3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyB8fCAxLCAyKSk7XHJcbiAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5yZW5kZXJlci5kb21FbGVtZW50KTtcclxuXHJcbiAgICB0aGlzLnNjZW5lID0gbmV3IFRIUkVFLlNjZW5lKCk7XHJcbiAgICB0aGlzLmNhbWVyYSA9IG5ldyBUSFJFRS5PcnRob2dyYXBoaWNDYW1lcmEoLTEsIDEsIDEsIC0xLCAwLCAxKTtcclxuXHJcbiAgICB0aGlzLnVuaWZvcm1zID0ge1xyXG4gICAgICB1VGltZTogeyB2YWx1ZTogMCB9LFxyXG4gICAgICB1UmVzb2x1dGlvbjogeyB2YWx1ZTogbmV3IFRIUkVFLlZlY3RvcjMoKSB9LFxyXG4gICAgICB1Rm9jYWw6IHsgdmFsdWU6IG5ldyBUSFJFRS5WZWN0b3IyKCkgfSxcclxuICAgICAgdVJvdGF0aW9uOiB7IHZhbHVlOiBuZXcgVEhSRUUuVmVjdG9yMigpIH0sXHJcbiAgICAgIHVTdGFyU3BlZWQ6IHsgdmFsdWU6IHRoaXMubmNTdGFyU3BlZWQgfSxcclxuICAgICAgdURlbnNpdHk6IHsgdmFsdWU6IHRoaXMubmNEZW5zaXR5IH0sXHJcbiAgICAgIHVIdWVTaGlmdDogeyB2YWx1ZTogdGhpcy5uY0h1ZVNoaWZ0IH0sXHJcbiAgICAgIHVTcGVlZDogeyB2YWx1ZTogdGhpcy5uY1NwZWVkIH0sXHJcbiAgICAgIHVNb3VzZTogeyB2YWx1ZTogW3RoaXMuc21vb3RoTW91c2VQb3MueCwgdGhpcy5zbW9vdGhNb3VzZVBvcy55XSB9LFxyXG4gICAgICB1R2xvd0ludGVuc2l0eTogeyB2YWx1ZTogdGhpcy5uY0dsb3dJbnRlbnNpdHkgfSxcclxuICAgICAgdVNhdHVyYXRpb246IHsgdmFsdWU6IHRoaXMubmNTYXR1cmF0aW9uIH0sXHJcbiAgICAgIHVNb3VzZVJlcHVsc2lvbjogeyB2YWx1ZTogdGhpcy5uY01vdXNlUmVwdWxzaW9uIH0sXHJcbiAgICAgIHVUd2lua2xlSW50ZW5zaXR5OiB7IHZhbHVlOiB0aGlzLm5jVHdpbmtsZUludGVuc2l0eSB9LFxyXG4gICAgICB1Um90YXRpb25TcGVlZDogeyB2YWx1ZTogdGhpcy5uY1JvdGF0aW9uU3BlZWQgfSxcclxuICAgICAgdVJlcHVsc2lvblN0cmVuZ3RoOiB7IHZhbHVlOiB0aGlzLm5jUmVwdWxzaW9uU3RyZW5ndGggfSxcclxuICAgICAgdU1vdXNlQWN0aXZlRmFjdG9yOiB7IHZhbHVlOiAwLjAgfSxcclxuICAgICAgdUF1dG9DZW50ZXJSZXB1bHNpb246IHsgdmFsdWU6IHRoaXMubmNBdXRvQ2VudGVyUmVwdWxzaW9uIH1cclxuICAgIH07XHJcblxyXG4gICAgdGhpcy51cGRhdGVVbmlmb3JtcygpO1xyXG5cclxuICAgIGNvbnN0IGdlb21ldHJ5ID0gbmV3IFRIUkVFLlBsYW5lR2VvbWV0cnkoMiwgMik7XHJcbiAgICB0aGlzLm1hdGVyaWFsID0gbmV3IFRIUkVFLlJhd1NoYWRlck1hdGVyaWFsKHtcclxuICAgICAgdmVydGV4U2hhZGVyLFxyXG4gICAgICBmcmFnbWVudFNoYWRlcixcclxuICAgICAgdW5pZm9ybXM6IHRoaXMudW5pZm9ybXMsXHJcbiAgICAgIHRyYW5zcGFyZW50OiB0cnVlLFxyXG4gICAgICBibGVuZGluZzogVEhSRUUuTm9ybWFsQmxlbmRpbmdcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IG1lc2ggPSBuZXcgVEhSRUUuTWVzaChnZW9tZXRyeSwgdGhpcy5tYXRlcmlhbCk7XHJcbiAgICB0aGlzLnNjZW5lLmFkZChtZXNoKTtcclxuXHJcbiAgICB0aGlzLnJlc2l6ZU9ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKCgpID0+IHRoaXMucmVzaXplKCkpO1xyXG4gICAgdGhpcy5yZXNpemVPYnNlcnZlci5vYnNlcnZlKGNvbnRhaW5lcik7XHJcbiAgICB0aGlzLnJlc2l6ZSgpO1xyXG5cclxuXHJcbiAgICB0aGlzLm5nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XHJcbiAgICAgIHRoaXMuYW5pbWF0ZSgwKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVVbmlmb3JtcygpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy51bmlmb3JtcyB8fCAhdGhpcy5yZW5kZXJlcikgcmV0dXJuO1xyXG5cclxuICAgIHRoaXMucmVuZGVyZXIuc2V0Q2xlYXJDb2xvcigweDAwMDAwMCwgMCk7XHJcbiAgICB0aGlzLm1hdGVyaWFsICYmICh0aGlzLm1hdGVyaWFsLnRyYW5zcGFyZW50ID0gdHJ1ZSk7XHJcblxyXG4gICAgdGhpcy51bmlmb3Jtcy51Rm9jYWwudmFsdWUuc2V0KHRoaXMubmNGb2NhbFswXSwgdGhpcy5uY0ZvY2FsWzFdKTtcclxuICAgIHRoaXMudW5pZm9ybXMudVJvdGF0aW9uLnZhbHVlLnNldCh0aGlzLm5jUm90YXRpb25bMF0sIHRoaXMubmNSb3RhdGlvblsxXSk7XHJcbiAgICB0aGlzLnVuaWZvcm1zLnVTdGFyU3BlZWQudmFsdWUgPSB0aGlzLm5jU3RhclNwZWVkO1xyXG4gICAgdGhpcy51bmlmb3Jtcy51RGVuc2l0eS52YWx1ZSA9IHRoaXMubmNEZW5zaXR5O1xyXG4gICAgdGhpcy51bmlmb3Jtcy51SHVlU2hpZnQudmFsdWUgPSB0aGlzLm5jSHVlU2hpZnQ7XHJcbiAgICB0aGlzLnVuaWZvcm1zLnVTcGVlZC52YWx1ZSA9IHRoaXMubmNTcGVlZDtcclxuICAgIHRoaXMudW5pZm9ybXMudUdsb3dJbnRlbnNpdHkudmFsdWUgPSB0aGlzLm5jR2xvd0ludGVuc2l0eTtcclxuICAgIHRoaXMudW5pZm9ybXMudVNhdHVyYXRpb24udmFsdWUgPSB0aGlzLm5jU2F0dXJhdGlvbjtcclxuICAgIHRoaXMudW5pZm9ybXMudU1vdXNlUmVwdWxzaW9uLnZhbHVlID0gdGhpcy5uY01vdXNlUmVwdWxzaW9uO1xyXG4gICAgdGhpcy51bmlmb3Jtcy51VHdpbmtsZUludGVuc2l0eS52YWx1ZSA9IHRoaXMubmNUd2lua2xlSW50ZW5zaXR5O1xyXG4gICAgdGhpcy51bmlmb3Jtcy51Um90YXRpb25TcGVlZC52YWx1ZSA9IHRoaXMubmNSb3RhdGlvblNwZWVkO1xyXG4gICAgdGhpcy51bmlmb3Jtcy51UmVwdWxzaW9uU3RyZW5ndGgudmFsdWUgPSB0aGlzLm5jUmVwdWxzaW9uU3RyZW5ndGg7XHJcbiAgICB0aGlzLnVuaWZvcm1zLnVBdXRvQ2VudGVyUmVwdWxzaW9uLnZhbHVlID0gdGhpcy5uY0F1dG9DZW50ZXJSZXB1bHNpb247XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlc2l6ZSgpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5jb250YWluZXJSZWYgfHwgIXRoaXMucmVuZGVyZXIpIHJldHVybjtcclxuICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuY29udGFpbmVyUmVmLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICBjb25zdCB3aWR0aCA9IGNvbnRhaW5lci5vZmZzZXRXaWR0aDtcclxuICAgIGNvbnN0IGhlaWdodCA9IGNvbnRhaW5lci5vZmZzZXRIZWlnaHQ7XHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTaXplKHdpZHRoLCBoZWlnaHQpO1xyXG4gICAgaWYgKHRoaXMudW5pZm9ybXMpIHtcclxuICAgICAgdGhpcy51bmlmb3Jtcy51UmVzb2x1dGlvbi52YWx1ZS5zZXQod2lkdGgsIGhlaWdodCwgd2lkdGggLyBoZWlnaHQpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhbmltYXRlID0gKHQ6IG51bWJlcikgPT4ge1xyXG4gICAgdGhpcy5hbmltYXRpb25JZCA9IHJlcXVlc3RBbmltYXRpb25GcmFtZSh0aGlzLmFuaW1hdGUpO1xyXG5cclxuICAgIGlmICghdGhpcy5uY0Rpc2FibGVBbmltYXRpb24pIHtcclxuICAgICAgdGhpcy51bmlmb3Jtcy51VGltZS52YWx1ZSA9IHQgKiAwLjAwMTtcclxuICAgICAgdGhpcy51bmlmb3Jtcy51U3RhclNwZWVkLnZhbHVlID0gKHQgKiAwLjAwMSAqIHRoaXMubmNTdGFyU3BlZWQpIC8gMTAuMDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBsZXJwRmFjdG9yID0gMC4wNTtcclxuICAgIHRoaXMuc21vb3RoTW91c2VQb3MueCArPSAodGhpcy50YXJnZXRNb3VzZVBvcy54IC0gdGhpcy5zbW9vdGhNb3VzZVBvcy54KSAqIGxlcnBGYWN0b3I7XHJcbiAgICB0aGlzLnNtb290aE1vdXNlUG9zLnkgKz0gKHRoaXMudGFyZ2V0TW91c2VQb3MueSAtIHRoaXMuc21vb3RoTW91c2VQb3MueSkgKiBsZXJwRmFjdG9yO1xyXG4gICAgdGhpcy5zbW9vdGhNb3VzZUFjdGl2ZSArPSAodGhpcy50YXJnZXRNb3VzZUFjdGl2ZSAtIHRoaXMuc21vb3RoTW91c2VBY3RpdmUpICogbGVycEZhY3RvcjtcclxuXHJcbiAgICB0aGlzLnVuaWZvcm1zLnVNb3VzZS52YWx1ZVswXSA9IHRoaXMuc21vb3RoTW91c2VQb3MueDtcclxuICAgIHRoaXMudW5pZm9ybXMudU1vdXNlLnZhbHVlWzFdID0gdGhpcy5zbW9vdGhNb3VzZVBvcy55O1xyXG4gICAgdGhpcy51bmlmb3Jtcy51TW91c2VBY3RpdmVGYWN0b3IudmFsdWUgPSB0aGlzLnNtb290aE1vdXNlQWN0aXZlO1xyXG5cclxuICAgIHRoaXMucmVuZGVyZXIucmVuZGVyKHRoaXMuc2NlbmUsIHRoaXMuY2FtZXJhKTtcclxuICB9O1xyXG5cclxuICBASG9zdExpc3RlbmVyKCdtb3VzZW1vdmUnLCBbJyRldmVudCddKVxyXG4gIG9uTW91c2VNb3ZlKGU6IE1vdXNlRXZlbnQpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5uY01vdXNlSW50ZXJhY3Rpb24pIHJldHVybjtcclxuICAgIHRoaXMudXBkYXRlTW91c2VQb3MoZS5jbGllbnRYLCBlLmNsaWVudFkpO1xyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignbW91c2VsZWF2ZScpXHJcbiAgb25Nb3VzZUxlYXZlKCk6IHZvaWQge1xyXG4gICAgdGhpcy5oYW5kbGVNb3VzZUxlYXZlKCk7XHJcbiAgfVxyXG5cclxuICBASG9zdExpc3RlbmVyKCd0b3VjaHN0YXJ0JywgWyckZXZlbnQnXSlcclxuICBASG9zdExpc3RlbmVyKCd0b3VjaG1vdmUnLCBbJyRldmVudCddKVxyXG4gIG9uVG91Y2hNb3ZlKGU6IFRvdWNoRXZlbnQpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5uY01vdXNlSW50ZXJhY3Rpb24gfHwgZS50b3VjaGVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xyXG4gICAgdGhpcy51cGRhdGVNb3VzZVBvcyhlLnRvdWNoZXNbMF0uY2xpZW50WCwgZS50b3VjaGVzWzBdLmNsaWVudFkpO1xyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcigndG91Y2hlbmQnKVxyXG4gIG9uVG91Y2hFbmQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmhhbmRsZU1vdXNlTGVhdmUoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlTW91c2VQb3MoY2xpZW50WDogbnVtYmVyLCBjbGllbnRZOiBudW1iZXIpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5jb250YWluZXJSZWYpIHJldHVybjtcclxuICAgIGNvbnN0IHJlY3QgPSB0aGlzLmNvbnRhaW5lclJlZi