ngx-acuw
Version:
Angular components using WEBGL (threejs)
354 lines (344 loc) • 35.5 kB
JavaScript
export class ImageTransitionShaders {
constructor() {
this.vertex = `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}`;
this.splitTransitionFrag = `
uniform float progress;
uniform float intensity;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform vec4 resolution1;
uniform vec4 resolution2;
varying vec2 vUv;
mat2 rotate(float a) {
float s = sin(a);
float c = cos(a);
return mat2(c, -s, s, c);
}
void main() {
vec2 newUV1 = (vUv - vec2(0.5,0.5))*resolution1.zw + vec2(0.5,0.5);
vec2 newUV2 = (vUv - vec2(0.5,0.5))*resolution2.zw + vec2(0.5,0.5);
vec2 uvDivided1 = fract(newUV1*vec2(intensity,1.));
vec2 uvDivided2 = fract(newUV2*vec2(intensity,1.));
vec2 uvDisplaced1 = newUV1 + rotate(3.1415926/4.)*uvDivided1*progress*0.1;
vec2 uvDisplaced2 = newUV2 + rotate(3.1415926/4.)*uvDivided2*(1. - progress)*0.1;
vec4 t1 = texture2D(texture1,uvDisplaced1);
vec4 t2 = texture2D(texture2,uvDisplaced2);
// Use black background color
// Top right
vec2 tr1 = step(newUV1, vec2(1.0, 1.0));
vec2 tr2 = step(newUV2, vec2(1.0, 1.0));
float pct1 = tr1.x * tr1.y;
float pct2 = tr2.x * tr2.y;
// Bottom left
vec2 bl1 = step(vec2(0.0, 0.0), newUV1);
vec2 bl2 = step(vec2(0.0, 0.0), newUV2);
pct1 *= bl1.x * bl1.y;
pct2 *= bl2.x * bl2.y;
vec4 t1wb = t1 * vec4(pct1,pct1,pct1,1.0);
vec4 t2wb = t2 * vec4(pct2,pct2,pct2,1.0);
gl_FragColor = mix(t1wb, t2wb, progress);
}
`;
this.fadeFrag = `
uniform float progress;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform vec4 resolution1;
uniform vec4 resolution2;
varying vec2 vUv;
mat2 rotate(float a) {
float s = sin(a);
float c = cos(a);
return mat2(c, -s, s, c);
}
void main() {
vec2 newUV1 = (vUv - vec2(0.5,0.5))*resolution1.zw + vec2(0.5,0.5);
vec2 newUV2 = (vUv - vec2(0.5,0.5))*resolution2.zw + vec2(0.5,0.5);
vec2 uvDisplaced1 = newUV1 + vec2(1.0,0)*progress*0.1;
vec2 uvDisplaced2 = newUV2 + vec2(1.0,0)*(1. - progress)*0.1;
vec4 t1 = texture2D(texture1,uvDisplaced1);
vec4 t2 = texture2D(texture2,uvDisplaced2);
// Use black background color
// Top right
vec2 tr1 = step(newUV1, vec2(1.0, 1.0));
vec2 tr2 = step(newUV2, vec2(1.0, 1.0));
float pct1 = tr1.x * tr1.y;
float pct2 = tr2.x * tr2.y;
// Bottom left
vec2 bl1 = step(vec2(0.0, 0.0), newUV1);
vec2 bl2 = step(vec2(0.0, 0.0), newUV2);
pct1 *= bl1.x * bl1.y;
pct2 *= bl2.x * bl2.y;
vec4 t1wb = t1 * vec4(pct1,pct1,pct1,1.0);
vec4 t2wb = t2 * vec4(pct2,pct2,pct2,1.0);
gl_FragColor = mix(t1wb, t2wb, progress);
}
`;
this.noiseFrag = `
uniform float time;
uniform float progress;
uniform float width;
uniform float scaleX;
uniform float scaleY;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform sampler2D displacement;
uniform vec4 resolution1;
uniform vec4 resolution2;
varying vec2 vUv;
varying vec4 vPosition;
// Classic Perlin 3D Noise
// by Stefan Gustavson
//
vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
vec4 fade(vec4 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}
float cnoise(vec4 P){
;
vec4 Pi0 = floor(P); // Integer part for indexing
vec4 Pi1 = Pi0 + 1.0; // Integer part + 1
Pi0 = mod(Pi0, 289.0);
Pi1 = mod(Pi1, 289.0);
vec4 Pf0 = fract(P); // Fractional part for interpolation
vec4 Pf1 = Pf0 - 1.0; // Fractional part - 1.0
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
vec4 iy = vec4(Pi0.yy, Pi1.yy);
vec4 iz0 = vec4(Pi0.zzzz);
vec4 iz1 = vec4(Pi1.zzzz);
vec4 iw0 = vec4(Pi0.wwww);
vec4 iw1 = vec4(Pi1.wwww);
vec4 ixy = permute(permute(ix) + iy);
vec4 ixy0 = permute(ixy + iz0);
vec4 ixy1 = permute(ixy + iz1);
vec4 ixy00 = permute(ixy0 + iw0);
vec4 ixy01 = permute(ixy0 + iw1);
vec4 ixy10 = permute(ixy1 + iw0);
vec4 ixy11 = permute(ixy1 + iw1);
vec4 gx00 = ixy00 / 7.0;
vec4 gy00 = floor(gx00) / 7.0;
vec4 gz00 = floor(gy00) / 6.0;
gx00 = fract(gx00) - 0.5;
gy00 = fract(gy00) - 0.5;
gz00 = fract(gz00) - 0.5;
vec4 gw00 = vec4(0.75) - abs(gx00) - abs(gy00) - abs(gz00);
vec4 sw00 = step(gw00, vec4(0.0));
gx00 -= sw00 * (step(0.0, gx00) - 0.5);
gy00 -= sw00 * (step(0.0, gy00) - 0.5);
vec4 gx01 = ixy01 / 7.0;
vec4 gy01 = floor(gx01) / 7.0;
vec4 gz01 = floor(gy01) / 6.0;
gx01 = fract(gx01) - 0.5;
gy01 = fract(gy01) - 0.5;
gz01 = fract(gz01) - 0.5;
vec4 gw01 = vec4(0.75) - abs(gx01) - abs(gy01) - abs(gz01);
vec4 sw01 = step(gw01, vec4(0.0));
gx01 -= sw01 * (step(0.0, gx01) - 0.5);
gy01 -= sw01 * (step(0.0, gy01) - 0.5);
vec4 gx10 = ixy10 / 7.0;
vec4 gy10 = floor(gx10) / 7.0;
vec4 gz10 = floor(gy10) / 6.0;
gx10 = fract(gx10) - 0.5;
gy10 = fract(gy10) - 0.5;
gz10 = fract(gz10) - 0.5;
vec4 gw10 = vec4(0.75) - abs(gx10) - abs(gy10) - abs(gz10);
vec4 sw10 = step(gw10, vec4(0.0));
gx10 -= sw10 * (step(0.0, gx10) - 0.5);
gy10 -= sw10 * (step(0.0, gy10) - 0.5);
vec4 gx11 = ixy11 / 7.0;
vec4 gy11 = floor(gx11) / 7.0;
vec4 gz11 = floor(gy11) / 6.0;
gx11 = fract(gx11) - 0.5;
gy11 = fract(gy11) - 0.5;
gz11 = fract(gz11) - 0.5;
vec4 gw11 = vec4(0.75) - abs(gx11) - abs(gy11) - abs(gz11);
vec4 sw11 = step(gw11, vec4(0.0));
gx11 -= sw11 * (step(0.0, gx11) - 0.5);
gy11 -= sw11 * (step(0.0, gy11) - 0.5);
vec4 g0000 = vec4(gx00.x,gy00.x,gz00.x,gw00.x);
vec4 g1000 = vec4(gx00.y,gy00.y,gz00.y,gw00.y);
vec4 g0100 = vec4(gx00.z,gy00.z,gz00.z,gw00.z);
vec4 g1100 = vec4(gx00.w,gy00.w,gz00.w,gw00.w);
vec4 g0010 = vec4(gx10.x,gy10.x,gz10.x,gw10.x);
vec4 g1010 = vec4(gx10.y,gy10.y,gz10.y,gw10.y);
vec4 g0110 = vec4(gx10.z,gy10.z,gz10.z,gw10.z);
vec4 g1110 = vec4(gx10.w,gy10.w,gz10.w,gw10.w);
vec4 g0001 = vec4(gx01.x,gy01.x,gz01.x,gw01.x);
vec4 g1001 = vec4(gx01.y,gy01.y,gz01.y,gw01.y);
vec4 g0101 = vec4(gx01.z,gy01.z,gz01.z,gw01.z);
vec4 g1101 = vec4(gx01.w,gy01.w,gz01.w,gw01.w);
vec4 g0011 = vec4(gx11.x,gy11.x,gz11.x,gw11.x);
vec4 g1011 = vec4(gx11.y,gy11.y,gz11.y,gw11.y);
vec4 g0111 = vec4(gx11.z,gy11.z,gz11.z,gw11.z);
vec4 g1111 = vec4(gx11.w,gy11.w,gz11.w,gw11.w);
vec4 norm00 = taylorInvSqrt(vec4(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));
g0000 *= norm00.x;
g0100 *= norm00.y;
g1000 *= norm00.z;
g1100 *= norm00.w;
vec4 norm01 = taylorInvSqrt(vec4(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));
g0001 *= norm01.x;
g0101 *= norm01.y;
g1001 *= norm01.z;
g1101 *= norm01.w;
vec4 norm10 = taylorInvSqrt(vec4(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));
g0010 *= norm10.x;
g0110 *= norm10.y;
g1010 *= norm10.z;
g1110 *= norm10.w;
vec4 norm11 = taylorInvSqrt(vec4(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));
g0011 *= norm11.x;
g0111 *= norm11.y;
g1011 *= norm11.z;
g1111 *= norm11.w;
float n0000 = dot(g0000, Pf0);
float n1000 = dot(g1000, vec4(Pf1.x, Pf0.yzw));
float n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.zw));
float n1100 = dot(g1100, vec4(Pf1.xy, Pf0.zw));
float n0010 = dot(g0010, vec4(Pf0.xy, Pf1.z, Pf0.w));
float n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w));
float n0110 = dot(g0110, vec4(Pf0.x, Pf1.yz, Pf0.w));
float n1110 = dot(g1110, vec4(Pf1.xyz, Pf0.w));
float n0001 = dot(g0001, vec4(Pf0.xyz, Pf1.w));
float n1001 = dot(g1001, vec4(Pf1.x, Pf0.yz, Pf1.w));
float n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w));
float n1101 = dot(g1101, vec4(Pf1.xy, Pf0.z, Pf1.w));
float n0011 = dot(g0011, vec4(Pf0.xy, Pf1.zw));
float n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.zw));
float n0111 = dot(g0111, vec4(Pf0.x, Pf1.yzw));
float n1111 = dot(g1111, Pf1);
vec4 fade_xyzw = fade(Pf0);
vec4 n_0w = mix(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w);
vec4 n_1w = mix(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w);
vec4 n_zw = mix(n_0w, n_1w, fade_xyzw.z);
vec2 n_yzw = mix(n_zw.xy, n_zw.zw, fade_xyzw.y);
float n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);
return 2.2 * n_xyzw;
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
float parabola( float x, float k ) {
return pow( 4. * x * ( 1. - x ), k );
}
void main() {
float dt = parabola(progress,1.);
float border = 1.;
vec2 newUV1 = (vUv - vec2(0.5,0.5))*resolution1.zw + vec2(0.5,0.5);
vec2 newUV2 = (vUv - vec2(0.5,0.5))*resolution2.zw + vec2(0.5,0.5);
vec4 t1 = texture2D(texture1,newUV1);
vec4 t2 = texture2D(texture2,newUV2);
// Use black background color
// Top right
vec2 tr1 = step(newUV1, vec2(1.0, 1.0));
vec2 tr2 = step(newUV2, vec2(1.0, 1.0));
float pct1 = tr1.x * tr1.y;
float pct2 = tr2.x * tr2.y;
// Bottom left
vec2 bl1 = step(vec2(0.0, 0.0), newUV1);
vec2 bl2 = step(vec2(0.0, 0.0), newUV2);
pct1 *= bl1.x * bl1.y;
pct2 *= bl2.x * bl2.y;
vec4 t1wb = t1 * vec4(pct1,pct1,pct1,1.0);
vec4 t2wb = t2 * vec4(pct2,pct2,pct2,1.0);
float realnoise = 0.5*(cnoise(vec4(newUV1.x*scaleX + 0.*time/3., newUV1.y*scaleY,0.*time/3.,0.)) +1.);
float w = width*dt;
float maskvalue = smoothstep(1. - w,1.,vUv.x + mix(-w/2., 1. - w/2., progress));
float mask = maskvalue + maskvalue*realnoise;
float final = smoothstep(border,border+0.01,mask);
gl_FragColor = mix(t1wb,t2wb,final);
}
`;
this.blurFrag = `
// author: gre
// license: MIT
uniform float progress;
uniform float intensity;
uniform float ratio;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform vec4 resolution1;
uniform vec4 resolution2;
varying vec2 vUv;
const int passes = 6;
void main() {
vec2 newUV1 = (vUv - vec2(0.5,0.5))*resolution1.zw + vec2(0.5,0.5);
vec2 newUV2 = (vUv - vec2(0.5,0.5))*resolution2.zw + vec2(0.5,0.5);
vec4 t1 = vec4(0.0);
vec4 t2 = vec4(0.0);
float disp = intensity/100.0*(0.5-distance(0.5, progress));
for (int xi=0; xi<passes; xi++)
{
float x = float(xi) / float(passes) - 0.5;
for (int yi=0; yi<passes; yi++)
{
float y = float(yi) / float(passes) - 0.5;
vec2 v = vec2(x,y);
float d = disp;
t1 += texture2D(texture1,newUV1 + d*v);
t2 += texture2D(texture2,newUV2 + d*v);
}
}
t1 /= float(passes*passes);
t2 /= float(passes*passes);
// Use black background color
// Top right
vec2 tr1 = step(newUV1, vec2(1.0, 1.0));
vec2 tr2 = step(newUV2, vec2(1.0, 1.0));
float pct1 = tr1.x * tr1.y;
float pct2 = tr2.x * tr2.y;
// Bottom left
vec2 bl1 = step(vec2(0.0, 0.0), newUV1);
vec2 bl2 = step(vec2(0.0, 0.0), newUV2);
pct1 *= bl1.x * bl1.y;
pct2 *= bl2.x * bl2.y;
vec4 t1wb = t1 * vec4(pct1,pct1,pct1,1.0);
vec4 t2wb = t2 * vec4(pct2,pct2,pct2,1.0);
gl_FragColor = mix(t1wb, t2wb, progress);
}
`;
this.distortionFrag = `
uniform float progress;
uniform sampler2D displacementTexture;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform vec4 resolution1;
uniform vec4 resolution2;
uniform float angle1;
uniform float angle2;
uniform float intensity;
varying vec2 vUv;
mat2 getRotM(float angle) {
float s = sin(angle);
float c = cos(angle);
return mat2(c, -s, s, c);
}
void main() {
vec2 newUV1 = (vUv - vec2(0.5,0.5))*resolution1.zw + vec2(0.5,0.5);
vec2 newUV2 = (vUv - vec2(0.5,0.5))*resolution2.zw + vec2(0.5,0.5);
vec4 t1 = texture2D(texture1,newUV1);
vec4 t2 = texture2D(texture2,newUV2);
vec4 disp = texture2D(displacementTexture, newUV1);
vec2 dispVec = vec2(disp.r, disp.g);
vec2 distortedPosition1 = newUV1 + getRotM(angle1) * dispVec * intensity / 100.0 * progress;
vec2 distortedPosition2 = newUV2 + getRotM(angle2) * dispVec * intensity / 100.0 * (1.0 - progress);
vec4 t1d = texture2D(texture1, distortedPosition1);
vec4 t2d = texture2D(texture2, distortedPosition2);
// Use black background color
// Top right
vec2 tr1 = step(newUV1, vec2(1.0, 1.0));
vec2 tr2 = step(newUV2, vec2(1.0, 1.0));
float pct1 = tr1.x * tr1.y;
float pct2 = tr2.x * tr2.y;
// Bottom left
vec2 bl1 = step(vec2(0.0, 0.0), newUV1);
vec2 bl2 = step(vec2(0.0, 0.0), newUV2);
pct1 *= bl1.x * bl1.y;
pct2 *= bl2.x * bl2.y;
vec4 t1wb = t1d * vec4(pct1,pct1,pct1,1.0);
vec4 t2wb = t2d * vec4(pct2,pct2,pct2,1.0);
gl_FragColor = mix(t1wb, t2wb, progress);
}
`;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2VUcmFuc2l0aW9uU2hhZGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1hY3V3L3NyYy9saWIvaW1hZ2UtdHJhbnNpdGlvbi9zaGFkZXJzL2ltYWdlVHJhbnNpdGlvblNoYWRlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxPQUFPLHNCQUFzQjtJQUFuQztRQUNJLFdBQU0sR0FBRyxtSEFBbUgsQ0FBQztRQUM3SCx3QkFBbUIsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztLQXFDckIsQ0FBQztRQUNGLGFBQVEsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztLQWtDVixDQUFDO1FBQ0YsY0FBUyxHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQTZLZCxDQUFDO1FBQ0MsYUFBUSxHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUFtRGIsQ0FBQztRQUNGLG1CQUFjLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQWdEaEIsQ0FBQztJQUNILENBQUM7Q0FBQSIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjbGFzcyBJbWFnZVRyYW5zaXRpb25TaGFkZXJze1xyXG4gICAgdmVydGV4ID0gYHZhcnlpbmcgdmVjMiB2VXY7dm9pZCBtYWluKCkge3ZVdiA9IHV2O2dsX1Bvc2l0aW9uID0gcHJvamVjdGlvbk1hdHJpeCAqIG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIHBvc2l0aW9uLCAxLjAgKTt9YDtcclxuICAgIHNwbGl0VHJhbnNpdGlvbkZyYWcgPSBgXHJcbiAgICAgICAgICAgIHVuaWZvcm0gZmxvYXQgcHJvZ3Jlc3M7XHJcbiAgICAgICAgICAgIHVuaWZvcm0gZmxvYXQgaW50ZW5zaXR5O1xyXG4gICAgICAgICAgICB1bmlmb3JtIHNhbXBsZXIyRCB0ZXh0dXJlMTtcclxuICAgICAgICAgICAgdW5pZm9ybSBzYW1wbGVyMkQgdGV4dHVyZTI7XHJcbiAgICAgICAgICAgIHVuaWZvcm0gdmVjNCByZXNvbHV0aW9uMTtcclxuICAgICAgICAgICAgdW5pZm9ybSB2ZWM0IHJlc29sdXRpb24yO1xyXG4gICAgICAgICAgICB2YXJ5aW5nIHZlYzIgdlV2O1xyXG4gICAgICAgICAgICBtYXQyIHJvdGF0ZShmbG9hdCBhKSB7XHJcbiAgICAgICAgICAgICAgZmxvYXQgcyA9IHNpbihhKTtcclxuICAgICAgICAgICAgICBmbG9hdCBjID0gY29zKGEpO1xyXG4gICAgICAgICAgICAgIHJldHVybiBtYXQyKGMsIC1zLCBzLCBjKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB2b2lkIG1haW4oKVx0e1xyXG4gICAgICAgICAgICAgIHZlYzIgbmV3VVYxID0gKHZVdiAtIHZlYzIoMC41LDAuNSkpKnJlc29sdXRpb24xLnp3ICsgdmVjMigwLjUsMC41KTtcclxuICAgICAgICAgICAgICB2ZWMyIG5ld1VWMiA9ICh2VXYgLSB2ZWMyKDAuNSwwLjUpKSpyZXNvbHV0aW9uMi56dyArIHZlYzIoMC41LDAuNSk7XHJcbiAgICAgICAgICAgICAgdmVjMiB1dkRpdmlkZWQxID0gZnJhY3QobmV3VVYxKnZlYzIoaW50ZW5zaXR5LDEuKSk7XHJcbiAgICAgICAgICAgICAgdmVjMiB1dkRpdmlkZWQyID0gZnJhY3QobmV3VVYyKnZlYzIoaW50ZW5zaXR5LDEuKSk7XHJcbiAgICAgICAgICAgICAgdmVjMiB1dkRpc3BsYWNlZDEgPSBuZXdVVjEgKyByb3RhdGUoMy4xNDE1OTI2LzQuKSp1dkRpdmlkZWQxKnByb2dyZXNzKjAuMTtcclxuICAgICAgICAgICAgICB2ZWMyIHV2RGlzcGxhY2VkMiA9IG5ld1VWMiArIHJvdGF0ZSgzLjE0MTU5MjYvNC4pKnV2RGl2aWRlZDIqKDEuIC0gcHJvZ3Jlc3MpKjAuMTtcclxuICAgICAgICAgICAgICB2ZWM0IHQxID0gdGV4dHVyZTJEKHRleHR1cmUxLHV2RGlzcGxhY2VkMSk7XHJcbiAgICAgICAgICAgICAgdmVjNCB0MiA9IHRleHR1cmUyRCh0ZXh0dXJlMix1dkRpc3BsYWNlZDIpO1xyXG4gICAgICAgICAgICAgIC8vIFVzZSBibGFjayBiYWNrZ3JvdW5kIGNvbG9yXHJcbiAgICAgICAgICAgICAgLy8gVG9wIHJpZ2h0XHJcbiAgICAgICAgICAgICAgdmVjMiB0cjEgPSBzdGVwKG5ld1VWMSwgdmVjMigxLjAsIDEuMCkpO1xyXG4gICAgICAgICAgICAgIHZlYzIgdHIyID0gc3RlcChuZXdVVjIsIHZlYzIoMS4wLCAxLjApKTtcclxuICAgICAgICAgICAgICBmbG9hdCBwY3QxID0gdHIxLnggKiB0cjEueTtcclxuICAgICAgICAgICAgICBmbG9hdCBwY3QyID0gdHIyLnggKiB0cjIueTtcclxuICAgICAgICAgICAgICAvLyBCb3R0b20gbGVmdFxyXG4gICAgICAgICAgICAgIHZlYzIgYmwxID0gc3RlcCh2ZWMyKDAuMCwgMC4wKSwgbmV3VVYxKTtcclxuICAgICAgICAgICAgICB2ZWMyIGJsMiA9IHN0ZXAodmVjMigwLjAsIDAuMCksIG5ld1VWMik7XHJcbiAgICAgICAgICAgICAgcGN0MSAqPSBibDEueCAqIGJsMS55O1xyXG4gICAgICAgICAgICAgIHBjdDIgKj0gYmwyLnggKiBibDIueTtcclxuICAgICAgICAgICAgICB2ZWM0IHQxd2IgPSB0MSAqIHZlYzQocGN0MSxwY3QxLHBjdDEsMS4wKTtcclxuICAgICAgICAgICAgICB2ZWM0IHQyd2IgPSB0MiAqIHZlYzQocGN0MixwY3QyLHBjdDIsMS4wKTtcclxuICAgICAgICAgICAgICBnbF9GcmFnQ29sb3IgPSBtaXgodDF3YiwgdDJ3YiwgcHJvZ3Jlc3MpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICBgO1xyXG4gICAgZmFkZUZyYWcgPSBgXHJcbiAgICAgICAgICAgIHVuaWZvcm0gZmxvYXQgcHJvZ3Jlc3M7XHJcbiAgICAgICAgICAgIHVuaWZvcm0gc2FtcGxlcjJEIHRleHR1cmUxO1xyXG4gICAgICAgICAgICB1bmlmb3JtIHNhbXBsZXIyRCB0ZXh0dXJlMjtcclxuICAgICAgICAgICAgdW5pZm9ybSB2ZWM0IHJlc29sdXRpb24xO1xyXG4gICAgICAgICAgICB1bmlmb3JtIHZlYzQgcmVzb2x1dGlvbjI7XHJcbiAgICAgICAgICAgIHZhcnlpbmcgdmVjMiB2VXY7XHJcbiAgICAgICAgICAgIG1hdDIgcm90YXRlKGZsb2F0IGEpIHtcclxuICAgICAgICAgICAgICBmbG9hdCBzID0gc2luKGEpO1xyXG4gICAgICAgICAgICAgIGZsb2F0IGMgPSBjb3MoYSk7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIG1hdDIoYywgLXMsIHMsIGMpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHZvaWQgbWFpbigpXHR7XHJcbiAgICAgICAgICAgICAgdmVjMiBuZXdVVjEgPSAodlV2IC0gdmVjMigwLjUsMC41KSkqcmVzb2x1dGlvbjEuencgKyB2ZWMyKDAuNSwwLjUpO1xyXG4gICAgICAgICAgICAgIHZlYzIgbmV3VVYyID0gKHZVdiAtIHZlYzIoMC41LDAuNSkpKnJlc29sdXRpb24yLnp3ICsgdmVjMigwLjUsMC41KTtcclxuICAgICAgICAgICAgICB2ZWMyIHV2RGlzcGxhY2VkMSA9IG5ld1VWMSArIHZlYzIoMS4wLDApKnByb2dyZXNzKjAuMTtcclxuICAgICAgICAgICAgICB2ZWMyIHV2RGlzcGxhY2VkMiA9IG5ld1VWMiArIHZlYzIoMS4wLDApKigxLiAtIHByb2dyZXNzKSowLjE7XHJcbiAgICAgICAgICAgICAgdmVjNCB0MSA9IHRleHR1cmUyRCh0ZXh0dXJlMSx1dkRpc3BsYWNlZDEpO1xyXG4gICAgICAgICAgICAgIHZlYzQgdDIgPSB0ZXh0dXJlMkQodGV4dHVyZTIsdXZEaXNwbGFjZWQyKTtcclxuICAgICAgICAgICAgICAvLyBVc2UgYmxhY2sgYmFja2dyb3VuZCBjb2xvclxyXG4gICAgICAgICAgICAgIC8vIFRvcCByaWdodFxyXG4gICAgICAgICAgICAgIHZlYzIgdHIxID0gc3RlcChuZXdVVjEsIHZlYzIoMS4wLCAxLjApKTtcclxuICAgICAgICAgICAgICB2ZWMyIHRyMiA9IHN0ZXAobmV3VVYyLCB2ZWMyKDEuMCwgMS4wKSk7XHJcbiAgICAgICAgICAgICAgZmxvYXQgcGN0MSA9IHRyMS54ICogdHIxLnk7XHJcbiAgICAgICAgICAgICAgZmxvYXQgcGN0MiA9IHRyMi54ICogdHIyLnk7XHJcbiAgICAgICAgICAgICAgLy8gQm90dG9tIGxlZnRcclxuICAgICAgICAgICAgICB2ZWMyIGJsMSA9IHN0ZXAodmVjMigwLjAsIDAuMCksIG5ld1VWMSk7XHJcbiAgICAgICAgICAgICAgdmVjMiBibDIgPSBzdGVwKHZlYzIoMC4wLCAwLjApLCBuZXdVVjIpO1xyXG4gICAgICAgICAgICAgIHBjdDEgKj0gYmwxLnggKiBibDEueTtcclxuICAgICAgICAgICAgICBwY3QyICo9IGJsMi54ICogYmwyLnk7XHJcbiAgICAgICAgICAgICAgdmVjNCB0MXdiID0gdDEgKiB2ZWM0KHBjdDEscGN0MSxwY3QxLDEuMCk7XHJcbiAgICAgICAgICAgICAgdmVjNCB0MndiID0gdDIgKiB2ZWM0KHBjdDIscGN0MixwY3QyLDEuMCk7XHJcbiAgICAgICAgICAgICAgZ2xfRnJhZ0NvbG9yID0gbWl4KHQxd2IsIHQyd2IsIHByb2dyZXNzKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgYDtcclxuICAgIG5vaXNlRnJhZyA9IGBcclxuXHRcdHVuaWZvcm0gZmxvYXQgdGltZTtcclxuXHRcdHVuaWZvcm0gZmxvYXQgcHJvZ3Jlc3M7XHJcblx0XHR1bmlmb3JtIGZsb2F0IHdpZHRoO1xyXG5cdFx0dW5pZm9ybSBmbG9hdCBzY2FsZVg7XHJcblx0XHR1bmlmb3JtIGZsb2F0IHNjYWxlWTtcclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHRleHR1cmUxO1xyXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgdGV4dHVyZTI7XHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCBkaXNwbGFjZW1lbnQ7XHJcblx0XHR1bmlmb3JtIHZlYzQgcmVzb2x1dGlvbjE7XHJcblx0XHR1bmlmb3JtIHZlYzQgcmVzb2x1dGlvbjI7XHJcblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xyXG5cdFx0dmFyeWluZyB2ZWM0IHZQb3NpdGlvbjtcclxuXHRcdC8vXHRDbGFzc2ljIFBlcmxpbiAzRCBOb2lzZVxyXG5cdFx0Ly9cdGJ5IFN0ZWZhbiBHdXN0YXZzb25cclxuXHRcdC8vXHJcblx0XHR2ZWM0IHBlcm11dGUodmVjNCB4KXtyZXR1cm4gbW9kKCgoeCozNC4wKSsxLjApKngsIDI4OS4wKTt9XHJcblx0XHR2ZWM0IHRheWxvckludlNxcnQodmVjNCByKXtyZXR1cm4gMS43OTI4NDI5MTQwMDE1OSAtIDAuODUzNzM0NzIwOTUzMTQgKiByO31cclxuXHRcdHZlYzQgZmFkZSh2ZWM0IHQpIHtyZXR1cm4gdCp0KnQqKHQqKHQqNi4wLTE1LjApKzEwLjApO31cclxuXHRcdGZsb2F0IGNub2lzZSh2ZWM0IFApe1xyXG5cdFx0ICA7XHJcblx0XHQgIHZlYzQgUGkwID0gZmxvb3IoUCk7IC8vIEludGVnZXIgcGFydCBmb3IgaW5kZXhpbmdcclxuXHRcdCAgdmVjNCBQaTEgPSBQaTAgKyAxLjA7IC8vIEludGVnZXIgcGFydCArIDFcclxuXHRcdCAgUGkwID0gbW9kKFBpMCwgMjg5LjApO1xyXG5cdFx0ICBQaTEgPSBtb2QoUGkxLCAyODkuMCk7XHJcblx0XHQgIHZlYzQgUGYwID0gZnJhY3QoUCk7IC8vIEZyYWN0aW9uYWwgcGFydCBmb3IgaW50ZXJwb2xhdGlvblxyXG5cdFx0ICB2ZWM0IFBmMSA9IFBmMCAtIDEuMDsgLy8gRnJhY3Rpb25hbCBwYXJ0IC0gMS4wXHJcblx0XHQgIHZlYzQgaXggPSB2ZWM0KFBpMC54LCBQaTEueCwgUGkwLngsIFBpMS54KTtcclxuXHRcdCAgdmVjNCBpeSA9IHZlYzQoUGkwLnl5LCBQaTEueXkpO1xyXG5cdFx0ICB2ZWM0IGl6MCA9IHZlYzQoUGkwLnp6enopO1xyXG5cdFx0ICB2ZWM0IGl6MSA9IHZlYzQoUGkxLnp6enopO1xyXG5cdFx0ICB2ZWM0IGl3MCA9IHZlYzQoUGkwLnd3d3cpO1xyXG5cdFx0ICB2ZWM0IGl3MSA9IHZlYzQoUGkxLnd3d3cpO1xyXG5cdFx0ICB2ZWM0IGl4eSA9IHBlcm11dGUocGVybXV0ZShpeCkgKyBpeSk7XHJcblx0XHQgIHZlYzQgaXh5MCA9IHBlcm11dGUoaXh5ICsgaXowKTtcclxuXHRcdCAgdmVjNCBpeHkxID0gcGVybXV0ZShpeHkgKyBpejEpO1xyXG5cdFx0ICB2ZWM0IGl4eTAwID0gcGVybXV0ZShpeHkwICsgaXcwKTtcclxuXHRcdCAgdmVjNCBpeHkwMSA9IHBlcm11dGUoaXh5MCArIGl3MSk7XHJcblx0XHQgIHZlYzQgaXh5MTAgPSBwZXJtdXRlKGl4eTEgKyBpdzApO1xyXG5cdFx0ICB2ZWM0IGl4eTExID0gcGVybXV0ZShpeHkxICsgaXcxKTtcclxuXHRcdCAgdmVjNCBneDAwID0gaXh5MDAgLyA3LjA7XHJcblx0XHQgIHZlYzQgZ3kwMCA9IGZsb29yKGd4MDApIC8gNy4wO1xyXG5cdFx0ICB2ZWM0IGd6MDAgPSBmbG9vcihneTAwKSAvIDYuMDtcclxuXHRcdCAgZ3gwMCA9IGZyYWN0KGd4MDApIC0gMC41O1xyXG5cdFx0ICBneTAwID0gZnJhY3QoZ3kwMCkgLSAwLjU7XHJcblx0XHQgIGd6MDAgPSBmcmFjdChnejAwKSAtIDAuNTtcclxuXHRcdCAgdmVjNCBndzAwID0gdmVjNCgwLjc1KSAtIGFicyhneDAwKSAtIGFicyhneTAwKSAtIGFicyhnejAwKTtcclxuXHRcdCAgdmVjNCBzdzAwID0gc3RlcChndzAwLCB2ZWM0KDAuMCkpO1xyXG5cdFx0ICBneDAwIC09IHN3MDAgKiAoc3RlcCgwLjAsIGd4MDApIC0gMC41KTtcclxuXHRcdCAgZ3kwMCAtPSBzdzAwICogKHN0ZXAoMC4wLCBneTAwKSAtIDAuNSk7XHJcblx0XHQgIHZlYzQgZ3gwMSA9IGl4eTAxIC8gNy4wO1xyXG5cdFx0ICB2ZWM0IGd5MDEgPSBmbG9vcihneDAxKSAvIDcuMDtcclxuXHRcdCAgdmVjNCBnejAxID0gZmxvb3IoZ3kwMSkgLyA2LjA7XHJcblx0XHQgIGd4MDEgPSBmcmFjdChneDAxKSAtIDAuNTtcclxuXHRcdCAgZ3kwMSA9IGZyYWN0KGd5MDEpIC0gMC41O1xyXG5cdFx0ICBnejAxID0gZnJhY3QoZ3owMSkgLSAwLjU7XHJcblx0XHQgIHZlYzQgZ3cwMSA9IHZlYzQoMC43NSkgLSBhYnMoZ3gwMSkgLSBhYnMoZ3kwMSkgLSBhYnMoZ3owMSk7XHJcblx0XHQgIHZlYzQgc3cwMSA9IHN0ZXAoZ3cwMSwgdmVjNCgwLjApKTtcclxuXHRcdCAgZ3gwMSAtPSBzdzAxICogKHN0ZXAoMC4wLCBneDAxKSAtIDAuNSk7XHJcblx0XHQgIGd5MDEgLT0gc3cwMSAqIChzdGVwKDAuMCwgZ3kwMSkgLSAwLjUpO1xyXG5cdFx0ICB2ZWM0IGd4MTAgPSBpeHkxMCAvIDcuMDtcclxuXHRcdCAgdmVjNCBneTEwID0gZmxvb3IoZ3gxMCkgLyA3LjA7XHJcblx0XHQgIHZlYzQgZ3oxMCA9IGZsb29yKGd5MTApIC8gNi4wO1xyXG5cdFx0ICBneDEwID0gZnJhY3QoZ3gxMCkgLSAwLjU7XHJcblx0XHQgIGd5MTAgPSBmcmFjdChneTEwKSAtIDAuNTtcclxuXHRcdCAgZ3oxMCA9IGZyYWN0KGd6MTApIC0gMC41O1xyXG5cdFx0ICB2ZWM0IGd3MTAgPSB2ZWM0KDAuNzUpIC0gYWJzKGd4MTApIC0gYWJzKGd5MTApIC0gYWJzKGd6MTApO1xyXG5cdFx0ICB2ZWM0IHN3MTAgPSBzdGVwKGd3MTAsIHZlYzQoMC4wKSk7XHJcblx0XHQgIGd4MTAgLT0gc3cxMCAqIChzdGVwKDAuMCwgZ3gxMCkgLSAwLjUpO1xyXG5cdFx0ICBneTEwIC09IHN3MTAgKiAoc3RlcCgwLjAsIGd5MTApIC0gMC41KTtcclxuXHRcdCAgdmVjNCBneDExID0gaXh5MTEgLyA3LjA7XHJcblx0XHQgIHZlYzQgZ3kxMSA9IGZsb29yKGd4MTEpIC8gNy4wO1xyXG5cdFx0ICB2ZWM0IGd6MTEgPSBmbG9vcihneTExKSAvIDYuMDtcclxuXHRcdCAgZ3gxMSA9IGZyYWN0KGd4MTEpIC0gMC41O1xyXG5cdFx0ICBneTExID0gZnJhY3QoZ3kxMSkgLSAwLjU7XHJcblx0XHQgIGd6MTEgPSBmcmFjdChnejExKSAtIDAuNTtcclxuXHRcdCAgdmVjNCBndzExID0gdmVjNCgwLjc1KSAtIGFicyhneDExKSAtIGFicyhneTExKSAtIGFicyhnejExKTtcclxuXHRcdCAgdmVjNCBzdzExID0gc3RlcChndzExLCB2ZWM0KDAuMCkpO1xyXG5cdFx0ICBneDExIC09IHN3MTEgKiAoc3RlcCgwLjAsIGd4MTEpIC0gMC41KTtcclxuXHRcdCAgZ3kxMSAtPSBzdzExICogKHN0ZXAoMC4wLCBneTExKSAtIDAuNSk7XHJcblx0XHQgIHZlYzQgZzAwMDAgPSB2ZWM0KGd4MDAueCxneTAwLngsZ3owMC54LGd3MDAueCk7XHJcblx0XHQgIHZlYzQgZzEwMDAgPSB2ZWM0KGd4MDAueSxneTAwLnksZ3owMC55LGd3MDAueSk7XHJcblx0XHQgIHZlYzQgZzAxMDAgPSB2ZWM0KGd4MDAueixneTAwLnosZ3owMC56LGd3MDAueik7XHJcblx0XHQgIHZlYzQgZzExMDAgPSB2ZWM0KGd4MDAudyxneTAwLncsZ3owMC53LGd3MDAudyk7XHJcblx0XHQgIHZlYzQgZzAwMTAgPSB2ZWM0KGd4MTAueCxneTEwLngsZ3oxMC54LGd3MTAueCk7XHJcblx0XHQgIHZlYzQgZzEwMTAgPSB2ZWM0KGd4MTAueSxneTEwLnksZ3oxMC55LGd3MTAueSk7XHJcblx0XHQgIHZlYzQgZzAxMTAgPSB2ZWM0KGd4MTAueixneTEwLnosZ3oxMC56LGd3MTAueik7XHJcblx0XHQgIHZlYzQgZzExMTAgPSB2ZWM0KGd4MTAudyxneTEwLncsZ3oxMC53LGd3MTAudyk7XHJcblx0XHQgIHZlYzQgZzAwMDEgPSB2ZWM0KGd4MDEueCxneTAxLngsZ3owMS54LGd3MDEueCk7XHJcblx0XHQgIHZlYzQgZzEwMDEgPSB2ZWM0KGd4MDEueSxneTAxLnksZ3owMS55LGd3MDEueSk7XHJcblx0XHQgIHZlYzQgZzAxMDEgPSB2ZWM0KGd4MDEueixneTAxLnosZ3owMS56LGd3MDEueik7XHJcblx0XHQgIHZlYzQgZzExMDEgPSB2ZWM0KGd4MDEudyxneTAxLncsZ3owMS53LGd3MDEudyk7XHJcblx0XHQgIHZlYzQgZzAwMTEgPSB2ZWM0KGd4MTEueCxneTExLngsZ3oxMS54LGd3MTEueCk7XHJcblx0XHQgIHZlYzQgZzEwMTEgPSB2ZWM0KGd4MTEueSxneTExLnksZ3oxMS55LGd3MTEueSk7XHJcblx0XHQgIHZlYzQgZzAxMTEgPSB2ZWM0KGd4MTEueixneTExLnosZ3oxMS56LGd3MTEueik7XHJcblx0XHQgIHZlYzQgZzExMTEgPSB2ZWM0KGd4MTEudyxneTExLncsZ3oxMS53LGd3MTEudyk7XHJcblx0XHQgIHZlYzQgbm9ybTAwID0gdGF5bG9ySW52U3FydCh2ZWM0KGRvdChnMDAwMCwgZzAwMDApLCBkb3QoZzAxMDAsIGcwMTAwKSwgZG90KGcxMDAwLCBnMTAwMCksIGRvdChnMTEwMCwgZzExMDApKSk7XHJcblx0XHQgIGcwMDAwICo9IG5vcm0wMC54O1xyXG5cdFx0ICBnMDEwMCAqPSBub3JtMDAueTtcclxuXHRcdCAgZzEwMDAgKj0gbm9ybTAwLno7XHJcblx0XHQgIGcxMTAwICo9IG5vcm0wMC53O1xyXG5cdFx0ICB2ZWM0IG5vcm0wMSA9IHRheWxvckludlNxcnQodmVjNChkb3QoZzAwMDEsIGcwMDAxKSwgZG90KGcwMTAxLCBnMDEwMSksIGRvdChnMTAwMSwgZzEwMDEpLCBkb3QoZzExMDEsIGcxMTAxKSkpO1xyXG5cdFx0ICBnMDAwMSAqPSBub3JtMDEueDtcclxuXHRcdCAgZzAxMDEgKj0gbm9ybTAxLnk7XHJcblx0XHQgIGcxMDAxICo9IG5vcm0wMS56O1xyXG5cdFx0ICBnMTEwMSAqPSBub3JtMDEudztcclxuXHRcdCAgdmVjNCBub3JtMTAgPSB0YXlsb3JJbnZTcXJ0KHZlYzQoZG90KGcwMDEwLCBnMDAxMCksIGRvdChnMDExMCwgZzAxMTApLCBkb3QoZzEwMTAsIGcxMDEwKSwgZG90KGcxMTEwLCBnMTExMCkpKTtcclxuXHRcdCAgZzAwMTAgKj0gbm9ybTEwLng7XHJcblx0XHQgIGcwMTEwICo9IG5vcm0xMC55O1xyXG5cdFx0ICBnMTAxMCAqPSBub3JtMTAuejtcclxuXHRcdCAgZzExMTAgKj0gbm9ybTEwLnc7XHJcblx0XHQgIHZlYzQgbm9ybTExID0gdGF5bG9ySW52U3FydCh2ZWM0KGRvdChnMDAxMSwgZzAwMTEpLCBkb3QoZzAxMTEsIGcwMTExKSwgZG90KGcxMDExLCBnMTAxMSksIGRvdChnMTExMSwgZzExMTEpKSk7XHJcblx0XHQgIGcwMDExICo9IG5vcm0xMS54O1xyXG5cdFx0ICBnMDExMSAqPSBub3JtMTEueTtcclxuXHRcdCAgZzEwMTEgKj0gbm9ybTExLno7XHJcblx0XHQgIGcxMTExICo9IG5vcm0xMS53O1xyXG5cdFx0ICBmbG9hdCBuMDAwMCA9IGRvdChnMDAwMCwgUGYwKTtcclxuXHRcdCAgZmxvYXQgbjEwMDAgPSBkb3QoZzEwMDAsIHZlYzQoUGYxLngsIFBmMC55encpKTtcclxuXHRcdCAgZmxvYXQgbjAxMDAgPSBkb3QoZzAxMDAsIHZlYzQoUGYwLngsIFBmMS55LCBQZjAuencpKTtcclxuXHRcdCAgZmxvYXQgbjExMDAgPSBkb3QoZzExMDAsIHZlYzQoUGYxLnh5LCBQZjAuencpKTtcclxuXHRcdCAgZmxvYXQgbjAwMTAgPSBkb3QoZzAwMTAsIHZlYzQoUGYwLnh5LCBQZjEueiwgUGYwLncpKTtcclxuXHRcdCAgZmxvYXQgbjEwMTAgPSBkb3QoZzEwMTAsIHZlYzQoUGYxLngsIFBmMC55LCBQZjEueiwgUGYwLncpKTtcclxuXHRcdCAgZmxvYXQgbjAxMTAgPSBkb3QoZzAxMTAsIHZlYzQoUGYwLngsIFBmMS55eiwgUGYwLncpKTtcclxuXHRcdCAgZmxvYXQgbjExMTAgPSBkb3QoZzExMTAsIHZlYzQoUGYxLnh5eiwgUGYwLncpKTtcclxuXHRcdCAgZmxvYXQgbjAwMDEgPSBkb3QoZzAwMDEsIHZlYzQoUGYwLnh5eiwgUGYxLncpKTtcclxuXHRcdCAgZmxvYXQgbjEwMDEgPSBkb3QoZzEwMDEsIHZlYzQoUGYxLngsIFBmMC55eiwgUGYxLncpKTtcclxuXHRcdCAgZmxvYXQgbjAxMDEgPSBkb3QoZzAxMDEsIHZlYzQoUGYwLngsIFBmMS55LCBQZjAueiwgUGYxLncpKTtcclxuXHRcdCAgZmxvYXQgbjExMDEgPSBkb3QoZzExMDEsIHZlYzQoUGYxLnh5LCBQZjAueiwgUGYxLncpKTtcclxuXHRcdCAgZmxvYXQgbjAwMTEgPSBkb3QoZzAwMTEsIHZlYzQoUGYwLnh5LCBQZjEuencpKTtcclxuXHRcdCAgZmxvYXQgbjEwMTEgPSBkb3QoZzEwMTEsIHZlYzQoUGYxLngsIFBmMC55LCBQZjEuencpKTtcclxuXHRcdCAgZmxvYXQgbjAxMTEgPSBkb3QoZzAxMTEsIHZlYzQoUGYwLngsIFBmMS55encpKTtcclxuXHRcdCAgZmxvYXQgbjExMTEgPSBkb3QoZzExMTEsIFBmMSk7XHJcblx0XHQgIHZlYzQgZmFkZV94eXp3ID0gZmFkZShQZjApO1xyXG5cdFx0ICB2ZWM0IG5fMHcgPSBtaXgodmVjNChuMDAwMCwgbjEwMDAsIG4wMTAwLCBuMTEwMCksIHZlYzQobjAwMDEsIG4xMDAxLCBuMDEwMSwgbjExMDEpLCBmYWRlX3h5encudyk7XHJcblx0XHQgIHZlYzQgbl8xdyA9IG1peCh2ZWM0KG4wMDEwLCBuMTAxMCwgbjAxMTAsIG4xMTEwKSwgdmVjNChuMDAxMSwgbjEwMTEsIG4wMTExLCBuMTExMSksIGZhZGVfeHl6dy53KTtcclxuXHRcdCAgdmVjNCBuX3p3ID0gbWl4KG5fMHcsIG5fMXcsIGZhZGVfeHl6dy56KTtcclxuXHRcdCAgdmVjMiBuX3l6dyA9IG1peChuX3p3Lnh5LCBuX3p3Lnp3LCBmYWRlX3h5encueSk7XHJcblx0XHQgIGZsb2F0IG5feHl6dyA9IG1peChuX3l6dy54LCBuX3l6dy55LCBmYWRlX3h5encueCk7XHJcblx0XHQgIHJldHVybiAyLjIgKiBuX3h5enc7XHJcblx0XHR9XHJcblx0XHRmbG9hdCBtYXAoZmxvYXQgdmFsdWUsIGZsb2F0IG1pbjEsIGZsb2F0IG1heDEsIGZsb2F0IG1pbjIsIGZsb2F0IG1heDIpIHtcclxuXHRcdCAgcmV0dXJuIG1pbjIgKyAodmFsdWUgLSBtaW4xKSAqIChtYXgyIC0gbWluMikgLyAobWF4MSAtIG1pbjEpO1xyXG5cdFx0fVxyXG5cdFx0ZmxvYXQgcGFyYWJvbGEoIGZsb2F0IHgsIGZsb2F0IGsgKSB7XHJcblx0XHQgIHJldHVybiBwb3coIDQuICogeCAqICggMS4gLSB4ICksIGsgKTtcclxuXHRcdH1cclxuXHRcdHZvaWQgbWFpbigpXHR7XHJcblx0XHRcdGZsb2F0IGR0ID0gcGFyYWJvbGEocHJvZ3Jlc3MsMS4pO1xyXG5cdFx0XHRmbG9hdCBib3JkZXIgPSAxLjtcclxuXHRcdFx0dmVjMiBuZXdVVjEgPSAodlV2IC0gdmVjMigwLjUsMC41KSkqcmVzb2x1dGlvbjEuencgKyB2ZWMyKDAuNSwwLjUpO1xyXG4gICAgICBcdFx0dmVjMiBuZXdVVjIgPSAodlV2IC0gdmVjMigwLjUsMC41KSkqcmVzb2x1dGlvbjIuencgKyB2ZWMyKDAuNSwwLjUpO1xyXG5cdFx0XHR2ZWM0IHQxID0gdGV4dHVyZTJEKHRleHR1cmUxLG5ld1VWMSk7XHJcbiAgICAgIFx0XHR2ZWM0IHQyID0gdGV4dHVyZTJEKHRleHR1cmUyLG5ld1VWMik7XHJcbiAgICAgIFx0XHQvLyBVc2UgYmxhY2sgYmFja2dyb3VuZCBjb2xvclxyXG4gICAgICBcdFx0Ly8gVG9wIHJpZ2h0XHJcbiAgICAgIFx0XHR2ZWMyIHRyMSA9IHN0ZXAobmV3VVYxLCB2ZWMyKDEuMCwgMS4wKSk7XHJcbiAgICAgIFx0XHR2ZWMyIHRyMiA9IHN0ZXAobmV3VVYyLCB2ZWMyKDEuMCwgMS4wKSk7XHJcbiAgICAgIFx0XHRmbG9hdCBwY3QxID0gdHIxLnggKiB0cjEueTtcclxuICAgICAgXHRcdGZsb2F0IHBjdDIgPSB0cjIueCAqIHRyMi55O1xyXG4gICAgICBcdFx0Ly8gQm90dG9tIGxlZnRcclxuICAgICAgXHRcdHZlYzIgYmwxID0gc3RlcCh2ZWMyKDAuMCwgMC4wKSwgbmV3VVYxKTtcclxuICAgICAgXHRcdHZlYzIgYmwyID0gc3RlcCh2ZWMyKDAuMCwgMC4wKSwgbmV3VVYyKTtcclxuICAgICAgXHRcdHBjdDEgKj0gYmwxLnggKiBibDEueTtcclxuICAgICAgXHRcdHBjdDIgKj0gYmwyLnggKiBibDIueTtcclxuICAgICAgXHRcdHZlYzQgdDF3YiA9IHQxICogdmVjNChwY3QxLHBjdDEscGN0MSwxLjApO1xyXG4gICAgICBcdFx0dmVjNCB0MndiID0gdDIgKiB2ZWM0KHBjdDIscGN0MixwY3QyLDEuMCk7XHJcblx0XHRcdGZsb2F0IHJlYWxub2lzZSA9IDAuNSooY25vaXNlKHZlYzQobmV3VVYxLngqc2NhbGVYICArIDAuKnRpbWUvMy4sIG5ld1VWMS55KnNjYWxlWSwwLip0aW1lLzMuLDAuKSkgKzEuKTtcclxuXHRcdFx0ZmxvYXQgdyA9IHdpZHRoKmR0O1xyXG5cdFx0XHRmbG9hdCBtYXNrdmFsdWUgPSBzbW9vdGhzdGVwKDEuIC0gdywxLix2VXYueCArIG1peCgtdy8yLiwgMS4gLSB3LzIuLCBwcm9ncmVzcykpO1xyXG5cdFx0XHRmbG9hdCBtYXNrID0gbWFza3ZhbHVlICsgbWFza3ZhbHVlKnJlYWxub2lzZTtcclxuXHRcdFx0ZmxvYXQgZmluYWwgPSBzbW9vdGhzdGVwKGJvcmRlcixib3JkZXIrMC4wMSxtYXNrKTtcclxuXHRcdFx0Z2xfRnJhZ0NvbG9yID0gbWl4KHQxd2IsdDJ3YixmaW5hbCk7XHJcblx0XHR9XHJcblx0YDtcclxuICAgIGJsdXJGcmFnID0gYFxyXG5cdFx0Ly8gYXV0aG9yOiBncmVcclxuXHRcdC8vIGxpY2Vuc2U6IE1JVFxyXG5cdFx0dW5pZm9ybSBmbG9hdCBwcm9ncmVzcztcclxuXHRcdHVuaWZvcm0gZmxvYXQgaW50ZW5zaXR5O1xyXG5cdFx0dW5pZm9ybSBmbG9hdCByYXRpbztcclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHRleHR1cmUxO1xyXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgdGV4dHVyZTI7XHJcblx0XHR1bmlmb3JtIHZlYzQgcmVzb2x1dGlvbjE7XHJcblx0XHR1bmlmb3JtIHZlYzQgcmVzb2x1dGlvbjI7XHJcblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xyXG5cdFx0Y29uc3QgaW50IHBhc3NlcyA9IDY7XHJcblxyXG5cdFx0dm9pZCBtYWluKCkge1xyXG5cdFx0XHR2ZWMyIG5ld1VWMSA9ICh2VXYgLSB2ZWMyKDAuNSwwLjUpKSpyZXNvbHV0aW9uMS56dyArIHZlYzIoMC41LDAuNSk7XHJcblx0XHRcdHZlYzIgbmV3VVYyID0gKHZVdiAtIHZlYzIoMC41LDAuNSkpKnJlc29sdXRpb24yLnp3ICsgdmVjMigwLjUsMC41KTtcclxuXHJcblx0XHRcdHZlYzQgdDEgPSB2ZWM0KDAuMCk7XHJcblx0XHRcdHZlYzQgdDIgPSB2ZWM0KDAuMCk7XHJcblx0XHRcdGZsb2F0IGRpc3AgPSBpbnRlbnNpdHkvMTAwLjAqKDAuNS1kaXN0YW5jZSgwLjUsIHByb2dyZXNzKSk7XHJcblx0XHRcdGZvciAoaW50IHhpPTA7IHhpPHBhc3NlczsgeGkrKylcclxuXHRcdFx0e1xyXG5cdFx0XHRcdGZsb2F0IHggPSBmbG9hdCh4aSkgLyBmbG9hdChwYXNzZXMpIC0gMC41O1xyXG5cdFx0XHRcdGZvciAoaW50IHlpPTA7IHlpPHBhc3NlczsgeWkrKylcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHRmbG9hdCB5ID0gZmxvYXQoeWkpIC8gZmxvYXQocGFzc2VzKSAtIDAuNTtcclxuXHRcdFx0XHRcdHZlYzIgdiA9IHZlYzIoeCx5KTtcclxuXHRcdFx0XHRcdGZsb2F0IGQgPSBkaXNwO1xyXG5cdFx0XHRcdFx0dDEgKz0gdGV4dHVyZTJEKHRleHR1cmUxLG5ld1VWMSArIGQqdik7XHJcblx0XHRcdFx0XHR0MiArPSB0ZXh0dXJlMkQodGV4dHVyZTIsbmV3VVYyICsgZCp2KTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHQxIC89IGZsb2F0KHBhc3NlcypwYXNzZXMpO1xyXG5cdFx0XHR0MiAvPSBmbG9hdChwYXNzZXMqcGFzc2VzKTtcclxuXHJcblx0XHRcdC8vIFVzZSBibGFjayBiYWNrZ3JvdW5kIGNvbG9yXHJcblx0XHRcdC8vIFRvcCByaWdodFxyXG5cdFx0XHR2ZWMyIHRyMSA9IHN0ZXAobmV3VVYxLCB2ZWMyKDEuMCwgMS4wKSk7XHJcblx0XHRcdHZlYzIgdHIyID0gc3RlcChuZXdVVjIsIHZlYzIoMS4wLCAxLjApKTtcclxuXHRcdFx0ZmxvYXQgcGN0MSA9IHRyMS54ICogdHIxLnk7XHJcblx0XHRcdGZsb2F0IHBjdDIgPSB0cjIueCAqIHRyMi55O1xyXG5cdFx0XHQvLyBCb3R0b20gbGVmdFxyXG5cdFx0XHR2ZWMyIGJsMSA9IHN0ZXAodmVjMigwLjAsIDAuMCksIG5ld1VWMSk7XHJcblx0XHRcdHZlYzIgYmwyID0gc3RlcCh2ZWMyKDAuMCwgMC4wKSwgbmV3VVYyKTtcclxuXHRcdFx0cGN0MSAqPSBibDEueCAqIGJsMS55O1xyXG5cdFx0XHRwY3QyICo9IGJsMi54ICogYmwyLnk7XHJcblx0XHRcdHZlYzQgdDF3YiA9IHQxICogdmVjNChwY3QxLHBjdDEscGN0MSwxLjApO1xyXG5cdFx0XHR2ZWM0IHQyd2IgPSB0MiAqIHZlYzQocGN0MixwY3QyLHBjdDIsMS4wKTtcclxuXHRcdFx0Z2xfRnJhZ0NvbG9yID0gbWl4KHQxd2IsIHQyd2IsIHByb2dyZXNzKTtcclxuXHRcdH1cclxuXHRgO1xyXG5cdGRpc3RvcnRpb25GcmFnID0gYFxyXG5cdHVuaWZvcm0gZmxvYXQgcHJvZ3Jlc3M7XHJcblx0dW5pZm9ybSBzYW1wbGVyMkQgZGlzcGxhY2VtZW50VGV4dHVyZTtcclxuXHR1bmlmb3JtIHNhbXBsZXIyRCB0ZXh0dXJlMTtcclxuICAgIHVuaWZvcm0gc2FtcGxlcjJEIHRleHR1cmUyO1xyXG4gICAgdW5pZm9ybSB2ZWM0IHJlc29sdXRpb24xO1xyXG4gICAgdW5pZm9ybSB2ZWM0IHJlc29sdXRpb24yO1xyXG5cdHVuaWZvcm0gZmxvYXQgYW5nbGUxO1xyXG5cdHVuaWZvcm0gZmxvYXQgYW5nbGUyO1xyXG5cdHVuaWZvcm0gZmxvYXQgaW50ZW5zaXR5O1xyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlV2O1xyXG5cclxuXHRtYXQyIGdldFJvdE0oZmxvYXQgYW5nbGUpIHtcclxuXHQgIGZsb2F0IHMgPSBzaW4oYW5nbGUpO1xyXG5cdCAgZmxvYXQgYyA9IGNvcyhhbmdsZSk7XHJcblx0ICByZXR1cm4gbWF0MihjLCAtcywgcywgYyk7XHJcblx0fVxyXG5cclxuXHR2b2lkIG1haW4oKSB7XHJcblx0ICB2ZWMyIG5ld1VWMSA9ICh2VXYgLSB2ZWMyKDAuNSwwLjUpKSpyZXNvbHV0aW9uMS56dyArIHZlYzIoMC41LDAuNSk7XHJcbiAgICAgIHZlYzIgbmV3VVYyID0gKHZVdiAtIHZlYzIoMC41LDAuNSkpKnJlc29sdXRpb24yLnp3ICsgdmVjMigwLjUsMC41KTtcclxuXHQgIHZlYzQgdDEgPSB0ZXh0dXJlMkQodGV4dHVyZTEsbmV3VVYxKTtcclxuICAgICAgdmVjNCB0MiA9IHRleHR1cmUyRCh0ZXh0dXJlMixuZXdVVjIpO1xyXG5cclxuXHQgIHZlYzQgZGlzcCA9IHRleHR1cmUyRChkaXNwbGFjZW1lbnRUZXh0dXJlLCBuZXdVVjEpO1xyXG5cdCAgdmVjMiBkaXNwVmVjID0gdmVjMihkaXNwLnIsIGRpc3AuZyk7XHJcblxyXG5cdCAgdmVjMiBkaXN0b3J0ZWRQb3NpdGlvbjEgPSBuZXdVVjEgKyBnZXRSb3RNKGFuZ2xlMSkgKiBkaXNwVmVjICogaW50ZW5zaXR5IC8gMTAwLjAgKiBwcm9ncmVzcztcclxuXHQgIHZlYzIgZGlzdG9ydGVkUG9zaXRpb24yID0gbmV3VVYyICsgZ2V0Um90TShhbmdsZTIpICogZGlzcFZlYyAqIGludGVuc2l0eSAvIDEwMC4wICogKDEuMCAtIHByb2dyZXNzKTtcclxuXHQgIHZlYzQgdDFkID0gdGV4dHVyZTJEKHRleHR1cmUxLCBkaXN0b3J0ZWRQb3NpdGlvbjEpO1xyXG5cdCAgdmVjNCB0MmQgPSB0ZXh0dXJlMkQodGV4dHVyZTIsIGRpc3RvcnRlZFBvc2l0aW9uMik7XHJcblxyXG5cdCAgLy8gVXNlIGJsYWNrIGJhY2tncm91bmQgY29sb3JcclxuXHQgIC8vIFRvcCByaWdodFxyXG5cdCAgdmVjMiB0cjEgPSBzdGVwKG5ld1VWMSwgdmVjMigxLjAsIDEuMCkpO1xyXG5cdCAgdmVjMiB0cjIgPSBzdGVwKG5ld1VWMiwgdmVjMigxLjAsIDEuMCkpO1xyXG5cdCAgZmxvYXQgcGN0MSA9IHRyMS54ICogdHIxLnk7XHJcblx0ICBmbG9hdCBwY3QyID0gdHIyLnggKiB0cjIueTtcclxuXHQgIC8vIEJvdHRvbSBsZWZ0XHJcblx0ICB2ZWMyIGJsMSA9IHN0ZXAodmVjMigwLjAsIDAuMCksIG5ld1VWMSk7XHJcblx0ICB2ZWMyIGJsMiA9IHN0ZXAodmVjMigwLjAsIDAuMCksIG5ld1VWMik7XHJcblx0ICBwY3QxICo9IGJsMS54ICogYmwxLnk7XHJcblx0ICBwY3QyICo9IGJsMi54ICogYmwyLnk7XHJcblx0ICB2ZWM0IHQxd2IgPSB0MWQgKiB2ZWM0KHBjdDEscGN0MSxwY3QxLDEuMCk7XHJcblx0ICB2ZWM0IHQyd2IgPSB0MmQgKiB2ZWM0KHBjdDIscGN0MixwY3QyLDEuMCk7XHJcblx0ICBnbF9GcmFnQ29sb3IgPSBtaXgodDF3YiwgdDJ3YiwgcHJvZ3Jlc3MpO1xyXG5cdH1cclxuXHRgO1xyXG59XHJcbiJdfQ==