angular-three-rapier 2.2.0

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.
@@ -0,0 +1,362 @@
1
+ import { ChangeDetectionStrategy, Component, computed, DestroyRef, effect, inject, input, signal, untracked, } from '@angular/core';
2
+ import { EventQueue } from '@dimforge/rapier3d-compat';
3
+ import { injectStore, pick, vector3 } from 'angular-three';
4
+ import { mergeInputs } from 'ngxtension/inject-inputs';
5
+ import { MathUtils } from 'three';
6
+ import { NgtrDebug } from './debug';
7
+ import { NgtrFrameStepper } from './frame-stepper';
8
+ import { _matrix4, _position, _rotation, _scale } from './shared';
9
+ import { createSingletonProxy, rapierQuaternionToQuaternion } from './utils';
10
+ import * as i0 from "@angular/core";
11
+ const defaultOptions = {
12
+ gravity: [0, -9.81, 0],
13
+ allowedLinearError: 0.001,
14
+ numSolverIterations: 4,
15
+ numAdditionalFrictionIterations: 4,
16
+ numInternalPgsIterations: 1,
17
+ predictionDistance: 0.002,
18
+ minIslandSize: 128,
19
+ maxCcdSubsteps: 1,
20
+ erp: 0.8,
21
+ lengthUnit: 1,
22
+ colliders: 'cuboid',
23
+ updateLoop: 'follow',
24
+ interpolate: true,
25
+ paused: false,
26
+ timeStep: 1 / 60,
27
+ debug: false,
28
+ };
29
+ export class NgtrPhysics {
30
+ options = input(defaultOptions, { transform: mergeInputs(defaultOptions) });
31
+ updatePriority = pick(this.options, 'updatePriority');
32
+ updateLoop = pick(this.options, 'updateLoop');
33
+ numSolverIterations = pick(this.options, 'numSolverIterations');
34
+ numAdditionalFrictionIterations = pick(this.options, 'numAdditionalFrictionIterations');
35
+ numInternalPgsIterations = pick(this.options, 'numInternalPgsIterations');
36
+ allowedLinearError = pick(this.options, 'allowedLinearError');
37
+ minIslandSize = pick(this.options, 'minIslandSize');
38
+ maxCcdSubsteps = pick(this.options, 'maxCcdSubsteps');
39
+ predictionDistance = pick(this.options, 'predictionDistance');
40
+ erp = pick(this.options, 'erp');
41
+ lengthUnit = pick(this.options, 'lengthUnit');
42
+ timeStep = pick(this.options, 'timeStep');
43
+ interpolate = pick(this.options, 'interpolate');
44
+ paused = pick(this.options, 'paused');
45
+ debug = pick(this.options, 'debug');
46
+ colliders = pick(this.options, 'colliders');
47
+ gravity = vector3(this.options, 'gravity');
48
+ store = injectStore();
49
+ destroyRef = inject(DestroyRef);
50
+ rapierConstruct = signal(null);
51
+ rapier = this.rapierConstruct.asReadonly();
52
+ ready = computed(() => !!this.rapier());
53
+ worldSingleton = computed(() => {
54
+ const rapier = this.rapier();
55
+ if (!rapier)
56
+ return null;
57
+ return createSingletonProxy(() => new rapier.World(untracked(this.gravity)));
58
+ });
59
+ rigidBodyStates = new Map();
60
+ colliderStates = new Map();
61
+ rigidBodyEvents = new Map();
62
+ colliderEvents = new Map();
63
+ beforeStepCallbacks = new Set();
64
+ afterStepCallbacks = new Set();
65
+ eventQueue = computed(() => {
66
+ const rapier = this.rapier();
67
+ if (!rapier)
68
+ return null;
69
+ return new EventQueue(false);
70
+ });
71
+ steppingState = { accumulator: 0, previousState: {} };
72
+ constructor() {
73
+ import('@dimforge/rapier3d-compat')
74
+ .then((rapier) => rapier.init().then(() => rapier))
75
+ .then(this.rapierConstruct.set.bind(this.rapierConstruct))
76
+ .catch((err) => {
77
+ console.error(`[NGT] Failed to load rapier3d-compat`, err);
78
+ return Promise.reject(err);
79
+ });
80
+ effect(() => {
81
+ this.updateWorldEffect();
82
+ });
83
+ this.destroyRef.onDestroy(() => {
84
+ const world = this.worldSingleton();
85
+ if (world) {
86
+ world.proxy.free();
87
+ world.reset();
88
+ }
89
+ });
90
+ }
91
+ step(delta) {
92
+ if (!this.paused()) {
93
+ this.internalStep(delta);
94
+ }
95
+ }
96
+ updateWorldEffect() {
97
+ const world = this.worldSingleton();
98
+ if (!world)
99
+ return;
100
+ world.proxy.gravity = this.gravity();
101
+ world.proxy.integrationParameters.numSolverIterations = this.numSolverIterations();
102
+ world.proxy.integrationParameters.numAdditionalFrictionIterations = this.numAdditionalFrictionIterations();
103
+ world.proxy.integrationParameters.numInternalPgsIterations = this.numInternalPgsIterations();
104
+ world.proxy.integrationParameters.normalizedAllowedLinearError = this.allowedLinearError();
105
+ world.proxy.integrationParameters.minIslandSize = this.minIslandSize();
106
+ world.proxy.integrationParameters.maxCcdSubsteps = this.maxCcdSubsteps();
107
+ world.proxy.integrationParameters.normalizedPredictionDistance = this.predictionDistance();
108
+ /**
109
+ * NOTE: we don't know if this is the correct way to set for contact_natural_frequency or not.
110
+ * but at least, it gets the `contact_erp` value to be very close with setting `erp`
111
+ */
112
+ world.proxy.integrationParameters.contact_natural_frequency = this.erp() * 1_000;
113
+ world.proxy.lengthUnit = this.lengthUnit();
114
+ }
115
+ internalStep(delta) {
116
+ const worldSingleton = this.worldSingleton();
117
+ if (!worldSingleton)
118
+ return;
119
+ const eventQueue = this.eventQueue();
120
+ if (!eventQueue)
121
+ return;
122
+ const world = worldSingleton.proxy;
123
+ const [timeStep, interpolate, paused] = [this.timeStep(), this.interpolate(), this.paused()];
124
+ /* Check if the timestep is supposed to be variable. We'll do this here
125
+ once so we don't have to string-check every frame. */
126
+ const timeStepVariable = timeStep === 'vary';
127
+ /**
128
+ * Fixed timeStep simulation progression
129
+ * @see https://gafferongames.com/post/fix_your_timestep/
130
+ */
131
+ const clampedDelta = MathUtils.clamp(delta, 0, 0.5);
132
+ const stepWorld = (innerDelta) => {
133
+ // Trigger beforeStep callbacks
134
+ this.beforeStepCallbacks.forEach((callback) => {
135
+ callback(world);
136
+ });
137
+ world.timestep = innerDelta;
138
+ world.step(eventQueue);
139
+ // Trigger afterStep callbacks
140
+ this.afterStepCallbacks.forEach((callback) => {
141
+ callback(world);
142
+ });
143
+ };
144
+ if (timeStepVariable) {
145
+ stepWorld(clampedDelta);
146
+ }
147
+ else {
148
+ // don't step time forwards if paused
149
+ // Increase accumulator
150
+ this.steppingState.accumulator += clampedDelta;
151
+ while (this.steppingState.accumulator >= timeStep) {
152
+ // Set up previous state
153
+ // needed for accurate interpolations if the world steps more than once
154
+ if (interpolate) {
155
+ this.steppingState.previousState = {};
156
+ world.forEachRigidBody((body) => {
157
+ this.steppingState.previousState[body.handle] = {
158
+ position: body.translation(),
159
+ rotation: body.rotation(),
160
+ };
161
+ });
162
+ }
163
+ stepWorld(timeStep);
164
+ this.steppingState.accumulator -= timeStep;
165
+ }
166
+ }
167
+ const interpolationAlpha = timeStepVariable || !interpolate || paused ? 1 : this.steppingState.accumulator / timeStep;
168
+ // Update meshes
169
+ this.rigidBodyStates.forEach((state, handle) => {
170
+ const rigidBody = world.getRigidBody(handle);
171
+ const events = this.rigidBodyEvents.get(handle);
172
+ if (events?.onSleep || events?.onWake) {
173
+ if (rigidBody.isSleeping() && !state.isSleeping)
174
+ events?.onSleep?.();
175
+ if (!rigidBody.isSleeping() && state.isSleeping)
176
+ events?.onWake?.();
177
+ state.isSleeping = rigidBody.isSleeping();
178
+ }
179
+ if (!rigidBody || (rigidBody.isSleeping() && !('isInstancedMesh' in state.object)) || !state.setMatrix) {
180
+ return;
181
+ }
182
+ // New states
183
+ let t = rigidBody.translation();
184
+ let r = rigidBody.rotation();
185
+ let previousState = this.steppingState.previousState[handle];
186
+ if (previousState) {
187
+ // Get previous simulated world position
188
+ _matrix4
189
+ .compose(previousState.position, rapierQuaternionToQuaternion(previousState.rotation), state.scale)
190
+ .premultiply(state.invertedWorldMatrix)
191
+ .decompose(_position, _rotation, _scale);
192
+ // Apply previous tick position
193
+ if (state.meshType == 'mesh') {
194
+ state.object.position.copy(_position);
195
+ state.object.quaternion.copy(_rotation);
196
+ }
197
+ }
198
+ // Get new position
199
+ _matrix4
200
+ .compose(t, rapierQuaternionToQuaternion(r), state.scale)
201
+ .premultiply(state.invertedWorldMatrix)
202
+ .decompose(_position, _rotation, _scale);
203
+ if (state.meshType == 'instancedMesh') {
204
+ state.setMatrix(_matrix4);
205
+ }
206
+ else {
207
+ // Interpolate to new position
208
+ state.object.position.lerp(_position, interpolationAlpha);
209
+ state.object.quaternion.slerp(_rotation, interpolationAlpha);
210
+ }
211
+ });
212
+ eventQueue.drainCollisionEvents((handle1, handle2, started) => {
213
+ const source1 = this.getSourceFromColliderHandle(handle1);
214
+ const source2 = this.getSourceFromColliderHandle(handle2);
215
+ // Collision Events
216
+ if (!source1?.collider.object || !source2?.collider.object) {
217
+ return;
218
+ }
219
+ const collisionPayload1 = this.getCollisionPayloadFromSource(source1, source2);
220
+ const collisionPayload2 = this.getCollisionPayloadFromSource(source2, source1);
221
+ if (started) {
222
+ world.contactPair(source1.collider.object, source2.collider.object, (manifold, flipped) => {
223
+ /* RigidBody events */
224
+ source1.rigidBody.events?.onCollisionEnter?.({ ...collisionPayload1, manifold, flipped });
225
+ source2.rigidBody.events?.onCollisionEnter?.({ ...collisionPayload2, manifold, flipped });
226
+ /* Collider events */
227
+ source1.collider.events?.onCollisionEnter?.({ ...collisionPayload1, manifold, flipped });
228
+ source2.collider.events?.onCollisionEnter?.({ ...collisionPayload2, manifold, flipped });
229
+ });
230
+ }
231
+ else {
232
+ source1.rigidBody.events?.onCollisionExit?.(collisionPayload1);
233
+ source2.rigidBody.events?.onCollisionExit?.(collisionPayload2);
234
+ source1.collider.events?.onCollisionExit?.(collisionPayload1);
235
+ source2.collider.events?.onCollisionExit?.(collisionPayload2);
236
+ }
237
+ // Sensor Intersections
238
+ if (started) {
239
+ if (world.intersectionPair(source1.collider.object, source2.collider.object)) {
240
+ source1.rigidBody.events?.onIntersectionEnter?.(collisionPayload1);
241
+ source2.rigidBody.events?.onIntersectionEnter?.(collisionPayload2);
242
+ source1.collider.events?.onIntersectionEnter?.(collisionPayload1);
243
+ source2.collider.events?.onIntersectionEnter?.(collisionPayload2);
244
+ }
245
+ }
246
+ else {
247
+ source1.rigidBody.events?.onIntersectionExit?.(collisionPayload1);
248
+ source2.rigidBody.events?.onIntersectionExit?.(collisionPayload2);
249
+ source1.collider.events?.onIntersectionExit?.(collisionPayload1);
250
+ source2.collider.events?.onIntersectionExit?.(collisionPayload2);
251
+ }
252
+ });
253
+ eventQueue.drainContactForceEvents((event) => {
254
+ const source1 = this.getSourceFromColliderHandle(event.collider1());
255
+ const source2 = this.getSourceFromColliderHandle(event.collider2());
256
+ // Collision Events
257
+ if (!source1?.collider.object || !source2?.collider.object) {
258
+ return;
259
+ }
260
+ const collisionPayload1 = this.getCollisionPayloadFromSource(source1, source2);
261
+ const collisionPayload2 = this.getCollisionPayloadFromSource(source2, source1);
262
+ source1.rigidBody.events?.onContactForce?.({
263
+ ...collisionPayload1,
264
+ totalForce: event.totalForce(),
265
+ totalForceMagnitude: event.totalForceMagnitude(),
266
+ maxForceDirection: event.maxForceDirection(),
267
+ maxForceMagnitude: event.maxForceMagnitude(),
268
+ });
269
+ source2.rigidBody.events?.onContactForce?.({
270
+ ...collisionPayload2,
271
+ totalForce: event.totalForce(),
272
+ totalForceMagnitude: event.totalForceMagnitude(),
273
+ maxForceDirection: event.maxForceDirection(),
274
+ maxForceMagnitude: event.maxForceMagnitude(),
275
+ });
276
+ source1.collider.events?.onContactForce?.({
277
+ ...collisionPayload1,
278
+ totalForce: event.totalForce(),
279
+ totalForceMagnitude: event.totalForceMagnitude(),
280
+ maxForceDirection: event.maxForceDirection(),
281
+ maxForceMagnitude: event.maxForceMagnitude(),
282
+ });
283
+ source2.collider.events?.onContactForce?.({
284
+ ...collisionPayload2,
285
+ totalForce: event.totalForce(),
286
+ totalForceMagnitude: event.totalForceMagnitude(),
287
+ maxForceDirection: event.maxForceDirection(),
288
+ maxForceMagnitude: event.maxForceMagnitude(),
289
+ });
290
+ });
291
+ world.forEachActiveRigidBody(() => {
292
+ this.store.snapshot.invalidate();
293
+ });
294
+ }
295
+ getSourceFromColliderHandle(handle) {
296
+ const world = this.worldSingleton();
297
+ if (!world)
298
+ return;
299
+ const collider = world.proxy.getCollider(handle);
300
+ const colEvents = this.colliderEvents.get(handle);
301
+ const colliderState = this.colliderStates.get(handle);
302
+ const rigidBodyHandle = collider.parent()?.handle;
303
+ const rigidBody = rigidBodyHandle !== undefined ? world.proxy.getRigidBody(rigidBodyHandle) : undefined;
304
+ const rigidBodyEvents = rigidBody && rigidBodyHandle !== undefined ? this.rigidBodyEvents.get(rigidBodyHandle) : undefined;
305
+ const rigidBodyState = rigidBodyHandle !== undefined ? this.rigidBodyStates.get(rigidBodyHandle) : undefined;
306
+ return {
307
+ collider: { object: collider, events: colEvents, state: colliderState },
308
+ rigidBody: { object: rigidBody, events: rigidBodyEvents, state: rigidBodyState },
309
+ };
310
+ }
311
+ getCollisionPayloadFromSource(target, other) {
312
+ return {
313
+ target: {
314
+ rigidBody: target.rigidBody.object,
315
+ collider: target.collider.object,
316
+ colliderObject: target.collider.state?.object,
317
+ rigidBodyObject: target.rigidBody.state?.object,
318
+ },
319
+ other: {
320
+ rigidBody: other.rigidBody.object,
321
+ collider: other.collider.object,
322
+ colliderObject: other.collider.state?.object,
323
+ rigidBodyObject: other.rigidBody.state?.object,
324
+ },
325
+ };
326
+ }
327
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: NgtrPhysics, deps: [], target: i0.ɵɵFactoryTarget.Component });
328
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.0", type: NgtrPhysics, isStandalone: true, selector: "ngtr-physics", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
329
+ @if (debug()) {
330
+ <ngtr-debug [world]="worldSingleton()?.proxy" />
331
+ }
332
+ <ngtr-frame-stepper
333
+ [ready]="ready()"
334
+ [stepFn]="step.bind(this)"
335
+ [type]="updateLoop()"
336
+ [updatePriority]="updatePriority()"
337
+ />
338
+ <ng-content />
339
+ `, isInline: true, dependencies: [{ kind: "component", type: NgtrDebug, selector: "ngtr-debug", inputs: ["world"] }, { kind: "directive", type: NgtrFrameStepper, selector: "ngtr-frame-stepper", inputs: ["ready", "updatePriority", "stepFn", "type"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
340
+ }
341
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: NgtrPhysics, decorators: [{
342
+ type: Component,
343
+ args: [{
344
+ selector: 'ngtr-physics',
345
+ standalone: true,
346
+ template: `
347
+ @if (debug()) {
348
+ <ngtr-debug [world]="worldSingleton()?.proxy" />
349
+ }
350
+ <ngtr-frame-stepper
351
+ [ready]="ready()"
352
+ [stepFn]="step.bind(this)"
353
+ [type]="updateLoop()"
354
+ [updatePriority]="updatePriority()"
355
+ />
356
+ <ng-content />
357
+ `,
358
+ changeDetection: ChangeDetectionStrategy.OnPush,
359
+ imports: [NgtrDebug, NgtrFrameStepper],
360
+ }]
361
+ }], ctorParameters: () => [] });
362
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGh5c2ljcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2xpYnMvcmFwaWVyL3NyYy9saWIvcGh5c2ljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxRQUFRLEVBQ1IsVUFBVSxFQUNWLE1BQU0sRUFDTixNQUFNLEVBQ04sS0FBSyxFQUNMLE1BQU0sRUFDTixTQUFTLEdBQ1QsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBZSxFQUFrQixVQUFVLEVBQTJCLE1BQU0sMkJBQTJCLENBQUM7QUFDeEcsT0FBTyxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsU0FBUyxFQUF1QixNQUFNLE9BQU8sQ0FBQztBQUN2RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFVbEUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLDRCQUE0QixFQUFFLE1BQU0sU0FBUyxDQUFDOztBQUU3RSxNQUFNLGNBQWMsR0FBdUI7SUFDMUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN0QixrQkFBa0IsRUFBRSxLQUFLO0lBQ3pCLG1CQUFtQixFQUFFLENBQUM7SUFDdEIsK0JBQStCLEVBQUUsQ0FBQztJQUNsQyx3QkFBd0IsRUFBRSxDQUFDO0lBQzNCLGtCQUFrQixFQUFFLEtBQUs7SUFDekIsYUFBYSxFQUFFLEdBQUc7SUFDbEIsY0FBYyxFQUFFLENBQUM7SUFDakIs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RUFBRSxjQUFjO29CQUN4QixVQUFVLEVBQUUsSUFBSTtvQkFDaEIsUUFBUSxFQUFFOzs7Ozs7Ozs7OztFQVdUO29CQUNELGVBQWUsRUFBRSx1QkFBdUIsQ0FBQyxNQUFNO29CQUMvQyxPQUFPLEVBQUUsQ0FBQyxTQUFTLEVBQUUsZ0JBQWdCLENBQUM7aUJBQ3RDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0Q2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG5cdENvbXBvbmVudCxcblx0Y29tcHV0ZWQsXG5cdERlc3Ryb3lSZWYsXG5cdGVmZmVjdCxcblx0aW5qZWN0LFxuXHRpbnB1dCxcblx0c2lnbmFsLFxuXHR1bnRyYWNrZWQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IFJBUElFUiwgeyBDb2xsaWRlckhhbmRsZSwgRXZlbnRRdWV1ZSwgUm90YXRpb24sIFZlY3RvciwgV29ybGQgfSBmcm9tICdAZGltZm9yZ2UvcmFwaWVyM2QtY29tcGF0JztcbmltcG9ydCB7IGluamVjdFN0b3JlLCBwaWNrLCB2ZWN0b3IzIH0gZnJvbSAnYW5ndWxhci10aHJlZSc7XG5pbXBvcnQgeyBtZXJnZUlucHV0cyB9IGZyb20gJ25neHRlbnNpb24vaW5qZWN0LWlucHV0cyc7XG5pbXBvcnQgeyBNYXRoVXRpbHMsIFF1YXRlcm5pb24sIFZlY3RvcjMgfSBmcm9tICd0aHJlZSc7XG5pbXBvcnQgeyBOZ3RyRGVidWcgfSBmcm9tICcuL2RlYnVnJztcbmltcG9ydCB7IE5ndHJGcmFtZVN0ZXBwZXIgfSBmcm9tICcuL2ZyYW1lLXN0ZXBwZXInO1xuaW1wb3J0IHsgX21hdHJpeDQsIF9wb3NpdGlvbiwgX3JvdGF0aW9uLCBfc2NhbGUgfSBmcm9tICcuL3NoYXJlZCc7XG5pbXBvcnQge1xuXHROZ3RyQ29sbGlkZXJTdGF0ZU1hcCxcblx0Tmd0ckNvbGxpc2lvblBheWxvYWQsXG5cdE5ndHJDb2xsaXNpb25Tb3VyY2UsXG5cdE5ndHJFdmVudE1hcCxcblx0Tmd0clBoeXNpY3NPcHRpb25zLFxuXHROZ3RyUmlnaWRCb2R5U3RhdGVNYXAsXG5cdE5ndHJXb3JsZFN0ZXBDYWxsYmFja1NldCxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBjcmVhdGVTaW5nbGV0b25Qcm94eSwgcmFwaWVyUXVhdGVybmlvblRvUXVhdGVybmlvbiB9IGZyb20gJy4vdXRpbHMnO1xuXG5jb25zdCBkZWZhdWx0T3B0aW9uczogTmd0clBoeXNpY3NPcHRpb25zID0ge1xuXHRncmF2aXR5OiBbMCwgLTkuODEsIDBdLFxuXHRhbGxvd2VkTGluZWFyRXJyb3I6IDAuMDAxLFxuXHRudW1Tb2x2ZXJJdGVyYXRpb25zOiA0LFxuXHRudW1BZGRpdGlvbmFsRnJpY3Rpb25JdGVyYXRpb25zOiA0LFxuXHRudW1JbnRlcm5hbFBnc0l0ZXJhdGlvbnM6IDEsXG5cdHByZWRpY3Rpb25EaXN0YW5jZTogMC4wMDIsXG5cdG1pbklzbGFuZFNpemU6IDEyOCxcblx0bWF4Q2NkU3Vic3RlcHM6IDEsXG5cdGVycDogMC44LFxuXHRsZW5ndGhVbml0OiAxLFxuXHRjb2xsaWRlcnM6ICdjdWJvaWQnLFxuXHR1cGRhdGVMb29wOiAnZm9sbG93Jyxcblx0aW50ZXJwb2xhdGU6IHRydWUsXG5cdHBhdXNlZDogZmFsc2UsXG5cdHRpbWVTdGVwOiAxIC8gNjAsXG5cdGRlYnVnOiBmYWxzZSxcbn07XG5cbkBDb21wb25lbnQoe1xuXHRzZWxlY3RvcjogJ25ndHItcGh5c2ljcycsXG5cdHN0YW5kYWxvbmU6IHRydWUsXG5cdHRlbXBsYXRlOiBgXG5cdFx0QGlmIChkZWJ1ZygpKSB7XG5cdFx0XHQ8bmd0ci1kZWJ1ZyBbd29ybGRdPVwid29ybGRTaW5nbGV0b24oKT8ucHJveHlcIiAvPlxuXHRcdH1cblx0XHQ8bmd0ci1mcmFtZS1zdGVwcGVyXG5cdFx0XHRbcmVhZHldPVwicmVhZHkoKVwiXG5cdFx0XHRbc3RlcEZuXT1cInN0ZXAuYmluZCh0aGlzKVwiXG5cdFx0XHRbdHlwZV09XCJ1cGRhdGVMb29wKClcIlxuXHRcdFx0W3VwZGF0ZVByaW9yaXR5XT1cInVwZGF0ZVByaW9yaXR5KClcIlxuXHRcdC8+XG5cdFx0PG5nLWNvbnRlbnQgLz5cblx0YCxcblx0Y2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG5cdGltcG9ydHM6IFtOZ3RyRGVidWcsIE5ndHJGcmFtZVN0ZXBwZXJdLFxufSlcbmV4cG9ydCBjbGFzcyBOZ3RyUGh5c2ljcyB7XG5cdG9wdGlvbnMgPSBpbnB1dChkZWZhdWx0T3B0aW9ucywgeyB0cmFuc2Zvcm06IG1lcmdlSW5wdXRzKGRlZmF1bHRPcHRpb25zKSB9KTtcblxuXHRwcm90ZWN0ZWQgdXBkYXRlUHJpb3JpdHkgPSBwaWNrKHRoaXMub3B0aW9ucywgJ3VwZGF0ZVByaW9yaXR5Jyk7XG5cdHByb3RlY3RlZCB1cGRhdGVMb29wID0gcGljayh0aGlzLm9wdGlvbnMsICd1cGRhdGVMb29wJyk7XG5cblx0cHJpdmF0ZSBudW1Tb2x2ZXJJdGVyYXRpb25zID0gcGljayh0aGlzLm9wdGlvbnMsICdudW1Tb2x2ZXJJdGVyYXRpb25zJyk7XG5cdHByaXZhdGUgbnVtQWRkaXRpb25hbEZyaWN0aW9uSXRlcmF0aW9ucyA9IHBpY2sodGhpcy5vcHRpb25zLCAnbnVtQWRkaXRpb25hbEZyaWN0aW9uSXRlcmF0aW9ucycpO1xuXHRwcml2YXRlIG51bUludGVybmFsUGdzSXRlcmF0aW9ucyA9IHBpY2sodGhpcy5vcHRpb25zLCAnbnVtSW50ZXJuYWxQZ3NJdGVyYXRpb25zJyk7XG5cdHByaXZhdGUgYWxsb3dlZExpbmVhckVycm9yID0gcGljayh0aGlzLm9wdGlvbnMsICdhbGxvd2VkTGluZWFyRXJyb3InKTtcblx0cHJpdmF0ZSBtaW5Jc2xhbmRTaXplID0gcGljayh0aGlzLm9wdGlvbnMsICdtaW5Jc2xhbmRTaXplJyk7XG5cdHByaXZhdGUgbWF4Q2NkU3Vic3RlcHMgPSBwaWNrKHRoaXMub3B0aW9ucywgJ21heENjZFN1YnN0ZXBzJyk7XG5cdHByaXZhdGUgcHJlZGljdGlvbkRpc3RhbmNlID0gcGljayh0aGlzLm9wdGlvbnMsICdwcmVkaWN0aW9uRGlzdGFuY2UnKTtcblx0cHJpdmF0ZSBlcnAgPSBwaWNrKHRoaXMub3B0aW9ucywgJ2VycCcpO1xuXHRwcml2YXRlIGxlbmd0aFVuaXQgPSBwaWNrKHRoaXMub3B0aW9ucywgJ2xlbmd0aFVuaXQnKTtcblx0cHJpdmF0ZSB0aW1lU3RlcCA9IHBpY2sodGhpcy5vcHRpb25zLCAndGltZVN0ZXAnKTtcblx0cHJpdmF0ZSBpbnRlcnBvbGF0ZSA9IHBpY2sodGhpcy5vcHRpb25zLCAnaW50ZXJwb2xhdGUnKTtcblxuXHRwYXVzZWQgPSBwaWNrKHRoaXMub3B0aW9ucywgJ3BhdXNlZCcpO1xuXHRkZWJ1ZyA9IHBpY2sodGhpcy5vcHRpb25zLCAnZGVidWcnKTtcblx0Y29sbGlkZXJzID0gcGljayh0aGlzLm9wdGlvbnMsICdjb2xsaWRlcnMnKTtcblx0Z3Jhdml0eSA9IHZlY3RvcjModGhpcy5vcHRpb25zLCAnZ3Jhdml0eScpO1xuXG5cdHByaXZhdGUgc3RvcmUgPSBpbmplY3RTdG9yZSgpO1xuXHRwcml2YXRlIGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG5cblx0cHJpdmF0ZSByYXBpZXJDb25zdHJ1Y3QgPSBzaWduYWw8dHlwZW9mIFJBUElFUiB8IG51bGw+KG51bGwpO1xuXHRyYXBpZXIgPSB0aGlzLnJhcGllckNvbnN0cnVjdC5hc1JlYWRvbmx5KCk7XG5cblx0cmVhZHkgPSBjb21wdXRlZCgoKSA9PiAhIXRoaXMucmFwaWVyKCkpO1xuXHR3b3JsZFNpbmdsZXRvbiA9IGNvbXB1dGVkKCgpID0+IHtcblx0XHRjb25zdCByYXBpZXIgPSB0aGlzLnJhcGllcigpO1xuXHRcdGlmICghcmFwaWVyKSByZXR1cm4gbnVsbDtcblx0XHRyZXR1cm4gY3JlYXRlU2luZ2xldG9uUHJveHk8V29ybGQ+KCgpID0+IG5ldyByYXBpZXIuV29ybGQodW50cmFja2VkKHRoaXMuZ3Jhdml0eSkpKTtcblx0fSk7XG5cblx0cmlnaWRCb2R5U3RhdGVzOiBOZ3RyUmlnaWRCb2R5U3RhdGVNYXAgPSBuZXcgTWFwKCk7XG5cdGNvbGxpZGVyU3RhdGVzOiBOZ3RyQ29sbGlkZXJTdGF0ZU1hcCA9IG5ldyBNYXAoKTtcblx0cmlnaWRCb2R5RXZlbnRzOiBOZ3RyRXZlbnRNYXAgPSBuZXcgTWFwKCk7XG5cdGNvbGxpZGVyRXZlbnRzOiBOZ3RyRXZlbnRNYXAgPSBuZXcgTWFwKCk7XG5cdGJlZm9yZVN0ZXBDYWxsYmFja3M6IE5ndHJXb3JsZFN0ZXBDYWxsYmFja1NldCA9IG5ldyBTZXQoKTtcblx0YWZ0ZXJTdGVwQ2FsbGJhY2tzOiBOZ3RyV29ybGRTdGVwQ2FsbGJhY2tTZXQgPSBuZXcgU2V0KCk7XG5cblx0cHJpdmF0ZSBldmVudFF1ZXVlID0gY29tcHV0ZWQoKCkgPT4ge1xuXHRcdGNvbnN0IHJhcGllciA9IHRoaXMucmFwaWVyKCk7XG5cdFx0aWYgKCFyYXBpZXIpIHJldHVybiBudWxsO1xuXHRcdHJldHVybiBuZXcgRXZlbnRRdWV1ZShmYWxzZSk7XG5cdH0pO1xuXG5cdHByaXZhdGUgc3RlcHBpbmdTdGF0ZToge1xuXHRcdGFjY3VtdWxhdG9yOiBudW1iZXI7XG5cdFx0cHJldmlvdXNTdGF0ZTogUmVjb3JkPG51bWJlciwgeyBwb3NpdGlvbjogVmVjdG9yOyByb3RhdGlvbjogUm90YXRpb24gfT47XG5cdH0gPSB7IGFjY3VtdWxhdG9yOiAwLCBwcmV2aW91c1N0YXRlOiB7fSB9O1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXHRcdGltcG9ydCgnQGRpbWZvcmdlL3JhcGllcjNkLWNvbXBhdCcpXG5cdFx0XHQudGhlbigocmFwaWVyKSA9PiByYXBpZXIuaW5pdCgpLnRoZW4oKCkgPT4gcmFwaWVyKSlcblx0XHRcdC50aGVuKHRoaXMucmFwaWVyQ29uc3RydWN0LnNldC5iaW5kKHRoaXMucmFwaWVyQ29uc3RydWN0KSlcblx0XHRcdC5jYXRjaCgoZXJyKSA9PiB7XG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoYFtOR1RdIEZhaWxlZCB0byBsb2FkIHJhcGllcjNkLWNvbXBhdGAsIGVycik7XG5cdFx0XHRcdHJldHVybiBQcm9taXNlLnJlamVjdChlcnIpO1xuXHRcdFx0fSk7XG5cblx0XHRlZmZlY3QoKCkgPT4ge1xuXHRcdFx0dGhpcy51cGRhdGVXb3JsZEVmZmVjdCgpO1xuXHRcdH0pO1xuXG5cdFx0dGhpcy5kZXN0cm95UmVmLm9uRGVzdHJveSgoKSA9PiB7XG5cdFx0XHRjb25zdCB3b3JsZCA9IHRoaXMud29ybGRTaW5nbGV0b24oKTtcblx0XHRcdGlmICh3b3JsZCkge1xuXHRcdFx0XHR3b3JsZC5wcm94eS5mcmVlKCk7XG5cdFx0XHRcdHdvcmxkLnJlc2V0KCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRzdGVwKGRlbHRhOiBudW1iZXIpIHtcblx0XHRpZiAoIXRoaXMucGF1c2VkKCkpIHtcblx0XHRcdHRoaXMuaW50ZXJuYWxTdGVwKGRlbHRhKTtcblx0XHR9XG5cdH1cblxuXHRwcml2YXRlIHVwZGF0ZVdvcmxkRWZmZWN0KCkge1xuXHRcdGNvbnN0IHdvcmxkID0gdGhpcy53b3JsZFNpbmdsZXRvbigpO1xuXHRcdGlmICghd29ybGQpIHJldHVybjtcblxuXHRcdHdvcmxkLnByb3h5LmdyYXZpdHkgPSB0aGlzLmdyYXZpdHkoKTtcblx0XHR3b3JsZC5wcm94eS5pbnRlZ3JhdGlvblBhcmFtZXRlcnMubnVtU29sdmVySXRlcmF0aW9ucyA9IHRoaXMubnVtU29sdmVySXRlcmF0aW9ucygpO1xuXHRcdHdvcmxkLnByb3h5LmludGVncmF0aW9uUGFyYW1ldGVycy5udW1BZGRpdGlvbmFsRnJpY3Rpb25JdGVyYXRpb25zID0gdGhpcy5udW1BZGRpdGlvbmFsRnJpY3Rpb25JdGVyYXRpb25zKCk7XG5cdFx0d29ybGQucHJveHkuaW50ZWdyYXRpb25QYXJhbWV0ZXJzLm51bUludGVybmFsUGdzSXRlcmF0aW9ucyA9IHRoaXMubnVtSW50ZXJuYWxQZ3NJdGVyYXRpb25zKCk7XG5cdFx0d29ybGQucHJveHkuaW50ZWdyYXRpb25QYXJhbWV0ZXJzLm5vcm1hbGl6ZWRBbGxvd2VkTGluZWFyRXJyb3IgPSB0aGlzLmFsbG93ZWRMaW5lYXJFcnJvcigpO1xuXHRcdHdvcmxkLnByb3h5LmludGVncmF0aW9uUGFyYW1ldGVycy5taW5Jc2xhbmRTaXplID0gdGhpcy5taW5Jc2xhbmRTaXplKCk7XG5cdFx0d29ybGQucHJveHkuaW50ZWdyYXRpb25QYXJhbWV0ZXJzLm1heENjZFN1YnN0ZXBzID0gdGhpcy5tYXhDY2RTdWJzdGVwcygpO1xuXHRcdHdvcmxkLnByb3h5LmludGVncmF0aW9uUGFyYW1ldGVycy5ub3JtYWxpemVkUHJlZGljdGlvbkRpc3RhbmNlID0gdGhpcy5wcmVkaWN0aW9uRGlzdGFuY2UoKTtcblx0XHQvKipcblx0XHQgKiBOT1RFOiB3ZSBkb24ndCBrbm93IGlmIHRoaXMgaXMgdGhlIGNvcnJlY3Qgd2F5IHRvIHNldCBmb3IgY29udGFjdF9uYXR1cmFsX2ZyZXF1ZW5jeSBvciBub3QuXG5cdFx0ICogYnV0IGF0IGxlYXN0LCBpdCBnZXRzIHRoZSBgY29udGFjdF9lcnBgIHZhbHVlIHRvIGJlIHZlcnkgY2xvc2Ugd2l0aCBzZXR0aW5nIGBlcnBgXG5cdFx0ICovXG5cdFx0d29ybGQucHJveHkuaW50ZWdyYXRpb25QYXJhbWV0ZXJzLmNvbnRhY3RfbmF0dXJhbF9mcmVxdWVuY3kgPSB0aGlzLmVycCgpICogMV8wMDA7XG5cdFx0d29ybGQucHJveHkubGVuZ3RoVW5pdCA9IHRoaXMubGVuZ3RoVW5pdCgpO1xuXHR9XG5cblx0cHJpdmF0ZSBpbnRlcm5hbFN0ZXAoZGVsdGE6IG51bWJlcikge1xuXHRcdGNvbnN0IHdvcmxkU2luZ2xldG9uID0gdGhpcy53b3JsZFNpbmdsZXRvbigpO1xuXHRcdGlmICghd29ybGRTaW5nbGV0b24pIHJldHVybjtcblxuXHRcdGNvbnN0IGV2ZW50UXVldWUgPSB0aGlzLmV2ZW50UXVldWUoKTtcblx0XHRpZiAoIWV2ZW50UXVldWUpIHJldHVybjtcblxuXHRcdGNvbnN0IHdvcmxkID0gd29ybGRTaW5nbGV0b24ucHJveHk7XG5cdFx0Y29uc3QgW3RpbWVTdGVwLCBpbnRlcnBvbGF0ZSwgcGF1c2VkXSA9IFt0aGlzLnRpbWVTdGVwKCksIHRoaXMuaW50ZXJwb2xhdGUoKSwgdGhpcy5wYXVzZWQoKV07XG5cblx0XHQvKiBDaGVjayBpZiB0aGUgdGltZXN0ZXAgaXMgc3VwcG9zZWQgdG8gYmUgdmFyaWFibGUuIFdlJ2xsIGRvIHRoaXMgaGVyZVxuICAgICAgb25jZSBzbyB3ZSBkb24ndCBoYXZlIHRvIHN0cmluZy1jaGVjayBldmVyeSBmcmFtZS4gKi9cblx0XHRjb25zdCB0aW1lU3RlcFZhcmlhYmxlID0gdGltZVN0ZXAgPT09ICd2YXJ5JztcblxuXHRcdC8qKlxuXHRcdCAqIEZpeGVkIHRpbWVTdGVwIHNpbXVsYXRpb24gcHJvZ3Jlc3Npb25cblx0XHQgKiBAc2VlIGh0dHBzOi8vZ2FmZmVyb25nYW1lcy5jb20vcG9zdC9maXhfeW91cl90aW1lc3RlcC9cblx0XHQgKi9cblx0XHRjb25zdCBjbGFtcGVkRGVsdGEgPSBNYXRoVXRpbHMuY2xhbXAoZGVsdGEsIDAsIDAuNSk7XG5cblx0XHRjb25zdCBzdGVwV29ybGQgPSAoaW5uZXJEZWx0YTogbnVtYmVyKSA9PiB7XG5cdFx0XHQvLyBUcmlnZ2VyIGJlZm9yZVN0ZXAgY2FsbGJhY2tzXG5cdFx0XHR0aGlzLmJlZm9yZVN0ZXBDYWxsYmFja3MuZm9yRWFjaCgoY2FsbGJhY2spID0+IHtcblx0XHRcdFx0Y2FsbGJhY2sod29ybGQpO1xuXHRcdFx0fSk7XG5cblx0XHRcdHdvcmxkLnRpbWVzdGVwID0gaW5uZXJEZWx0YTtcblx0XHRcdHdvcmxkLnN0ZXAoZXZlbnRRdWV1ZSk7XG5cblx0XHRcdC8vIFRyaWdnZXIgYWZ0ZXJTdGVwIGNhbGxiYWNrc1xuXHRcdFx0dGhpcy5hZnRlclN0ZXBDYWxsYmFja3MuZm9yRWFjaCgoY2FsbGJhY2spID0+IHtcblx0XHRcdFx0Y2FsbGJhY2sod29ybGQpO1xuXHRcdFx0fSk7XG5cdFx0fTtcblxuXHRcdGlmICh0aW1lU3RlcFZhcmlhYmxlKSB7XG5cdFx0XHRzdGVwV29ybGQoY2xhbXBlZERlbHRhKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gZG9uJ3Qgc3RlcCB0aW1lIGZvcndhcmRzIGlmIHBhdXNlZFxuXHRcdFx0Ly8gSW5jcmVhc2UgYWNjdW11bGF0b3Jcblx0XHRcdHRoaXMuc3RlcHBpbmdTdGF0ZS5hY2N1bXVsYXRvciArPSBjbGFtcGVkRGVsdGE7XG5cblx0XHRcdHdoaWxlICh0aGlzLnN0ZXBwaW5nU3RhdGUuYWNjdW11bGF0b3IgPj0gdGltZVN0ZXApIHtcblx0XHRcdFx0Ly8gU2V0IHVwIHByZXZpb3VzIHN0YXRlXG5cdFx0XHRcdC8vIG5lZWRlZCBmb3IgYWNjdXJhdGUgaW50ZXJwb2xhdGlvbnMgaWYgdGhlIHdvcmxkIHN0ZXBzIG1vcmUgdGhhbiBvbmNlXG5cdFx0XHRcdGlmIChpbnRlcnBvbGF0ZSkge1xuXHRcdFx0XHRcdHRoaXMuc3RlcHBpbmdTdGF0ZS5wcmV2aW91c1N0YXRlID0ge307XG5cdFx0XHRcdFx0d29ybGQuZm9yRWFjaFJpZ2lkQm9keSgoYm9keSkgPT4ge1xuXHRcdFx0XHRcdFx0dGhpcy5zdGVwcGluZ1N0YXRlLnByZXZpb3VzU3RhdGVbYm9keS5oYW5kbGVdID0ge1xuXHRcdFx0XHRcdFx0XHRwb3NpdGlvbjogYm9keS50cmFuc2xhdGlvbigpLFxuXHRcdFx0XHRcdFx0XHRyb3RhdGlvbjogYm9keS5yb3RhdGlvbigpLFxuXHRcdFx0XHRcdFx0fTtcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHN0ZXBXb3JsZCh0aW1lU3RlcCk7XG5cdFx0XHRcdHRoaXMuc3RlcHBpbmdTdGF0ZS5hY2N1bXVsYXRvciAtPSB0aW1lU3RlcDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRjb25zdCBpbnRlcnBvbGF0aW9uQWxwaGEgPVxuXHRcdFx0dGltZVN0ZXBWYXJpYWJsZSB8fCAhaW50ZXJwb2xhdGUgfHwgcGF1c2VkID8gMSA6IHRoaXMuc3RlcHBpbmdTdGF0ZS5hY2N1bXVsYXRvciAvIHRpbWVTdGVwO1xuXG5cdFx0Ly8gVXBkYXRlIG1lc2hlc1xuXHRcdHRoaXMucmlnaWRCb2R5U3RhdGVzLmZvckVhY2goKHN0YXRlLCBoYW5kbGUpID0+IHtcblx0XHRcdGNvbnN0IHJpZ2lkQm9keSA9IHdvcmxkLmdldFJpZ2lkQm9keShoYW5kbGUpO1xuXG5cdFx0XHRjb25zdCBldmVudHMgPSB0aGlzLnJpZ2lkQm9keUV2ZW50cy5nZXQoaGFuZGxlKTtcblx0XHRcdGlmIChldmVudHM/Lm9uU2xlZXAgfHwgZXZlbnRzPy5vbldha2UpIHtcblx0XHRcdFx0aWYgKHJpZ2lkQm9keS5pc1NsZWVwaW5nKCkgJiYgIXN0YXRlLmlzU2xlZXBpbmcpIGV2ZW50cz8ub25TbGVlcD8uKCk7XG5cdFx0XHRcdGlmICghcmlnaWRCb2R5LmlzU2xlZXBpbmcoKSAmJiBzdGF0ZS5pc1NsZWVwaW5nKSBldmVudHM/Lm9uV2FrZT8uKCk7XG5cdFx0XHRcdHN0YXRlLmlzU2xlZXBpbmcgPSByaWdpZEJvZHkuaXNTbGVlcGluZygpO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIXJpZ2lkQm9keSB8fCAocmlnaWRCb2R5LmlzU2xlZXBpbmcoKSAmJiAhKCdpc0luc3RhbmNlZE1lc2gnIGluIHN0YXRlLm9iamVjdCkpIHx8ICFzdGF0ZS5zZXRNYXRyaXgpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBOZXcgc3RhdGVzXG5cdFx0XHRsZXQgdCA9IHJpZ2lkQm9keS50cmFuc2xhdGlvbigpIGFzIFZlY3RvcjM7XG5cdFx0XHRsZXQgciA9IHJpZ2lkQm9keS5yb3RhdGlvbigpIGFzIFF1YXRlcm5pb247XG5cblx0XHRcdGxldCBwcmV2aW91c1N0YXRlID0gdGhpcy5zdGVwcGluZ1N0YXRlLnByZXZpb3VzU3RhdGVbaGFuZGxlXTtcblxuXHRcdFx0aWYgKHByZXZpb3VzU3RhdGUpIHtcblx0XHRcdFx0Ly8gR2V0IHByZXZpb3VzIHNpbXVsYXRlZCB3b3JsZCBwb3NpdGlvblxuXHRcdFx0XHRfbWF0cml4NFxuXHRcdFx0XHRcdC5jb21wb3NlKHByZXZpb3VzU3RhdGUucG9zaXRpb24gYXMgVmVjdG9yMywgcmFwaWVyUXVhdGVybmlvblRvUXVhdGVybmlvbihwcmV2aW91c1N0YXRlLnJvdGF0aW9uKSwgc3RhdGUuc2NhbGUpXG5cdFx0XHRcdFx0LnByZW11bHRpcGx5KHN0YXRlLmludmVydGVkV29ybGRNYXRyaXgpXG5cdFx0XHRcdFx0LmRlY29tcG9zZShfcG9zaXRpb24sIF9yb3RhdGlvbiwgX3NjYWxlKTtcblxuXHRcdFx0XHQvLyBBcHBseSBwcmV2aW91cyB0aWNrIHBvc2l0aW9uXG5cdFx0XHRcdGlmIChzdGF0ZS5tZXNoVHlwZSA9PSAnbWVzaCcpIHtcblx0XHRcdFx0XHRzdGF0ZS5vYmplY3QucG9zaXRpb24uY29weShfcG9zaXRpb24pO1xuXHRcdFx0XHRcdHN0YXRlLm9iamVjdC5xdWF0ZXJuaW9uLmNvcHkoX3JvdGF0aW9uKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBHZXQgbmV3IHBvc2l0aW9uXG5cdFx0XHRfbWF0cml4NFxuXHRcdFx0XHQuY29tcG9zZSh0LCByYXBpZXJRdWF0ZXJuaW9uVG9RdWF0ZXJuaW9uKHIpLCBzdGF0ZS5zY2FsZSlcblx0XHRcdFx0LnByZW11bHRpcGx5KHN0YXRlLmludmVydGVkV29ybGRNYXRyaXgpXG5cdFx0XHRcdC5kZWNvbXBvc2UoX3Bvc2l0aW9uLCBfcm90YXRpb24sIF9zY2FsZSk7XG5cblx0XHRcdGlmIChzdGF0ZS5tZXNoVHlwZSA9PSAnaW5zdGFuY2VkTWVzaCcpIHtcblx0XHRcdFx0c3RhdGUuc2V0TWF0cml4KF9tYXRyaXg0KTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIEludGVycG9sYXRlIHRvIG5ldyBwb3NpdGlvblxuXHRcdFx0XHRzdGF0ZS5vYmplY3QucG9zaXRpb24ubGVycChfcG9zaXRpb24sIGludGVycG9sYXRpb25BbHBoYSk7XG5cdFx0XHRcdHN0YXRlLm9iamVjdC5xdWF0ZXJuaW9uLnNsZXJwKF9yb3RhdGlvbiwgaW50ZXJwb2xhdGlvbkFscGhhKTtcblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdGV2ZW50UXVldWUuZHJhaW5Db2xsaXNpb25FdmVudHMoKGhhbmRsZTEsIGhhbmRsZTIsIHN0YXJ0ZWQpID0+IHtcblx0XHRcdGNvbnN0IHNvdXJjZTEgPSB0aGlzLmdldFNvdXJjZUZyb21Db2xsaWRlckhhbmRsZShoYW5kbGUxKTtcblx0XHRcdGNvbnN0IHNvdXJjZTIgPSB0aGlzLmdldFNvdXJjZUZyb21Db2xsaWRlckhhbmRsZShoYW5kbGUyKTtcblxuXHRcdFx0Ly8gQ29sbGlzaW9uIEV2ZW50c1xuXHRcdFx0aWYgKCFzb3VyY2UxPy5jb2xsaWRlci5vYmplY3QgfHwgIXNvdXJjZTI/LmNvbGxpZGVyLm9iamVjdCkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGNvbGxpc2lvblBheWxvYWQxID0gdGhpcy5nZXRDb2xsaXNpb25QYXlsb2FkRnJvbVNvdXJjZShzb3VyY2UxLCBzb3VyY2UyKTtcblx0XHRcdGNvbnN0IGNvbGxpc2lvblBheWxvYWQyID0gdGhpcy5nZXRDb2xsaXNpb25QYXlsb2FkRnJvbVNvdXJjZShzb3VyY2UyLCBzb3VyY2UxKTtcblxuXHRcdFx0aWYgKHN0YXJ0ZWQpIHtcblx0XHRcdFx0d29ybGQuY29udGFjdFBhaXIoc291cmNlMS5jb2xsaWRlci5vYmplY3QsIHNvdXJjZTIuY29sbGlkZXIub2JqZWN0LCAobWFuaWZvbGQsIGZsaXBwZWQpID0+IHtcblx0XHRcdFx0XHQvKiBSaWdpZEJvZHkgZXZlbnRzICovXG5cdFx0XHRcdFx0c291cmNlMS5yaWdpZEJvZHkuZXZlbnRzPy5vbkNvbGxpc2lvbkVudGVyPy4oeyAuLi5jb2xsaXNpb25QYXlsb2FkMSwgbWFuaWZvbGQsIGZsaXBwZWQgfSk7XG5cdFx0XHRcdFx0c291cmNlMi5yaWdpZEJvZHkuZXZlbnRzPy5vbkNvbGxpc2lvbkVudGVyPy4oeyAuLi5jb2xsaXNpb25QYXlsb2FkMiwgbWFuaWZvbGQsIGZsaXBwZWQgfSk7XG5cblx0XHRcdFx0XHQvKiBDb2xsaWRlciBldmVudHMgKi9cblx0XHRcdFx0XHRzb3VyY2UxLmNvbGxpZGVyLmV2ZW50cz8ub25Db2xsaXNpb25FbnRlcj8uKHsgLi4uY29sbGlzaW9uUGF5bG9hZDEsIG1hbmlmb2xkLCBmbGlwcGVkIH0pO1xuXHRcdFx0XHRcdHNvdXJjZTIuY29sbGlkZXIuZXZlbnRzPy5vbkNvbGxpc2lvbkVudGVyPy4oeyAuLi5jb2xsaXNpb25QYXlsb2FkMiwgbWFuaWZvbGQsIGZsaXBwZWQgfSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0c291cmNlMS5yaWdpZEJvZHkuZXZlbnRzPy5vbkNvbGxpc2lvbkV4aXQ/Lihjb2xsaXNpb25QYXlsb2FkMSk7XG5cdFx0XHRcdHNvdXJjZTIucmlnaWRCb2R5LmV2ZW50cz8ub25Db2xsaXNpb25FeGl0Py4oY29sbGlzaW9uUGF5bG9hZDIpO1xuXHRcdFx0XHRzb3VyY2UxLmNvbGxpZGVyLmV2ZW50cz8ub25Db2xsaXNpb25FeGl0Py4oY29sbGlzaW9uUGF5bG9hZDEpO1xuXHRcdFx0XHRzb3VyY2UyLmNvbGxpZGVyLmV2ZW50cz8ub25Db2xsaXNpb25FeGl0Py4oY29sbGlzaW9uUGF5bG9hZDIpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTZW5zb3IgSW50ZXJzZWN0aW9uc1xuXHRcdFx0aWYgKHN0YXJ0ZWQpIHtcblx0XHRcdFx0aWYgKHdvcmxkLmludGVyc2VjdGlvblBhaXIoc291cmNlMS5jb2xsaWRlci5vYmplY3QsIHNvdXJjZTIuY29sbGlkZXIub2JqZWN0KSkge1xuXHRcdFx0XHRcdHNvdXJjZTEucmlnaWRCb2R5LmV2ZW50cz8ub25JbnRlcnNlY3Rpb25FbnRlcj8uKGNvbGxpc2lvblBheWxvYWQxKTtcblx0XHRcdFx0XHRzb3VyY2UyLnJpZ2lkQm9keS5ldmVudHM/Lm9uSW50ZXJzZWN0aW9uRW50ZXI/Lihjb2xsaXNpb25QYXlsb2FkMik7XG5cdFx0XHRcdFx0c291cmNlMS5jb2xsaWRlci5ldmVudHM/Lm9uSW50ZXJzZWN0aW9uRW50ZXI/Lihjb2xsaXNpb25QYXlsb2FkMSk7XG5cdFx0XHRcdFx0c291cmNlMi5jb2xsaWRlci5ldmVudHM/Lm9uSW50ZXJzZWN0aW9uRW50ZXI/Lihjb2xsaXNpb25QYXlsb2FkMik7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHNvdXJjZTEucmlnaWRCb2R5LmV2ZW50cz8ub25JbnRlcnNlY3Rpb25FeGl0Py4oY29sbGlzaW9uUGF5bG9hZDEpO1xuXHRcdFx0XHRzb3VyY2UyLnJpZ2lkQm9keS5ldmVudHM/Lm9uSW50ZXJzZWN0aW9uRXhpdD8uKGNvbGxpc2lvblBheWxvYWQyKTtcblx0XHRcdFx0c291cmNlMS5jb2xsaWRlci5ldmVudHM/Lm9uSW50ZXJzZWN0aW9uRXhpdD8uKGNvbGxpc2lvblBheWxvYWQxKTtcblx0XHRcdFx0c291cmNlMi5jb2xsaWRlci5ldmVudHM/Lm9uSW50ZXJzZWN0aW9uRXhpdD8uKGNvbGxpc2lvblBheWxvYWQyKTtcblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdGV2ZW50UXVldWUuZHJhaW5Db250YWN0Rm9yY2VFdmVudHMoKGV2ZW50KSA9PiB7XG5cdFx0XHRjb25zdCBzb3VyY2UxID0gdGhpcy5nZXRTb3VyY2VGcm9tQ29sbGlkZXJIYW5kbGUoZXZlbnQuY29sbGlkZXIxKCkpO1xuXHRcdFx0Y29uc3Qgc291cmNlMiA9IHRoaXMuZ2V0U291cmNlRnJvbUNvbGxpZGVySGFuZGxlKGV2ZW50LmNvbGxpZGVyMigpKTtcblxuXHRcdFx0Ly8gQ29sbGlzaW9uIEV2ZW50c1xuXHRcdFx0aWYgKCFzb3VyY2UxPy5jb2xsaWRlci5vYmplY3QgfHwgIXNvdXJjZTI/LmNvbGxpZGVyLm9iamVjdCkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGNvbGxpc2lvblBheWxvYWQxID0gdGhpcy5nZXRDb2xsaXNpb25QYXlsb2FkRnJvbVNvdXJjZShzb3VyY2UxLCBzb3VyY2UyKTtcblx0XHRcdGNvbnN0IGNvbGxpc2lvblBheWxvYWQyID0gdGhpcy5nZXRDb2xsaXNpb25QYXlsb2FkRnJvbVNvdXJjZShzb3VyY2UyLCBzb3VyY2UxKTtcblxuXHRcdFx0c291cmNlMS5yaWdpZEJvZHkuZXZlbnRzPy5vbkNvbnRhY3RGb3JjZT8uKHtcblx0XHRcdFx0Li4uY29sbGlzaW9uUGF5bG9hZDEsXG5cdFx0XHRcdHRvdGFsRm9yY2U6IGV2ZW50LnRvdGFsRm9yY2UoKSxcblx0XHRcdFx0dG90YWxGb3JjZU1hZ25pdHVkZTogZXZlbnQudG90YWxGb3JjZU1hZ25pdHVkZSgpLFxuXHRcdFx0XHRtYXhGb3JjZURpcmVjdGlvbjogZXZlbnQubWF4Rm9yY2VEaXJlY3Rpb24oKSxcblx0XHRcdFx0bWF4Rm9yY2VNYWduaXR1ZGU6IGV2ZW50Lm1heEZvcmNlTWFnbml0dWRlKCksXG5cdFx0XHR9KTtcblxuXHRcdFx0c291cmNlMi5yaWdpZEJvZHkuZXZlbnRzPy5vbkNvbnRhY3RGb3JjZT8uKHtcblx0XHRcdFx0Li4uY29sbGlzaW9uUGF5bG9hZDIsXG5cdFx0XHRcdHRvdGFsRm9yY2U6IGV2ZW50LnRvdGFsRm9yY2UoKSxcblx0XHRcdFx0dG90YWxGb3JjZU1hZ25pdHVkZTogZXZlbnQudG90YWxGb3JjZU1hZ25pdHVkZSgpLFxuXHRcdFx0XHRtYXhGb3JjZURpcmVjdGlvbjogZXZlbnQubWF4Rm9yY2VEaXJlY3Rpb24oKSxcblx0XHRcdFx0bWF4Rm9yY2VNYWduaXR1ZGU6IGV2ZW50Lm1heEZvcmNlTWFnbml0dWRlKCksXG5cdFx0XHR9KTtcblxuXHRcdFx0c291cmNlMS5jb2xsaWRlci5ldmVudHM/Lm9uQ29udGFjdEZvcmNlPy4oe1xuXHRcdFx0XHQuLi5jb2xsaXNpb25QYXlsb2FkMSxcblx0XHRcdFx0dG90YWxGb3JjZTogZXZlbnQudG90YWxGb3JjZSgpLFxuXHRcdFx0XHR0b3RhbEZvcmNlTWFnbml0dWRlOiBldmVudC50b3RhbEZvcmNlTWFnbml0dWRlKCksXG5cdFx0XHRcdG1heEZvcmNlRGlyZWN0aW9uOiBldmVudC5tYXhGb3JjZURpcmVjdGlvbigpLFxuXHRcdFx0XHRtYXhGb3JjZU1hZ25pdHVkZTogZXZlbnQubWF4Rm9yY2VNYWduaXR1ZGUoKSxcblx0XHRcdH0pO1xuXG5cdFx0XHRzb3VyY2UyLmNvbGxpZGVyLmV2ZW50cz8ub25Db250YWN0Rm9yY2U/Lih7XG5cdFx0XHRcdC4uLmNvbGxpc2lvblBheWxvYWQyLFxuXHRcdFx0XHR0b3RhbEZvcmNlOiBldmVudC50b3RhbEZvcmNlKCksXG5cdFx0XHRcdHRvdGFsRm9yY2VNYWduaXR1ZGU6IGV2ZW50LnRvdGFsRm9yY2VNYWduaXR1ZGUoKSxcblx0XHRcdFx0bWF4Rm9yY2VEaXJlY3Rpb246IGV2ZW50Lm1heEZvcmNlRGlyZWN0aW9uKCksXG5cdFx0XHRcdG1heEZvcmNlTWFnbml0dWRlOiBldmVudC5tYXhGb3JjZU1hZ25pdHVkZSgpLFxuXHRcdFx0fSk7XG5cdFx0fSk7XG5cblx0XHR3b3JsZC5mb3JFYWNoQWN0aXZlUmlnaWRCb2R5KCgpID0+IHtcblx0XHRcdHRoaXMuc3RvcmUuc25hcHNob3QuaW52YWxpZGF0ZSgpO1xuXHRcdH0pO1xuXHR9XG5cblx0cHJpdmF0ZSBnZXRTb3VyY2VGcm9tQ29sbGlkZXJIYW5kbGUoaGFuZGxlOiBDb2xsaWRlckhhbmRsZSkge1xuXHRcdGNvbnN0IHdvcmxkID0gdGhpcy53b3JsZFNpbmdsZXRvbigpO1xuXHRcdGlmICghd29ybGQpIHJldHVybjtcblxuXHRcdGNvbnN0IGNvbGxpZGVyID0gd29ybGQucHJveHkuZ2V0Q29sbGlkZXIoaGFuZGxlKTtcblx0XHRjb25zdCBjb2xFdmVudHMgPSB0aGlzLmNvbGxpZGVyRXZlbnRzLmdldChoYW5kbGUpO1xuXHRcdGNvbnN0IGNvbGxpZGVyU3RhdGUgPSB0aGlzLmNvbGxpZGVyU3RhdGVzLmdldChoYW5kbGUpO1xuXG5cdFx0Y29uc3QgcmlnaWRCb2R5SGFuZGxlID0gY29sbGlkZXIucGFyZW50KCk/LmhhbmRsZTtcblx0XHRjb25zdCByaWdpZEJvZHkgPSByaWdpZEJvZHlIYW5kbGUgIT09IHVuZGVmaW5lZCA/IHdvcmxkLnByb3h5LmdldFJpZ2lkQm9keShyaWdpZEJvZHlIYW5kbGUpIDogdW5kZWZpbmVkO1xuXHRcdGNvbnN0IHJpZ2lkQm9keUV2ZW50cyA9XG5cdFx0XHRyaWdpZEJvZHkgJiYgcmlnaWRCb2R5SGFuZGxlICE9PSB1bmRlZmluZWQgPyB0aGlzLnJpZ2lkQm9keUV2ZW50cy5nZXQocmlnaWRCb2R5SGFuZGxlKSA6IHVuZGVmaW5lZDtcblx0XHRjb25zdCByaWdpZEJvZHlTdGF0ZSA9IHJpZ2lkQm9keUhhbmRsZSAhPT0gdW5kZWZpbmVkID8gdGhpcy5yaWdpZEJvZHlTdGF0ZXMuZ2V0KHJpZ2lkQm9keUhhbmRsZSkgOiB1bmRlZmluZWQ7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0Y29sbGlkZXI6IHsgb2JqZWN0OiBjb2xsaWRlciwgZXZlbnRzOiBjb2xFdmVudHMsIHN0YXRlOiBjb2xsaWRlclN0YXRlIH0sXG5cdFx0XHRyaWdpZEJvZHk6IHsgb2JqZWN0OiByaWdpZEJvZHksIGV2ZW50czogcmlnaWRCb2R5RXZlbnRzLCBzdGF0ZTogcmlnaWRCb2R5U3RhdGUgfSxcblx0XHR9IGFzIE5ndHJDb2xsaXNpb25Tb3VyY2U7XG5cdH1cblxuXHRwcml2YXRlIGdldENvbGxpc2lvblBheWxvYWRGcm9tU291cmNlKHRhcmdldDogTmd0ckNvbGxpc2lvblNvdXJjZSwgb3RoZXI6IE5ndHJDb2xsaXNpb25Tb3VyY2UpOiBOZ3RyQ29sbGlzaW9uUGF5bG9hZCB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHRhcmdldDoge1xuXHRcdFx0XHRyaWdpZEJvZHk6IHRhcmdldC5yaWdpZEJvZHkub2JqZWN0LFxuXHRcdFx0XHRjb2xsaWRlcjogdGFyZ2V0LmNvbGxpZGVyLm9iamVjdCxcblx0XHRcdFx0Y29sbGlkZXJPYmplY3Q6IHRhcmdldC5jb2xsaWRlci5zdGF0ZT8ub2JqZWN0LFxuXHRcdFx0XHRyaWdpZEJvZHlPYmplY3Q6IHRhcmdldC5yaWdpZEJvZHkuc3RhdGU/Lm9iamVjdCxcblx0XHRcdH0sXG5cdFx0XHRvdGhlcjoge1xuXHRcdFx0XHRyaWdpZEJvZHk6IG90aGVyLnJpZ2lkQm9keS5vYmplY3QsXG5cdFx0XHRcdGNvbGxpZGVyOiBvdGhlci5jb2xsaWRlci5vYmplY3QsXG5cdFx0XHRcdGNvbGxpZGVyT2JqZWN0OiBvdGhlci5jb2xsaWRlci5zdGF0ZT8ub2JqZWN0LFxuXHRcdFx0XHRyaWdpZEJvZHlPYmplY3Q6IG90aGVyLnJpZ2lkQm9keS5zdGF0ZT8ub2JqZWN0LFxuXHRcdFx0fSxcblx0XHR9O1xuXHR9XG59XG4iXX0=