@wolsok/thanos 3.0.1 → 16.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -107
- package/{esm2020 → esm2022}/index.mjs +10 -10
- package/esm2022/lib/animation.state.mjs +2 -0
- package/esm2022/lib/create-ws-thanos-options.mjs +9 -0
- package/{esm2020 → esm2022}/lib/simplex-noise-options.mjs +1 -1
- package/esm2022/lib/simplex-noise.mjs +194 -0
- package/{esm2020 → esm2022}/lib/ws-thanos-options.token.mjs +13 -13
- package/esm2022/lib/ws-thanos.directive.mjs +76 -0
- package/{esm2020 → esm2022}/lib/ws-thanos.options.mjs +1 -1
- package/esm2022/lib/ws-thanos.service.mjs +253 -0
- package/{esm2020 → esm2022}/wolsok-thanos.mjs +4 -4
- package/index.d.ts +8 -6
- package/index.d.ts.map +1 -0
- package/lib/animation.state.d.ts +7 -0
- package/lib/animation.state.d.ts.map +1 -0
- package/lib/create-ws-thanos-options.d.ts +3 -2
- package/lib/create-ws-thanos-options.d.ts.map +1 -0
- package/lib/simplex-noise-options.d.ts +10 -9
- package/lib/simplex-noise-options.d.ts.map +1 -0
- package/lib/simplex-noise.d.ts +19 -18
- package/lib/simplex-noise.d.ts.map +1 -0
- package/lib/ws-thanos-options.token.d.ts +5 -4
- package/lib/ws-thanos-options.token.d.ts.map +1 -0
- package/lib/ws-thanos.directive.d.ts +36 -18
- package/lib/ws-thanos.directive.d.ts.map +1 -0
- package/lib/ws-thanos.options.d.ts +6 -5
- package/lib/ws-thanos.options.d.ts.map +1 -0
- package/lib/ws-thanos.service.d.ts +27 -32
- package/lib/ws-thanos.service.d.ts.map +1 -0
- package/package.json +16 -17
- package/wolsok-thanos.d.ts.map +1 -0
- package/esm2020/lib/create-ws-thanos-options.mjs +0 -9
- package/esm2020/lib/simplex-noise.mjs +0 -199
- package/esm2020/lib/ws-thanos.directive.mjs +0 -56
- package/esm2020/lib/ws-thanos.service.mjs +0 -260
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import { Inject, Injectable, NgZone } from '@angular/core';
|
|
2
|
-
import { default as html2canvas } from 'html2canvas';
|
|
3
|
-
import { animationFrameScheduler, from, interval, map, switchMap, takeWhile, tap, timeInterval, } from 'rxjs';
|
|
4
|
-
import { SimplexNoise } from './simplex-noise';
|
|
5
|
-
import { WS_THANOS_OPTIONS_TOKEN } from './ws-thanos-options.token';
|
|
6
|
-
import * as i0 from "@angular/core";
|
|
7
|
-
const PARTICLE_BYTE_LENGTH = 10;
|
|
8
|
-
const MIN_PARTICLE_ALPHA = ~~(255 * 0.01);
|
|
9
|
-
const HEIGHT_SCALE = 5;
|
|
10
|
-
const WIDTH_SCALE = 2;
|
|
11
|
-
const FLOW_FIELD_RES = 0.05;
|
|
12
|
-
export class WsThanosService {
|
|
13
|
-
constructor(thanosOptions, ngZone) {
|
|
14
|
-
this.thanosOptions = thanosOptions;
|
|
15
|
-
this.ngZone = ngZone;
|
|
16
|
-
}
|
|
17
|
-
static getParticleIndicesForBase(base) {
|
|
18
|
-
return {
|
|
19
|
-
x: base,
|
|
20
|
-
y: base + 1,
|
|
21
|
-
dx: base + 2,
|
|
22
|
-
dy: base + 3,
|
|
23
|
-
ax: base + 4,
|
|
24
|
-
ay: base + 5,
|
|
25
|
-
r: base + 6,
|
|
26
|
-
g: base + 7,
|
|
27
|
-
b: base + 8,
|
|
28
|
-
a: base + 9,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
static getColorIndicesForCoord(x, y, width) {
|
|
32
|
-
const red = y * (width * 4) + x * 4;
|
|
33
|
-
return { r: red, g: red + 1, b: red + 2, a: red + 3 };
|
|
34
|
-
}
|
|
35
|
-
static updateParticles({ seed, noise, particlesData, thanosOptions, animationState, }) {
|
|
36
|
-
const { deltaTSec, animationT, maxWidth, maxHeight } = animationState;
|
|
37
|
-
const { particleAcceleration } = thanosOptions;
|
|
38
|
-
const { particles, maxParticleX, minParticleY } = particlesData;
|
|
39
|
-
// the time is used to calculate the vaporization front.
|
|
40
|
-
const time = Math.sin(animationT * (Math.PI / 2)) * 1.1;
|
|
41
|
-
const startAccelerateX = maxParticleX - time * maxParticleX;
|
|
42
|
-
const startAccelerateY = time * (maxHeight - minParticleY) + minParticleY;
|
|
43
|
-
const lengthY = maxHeight - startAccelerateY;
|
|
44
|
-
const accelerateRadiusPow = startAccelerateX * startAccelerateX + lengthY * lengthY;
|
|
45
|
-
for (let i = 0; i < particles.length; i += PARTICLE_BYTE_LENGTH) {
|
|
46
|
-
const { x, y, dx, dy, ax, ay, a } = WsThanosService.getParticleIndicesForBase(i);
|
|
47
|
-
const particleX = particles[x];
|
|
48
|
-
const particleY = particles[y];
|
|
49
|
-
// only update particles that are inside view and visible
|
|
50
|
-
if (particleX > maxWidth ||
|
|
51
|
-
particleX < 0 ||
|
|
52
|
-
particleY > maxHeight ||
|
|
53
|
-
particleY < 0 ||
|
|
54
|
-
particles[a] < MIN_PARTICLE_ALPHA) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
if (!(Math.abs(particles[ax]) > 0 || Math.abs(particles[ay]) > 0)) {
|
|
58
|
-
let pYLength = maxHeight - particleY;
|
|
59
|
-
let pXLength = particleX;
|
|
60
|
-
// we calculate some random looking numbers and functions to have nice looking vaporizing front of particles
|
|
61
|
-
// todo consider to use noise;
|
|
62
|
-
pXLength += Math.tan((pXLength / 20.12) * time + seed) * 0.5;
|
|
63
|
-
pXLength += (particleX % deltaTSec) * 0.5;
|
|
64
|
-
pXLength +=
|
|
65
|
-
Math.sin((pXLength / 30 + 723.394) * time + seed * 12.5) * 11;
|
|
66
|
-
pYLength += Math.tan((pYLength / 0.45) * time + seed * 1.5) * 0.5;
|
|
67
|
-
pYLength +=
|
|
68
|
-
Math.cos((pYLength / 100 + 2323.234) * time + seed * 456.1) * 23;
|
|
69
|
-
const pLength = pXLength * pXLength + pYLength * pYLength;
|
|
70
|
-
if (pLength > accelerateRadiusPow) {
|
|
71
|
-
particles[ax] = Math.random();
|
|
72
|
-
particles[ay] = Math.random() * -1;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// use noise to flow along velocity field
|
|
77
|
-
const flowFieldAcc = WsThanosService.getXYFromFlowField(noise, seed, particleX, particleY);
|
|
78
|
-
const accelerationX = flowFieldAcc[0];
|
|
79
|
-
const accelerationY = flowFieldAcc[1];
|
|
80
|
-
particles[ax] += accelerationX;
|
|
81
|
-
particles[ay] += accelerationY;
|
|
82
|
-
}
|
|
83
|
-
// * Math.pow(1 + animationT, 4)
|
|
84
|
-
particles[dx] += particles[ax] * particleAcceleration * deltaTSec;
|
|
85
|
-
particles[dy] += particles[ay] * particleAcceleration * deltaTSec;
|
|
86
|
-
particles[x] += particles[dx] * deltaTSec;
|
|
87
|
-
particles[y] += particles[dy] * deltaTSec;
|
|
88
|
-
// fade particle out ( very late);
|
|
89
|
-
particles[a] *= 1 - Math.pow(animationT, 15); // 255 - Math.sqrt(particles[dx] * particles[dx] + particles[dy] * particles[dy]) / 1.2;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
static drawParticles(drawCtx, particles) {
|
|
93
|
-
const { width, height } = drawCtx.canvas;
|
|
94
|
-
drawCtx.clearRect(0, 0, width, height);
|
|
95
|
-
const image = drawCtx.getImageData(0, 0, width, height);
|
|
96
|
-
const imageData = image.data;
|
|
97
|
-
for (let i = 0; i < particles.length; i += PARTICLE_BYTE_LENGTH) {
|
|
98
|
-
const particleX = particles[i];
|
|
99
|
-
const particleY = particles[i + 1];
|
|
100
|
-
const pI = WsThanosService.getParticleIndicesForBase(i);
|
|
101
|
-
if (particleX > width ||
|
|
102
|
-
particleX < 0 ||
|
|
103
|
-
particleY > height ||
|
|
104
|
-
particleY < 0 ||
|
|
105
|
-
particles[pI.a] < MIN_PARTICLE_ALPHA) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
const { r, g, b, a } = WsThanosService.getColorIndicesForCoord(~~particles[pI.x], ~~particles[pI.y], width);
|
|
109
|
-
imageData[r] = ~~particles[pI.r];
|
|
110
|
-
imageData[g] = ~~particles[pI.g];
|
|
111
|
-
imageData[b] = ~~particles[pI.b];
|
|
112
|
-
imageData[a] = ~~particles[pI.a];
|
|
113
|
-
}
|
|
114
|
-
drawCtx.putImageData(image, 0, 0);
|
|
115
|
-
}
|
|
116
|
-
static prepareCanvasForVaporize(divCanvas, maxParticleCount) {
|
|
117
|
-
const { width, height } = divCanvas;
|
|
118
|
-
// scale result canvas to have more room to draw particles while vaporizing;
|
|
119
|
-
const resultHeight = height * HEIGHT_SCALE;
|
|
120
|
-
const resultWidth = width * WIDTH_SCALE;
|
|
121
|
-
const resultCanvas = document.createElement('canvas');
|
|
122
|
-
resultCanvas.height = resultHeight;
|
|
123
|
-
resultCanvas.width = resultWidth;
|
|
124
|
-
const imageData = divCanvas
|
|
125
|
-
.getContext('2d')
|
|
126
|
-
?.getImageData(0, 0, width, height);
|
|
127
|
-
if (imageData == null) {
|
|
128
|
-
throw new Error('Could not get image data from canvas');
|
|
129
|
-
}
|
|
130
|
-
const particlesData = WsThanosService.createParticlesForImageData(imageData, maxParticleCount, resultHeight);
|
|
131
|
-
return { resultCanvas, particlesData };
|
|
132
|
-
}
|
|
133
|
-
static createParticlesForImageData(imageData, maxParticleCount, resultHeight) {
|
|
134
|
-
const { width, height } = imageData;
|
|
135
|
-
let particleCandidates = 0;
|
|
136
|
-
let particleCount = 0;
|
|
137
|
-
const particleCandiatesList = [];
|
|
138
|
-
for (let y = 0; y < height; y++) {
|
|
139
|
-
for (let x = 0; x < width; x++) {
|
|
140
|
-
const { a } = WsThanosService.getColorIndicesForCoord(x, y, width);
|
|
141
|
-
if (imageData.data[a] >= MIN_PARTICLE_ALPHA) {
|
|
142
|
-
particleCandidates++;
|
|
143
|
-
particleCandiatesList.push({ x, y });
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const maxNumParticles = Math.min(particleCandidates, maxParticleCount);
|
|
148
|
-
const particles = new Float32Array(Float32Array.BYTES_PER_ELEMENT * maxNumParticles * PARTICLE_BYTE_LENGTH);
|
|
149
|
-
let maxParticleX = 0;
|
|
150
|
-
let minParticleY = resultHeight;
|
|
151
|
-
while (particleCount < maxNumParticles) {
|
|
152
|
-
// select random index from candiates
|
|
153
|
-
const index = ~~(Math.random() * particleCandiatesList.length);
|
|
154
|
-
const { x, y } = particleCandiatesList[index];
|
|
155
|
-
// overwrite index with last element to prevent double selection of particles
|
|
156
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
157
|
-
particleCandiatesList[index] = particleCandiatesList.pop();
|
|
158
|
-
maxParticleX = Math.max(maxParticleX, x);
|
|
159
|
-
minParticleY = Math.min(minParticleY, y);
|
|
160
|
-
const { dx, dy, ax, ay, r, g, b, a, ...xy } = WsThanosService.getParticleIndicesForBase(particleCount * PARTICLE_BYTE_LENGTH);
|
|
161
|
-
particles[xy.x] = x;
|
|
162
|
-
particles[xy.y] = y + resultHeight - height;
|
|
163
|
-
particles[dx] = 0;
|
|
164
|
-
particles[dy] = 0;
|
|
165
|
-
particles[ax] = 0;
|
|
166
|
-
particles[ay] = 0;
|
|
167
|
-
const indicesImage = WsThanosService.getColorIndicesForCoord(x, y, width);
|
|
168
|
-
particles[r] = imageData.data[indicesImage.r];
|
|
169
|
-
particles[g] = imageData.data[indicesImage.g];
|
|
170
|
-
particles[b] = imageData.data[indicesImage.b];
|
|
171
|
-
particles[a] = imageData.data[indicesImage.a];
|
|
172
|
-
particleCount++;
|
|
173
|
-
}
|
|
174
|
-
return { particles, maxParticleX, minParticleY };
|
|
175
|
-
}
|
|
176
|
-
static getXYFromFlowField(noise, seed, x, y) {
|
|
177
|
-
const sampleX = noise.scaled3D(x, y, seed + 33.23, FLOW_FIELD_RES);
|
|
178
|
-
const sampleY = noise.scaled3D(x, seed / 13.23, y, FLOW_FIELD_RES) * -1;
|
|
179
|
-
return [sampleX, sampleY];
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* start the vaporize-effect.
|
|
183
|
-
*
|
|
184
|
-
* It's running outside the ngZone.
|
|
185
|
-
*/
|
|
186
|
-
vaporize(elem) {
|
|
187
|
-
return this.ngZone.runOutsideAngular(() => this.vaporizeIntern(elem));
|
|
188
|
-
}
|
|
189
|
-
vaporizeIntern(elem) {
|
|
190
|
-
elem.style.opacity = elem.style.opacity || '1';
|
|
191
|
-
elem.style.transition = `opacity ${Math.floor(this.thanosOptions.animationLength * 0.8)}ms ease-out`;
|
|
192
|
-
const noise = new SimplexNoise({ frequency: 0.01, min: 0 });
|
|
193
|
-
const seed = new Date().getDate() * Math.random();
|
|
194
|
-
const html2CanvasPromise = html2canvas(elem, {
|
|
195
|
-
backgroundColor: null,
|
|
196
|
-
scale: 1,
|
|
197
|
-
allowTaint: true,
|
|
198
|
-
windowHeight: window.innerHeight,
|
|
199
|
-
windowWidth: window.innerWidth,
|
|
200
|
-
scrollY: -window.scrollY,
|
|
201
|
-
});
|
|
202
|
-
return from(html2CanvasPromise).pipe(map((canvasFromHtmlElem) => {
|
|
203
|
-
const canvasAndParticles = WsThanosService.prepareCanvasForVaporize(canvasFromHtmlElem, this.thanosOptions.maxParticleCount);
|
|
204
|
-
const { resultCanvas } = canvasAndParticles;
|
|
205
|
-
if (elem.parentElement) {
|
|
206
|
-
elem.parentElement.style.position =
|
|
207
|
-
elem.parentElement.style.position || 'relative';
|
|
208
|
-
}
|
|
209
|
-
resultCanvas.style.position = 'absolute';
|
|
210
|
-
resultCanvas.style.left = 0 + 'px';
|
|
211
|
-
resultCanvas.style.top =
|
|
212
|
-
'-' + elem.getBoundingClientRect().height * (HEIGHT_SCALE - 1) + 'px';
|
|
213
|
-
resultCanvas.style.zIndex = '2000';
|
|
214
|
-
resultCanvas.style.pointerEvents = 'none';
|
|
215
|
-
elem.insertAdjacentElement('beforebegin', resultCanvas);
|
|
216
|
-
// this should start the transition above defined
|
|
217
|
-
elem.style.opacity = '0';
|
|
218
|
-
return canvasAndParticles;
|
|
219
|
-
}), switchMap(({ resultCanvas, particlesData }) => {
|
|
220
|
-
let time = 0;
|
|
221
|
-
const { animationLength, maxParticleCount, particleAcceleration } = this.thanosOptions;
|
|
222
|
-
return interval(1000 / 60, animationFrameScheduler).pipe(timeInterval(), tap((deltaT) => (time += deltaT.interval)), map((deltaT) => ({
|
|
223
|
-
deltaTSec: deltaT.interval / 1000,
|
|
224
|
-
animationT: time / animationLength,
|
|
225
|
-
maxWidth: resultCanvas.width,
|
|
226
|
-
maxHeight: resultCanvas.height,
|
|
227
|
-
})), tap((animationState) => {
|
|
228
|
-
WsThanosService.updateParticles({
|
|
229
|
-
particlesData,
|
|
230
|
-
animationState,
|
|
231
|
-
thanosOptions: {
|
|
232
|
-
animationLength,
|
|
233
|
-
maxParticleCount,
|
|
234
|
-
particleAcceleration,
|
|
235
|
-
},
|
|
236
|
-
noise,
|
|
237
|
-
seed,
|
|
238
|
-
});
|
|
239
|
-
const context = resultCanvas.getContext('2d');
|
|
240
|
-
if (context) {
|
|
241
|
-
WsThanosService.drawParticles(context, particlesData.particles);
|
|
242
|
-
}
|
|
243
|
-
}), takeWhile((animationState) => animationState.animationT <= 1), tap({
|
|
244
|
-
complete: () => {
|
|
245
|
-
return resultCanvas.remove();
|
|
246
|
-
},
|
|
247
|
-
}));
|
|
248
|
-
}));
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
WsThanosService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: WsThanosService, deps: [{ token: WS_THANOS_OPTIONS_TOKEN }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
252
|
-
WsThanosService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: WsThanosService, providedIn: 'root' });
|
|
253
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: WsThanosService, decorators: [{
|
|
254
|
-
type: Injectable,
|
|
255
|
-
args: [{ providedIn: 'root' }]
|
|
256
|
-
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
257
|
-
type: Inject,
|
|
258
|
-
args: [WS_THANOS_OPTIONS_TOKEN]
|
|
259
|
-
}] }, { type: i0.NgZone }]; } });
|
|
260
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3MtdGhhbm9zLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL3B1YmxpYy93cy10aGFub3Mvc3JjL2xpYi93cy10aGFub3Muc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFM0QsT0FBTyxFQUFFLE9BQU8sSUFBSSxXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDckQsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixJQUFJLEVBQ0osUUFBUSxFQUNSLEdBQUcsRUFFSCxTQUFTLEVBQ1QsU0FBUyxFQUNULEdBQUcsRUFDSCxZQUFZLEdBQ2IsTUFBTSxNQUFNLENBQUM7QUFDZCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7O0FBR3BFLE1BQU0sb0JBQW9CLEdBQUcsRUFBRSxDQUFDO0FBQ2hDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDO0FBQzFDLE1BQU0sWUFBWSxHQUFHLENBQUMsQ0FBQztBQUN2QixNQUFNLFdBQVcsR0FBRyxDQUFDLENBQUM7QUFDdEIsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDO0FBcUM1QixNQUFNLE9BQU8sZUFBZTtJQUMxQixZQUVVLGFBQThCLEVBQzlCLE1BQWM7UUFEZCxrQkFBYSxHQUFiLGFBQWEsQ0FBaUI7UUFDOUIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtJQUNyQixDQUFDO0lBRUksTUFBTSxDQUFDLHlCQUF5QixDQUFDLElBQVk7UUFDbkQsT0FBTztZQUNMLENBQUMsRUFBRSxJQUFJO1lBQ1AsQ0FBQyxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1gsRUFBRSxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1osRUFBRSxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1osRUFBRSxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1osRUFBRSxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1osQ0FBQyxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1gsQ0FBQyxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1gsQ0FBQyxFQUFFLElBQUksR0FBRyxDQUFDO1lBQ1gsQ0FBQyxFQUFFLElBQUksR0FBRyxDQUFDO1NBQ1osQ0FBQztJQUNKLENBQUM7SUFFTyxNQUFNLENBQUMsdUJBQXVCLENBQ3BDLENBQVMsRUFDVCxDQUFTLEVBQ1QsS0FBYTtRQUViLE1BQU0sR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BDLE9BQU8sRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUM7SUFDeEQsQ0FBQztJQUVPLE1BQU0sQ0FBQyxlQUFlLENBQUMsRUFDN0IsSUFBSSxFQUNKLEtBQUssRUFDTCxhQUFhLEVBQ2IsYUFBYSxFQUNiLGNBQWMsR0FDTztRQUNyQixNQUFNLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLEdBQUcsY0FBYyxDQUFDO1FBQ3RFLE1BQU0sRUFBRSxvQkFBb0IsRUFBRSxHQUFHLGFBQWEsQ0FBQztRQUMvQyxNQUFNLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsR0FBRyxhQUFhLENBQUM7UUFFaEUsd0RBQXdEO1FBQ3hELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQztRQUV4RCxNQUFNLGdCQUFnQixHQUFHLFlBQVksR0FBRyxJQUFJLEdBQUcsWUFBWSxDQUFDO1FBQzVELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxHQUFHLENBQUMsU0FBUyxHQUFHLFlBQVksQ0FBQyxHQUFHLFlBQVksQ0FBQztRQUUxRSxNQUFNLE9BQU8sR0FBRyxTQUFTLEdBQUcsZ0JBQWdCLENBQUM7UUFDN0MsTUFBTSxtQkFBbUIsR0FDdkIsZ0JBQWdCLEdBQUcsZ0JBQWdCLEdBQUcsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUUxRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksb0JBQW9CLEVBQUU7WUFDL0QsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxHQUMvQixlQUFlLENBQUMseUJBQXlCLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0MsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUUvQix5REFBeUQ7WUFDekQsSUFDRSxTQUFTLEdBQUcsUUFBUTtnQkFDcEIsU0FBUyxHQUFHLENBQUM7Z0JBQ2IsU0FBUyxHQUFHLFNBQVM7Z0JBQ3JCLFNBQVMsR0FBRyxDQUFDO2dCQUNiLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxrQkFBa0IsRUFDakM7Z0JBQ0EsU0FBUzthQUNWO1lBRUQsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRTtnQkFDakUsSUFBSSxRQUFRLEdBQUcsU0FBUyxHQUFHLFNBQVMsQ0FBQztnQkFDckMsSUFBSSxRQUFRLEdBQUcsU0FBUyxDQUFDO2dCQUV6Qiw0R0FBNEc7Z0JBQzVHLDhCQUE4QjtnQkFDOUIsUUFBUSxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLEdBQUcsQ0FBQztnQkFDN0QsUUFBUSxJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQyxHQUFHLEdBQUcsQ0FBQztnQkFDMUMsUUFBUTtvQkFDTixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxHQUFHLEVBQUUsR0FBRyxPQUFPLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDaEUsUUFBUSxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsSUFBSSxHQUFHLElBQUksR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUM7Z0JBQ2xFLFFBQVE7b0JBQ04sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsR0FBRyxHQUFHLEdBQUcsUUFBUSxDQUFDLEdBQUcsSUFBSSxHQUFHLElBQUksR0FBRyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBRW5FLE1BQU0sT0FBTyxHQUFHLFFBQVEsR0FBRyxRQUFRLEdBQUcsUUFBUSxHQUFHLFFBQVEsQ0FBQztnQkFDMUQsSUFBSSxPQUFPLEdBQUcsbUJBQW1CLEVBQUU7b0JBQ2pDLFNBQVMsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQzlCLFNBQVMsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7aUJBQ3BDO2FBQ0Y7aUJBQU07Z0JBQ0wseUNBQXlDO2dCQUN6QyxNQUFNLFlBQVksR0FBRyxlQUFlLENBQUMsa0JBQWtCLENBQ3JELEtBQUssRUFDTCxJQUFJLEVBQ0osU0FBUyxFQUNULFNBQVMsQ0FDVixDQUFDO2dCQUNGLE1BQU0sYUFBYSxHQUFHLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDdEMsTUFBTSxhQUFhLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN0QyxTQUFTLENBQUMsRUFBRSxDQUFDLElBQUksYUFBYSxDQUFDO2dCQUMvQixTQUFTLENBQUMsRUFBRSxDQUFDLElBQUksYUFBYSxDQUFDO2FBQ2hDO1lBRUQsZ0NBQWdDO1lBQ2hDLFNBQVMsQ0FBQyxFQUFFLENBQUMsSUFBSSxTQUFTLENBQUMsRUFBRSxDQUFDLEdBQUcsb0JBQW9CLEdBQUcsU0FBUyxDQUFDO1lBQ2xFLFNBQVMsQ0FBQyxFQUFFLENBQUMsSUFBSSxTQUFTLENBQUMsRUFBRSxDQUFDLEdBQUcsb0JBQW9CLEdBQUcsU0FBUyxDQUFDO1lBQ2xFLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxTQUFTLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDO1lBQzFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxTQUFTLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDO1lBQzFDLGtDQUFrQztZQUNsQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsd0ZBQXdGO1NBQ3ZJO0lBQ0gsQ0FBQztJQUVPLE1BQU0sQ0FBQyxhQUFhLENBQzFCLE9BQWlDLEVBQ2pDLFNBQXVCO1FBRXZCLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQztRQUN6QyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3ZDLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDeEQsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztRQUM3QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksb0JBQW9CLEVBQUU7WUFDL0QsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDbkMsTUFBTSxFQUFFLEdBQUcsZUFBZSxDQUFDLHlCQUF5QixDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3hELElBQ0UsU0FBUyxHQUFHLEtBQUs7Z0JBQ2pCLFNBQVMsR0FBRyxDQUFDO2dCQUNiLFNBQVMsR0FBRyxNQUFNO2dCQUNsQixTQUFTLEdBQUcsQ0FBQztnQkFDYixTQUFTLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLGtCQUFrQixFQUNwQztnQkFDQSxTQUFTO2FBQ1Y7WUFDRCxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUcsZUFBZSxDQUFDLHVCQUF1QixDQUM1RCxDQUFDLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFDakIsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQ2pCLEtBQUssQ0FDTixDQUFDO1lBQ0YsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2pDLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNqQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDakMsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ2xDO1FBQ0QsT0FBTyxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFTyxNQUFNLENBQUMsd0JBQXdCLENBQ3JDLFNBQTRCLEVBQzVCLGdCQUF3QjtRQUt4QixNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQztRQUVwQyw0RUFBNEU7UUFDNUUsTUFBTSxZQUFZLEdBQUcsTUFBTSxHQUFHLFlBQVksQ0FBQztRQUMzQyxNQUFNLFdBQVcsR0FBRyxLQUFLLEdBQUcsV0FBVyxDQUFDO1FBQ3hDLE1BQU0sWUFBWSxHQUFzQixRQUFRLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3pFLFlBQVksQ0FBQyxNQUFNLEdBQUcsWUFBWSxDQUFDO1FBQ25DLFlBQVksQ0FBQyxLQUFLLEdBQUcsV0FBVyxDQUFDO1FBRWpDLE1BQU0sU0FBUyxHQUFHLFNBQVM7YUFDeEIsVUFBVSxDQUFDLElBQUksQ0FBQztZQUNqQixFQUFFLFlBQVksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztRQUN0QyxJQUFJLFNBQVMsSUFBSSxJQUFJLEVBQUU7WUFDckIsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1NBQ3pEO1FBQ0QsTUFBTSxhQUFhLEdBQUcsZUFBZSxDQUFDLDJCQUEyQixDQUMvRCxTQUFTLEVBQ1QsZ0JBQWdCLEVBQ2hCLFlBQVksQ0FDYixDQUFDO1FBQ0YsT0FBTyxFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsQ0FBQztJQUN6QyxDQUFDO0lBRU8sTUFBTSxDQUFDLDJCQUEyQixDQUN4QyxTQUFvQixFQUNwQixnQkFBd0IsRUFDeEIsWUFBb0I7UUFFcEIsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUM7UUFDcEMsSUFBSSxrQkFBa0IsR0FBRyxDQUFDLENBQUM7UUFDM0IsSUFBSSxhQUFhLEdBQUcsQ0FBQyxDQUFDO1FBRXRCLE1BQU0scUJBQXFCLEdBQStCLEVBQUUsQ0FBQztRQUM3RCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQy9CLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7Z0JBQzlCLE1BQU0sRUFBRSxDQUFDLEVBQUUsR0FBRyxlQUFlLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFDbkUsSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLGtCQUFrQixFQUFFO29CQUMzQyxrQkFBa0IsRUFBRSxDQUFDO29CQUNyQixxQkFBcUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztpQkFDdEM7YUFDRjtTQUNGO1FBRUQsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sU0FBUyxHQUFHLElBQUksWUFBWSxDQUNoQyxZQUFZLENBQUMsaUJBQWlCLEdBQUcsZUFBZSxHQUFHLG9CQUFvQixDQUN4RSxDQUFDO1FBRUYsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUFDO1FBQ3JCLElBQUksWUFBWSxHQUFHLFlBQVksQ0FBQztRQUNoQyxPQUFPLGFBQWEsR0FBRyxlQUFlLEVBQUU7WUFDdEMscUNBQXFDO1lBQ3JDLE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUMvRCxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRTlDLDZFQUE2RTtZQUM3RSxvRUFBb0U7WUFDcEUscUJBQXFCLENBQUMsS0FBSyxDQUFDLEdBQUcscUJBQXFCLENBQUMsR0FBRyxFQUFHLENBQUM7WUFFNUQsWUFBWSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3pDLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsQ0FBQztZQUN6QyxNQUFNLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBRSxHQUN6QyxlQUFlLENBQUMseUJBQXlCLENBQ3ZDLGFBQWEsR0FBRyxvQkFBb0IsQ0FDckMsQ0FBQztZQUNKLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3BCLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFlBQVksR0FBRyxNQUFNLENBQUM7WUFDNUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNsQixTQUFTLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ2xCLFNBQVMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDbEIsU0FBUyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUVsQixNQUFNLFlBQVksR0FBRyxlQUFlLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUUxRSxTQUFTLENBQUMsQ0FBQyxDQUFDLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDOUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzlDLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM5QyxTQUFTLENBQUMsQ0FBQyxDQUFDLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDOUMsYUFBYSxFQUFFLENBQUM7U0FDakI7UUFDRCxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsQ0FBQztJQUNuRCxDQUFDO0lBRU8sTUFBTSxDQUFDLGtCQUFrQixDQUMvQixLQUFtQixFQUNuQixJQUFZLEVBQ1osQ0FBUyxFQUNULENBQVM7UUFFVCxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxHQUFHLEtBQUssRUFBRSxjQUFjLENBQUMsQ0FBQztRQUNuRSxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxJQUFJLEdBQUcsS0FBSyxFQUFFLENBQUMsRUFBRSxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN4RSxPQUFPLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzVCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsUUFBUSxDQUFDLElBQWlCO1FBQ3hCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVPLGNBQWMsQ0FBQyxJQUFpQjtRQUN0QyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sSUFBSSxHQUFHLENBQUM7UUFDL0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLEdBQUcsV0FBVyxJQUFJLENBQUMsS0FBSyxDQUMzQyxJQUFJLENBQUMsYUFBYSxDQUFDLGVBQWUsR0FBRyxHQUFHLENBQ3pDLGFBQWEsQ0FBQztRQUNmLE1BQU0sS0FBSyxHQUFHLElBQUksWUFBWSxDQUFDLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM1RCxNQUFNLElBQUksR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNsRCxNQUFNLGtCQUFrQixHQUErQixXQUFXLENBQUMsSUFBSSxFQUFFO1lBQ3ZFLGVBQWUsRUFBRSxJQUFJO1lBQ3JCLEtBQUssRUFBRSxDQUFDO1lBQ1IsVUFBVSxFQUFFLElBQUk7WUFDaEIsWUFBWSxFQUFFLE1BQU0sQ0FBQyxXQUFXO1lBQ2hDLFdBQVcsRUFBRSxNQUFNLENBQUMsVUFBVTtZQUM5QixPQUFPLEVBQUUsQ0FBQyxNQUFNLENBQUMsT0FBTztTQUN6QixDQUFDLENBQUM7UUFFSCxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLElBQUksQ0FDbEMsR0FBRyxDQUFDLENBQUMsa0JBQWtCLEVBQUUsRUFBRTtZQUN6QixNQUFNLGtCQUFrQixHQUFHLGVBQWUsQ0FBQyx3QkFBd0IsQ0FDakUsa0JBQWtCLEVBQ2xCLElBQUksQ0FBQyxhQUFhLENBQUMsZ0JBQWdCLENBQ3BDLENBQUM7WUFDRixNQUFNLEVBQUUsWUFBWSxFQUFFLEdBQUcsa0JBQWtCLENBQUM7WUFDNUMsSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFO2dCQUN0QixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxRQUFRO29CQUMvQixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxRQUFRLElBQUksVUFBVSxDQUFDO2FBQ25EO1lBQ0QsWUFBWSxDQUFDLEtBQUssQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO1lBQ3pDLFlBQVksQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUM7WUFDbkMsWUFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHO2dCQUNwQixHQUFHLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUMsTUFBTSxHQUFHLENBQUMsWUFBWSxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUN4RSxZQUFZLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7WUFDbkMsWUFBWSxDQUFDLEtBQUssQ0FBQyxhQUFhLEdBQUcsTUFBTSxDQUFDO1lBRTFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxhQUFhLEVBQUUsWUFBWSxDQUFDLENBQUM7WUFDeEQsaURBQWlEO1lBQ2pELElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQztZQUN6QixPQUFPLGtCQUFrQixDQUFDO1FBQzVCLENBQUMsQ0FBQyxFQUNGLFNBQVMsQ0FBQyxDQUFDLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxFQUFFLEVBQUU7WUFDNUMsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO1lBQ2IsTUFBTSxFQUFFLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxvQkFBb0IsRUFBRSxHQUMvRCxJQUFJLENBQUMsYUFBYSxDQUFDO1lBQ3JCLE9BQU8sUUFBUSxDQUFDLElBQUksR0FBRyxFQUFFLEVBQUUsdUJBQXVCLENBQUMsQ0FBQyxJQUFJLENBQ3RELFlBQVksRUFBRSxFQUNkLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQzFDLEdBQUcsQ0FDRCxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQ1QsQ0FBQztnQkFDQyxTQUFTLEVBQUUsTUFBTSxDQUFDLFFBQVEsR0FBRyxJQUFJO2dCQUNqQyxVQUFVLEVBQUUsSUFBSSxHQUFHLGVBQWU7Z0JBQ2xDLFFBQVEsRUFBRSxZQUFZLENBQUMsS0FBSztnQkFDNUIsU0FBUyxFQUFFLFlBQVksQ0FBQyxNQUFNO2FBQ1osQ0FBQSxDQUN2QixFQUNELEdBQUcsQ0FBQyxDQUFDLGNBQWMsRUFBRSxFQUFFO2dCQUNyQixlQUFlLENBQUMsZUFBZSxDQUFDO29CQUM5QixhQUFhO29CQUNiLGNBQWM7b0JBQ2QsYUFBYSxFQUFFO3dCQUNiLGVBQWU7d0JBQ2YsZ0JBQWdCO3dCQUNoQixvQkFBb0I7cUJBQ3JCO29CQUNELEtBQUs7b0JBQ0wsSUFBSTtpQkFDTCxDQUFDLENBQUM7Z0JBQ0gsTUFBTSxPQUFPLEdBQUcsWUFBWSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDOUMsSUFBSSxPQUFPLEVBQUU7b0JBQ1gsZUFBZSxDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2lCQUNqRTtZQUNILENBQUMsQ0FBQyxFQUNGLFNBQVMsQ0FBQyxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUMsY0FBYyxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUMsRUFDN0QsR0FBRyxDQUFDO2dCQUNGLFFBQVEsRUFBRSxHQUFHLEVBQUU7b0JBQ2IsT0FBTyxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQy9CLENBQUM7YUFDRixDQUFDLENBQ0gsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDOzs0R0FqVlUsZUFBZSxrQkFFaEIsdUJBQXVCO2dIQUZ0QixlQUFlLGNBREYsTUFBTTsyRkFDbkIsZUFBZTtrQkFEM0IsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUU7OzBCQUc3QixNQUFNOzJCQUFDLHVCQUF1QiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSwgTmdab25lIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IGRlZmF1bHQgYXMgaHRtbDJjYW52YXMgfSBmcm9tICdodG1sMmNhbnZhcyc7XG5pbXBvcnQge1xuICBhbmltYXRpb25GcmFtZVNjaGVkdWxlcixcbiAgZnJvbSxcbiAgaW50ZXJ2YWwsXG4gIG1hcCxcbiAgT2JzZXJ2YWJsZSxcbiAgc3dpdGNoTWFwLFxuICB0YWtlV2hpbGUsXG4gIHRhcCxcbiAgdGltZUludGVydmFsLFxufSBmcm9tICdyeGpzJztcbmltcG9ydCB7IFNpbXBsZXhOb2lzZSB9IGZyb20gJy4vc2ltcGxleC1ub2lzZSc7XG5pbXBvcnQgeyBXU19USEFOT1NfT1BUSU9OU19UT0tFTiB9IGZyb20gJy4vd3MtdGhhbm9zLW9wdGlvbnMudG9rZW4nO1xuaW1wb3J0IHR5cGUgeyBXc1RoYW5vc09wdGlvbnMgfSBmcm9tICcuL3dzLXRoYW5vcy5vcHRpb25zJztcblxuY29uc3QgUEFSVElDTEVfQllURV9MRU5HVEggPSAxMDtcbmNvbnN0IE1JTl9QQVJUSUNMRV9BTFBIQSA9IH5+KDI1NSAqIDAuMDEpO1xuY29uc3QgSEVJR0hUX1NDQUxFID0gNTtcbmNvbnN0IFdJRFRIX1NDQUxFID0gMjtcbmNvbnN0IEZMT1dfRklFTERfUkVTID0gMC4wNTtcblxuaW50ZXJmYWNlIFBhcnRpY2xlc0RhdGEge1xuICBwYXJ0aWNsZXM6IEZsb2F0MzJBcnJheTtcbiAgbWF4UGFydGljbGVYOiBudW1iZXI7XG4gIG1pblBhcnRpY2xlWTogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgQW5pbWF0aW9uU3RhdGUge1xuICBkZWx0YVRTZWM6IG51bWJlcjtcbiAgYW5pbWF0aW9uVDogbnVtYmVyO1xuICBtYXhXaWR0aDogbnVtYmVyO1xuICBtYXhIZWlnaHQ6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFVwZGF0ZVBhcnRpY2xlUGFyYW1zIHtcbiAgcGFydGljbGVzRGF0YTogUGFydGljbGVzRGF0YTtcbiAgYW5pbWF0aW9uU3RhdGU6IEFuaW1hdGlvblN0YXRlO1xuICB0aGFub3NPcHRpb25zOiBXc1RoYW5vc09wdGlvbnM7XG4gIG5vaXNlOiBTaW1wbGV4Tm9pc2U7XG4gIHNlZWQ6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFBhcnRpY2xlSW5kaWNlcyB7XG4gIHg6IG51bWJlcjtcbiAgeTogbnVtYmVyO1xuICBkeDogbnVtYmVyO1xuICBkeTogbnVtYmVyO1xuICBheDogbnVtYmVyO1xuICBheTogbnVtYmVyO1xuICByOiBudW1iZXI7XG4gIGc6IG51bWJlcjtcbiAgYjogbnVtYmVyO1xuICBhOiBudW1iZXI7XG59XG5cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgV3NUaGFub3NTZXJ2aWNlIHtcbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChXU19USEFOT1NfT1BUSU9OU19UT0tFTilcbiAgICBwcml2YXRlIHRoYW5vc09wdGlvbnM6IFdzVGhhbm9zT3B0aW9ucyxcbiAgICBwcml2YXRlIG5nWm9uZTogTmdab25lXG4gICkge31cblxuICBwcml2YXRlIHN0YXRpYyBnZXRQYXJ0aWNsZUluZGljZXNGb3JCYXNlKGJhc2U6IG51bWJlcik6IFBhcnRpY2xlSW5kaWNlcyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHg6IGJhc2UsXG4gICAgICB5OiBiYXNlICsgMSxcbiAgICAgIGR4OiBiYXNlICsgMixcbiAgICAgIGR5OiBiYXNlICsgMyxcbiAgICAgIGF4OiBiYXNlICsgNCxcbiAgICAgIGF5OiBiYXNlICsgNSxcbiAgICAgIHI6IGJhc2UgKyA2LFxuICAgICAgZzogYmFzZSArIDcsXG4gICAgICBiOiBiYXNlICsgOCxcbiAgICAgIGE6IGJhc2UgKyA5LFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBnZXRDb2xvckluZGljZXNGb3JDb29yZChcbiAgICB4OiBudW1iZXIsXG4gICAgeTogbnVtYmVyLFxuICAgIHdpZHRoOiBudW1iZXJcbiAgKTogeyBhOiBudW1iZXI7IHI6IG51bWJlcjsgYjogbnVtYmVyOyBnOiBudW1iZXIgfSB7XG4gICAgY29uc3QgcmVkID0geSAqICh3aWR0aCAqIDQpICsgeCAqIDQ7XG4gICAgcmV0dXJuIHsgcjogcmVkLCBnOiByZWQgKyAxLCBiOiByZWQgKyAyLCBhOiByZWQgKyAzIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyB1cGRhdGVQYXJ0aWNsZXMoe1xuICAgIHNlZWQsXG4gICAgbm9pc2UsXG4gICAgcGFydGljbGVzRGF0YSxcbiAgICB0aGFub3NPcHRpb25zLFxuICAgIGFuaW1hdGlvblN0YXRlLFxuICB9OiBVcGRhdGVQYXJ0aWNsZVBhcmFtcyk6IHZvaWQge1xuICAgIGNvbnN0IHsgZGVsdGFUU2VjLCBhbmltYXRpb25ULCBtYXhXaWR0aCwgbWF4SGVpZ2h0IH0gPSBhbmltYXRpb25TdGF0ZTtcbiAgICBjb25zdCB7IHBhcnRpY2xlQWNjZWxlcmF0aW9uIH0gPSB0aGFub3NPcHRpb25zO1xuICAgIGNvbnN0IHsgcGFydGljbGVzLCBtYXhQYXJ0aWNsZVgsIG1pblBhcnRpY2xlWSB9ID0gcGFydGljbGVzRGF0YTtcblxuICAgIC8vIHRoZSB0aW1lIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSB2YXBvcml6YXRpb24gZnJvbnQuXG4gICAgY29uc3QgdGltZSA9IE1hdGguc2luKGFuaW1hdGlvblQgKiAoTWF0aC5QSSAvIDIpKSAqIDEuMTtcblxuICAgIGNvbnN0IHN0YXJ0QWNjZWxlcmF0ZVggPSBtYXhQYXJ0aWNsZVggLSB0aW1lICogbWF4UGFydGljbGVYO1xuICAgIGNvbnN0IHN0YXJ0QWNjZWxlcmF0ZVkgPSB0aW1lICogKG1heEhlaWdodCAtIG1pblBhcnRpY2xlWSkgKyBtaW5QYXJ0aWNsZVk7XG5cbiAgICBjb25zdCBsZW5ndGhZID0gbWF4SGVpZ2h0IC0gc3RhcnRBY2NlbGVyYXRlWTtcbiAgICBjb25zdCBhY2NlbGVyYXRlUmFkaXVzUG93ID1cbiAgICAgIHN0YXJ0QWNjZWxlcmF0ZVggKiBzdGFydEFjY2VsZXJhdGVYICsgbGVuZ3RoWSAqIGxlbmd0aFk7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcnRpY2xlcy5sZW5ndGg7IGkgKz0gUEFSVElDTEVfQllURV9MRU5HVEgpIHtcbiAgICAgIGNvbnN0IHsgeCwgeSwgZHgsIGR5LCBheCwgYXksIGEgfSA9XG4gICAgICAgIFdzVGhhbm9zU2VydmljZS5nZXRQYXJ0aWNsZUluZGljZXNGb3JCYXNlKGkpO1xuICAgICAgY29uc3QgcGFydGljbGVYID0gcGFydGljbGVzW3hdO1xuICAgICAgY29uc3QgcGFydGljbGVZID0gcGFydGljbGVzW3ldO1xuXG4gICAgICAvLyBvbmx5IHVwZGF0ZSBwYXJ0aWNsZXMgdGhhdCBhcmUgaW5zaWRlIHZpZXcgYW5kIHZpc2libGVcbiAgICAgIGlmIChcbiAgICAgICAgcGFydGljbGVYID4gbWF4V2lkdGggfHxcbiAgICAgICAgcGFydGljbGVYIDwgMCB8fFxuICAgICAgICBwYXJ0aWNsZVkgPiBtYXhIZWlnaHQgfHxcbiAgICAgICAgcGFydGljbGVZIDwgMCB8fFxuICAgICAgICBwYXJ0aWNsZXNbYV0gPCBNSU5fUEFSVElDTEVfQUxQSEFcbiAgICAgICkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCEoTWF0aC5hYnMocGFydGljbGVzW2F4XSkgPiAwIHx8IE1hdGguYWJzKHBhcnRpY2xlc1theV0pID4gMCkpIHtcbiAgICAgICAgbGV0IHBZTGVuZ3RoID0gbWF4SGVpZ2h0IC0gcGFydGljbGVZO1xuICAgICAgICBsZXQgcFhMZW5ndGggPSBwYXJ0aWNsZVg7XG5cbiAgICAgICAgLy8gd2UgY2FsY3VsYXRlIHNvbWUgcmFuZG9tIGxvb2tpbmcgbnVtYmVycyBhbmQgZnVuY3Rpb25zIHRvIGhhdmUgbmljZSBsb29raW5nIHZhcG9yaXppbmcgZnJvbnQgb2YgcGFydGljbGVzXG4gICAgICAgIC8vIHRvZG8gY29uc2lkZXIgdG8gdXNlIG5vaXNlO1xuICAgICAgICBwWExlbmd0aCArPSBNYXRoLnRhbigocFhMZW5ndGggLyAyMC4xMikgKiB0aW1lICsgc2VlZCkgKiAwLjU7XG4gICAgICAgIHBYTGVuZ3RoICs9IChwYXJ0aWNsZVggJSBkZWx0YVRTZWMpICogMC41O1xuICAgICAgICBwWExlbmd0aCArPVxuICAgICAgICAgIE1hdGguc2luKChwWExlbmd0aCAvIDMwICsgNzIzLjM5NCkgKiB0aW1lICsgc2VlZCAqIDEyLjUpICogMTE7XG4gICAgICAgIHBZTGVuZ3RoICs9IE1hdGgudGFuKChwWUxlbmd0aCAvIDAuNDUpICogdGltZSArIHNlZWQgKiAxLjUpICogMC41O1xuICAgICAgICBwWUxlbmd0aCArPVxuICAgICAgICAgIE1hdGguY29zKChwWUxlbmd0aCAvIDEwMCArIDIzMjMuMjM0KSAqIHRpbWUgKyBzZWVkICogNDU2LjEpICogMjM7XG5cbiAgICAgICAgY29uc3QgcExlbmd0aCA9IHBYTGVuZ3RoICogcFhMZW5ndGggKyBwWUxlbmd0aCAqIHBZTGVuZ3RoO1xuICAgICAgICBpZiAocExlbmd0aCA+IGFjY2VsZXJhdGVSYWRpdXNQb3cpIHtcbiAgICAgICAgICBwYXJ0aWNsZXNbYXhdID0gTWF0aC5yYW5kb20oKTtcbiAgICAgICAgICBwYXJ0aWNsZXNbYXldID0gTWF0aC5yYW5kb20oKSAqIC0xO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyB1c2Ugbm9pc2UgdG8gZmxvdyBhbG9uZyB2ZWxvY2l0eSBmaWVsZFxuICAgICAgICBjb25zdCBmbG93RmllbGRBY2MgPSBXc1RoYW5vc1NlcnZpY2UuZ2V0WFlGcm9tRmxvd0ZpZWxkKFxuICAgICAgICAgIG5vaXNlLFxuICAgICAgICAgIHNlZWQsXG4gICAgICAgICAgcGFydGljbGVYLFxuICAgICAgICAgIHBhcnRpY2xlWVxuICAgICAgICApO1xuICAgICAgICBjb25zdCBhY2NlbGVyYXRpb25YID0gZmxvd0ZpZWxkQWNjWzBdO1xuICAgICAgICBjb25zdCBhY2NlbGVyYXRpb25ZID0gZmxvd0ZpZWxkQWNjWzFdO1xuICAgICAgICBwYXJ0aWNsZXNbYXhdICs9IGFjY2VsZXJhdGlvblg7XG4gICAgICAgIHBhcnRpY2xlc1theV0gKz0gYWNjZWxlcmF0aW9uWTtcbiAgICAgIH1cblxuICAgICAgLy8gKiBNYXRoLnBvdygxICsgYW5pbWF0aW9uVCwgNClcbiAgICAgIHBhcnRpY2xlc1tkeF0gKz0gcGFydGljbGVzW2F4XSAqIHBhcnRpY2xlQWNjZWxlcmF0aW9uICogZGVsdGFUU2VjO1xuICAgICAgcGFydGljbGVzW2R5XSArPSBwYXJ0aWNsZXNbYXldICogcGFydGljbGVBY2NlbGVyYXRpb24gKiBkZWx0YVRTZWM7XG4gICAgICBwYXJ0aWNsZXNbeF0gKz0gcGFydGljbGVzW2R4XSAqIGRlbHRhVFNlYztcbiAgICAgIHBhcnRpY2xlc1t5XSArPSBwYXJ0aWNsZXNbZHldICogZGVsdGFUU2VjO1xuICAgICAgLy8gZmFkZSBwYXJ0aWNsZSBvdXQgKCB2ZXJ5IGxhdGUpO1xuICAgICAgcGFydGljbGVzW2FdICo9IDEgLSBNYXRoLnBvdyhhbmltYXRpb25ULCAxNSk7IC8vIDI1NSAtIE1hdGguc3FydChwYXJ0aWNsZXNbZHhdICogcGFydGljbGVzW2R4XSArIHBhcnRpY2xlc1tkeV0gKiBwYXJ0aWNsZXNbZHldKSAvIDEuMjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBkcmF3UGFydGljbGVzKFxuICAgIGRyYXdDdHg6IENhbnZhc1JlbmRlcmluZ0NvbnRleHQyRCxcbiAgICBwYXJ0aWNsZXM6IEZsb2F0MzJBcnJheVxuICApOiB2b2lkIHtcbiAgICBjb25zdCB7IHdpZHRoLCBoZWlnaHQgfSA9IGRyYXdDdHguY2FudmFzO1xuICAgIGRyYXdDdHguY2xlYXJSZWN0KDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xuICAgIGNvbnN0IGltYWdlID0gZHJhd0N0eC5nZXRJbWFnZURhdGEoMCwgMCwgd2lkdGgsIGhlaWdodCk7XG4gICAgY29uc3QgaW1hZ2VEYXRhID0gaW1hZ2UuZGF0YTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcnRpY2xlcy5sZW5ndGg7IGkgKz0gUEFSVElDTEVfQllURV9MRU5HVEgpIHtcbiAgICAgIGNvbnN0IHBhcnRpY2xlWCA9IHBhcnRpY2xlc1tpXTtcbiAgICAgIGNvbnN0IHBhcnRpY2xlWSA9IHBhcnRpY2xlc1tpICsgMV07XG4gICAgICBjb25zdCBwSSA9IFdzVGhhbm9zU2VydmljZS5nZXRQYXJ0aWNsZUluZGljZXNGb3JCYXNlKGkpO1xuICAgICAgaWYgKFxuICAgICAgICBwYXJ0aWNsZVggPiB3aWR0aCB8fFxuICAgICAgICBwYXJ0aWNsZVggPCAwIHx8XG4gICAgICAgIHBhcnRpY2xlWSA+IGhlaWdodCB8fFxuICAgICAgICBwYXJ0aWNsZVkgPCAwIHx8XG4gICAgICAgIHBhcnRpY2xlc1twSS5hXSA8IE1JTl9QQVJUSUNMRV9BTFBIQVxuICAgICAgKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgeyByLCBnLCBiLCBhIH0gPSBXc1RoYW5vc1NlcnZpY2UuZ2V0Q29sb3JJbmRpY2VzRm9yQ29vcmQoXG4gICAgICAgIH5+cGFydGljbGVzW3BJLnhdLFxuICAgICAgICB+fnBhcnRpY2xlc1twSS55XSxcbiAgICAgICAgd2lkdGhcbiAgICAgICk7XG4gICAgICBpbWFnZURhdGFbcl0gPSB+fnBhcnRpY2xlc1twSS5yXTtcbiAgICAgIGltYWdlRGF0YVtnXSA9IH5+cGFydGljbGVzW3BJLmddO1xuICAgICAgaW1hZ2VEYXRhW2JdID0gfn5wYXJ0aWNsZXNbcEkuYl07XG4gICAgICBpbWFnZURhdGFbYV0gPSB+fnBhcnRpY2xlc1twSS5hXTtcbiAgICB9XG4gICAgZHJhd0N0eC5wdXRJbWFnZURhdGEoaW1hZ2UsIDAsIDApO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgcHJlcGFyZUNhbnZhc0ZvclZhcG9yaXplKFxuICAgIGRpdkNhbnZhczogSFRNTENhbnZhc0VsZW1lbnQsXG4gICAgbWF4UGFydGljbGVDb3VudDogbnVtYmVyXG4gICk6IHtcbiAgICBwYXJ0aWNsZXNEYXRhOiBQYXJ0aWNsZXNEYXRhO1xuICAgIHJlc3VsdENhbnZhczogSFRNTENhbnZhc0VsZW1lbnQ7XG4gIH0ge1xuICAgIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gZGl2Q2FudmFzO1xuXG4gICAgLy8gc2NhbGUgcmVzdWx0IGNhbnZhcyB0byBoYXZlIG1vcmUgcm9vbSB0byBkcmF3IHBhcnRpY2xlcyB3aGlsZSB2YXBvcml6aW5nO1xuICAgIGNvbnN0IHJlc3VsdEhlaWdodCA9IGhlaWdodCAqIEhFSUdIVF9TQ0FMRTtcbiAgICBjb25zdCByZXN1bHRXaWR0aCA9IHdpZHRoICogV0lEVEhfU0NBTEU7XG4gICAgY29uc3QgcmVzdWx0Q2FudmFzOiBIVE1MQ2FudmFzRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgIHJlc3VsdENhbnZhcy5oZWlnaHQgPSByZXN1bHRIZWlnaHQ7XG4gICAgcmVzdWx0Q2FudmFzLndpZHRoID0gcmVzdWx0V2lkdGg7XG5cbiAgICBjb25zdCBpbWFnZURhdGEgPSBkaXZDYW52YXNcbiAgICAgIC5nZXRDb250ZXh0KCcyZCcpXG4gICAgICA/LmdldEltYWdlRGF0YSgwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICBpZiAoaW1hZ2VEYXRhID09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGdldCBpbWFnZSBkYXRhIGZyb20gY2FudmFzJyk7XG4gICAgfVxuICAgIGNvbnN0IHBhcnRpY2xlc0RhdGEgPSBXc1RoYW5vc1NlcnZpY2UuY3JlYXRlUGFydGljbGVzRm9ySW1hZ2VEYXRhKFxuICAgICAgaW1hZ2VEYXRhLFxuICAgICAgbWF4UGFydGljbGVDb3VudCxcbiAgICAgIHJlc3VsdEhlaWdodFxuICAgICk7XG4gICAgcmV0dXJuIHsgcmVzdWx0Q2FudmFzLCBwYXJ0aWNsZXNEYXRhIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVQYXJ0aWNsZXNGb3JJbWFnZURhdGEoXG4gICAgaW1hZ2VEYXRhOiBJbWFnZURhdGEsXG4gICAgbWF4UGFydGljbGVDb3VudDogbnVtYmVyLFxuICAgIHJlc3VsdEhlaWdodDogbnVtYmVyXG4gICk6IHsgbWluUGFydGljbGVZOiBudW1iZXI7IG1heFBhcnRpY2xlWDogbnVtYmVyOyBwYXJ0aWNsZXM6IEZsb2F0MzJBcnJheSB9IHtcbiAgICBjb25zdCB7IHdpZHRoLCBoZWlnaHQgfSA9IGltYWdlRGF0YTtcbiAgICBsZXQgcGFydGljbGVDYW5kaWRhdGVzID0gMDtcbiAgICBsZXQgcGFydGljbGVDb3VudCA9IDA7XG5cbiAgICBjb25zdCBwYXJ0aWNsZUNhbmRpYXRlc0xpc3Q6IHsgeDogbnVtYmVyOyB5OiBudW1iZXIgfVtdID0gW107XG4gICAgZm9yIChsZXQgeSA9IDA7IHkgPCBoZWlnaHQ7IHkrKykge1xuICAgICAgZm9yIChsZXQgeCA9IDA7IHggPCB3aWR0aDsgeCsrKSB7XG4gICAgICAgIGNvbnN0IHsgYSB9ID0gV3NUaGFub3NTZXJ2aWNlLmdldENvbG9ySW5kaWNlc0ZvckNvb3JkKHgsIHksIHdpZHRoKTtcbiAgICAgICAgaWYgKGltYWdlRGF0YS5kYXRhW2FdID49IE1JTl9QQVJUSUNMRV9BTFBIQSkge1xuICAgICAgICAgIHBhcnRpY2xlQ2FuZGlkYXRlcysrO1xuICAgICAgICAgIHBhcnRpY2xlQ2FuZGlhdGVzTGlzdC5wdXNoKHsgeCwgeSB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IG1heE51bVBhcnRpY2xlcyA9IE1hdGgubWluKHBhcnRpY2xlQ2FuZGlkYXRlcywgbWF4UGFydGljbGVDb3VudCk7XG4gICAgY29uc3QgcGFydGljbGVzID0gbmV3IEZsb2F0MzJBcnJheShcbiAgICAgIEZsb2F0MzJBcnJheS5CWVRFU19QRVJfRUxFTUVOVCAqIG1heE51bVBhcnRpY2xlcyAqIFBBUlRJQ0xFX0JZVEVfTEVOR1RIXG4gICAgKTtcblxuICAgIGxldCBtYXhQYXJ0aWNsZVggPSAwO1xuICAgIGxldCBtaW5QYXJ0aWNsZVkgPSByZXN1bHRIZWlnaHQ7XG4gICAgd2hpbGUgKHBhcnRpY2xlQ291bnQgPCBtYXhOdW1QYXJ0aWNsZXMpIHtcbiAgICAgIC8vIHNlbGVjdCByYW5kb20gaW5kZXggZnJvbSBjYW5kaWF0ZXNcbiAgICAgIGNvbnN0IGluZGV4ID0gfn4oTWF0aC5yYW5kb20oKSAqIHBhcnRpY2xlQ2FuZGlhdGVzTGlzdC5sZW5ndGgpO1xuICAgICAgY29uc3QgeyB4LCB5IH0gPSBwYXJ0aWNsZUNhbmRpYXRlc0xpc3RbaW5kZXhdO1xuXG4gICAgICAvLyBvdmVyd3JpdGUgaW5kZXggd2l0aCBsYXN0IGVsZW1lbnQgdG8gcHJldmVudCBkb3VibGUgc2VsZWN0aW9uIG9mIHBhcnRpY2xlc1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgIHBhcnRpY2xlQ2FuZGlhdGVzTGlzdFtpbmRleF0gPSBwYXJ0aWNsZUNhbmRpYXRlc0xpc3QucG9wKCkhO1xuXG4gICAgICBtYXhQYXJ0aWNsZVggPSBNYXRoLm1heChtYXhQYXJ0aWNsZVgsIHgpO1xuICAgICAgbWluUGFydGljbGVZID0gTWF0aC5taW4obWluUGFydGljbGVZLCB5KTtcbiAgICAgIGNvbnN0IHsgZHgsIGR5LCBheCwgYXksIHIsIGcsIGIsIGEsIC4uLnh5IH0gPVxuICAgICAgICBXc1RoYW5vc1NlcnZpY2UuZ2V0UGFydGljbGVJbmRpY2VzRm9yQmFzZShcbiAgICAgICAgICBwYXJ0aWNsZUNvdW50ICogUEFSVElDTEVfQllURV9MRU5HVEhcbiAgICAgICAgKTtcbiAgICAgIHBhcnRpY2xlc1t4eS54XSA9IHg7XG4gICAgICBwYXJ0aWNsZXNbeHkueV0gPSB5ICsgcmVzdWx0SGVpZ2h0IC0gaGVpZ2h0O1xuICAgICAgcGFydGljbGVzW2R4XSA9IDA7XG4gICAgICBwYXJ0aWNsZXNbZHldID0gMDtcbiAgICAgIHBhcnRpY2xlc1theF0gPSAwO1xuICAgICAgcGFydGljbGVzW2F5XSA9IDA7XG5cbiAgICAgIGNvbnN0IGluZGljZXNJbWFnZSA9IFdzVGhhbm9zU2VydmljZS5nZXRDb2xvckluZGljZXNGb3JDb29yZCh4LCB5LCB3aWR0aCk7XG5cbiAgICAgIHBhcnRpY2xlc1tyXSA9IGltYWdlRGF0YS5kYXRhW2luZGljZXNJbWFnZS5yXTtcbiAgICAgIHBhcnRpY2xlc1tnXSA9IGltYWdlRGF0YS5kYXRhW2luZGljZXNJbWFnZS5nXTtcbiAgICAgIHBhcnRpY2xlc1tiXSA9IGltYWdlRGF0YS5kYXRhW2luZGljZXNJbWFnZS5iXTtcbiAgICAgIHBhcnRpY2xlc1thXSA9IGltYWdlRGF0YS5kYXRhW2luZGljZXNJbWFnZS5hXTtcbiAgICAgIHBhcnRpY2xlQ291bnQrKztcbiAgICB9XG4gICAgcmV0dXJuIHsgcGFydGljbGVzLCBtYXhQYXJ0aWNsZVgsIG1pblBhcnRpY2xlWSB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0WFlGcm9tRmxvd0ZpZWxkKFxuICAgIG5vaXNlOiBTaW1wbGV4Tm9pc2UsXG4gICAgc2VlZDogbnVtYmVyLFxuICAgIHg6IG51bWJlcixcbiAgICB5OiBudW1iZXJcbiAgKSB7XG4gICAgY29uc3Qgc2FtcGxlWCA9IG5vaXNlLnNjYWxlZDNEKHgsIHksIHNlZWQgKyAzMy4yMywgRkxPV19GSUVMRF9SRVMpO1xuICAgIGNvbnN0IHNhbXBsZVkgPSBub2lzZS5zY2FsZWQzRCh4LCBzZWVkIC8gMTMuMjMsIHksIEZMT1dfRklFTERfUkVTKSAqIC0xO1xuICAgIHJldHVybiBbc2FtcGxlWCwgc2FtcGxlWV07XG4gIH1cblxuICAvKipcbiAgICogc3RhcnQgdGhlIHZhcG9yaXplLWVmZmVjdC5cbiAgICpcbiAgICogSXQncyBydW5uaW5nIG91dHNpZGUgdGhlIG5nWm9uZS5cbiAgICovXG4gIHZhcG9yaXplKGVsZW06IEhUTUxFbGVtZW50KTogT2JzZXJ2YWJsZTxBbmltYXRpb25TdGF0ZT4ge1xuICAgIHJldHVybiB0aGlzLm5nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB0aGlzLnZhcG9yaXplSW50ZXJuKGVsZW0pKTtcbiAgfVxuXG4gIHByaXZhdGUgdmFwb3JpemVJbnRlcm4oZWxlbTogSFRNTEVsZW1lbnQpOiBPYnNlcnZhYmxlPEFuaW1hdGlvblN0YXRlPiB7XG4gICAgZWxlbS5zdHlsZS5vcGFjaXR5ID0gZWxlbS5zdHlsZS5vcGFjaXR5IHx8ICcxJztcbiAgICBlbGVtLnN0eWxlLnRyYW5zaXRpb24gPSBgb3BhY2l0eSAke01hdGguZmxvb3IoXG4gICAgICB0aGlzLnRoYW5vc09wdGlvbnMuYW5pbWF0aW9uTGVuZ3RoICogMC44XG4gICAgKX1tcyBlYXNlLW91dGA7XG4gICAgY29uc3Qgbm9pc2UgPSBuZXcgU2ltcGxleE5vaXNlKHsgZnJlcXVlbmN5OiAwLjAxLCBtaW46IDAgfSk7XG4gICAgY29uc3Qgc2VlZCA9IG5ldyBEYXRlKCkuZ2V0RGF0ZSgpICogTWF0aC5yYW5kb20oKTtcbiAgICBjb25zdCBodG1sMkNhbnZhc1Byb21pc2U6IFByb21pc2U8SFRNTENhbnZhc0VsZW1lbnQ+ID0gaHRtbDJjYW52YXMoZWxlbSwge1xuICAgICAgYmFja2dyb3VuZENvbG9yOiBudWxsLFxuICAgICAgc2NhbGU6IDEsXG4gICAgICBhbGxvd1RhaW50OiB0cnVlLFxuICAgICAgd2luZG93SGVpZ2h0OiB3aW5kb3cuaW5uZXJIZWlnaHQsXG4gICAgICB3aW5kb3dXaWR0aDogd2luZG93LmlubmVyV2lkdGgsXG4gICAgICBzY3JvbGxZOiAtd2luZG93LnNjcm9sbFksXG4gICAgfSk7XG5cbiAgICByZXR1cm4gZnJvbShodG1sMkNhbnZhc1Byb21pc2UpLnBpcGUoXG4gICAgICBtYXAoKGNhbnZhc0Zyb21IdG1sRWxlbSkgPT4ge1xuICAgICAgICBjb25zdCBjYW52YXNBbmRQYXJ0aWNsZXMgPSBXc1RoYW5vc1NlcnZpY2UucHJlcGFyZUNhbnZhc0ZvclZhcG9yaXplKFxuICAgICAgICAgIGNhbnZhc0Zyb21IdG1sRWxlbSxcbiAgICAgICAgICB0aGlzLnRoYW5vc09wdGlvbnMubWF4UGFydGljbGVDb3VudFxuICAgICAgICApO1xuICAgICAgICBjb25zdCB7IHJlc3VsdENhbnZhcyB9ID0gY2FudmFzQW5kUGFydGljbGVzO1xuICAgICAgICBpZiAoZWxlbS5wYXJlbnRFbGVtZW50KSB7XG4gICAgICAgICAgZWxlbS5wYXJlbnRFbGVtZW50LnN0eWxlLnBvc2l0aW9uID1cbiAgICAgICAgICAgIGVsZW0ucGFyZW50RWxlbWVudC5zdHlsZS5wb3NpdGlvbiB8fCAncmVsYXRpdmUnO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdENhbnZhcy5zdHlsZS5wb3NpdGlvbiA9ICdhYnNvbHV0ZSc7XG4gICAgICAgIHJlc3VsdENhbnZhcy5zdHlsZS5sZWZ0ID0gMCArICdweCc7XG4gICAgICAgIHJlc3VsdENhbnZhcy5zdHlsZS50b3AgPVxuICAgICAgICAgICctJyArIGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0ICogKEhFSUdIVF9TQ0FMRSAtIDEpICsgJ3B4JztcbiAgICAgICAgcmVzdWx0Q2FudmFzLnN0eWxlLnpJbmRleCA9ICcyMDAwJztcbiAgICAgICAgcmVzdWx0Q2FudmFzLnN0eWxlLnBvaW50ZXJFdmVudHMgPSAnbm9uZSc7XG5cbiAgICAgICAgZWxlbS5pbnNlcnRBZGphY2VudEVsZW1lbnQoJ2JlZm9yZWJlZ2luJywgcmVzdWx0Q2FudmFzKTtcbiAgICAgICAgLy8gdGhpcyBzaG91bGQgc3RhcnQgdGhlIHRyYW5zaXRpb24gYWJvdmUgZGVmaW5lZFxuICAgICAgICBlbGVtLnN0eWxlLm9wYWNpdHkgPSAnMCc7XG4gICAgICAgIHJldHVybiBjYW52YXNBbmRQYXJ0aWNsZXM7XG4gICAgICB9KSxcbiAgICAgIHN3aXRjaE1hcCgoeyByZXN1bHRDYW52YXMsIHBhcnRpY2xlc0RhdGEgfSkgPT4ge1xuICAgICAgICBsZXQgdGltZSA9IDA7XG4gICAgICAgIGNvbnN0IHsgYW5pbWF0aW9uTGVuZ3RoLCBtYXhQYXJ0aWNsZUNvdW50LCBwYXJ0aWNsZUFjY2VsZXJhdGlvbiB9ID1cbiAgICAgICAgICB0aGlzLnRoYW5vc09wdGlvbnM7XG4gICAgICAgIHJldHVybiBpbnRlcnZhbCgxMDAwIC8gNjAsIGFuaW1hdGlvbkZyYW1lU2NoZWR1bGVyKS5waXBlKFxuICAgICAgICAgIHRpbWVJbnRlcnZhbCgpLFxuICAgICAgICAgIHRhcCgoZGVsdGFUKSA9PiAodGltZSArPSBkZWx0YVQuaW50ZXJ2YWwpKSxcbiAgICAgICAgICBtYXAoXG4gICAgICAgICAgICAoZGVsdGFUKSA9PlxuICAgICAgICAgICAgICAoe1xuICAgICAgICAgICAgICAgIGRlbHRhVFNlYzogZGVsdGFULmludGVydmFsIC8gMTAwMCxcbiAgICAgICAgICAgICAgICBhbmltYXRpb25UOiB0aW1lIC8gYW5pbWF0aW9uTGVuZ3RoLFxuICAgICAgICAgICAgICAgIG1heFdpZHRoOiByZXN1bHRDYW52YXMud2lkdGgsXG4gICAgICAgICAgICAgICAgbWF4SGVpZ2h0OiByZXN1bHRDYW52YXMuaGVpZ2h0LFxuICAgICAgICAgICAgICB9IGFzIEFuaW1hdGlvblN0YXRlKVxuICAgICAgICAgICksXG4gICAgICAgICAgdGFwKChhbmltYXRpb25TdGF0ZSkgPT4ge1xuICAgICAgICAgICAgV3NUaGFub3NTZXJ2aWNlLnVwZGF0ZVBhcnRpY2xlcyh7XG4gICAgICAgICAgICAgIHBhcnRpY2xlc0RhdGEsXG4gICAgICAgICAgICAgIGFuaW1hdGlvblN0YXRlLFxuICAgICAgICAgICAgICB0aGFub3NPcHRpb25zOiB7XG4gICAgICAgICAgICAgICAgYW5pbWF0aW9uTGVuZ3RoLFxuICAgICAgICAgICAgICAgIG1heFBhcnRpY2xlQ291bnQsXG4gICAgICAgICAgICAgICAgcGFydGljbGVBY2NlbGVyYXRpb24sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIG5vaXNlLFxuICAgICAgICAgICAgICBzZWVkLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb25zdCBjb250ZXh0ID0gcmVzdWx0Q2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgICAgICAgICBpZiAoY29udGV4dCkge1xuICAgICAgICAgICAgICBXc1RoYW5vc1NlcnZpY2UuZHJhd1BhcnRpY2xlcyhjb250ZXh0LCBwYXJ0aWNsZXNEYXRhLnBhcnRpY2xlcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSksXG4gICAgICAgICAgdGFrZVdoaWxlKChhbmltYXRpb25TdGF0ZSkgPT4gYW5pbWF0aW9uU3RhdGUuYW5pbWF0aW9uVCA8PSAxKSxcbiAgICAgICAgICB0YXAoe1xuICAgICAgICAgICAgY29tcGxldGU6ICgpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdENhbnZhcy5yZW1vdmUoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxufVxuIl19
|