gx
chenyc
2025-06-12 7b72ac13a83764a662159d4a49b7fffb90476ecb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
/**
 * @license
 * Copyright 2018 Google LLC
 *
 * Use of this source code is governed by an MIT-style
 * license that can be found in the LICENSE file or at
 * https://opensource.org/licenses/MIT.
 * =============================================================================
 */
/**
 * TensorFlow.js Layers: Convolutional Layers
 */
import * as tfc from '@tensorflow/tfjs-core';
import { serialization, tidy } from '@tensorflow/tfjs-core';
import { getActivation, serializeActivation } from '../activations';
import { imageDataFormat } from '../backend/common';
import * as K from '../backend/tfjs_backend';
import { checkDataFormat, checkInterpolationFormat, checkPaddingMode } from '../common';
import { getConstraint, serializeConstraint } from '../constraints';
import { InputSpec, Layer } from '../engine/topology';
import { NotImplementedError, ValueError } from '../errors';
import { getInitializer, serializeInitializer } from '../initializers';
import { getRegularizer, serializeRegularizer } from '../regularizers';
import { convOutputLength, deconvLength, normalizeArray } from '../utils/conv_utils';
import * as generic_utils from '../utils/generic_utils';
import { getExactlyOneShape, getExactlyOneTensor } from '../utils/types_utils';
/**
 * Transpose and cast the input before the conv2d.
 * @param x Input image tensor.
 * @param dataFormat
 */
export function preprocessConv2DInput(x, dataFormat) {
    // TODO(cais): Cast type to float32 if not.
    return tidy(() => {
        checkDataFormat(dataFormat);
        if (dataFormat === 'channelsFirst') {
            return tfc.transpose(x, [0, 2, 3, 1]); // NCHW -> NHWC.
        }
        else {
            return x;
        }
    });
}
/**
 * Transpose and cast the input before the conv3d.
 * @param x Input image tensor.
 * @param dataFormat
 */
export function preprocessConv3DInput(x, dataFormat) {
    return tidy(() => {
        checkDataFormat(dataFormat);
        if (dataFormat === 'channelsFirst') {
            return tfc.transpose(x, [0, 2, 3, 4, 1]); // NCDHW -> NDHWC.
        }
        else {
            return x;
        }
    });
}
/**
 * 1D-convolution with bias added.
 *
 * Porting Note: This function does not exist in the Python Keras backend.
 *   It is exactly the same as `conv2d`, except the added `bias`.
 *
 * @param x Input tensor, rank-3, of shape `[batchSize, width, inChannels]`.
 * @param kernel Kernel, rank-3, of shape `[filterWidth, inDepth, outDepth]`.
 * @param bias Bias, rank-3, of shape `[outDepth]`.
 * @param strides
 * @param padding Padding mode.
 * @param dataFormat Data format.
 * @param dilationRate
 * @returns The result of the 1D convolution.
 * @throws ValueError, if `x`, `kernel` or `bias` is not of the correct rank.
 */
export function conv1dWithBias(x, kernel, bias, strides = 1, padding = 'valid', dataFormat, dilationRate = 1) {
    return tidy(() => {
        if (dataFormat == null) {
            dataFormat = imageDataFormat();
        }
        checkDataFormat(dataFormat);
        // Check the ranks of x, kernel and bias.
        if (x.shape.length !== 3) {
            throw new ValueError(`The input of a conv1dWithBias operation should be 3, but is ` +
                `${x.shape.length} instead.`);
        }
        if (kernel.shape.length !== 3) {
            throw new ValueError(`The kernel for a conv1dWithBias operation should be 3, but is ` +
                `${kernel.shape.length} instead`);
        }
        if (bias != null && bias.shape.length !== 1) {
            throw new ValueError(`The bias for a conv1dWithBias operation should be 1, but is ` +
                `${kernel.shape.length} instead`);
        }
        // TODO(cais): Support CAUSAL padding mode.
        if (dataFormat === 'channelsFirst') {
            x = tfc.transpose(x, [0, 2, 1]); // NCW -> NWC.
        }
        if (padding === 'causal') {
            throw new NotImplementedError('The support for CAUSAL padding mode in conv1dWithBias is not ' +
                'implemented yet.');
        }
        let y = tfc.conv1d(x, kernel, strides, padding === 'same' ? 'same' : 'valid', 'NWC', dilationRate);
        if (bias != null) {
            y = K.biasAdd(y, bias);
        }
        return y;
    });
}
/**
 * 1D-convolution.
 *
 * @param x Input tensor, rank-3, of shape `[batchSize, width, inChannels]`.
 * @param kernel Kernel, rank-3, of shape `[filterWidth, inDepth, outDepth]`.s
 * @param strides
 * @param padding Padding mode.
 * @param dataFormat Data format.
 * @param dilationRate
 * @returns The result of the 1D convolution.
 * @throws ValueError, if `x`, `kernel` or `bias` is not of the correct rank.
 */
export function conv1d(x, kernel, strides = 1, padding = 'valid', dataFormat, dilationRate = 1) {
    return tidy(() => {
        checkDataFormat(dataFormat);
        return conv1dWithBias(x, kernel, null, strides, padding, dataFormat, dilationRate);
    });
}
/**
 * 2D Convolution
 * @param x
 * @param kernel kernel of the convolution.
 * @param strides strides array.
 * @param padding padding mode. Default to 'valid'.
 * @param dataFormat data format. Defaults to 'channelsLast'.
 * @param dilationRate dilation rate array.
 * @returns Result of the 2D pooling.
 */
export function conv2d(x, kernel, strides = [1, 1], padding = 'valid', dataFormat, dilationRate) {
    return tidy(() => {
        checkDataFormat(dataFormat);
        return conv2dWithBiasActivation(x, kernel, null, strides, padding, dataFormat, dilationRate);
    });
}
/**
 * 2D Convolution with an added bias and optional activation.
 * Note: This function does not exist in the Python Keras Backend. This function
 * is exactly the same as `conv2d`, except the added `bias`.
 */
export function conv2dWithBiasActivation(x, kernel, bias, strides = [1, 1], padding = 'valid', dataFormat, dilationRate, activation = null) {
    return tidy(() => {
        if (dataFormat == null) {
            dataFormat = imageDataFormat();
        }
        checkDataFormat(dataFormat);
        if (x.rank !== 3 && x.rank !== 4) {
            throw new ValueError(`conv2dWithBiasActivation expects input to be of rank 3 or 4, ` +
                `but received ${x.rank}.`);
        }
        if (kernel.rank !== 3 && kernel.rank !== 4) {
            throw new ValueError(`conv2dWithBiasActivation expects kernel to be of rank 3 or 4, ` +
                `but received ${x.rank}.`);
        }
        let y = preprocessConv2DInput(x, dataFormat);
        if (padding === 'causal') {
            throw new NotImplementedError('The support for CAUSAL padding mode in conv1dWithBias is not ' +
                'implemented yet.');
        }
        y = tfc.fused.conv2d({
            x: y,
            filter: kernel,
            strides: strides,
            pad: padding === 'same' ? 'same' : 'valid',
            dilations: dilationRate,
            dataFormat: 'NHWC',
            bias,
            activation
        });
        if (dataFormat === 'channelsFirst') {
            y = tfc.transpose(y, [0, 3, 1, 2]);
        }
        return y;
    });
}
/**
 * 3D Convolution.
 * @param x
 * @param kernel kernel of the convolution.
 * @param strides strides array.
 * @param padding padding mode. Default to 'valid'.
 * @param dataFormat data format. Defaults to 'channelsLast'.
 * @param dilationRate dilation rate array.
 * @returns Result of the 3D convolution.
 */
export function conv3d(x, kernel, strides = [1, 1, 1], padding = 'valid', dataFormat, dilationRate) {
    return tidy(() => {
        checkDataFormat(dataFormat);
        return conv3dWithBias(x, kernel, null, strides, padding, dataFormat, dilationRate);
    });
}
/**
 * 3D Convolution with an added bias.
 * Note: This function does not exist in the Python Keras Backend. This function
 * is exactly the same as `conv3d`, except the added `bias`.
 */
export function conv3dWithBias(x, kernel, bias, strides = [1, 1, 1], padding = 'valid', dataFormat, dilationRate) {
    return tidy(() => {
        if (dataFormat == null) {
            dataFormat = imageDataFormat();
        }
        checkDataFormat(dataFormat);
        if (x.rank !== 4 && x.rank !== 5) {
            throw new ValueError(`conv3dWithBias expects input to be of rank 4 or 5, but received ` +
                `${x.rank}.`);
        }
        if (kernel.rank !== 4 && kernel.rank !== 5) {
            throw new ValueError(`conv3dWithBias expects kernel to be of rank 4 or 5, but received ` +
                `${x.rank}.`);
        }
        let y = preprocessConv3DInput(x, dataFormat);
        if (padding === 'causal') {
            throw new NotImplementedError('The support for CAUSAL padding mode in conv3dWithBias is not ' +
                'implemented yet.');
        }
        y = tfc.conv3d(y, kernel, strides, padding === 'same' ? 'same' : 'valid', 'NDHWC', dilationRate);
        if (bias != null) {
            y = K.biasAdd(y, bias);
        }
        if (dataFormat === 'channelsFirst') {
            y = tfc.transpose(y, [0, 4, 1, 2, 3]);
        }
        return y;
    });
}
/**
 * Abstract convolution layer.
 */
export class BaseConv extends Layer {
    constructor(rank, args) {
        super(args);
        this.bias = null;
        this.DEFAULT_KERNEL_INITIALIZER = 'glorotNormal';
        this.DEFAULT_BIAS_INITIALIZER = 'zeros';
        BaseConv.verifyArgs(args);
        this.rank = rank;
        generic_utils.assertPositiveInteger(this.rank, 'rank');
        if (this.rank !== 1 && this.rank !== 2 && this.rank !== 3) {
            throw new NotImplementedError(`Convolution layer for rank other than 1, 2, or 3 (${this.rank}) is ` +
                `not implemented yet.`);
        }
        this.kernelSize = normalizeArray(args.kernelSize, rank, 'kernelSize');
        this.strides = normalizeArray(args.strides == null ? 1 : args.strides, rank, 'strides');
        this.padding = args.padding == null ? 'valid' : args.padding;
        checkPaddingMode(this.padding);
        this.dataFormat =
            args.dataFormat == null ? 'channelsLast' : args.dataFormat;
        checkDataFormat(this.dataFormat);
        this.activation = getActivation(args.activation);
        this.useBias = args.useBias == null ? true : args.useBias;
        this.biasInitializer =
            getInitializer(args.biasInitializer || this.DEFAULT_BIAS_INITIALIZER);
        this.biasConstraint = getConstraint(args.biasConstraint);
        this.biasRegularizer = getRegularizer(args.biasRegularizer);
        this.activityRegularizer = getRegularizer(args.activityRegularizer);
        this.dilationRate = normalizeArray(args.dilationRate == null ? 1 : args.dilationRate, rank, 'dilationRate');
        if (this.rank === 1 &&
            (Array.isArray(this.dilationRate) && this.dilationRate.length !== 1)) {
            throw new ValueError(`dilationRate must be a number or an array of a single number ` +
                `for 1D convolution, but received ` +
                `${JSON.stringify(this.dilationRate)}`);
        }
        else if (this.rank === 2) {
            if (typeof this.dilationRate === 'number') {
                this.dilationRate = [this.dilationRate, this.dilationRate];
            }
            else if (this.dilationRate.length !== 2) {
                throw new ValueError(`dilationRate must be a number or array of two numbers for 2D ` +
                    `convolution, but received ${JSON.stringify(this.dilationRate)}`);
            }
        }
        else if (this.rank === 3) {
            if (typeof this.dilationRate === 'number') {
                this.dilationRate =
                    [this.dilationRate, this.dilationRate, this.dilationRate];
            }
            else if (this.dilationRate.length !== 3) {
                throw new ValueError(`dilationRate must be a number or array of three numbers for 3D ` +
                    `convolution, but received ${JSON.stringify(this.dilationRate)}`);
            }
        }
    }
    static verifyArgs(args) {
        // Check config.kernelSize type and shape.
        generic_utils.assert('kernelSize' in args, `required key 'kernelSize' not in config`);
        if (typeof args.kernelSize !== 'number' &&
            !generic_utils.checkArrayTypeAndLength(args.kernelSize, 'number', 1, 3)) {
            throw new ValueError(`BaseConv expects config.kernelSize to be number or number[] with ` +
                `length 1, 2, or 3, but received ${JSON.stringify(args.kernelSize)}.`);
        }
    }
    getConfig() {
        const config = {
            kernelSize: this.kernelSize,
            strides: this.strides,
            padding: this.padding,
            dataFormat: this.dataFormat,
            dilationRate: this.dilationRate,
            activation: serializeActivation(this.activation),
            useBias: this.useBias,
            biasInitializer: serializeInitializer(this.biasInitializer),
            biasRegularizer: serializeRegularizer(this.biasRegularizer),
            activityRegularizer: serializeRegularizer(this.activityRegularizer),
            biasConstraint: serializeConstraint(this.biasConstraint)
        };
        const baseConfig = super.getConfig();
        Object.assign(config, baseConfig);
        return config;
    }
}
/**
 * Abstract nD convolution layer.  Ancestor of convolution layers which reduce
 * across channels, i.e., Conv1D and Conv2D, but not DepthwiseConv2D.
 */
export class Conv extends BaseConv {
    constructor(rank, args) {
        super(rank, args);
        this.kernel = null;
        Conv.verifyArgs(args);
        this.filters = args.filters;
        generic_utils.assertPositiveInteger(this.filters, 'filters');
        this.kernelInitializer = getInitializer(args.kernelInitializer || this.DEFAULT_KERNEL_INITIALIZER);
        this.kernelConstraint = getConstraint(args.kernelConstraint);
        this.kernelRegularizer = getRegularizer(args.kernelRegularizer);
    }
    build(inputShape) {
        inputShape = getExactlyOneShape(inputShape);
        const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1;
        if (inputShape[channelAxis] == null) {
            throw new ValueError(`The channel dimension of the input should be defined. ` +
                `Found ${inputShape[channelAxis]}`);
        }
        const inputDim = inputShape[channelAxis];
        const kernelShape = this.kernelSize.concat([inputDim, this.filters]);
        this.kernel = this.addWeight('kernel', kernelShape, null, this.kernelInitializer, this.kernelRegularizer, true, this.kernelConstraint);
        if (this.useBias) {
            this.bias = this.addWeight('bias', [this.filters], null, this.biasInitializer, this.biasRegularizer, true, this.biasConstraint);
        }
        this.inputSpec = [{ ndim: this.rank + 2, axes: { [channelAxis]: inputDim } }];
        this.built = true;
    }
    call(inputs, kwargs) {
        return tidy(() => {
            inputs = getExactlyOneTensor(inputs);
            let outputs;
            const biasValue = this.bias == null ? null : this.bias.read();
            const fusedActivationName = generic_utils.mapActivationToFusedKernel(this.activation.getClassName());
            if (fusedActivationName != null && this.rank === 2) {
                outputs = conv2dWithBiasActivation(inputs, this.kernel.read(), biasValue, this.strides, this.padding, this.dataFormat, this.dilationRate, fusedActivationName);
            }
            else {
                if (this.rank === 1) {
                    outputs = conv1dWithBias(inputs, this.kernel.read(), biasValue, this.strides[0], this.padding, this.dataFormat, this.dilationRate[0]);
                }
                else if (this.rank === 2) {
                    // TODO(cais): Move up to constructor.
                    outputs = conv2dWithBiasActivation(inputs, this.kernel.read(), biasValue, this.strides, this.padding, this.dataFormat, this.dilationRate);
                }
                else if (this.rank === 3) {
                    outputs = conv3dWithBias(inputs, this.kernel.read(), biasValue, this.strides, this.padding, this.dataFormat, this.dilationRate);
                }
                else {
                    throw new NotImplementedError('convolutions greater than 3D are not implemented yet.');
                }
                if (this.activation != null) {
                    outputs = this.activation.apply(outputs);
                }
            }
            return outputs;
        });
    }
    computeOutputShape(inputShape) {
        inputShape = getExactlyOneShape(inputShape);
        const newSpace = [];
        const space = (this.dataFormat === 'channelsLast') ?
            inputShape.slice(1, inputShape.length - 1) :
            inputShape.slice(2);
        for (let i = 0; i < space.length; ++i) {
            const newDim = convOutputLength(space[i], this.kernelSize[i], this.padding, this.strides[i], typeof this.dilationRate === 'number' ? this.dilationRate :
                this.dilationRate[i]);
            newSpace.push(newDim);
        }
        let outputShape = [inputShape[0]];
        if (this.dataFormat === 'channelsLast') {
            outputShape = outputShape.concat(newSpace);
            outputShape.push(this.filters);
        }
        else {
            outputShape.push(this.filters);
            outputShape = outputShape.concat(newSpace);
        }
        return outputShape;
    }
    getConfig() {
        const config = {
            filters: this.filters,
            kernelInitializer: serializeInitializer(this.kernelInitializer),
            kernelRegularizer: serializeRegularizer(this.kernelRegularizer),
            kernelConstraint: serializeConstraint(this.kernelConstraint)
        };
        const baseConfig = super.getConfig();
        Object.assign(config, baseConfig);
        return config;
    }
    static verifyArgs(args) {
        // Check config.filters type, shape, and value.
        if (!('filters' in args) || typeof args.filters !== 'number' ||
            args.filters < 1) {
            throw new ValueError(`Convolution layer expected config.filters to be a 'number' > 0 ` +
                `but got ${JSON.stringify(args.filters)}`);
        }
    }
}
class Conv2D extends Conv {
    constructor(args) {
        super(2, args);
        Conv2D.verifyArgs(args);
    }
    getConfig() {
        const config = super.getConfig();
        delete config['rank'];
        return config;
    }
    static verifyArgs(args) {
        // config.kernelSize must be a number or array of numbers.
        if ((typeof args.kernelSize !== 'number') &&
            !generic_utils.checkArrayTypeAndLength(args.kernelSize, 'number', 1, 2)) {
            throw new ValueError(`Conv2D expects config.kernelSize to be number or number[] with ` +
                `length 1 or 2, but received ${JSON.stringify(args.kernelSize)}.`);
        }
    }
}
/** @nocollapse */
Conv2D.className = 'Conv2D';
export { Conv2D };
serialization.registerClass(Conv2D);
class Conv3D extends Conv {
    constructor(args) {
        super(3, args);
        Conv3D.verifyArgs(args);
    }
    getConfig() {
        const config = super.getConfig();
        delete config['rank'];
        return config;
    }
    static verifyArgs(args) {
        // config.kernelSize must be a number or array of numbers.
        if (typeof args.kernelSize !== 'number') {
            if (!(Array.isArray(args.kernelSize) &&
                (args.kernelSize.length === 1 || args.kernelSize.length === 3))) {
                throw new ValueError(`Conv3D expects config.kernelSize to be number or` +
                    ` [number, number, number], but received ${JSON.stringify(args.kernelSize)}.`);
            }
        }
    }
}
/** @nocollapse */
Conv3D.className = 'Conv3D';
export { Conv3D };
serialization.registerClass(Conv3D);
class Conv2DTranspose extends Conv2D {
    constructor(args) {
        super(args);
        this.inputSpec = [new InputSpec({ ndim: 4 })];
        if (this.padding !== 'same' && this.padding !== 'valid') {
            throw new ValueError(`Conv2DTranspose currently supports only padding modes 'same' ` +
                `and 'valid', but received padding mode ${this.padding}`);
        }
    }
    build(inputShape) {
        inputShape = getExactlyOneShape(inputShape);
        if (inputShape.length !== 4) {
            throw new ValueError('Input should have rank 4; Received input shape: ' +
                JSON.stringify(inputShape));
        }
        const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1;
        if (inputShape[channelAxis] == null) {
            throw new ValueError('The channel dimension of the inputs should be defined. ' +
                'Found `None`.');
        }
        const inputDim = inputShape[channelAxis];
        const kernelShape = this.kernelSize.concat([this.filters, inputDim]);
        this.kernel = this.addWeight('kernel', kernelShape, 'float32', this.kernelInitializer, this.kernelRegularizer, true, this.kernelConstraint);
        if (this.useBias) {
            this.bias = this.addWeight('bias', [this.filters], 'float32', this.biasInitializer, this.biasRegularizer, true, this.biasConstraint);
        }
        // Set input spec.
        this.inputSpec =
            [new InputSpec({ ndim: 4, axes: { [channelAxis]: inputDim } })];
        this.built = true;
    }
    call(inputs, kwargs) {
        return tfc.tidy(() => {
            let input = getExactlyOneTensor(inputs);
            if (input.shape.length !== 4) {
                throw new ValueError(`Conv2DTranspose.call() expects input tensor to be rank-4, but ` +
                    `received a tensor of rank-${input.shape.length}`);
            }
            const inputShape = input.shape;
            const batchSize = inputShape[0];
            let hAxis;
            let wAxis;
            if (this.dataFormat === 'channelsFirst') {
                hAxis = 2;
                wAxis = 3;
            }
            else {
                hAxis = 1;
                wAxis = 2;
            }
            const height = inputShape[hAxis];
            const width = inputShape[wAxis];
            const kernelH = this.kernelSize[0];
            const kernelW = this.kernelSize[1];
            const strideH = this.strides[0];
            const strideW = this.strides[1];
            // Infer the dynamic output shape.
            const outHeight = deconvLength(height, strideH, kernelH, this.padding);
            const outWidth = deconvLength(width, strideW, kernelW, this.padding);
            // Porting Note: We don't branch based on `this.dataFormat` here,
            // because
            //   the tjfs-core function `conv2dTranspose` called below always
            //   assumes channelsLast.
            const outputShape = [batchSize, outHeight, outWidth, this.filters];
            if (this.dataFormat !== 'channelsLast') {
                input = tfc.transpose(input, [0, 2, 3, 1]);
            }
            let outputs = tfc.conv2dTranspose(input, this.kernel.read(), outputShape, this.strides, this.padding);
            if (this.dataFormat !== 'channelsLast') {
                outputs = tfc.transpose(outputs, [0, 3, 1, 2]);
            }
            if (this.bias != null) {
                outputs =
                    K.biasAdd(outputs, this.bias.read(), this.dataFormat);
            }
            if (this.activation != null) {
                outputs = this.activation.apply(outputs);
            }
            return outputs;
        });
    }
    computeOutputShape(inputShape) {
        inputShape = getExactlyOneShape(inputShape);
        const outputShape = inputShape.slice();
        let channelAxis;
        let heightAxis;
        let widthAxis;
        if (this.dataFormat === 'channelsFirst') {
            channelAxis = 1;
            heightAxis = 2;
            widthAxis = 3;
        }
        else {
            channelAxis = 3;
            heightAxis = 1;
            widthAxis = 2;
        }
        const kernelH = this.kernelSize[0];
        const kernelW = this.kernelSize[1];
        const strideH = this.strides[0];
        const strideW = this.strides[1];
        outputShape[channelAxis] = this.filters;
        outputShape[heightAxis] =
            deconvLength(outputShape[heightAxis], strideH, kernelH, this.padding);
        outputShape[widthAxis] =
            deconvLength(outputShape[widthAxis], strideW, kernelW, this.padding);
        return outputShape;
    }
    getConfig() {
        const config = super.getConfig();
        delete config['dilationRate'];
        return config;
    }
}
/** @nocollapse */
Conv2DTranspose.className = 'Conv2DTranspose';
export { Conv2DTranspose };
serialization.registerClass(Conv2DTranspose);
class Conv3DTranspose extends Conv3D {
    constructor(args) {
        super(args);
        this.inputSpec = [new InputSpec({ ndim: 5 })];
        if (this.padding !== 'same' && this.padding !== 'valid') {
            throw new ValueError(`Conv3DTranspose currently supports only padding modes 'same' ` +
                `and 'valid', but received padding mode ${this.padding}`);
        }
    }
    build(inputShape) {
        inputShape = getExactlyOneShape(inputShape);
        if (inputShape.length !== 5) {
            throw new ValueError('Input should have rank 5; Received input shape: ' +
                JSON.stringify(inputShape));
        }
        const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1;
        if (inputShape[channelAxis] == null) {
            throw new ValueError('The channel dimension of the inputs should be defined. ' +
                'Found `None`.');
        }
        const inputDim = inputShape[channelAxis];
        const kernelShape = this.kernelSize.concat([this.filters, inputDim]);
        this.kernel = this.addWeight('kernel', kernelShape, 'float32', this.kernelInitializer, this.kernelRegularizer, true, this.kernelConstraint);
        if (this.useBias) {
            this.bias = this.addWeight('bias', [this.filters], 'float32', this.biasInitializer, this.biasRegularizer, true, this.biasConstraint);
        }
        // Set input spec.
        this.inputSpec =
            [new InputSpec({ ndim: 5, axes: { [channelAxis]: inputDim } })];
        this.built = true;
    }
    call(inputs, kwargs) {
        return tfc.tidy(() => {
            let input = getExactlyOneTensor(inputs);
            if (input.shape.length !== 5) {
                throw new ValueError(`Conv3DTranspose.call() expects input tensor to be rank-4, but ` +
                    `received a tensor of rank-${input.shape.length}`);
            }
            const inputShape = input.shape;
            const batchSize = inputShape[0];
            let hAxis;
            let wAxis;
            let dAxis;
            if (this.dataFormat === 'channelsFirst') {
                dAxis = 2;
                hAxis = 3;
                wAxis = 4;
            }
            else {
                dAxis = 1;
                hAxis = 2;
                wAxis = 3;
            }
            const depth = inputShape[dAxis];
            const height = inputShape[hAxis];
            const width = inputShape[wAxis];
            const kernelD = this.kernelSize[0];
            const kernelH = this.kernelSize[1];
            const kernelW = this.kernelSize[2];
            const strideD = this.strides[0];
            const strideH = this.strides[1];
            const strideW = this.strides[2];
            // Infer the dynamic output shape.
            const outDepth = deconvLength(depth, strideD, kernelD, this.padding);
            const outHeight = deconvLength(height, strideH, kernelH, this.padding);
            const outWidth = deconvLength(width, strideW, kernelW, this.padding);
            // Same as `conv2dTranspose`. We always assumes channelsLast.
            const outputShape = [batchSize, outDepth, outHeight, outWidth, this.filters];
            if (this.dataFormat !== 'channelsLast') {
                input = tfc.transpose(input, [0, 2, 3, 4, 1]);
            }
            let outputs = tfc.conv3dTranspose(input, this.kernel.read(), outputShape, this.strides, this.padding);
            if (this.dataFormat !== 'channelsLast') {
                outputs = tfc.transpose(outputs, [0, 4, 1, 2, 3]);
            }
            if (this.bias !== null) {
                outputs =
                    K.biasAdd(outputs, this.bias.read(), this.dataFormat);
            }
            if (this.activation !== null) {
                outputs = this.activation.apply(outputs);
            }
            return outputs;
        });
    }
    computeOutputShape(inputShape) {
        inputShape = getExactlyOneShape(inputShape);
        const outputShape = inputShape.slice();
        let channelAxis;
        let depthAxis;
        let heightAxis;
        let widthAxis;
        if (this.dataFormat === 'channelsFirst') {
            channelAxis = 1;
            depthAxis = 2;
            heightAxis = 3;
            widthAxis = 4;
        }
        else {
            channelAxis = 4;
            depthAxis = 1;
            heightAxis = 2;
            widthAxis = 3;
        }
        const kernelD = this.kernelSize[0];
        const kernelH = this.kernelSize[1];
        const kernelW = this.kernelSize[2];
        const strideD = this.strides[0];
        const strideH = this.strides[1];
        const strideW = this.strides[2];
        outputShape[channelAxis] = this.filters;
        outputShape[depthAxis] =
            deconvLength(outputShape[depthAxis], strideD, kernelD, this.padding);
        outputShape[heightAxis] =
            deconvLength(outputShape[heightAxis], strideH, kernelH, this.padding);
        outputShape[widthAxis] =
            deconvLength(outputShape[widthAxis], strideW, kernelW, this.padding);
        return outputShape;
    }
    getConfig() {
        const config = super.getConfig();
        delete config['dilationRate'];
        return config;
    }
}
/** @nocollapse */
Conv3DTranspose.className = 'Conv3DTranspose';
export { Conv3DTranspose };
serialization.registerClass(Conv3DTranspose);
class SeparableConv extends Conv {
    constructor(rank, config) {
        super(rank, config);
        this.DEFAULT_DEPTHWISE_INITIALIZER = 'glorotUniform';
        this.DEFAULT_POINTWISE_INITIALIZER = 'glorotUniform';
        this.depthwiseKernel = null;
        this.pointwiseKernel = null;
        if (config.filters == null) {
            throw new ValueError('The `filters` configuration field is required by SeparableConv, ' +
                'but is unspecified.');
        }
        if (config.kernelInitializer != null || config.kernelRegularizer != null ||
            config.kernelConstraint != null) {
            throw new ValueError('Fields kernelInitializer, kernelRegularizer and kernelConstraint ' +
                'are invalid for SeparableConv2D. Use depthwiseInitializer, ' +
                'depthwiseRegularizer, depthwiseConstraint, pointwiseInitializer, ' +
                'pointwiseRegularizer and pointwiseConstraint instead.');
        }
        if (config.padding != null && config.padding !== 'same' &&
            config.padding !== 'valid') {
            throw new ValueError(`SeparableConv${this.rank}D supports only padding modes: ` +
                `'same' and 'valid', but received ${JSON.stringify(config.padding)}`);
        }
        this.depthMultiplier =
            config.depthMultiplier == null ? 1 : config.depthMultiplier;
        this.depthwiseInitializer = getInitializer(config.depthwiseInitializer || this.DEFAULT_DEPTHWISE_INITIALIZER);
        this.depthwiseRegularizer = getRegularizer(config.depthwiseRegularizer);
        this.depthwiseConstraint = getConstraint(config.depthwiseConstraint);
        this.pointwiseInitializer = getInitializer(config.depthwiseInitializer || this.DEFAULT_POINTWISE_INITIALIZER);
        this.pointwiseRegularizer = getRegularizer(config.pointwiseRegularizer);
        this.pointwiseConstraint = getConstraint(config.pointwiseConstraint);
    }
    build(inputShape) {
        inputShape = getExactlyOneShape(inputShape);
        if (inputShape.length < this.rank + 2) {
            throw new ValueError(`Inputs to SeparableConv${this.rank}D should have rank ` +
                `${this.rank + 2}, but received input shape: ` +
                `${JSON.stringify(inputShape)}`);
        }
        const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1;
        if (inputShape[channelAxis] == null || inputShape[channelAxis] < 0) {
            throw new ValueError(`The channel dimension of the inputs should be defined, ` +
                `but found ${JSON.stringify(inputShape[channelAxis])}`);
        }
        const inputDim = inputShape[channelAxis];
        const depthwiseKernelShape = this.kernelSize.concat([inputDim, this.depthMultiplier]);
        const pointwiseKernelShape = [];
        for (let i = 0; i < this.rank; ++i) {
            pointwiseKernelShape.push(1);
        }
        pointwiseKernelShape.push(inputDim * this.depthMultiplier, this.filters);
        const trainable = true;
        this.depthwiseKernel = this.addWeight('depthwise_kernel', depthwiseKernelShape, 'float32', this.depthwiseInitializer, this.depthwiseRegularizer, trainable, this.depthwiseConstraint);
        this.pointwiseKernel = this.addWeight('pointwise_kernel', pointwiseKernelShape, 'float32', this.pointwiseInitializer, this.pointwiseRegularizer, trainable, this.pointwiseConstraint);
        if (this.useBias) {
            this.bias = this.addWeight('bias', [this.filters], 'float32', this.biasInitializer, this.biasRegularizer, trainable, this.biasConstraint);
        }
        else {
            this.bias = null;
        }
        this.inputSpec =
            [new InputSpec({ ndim: this.rank + 2, axes: { [channelAxis]: inputDim } })];
        this.built = true;
    }
    call(inputs, kwargs) {
        return tidy(() => {
            inputs = getExactlyOneTensor(inputs);
            let output;
            if (this.rank === 1) {
                throw new NotImplementedError('1D separable convolution is not implemented yet.');
            }
            else if (this.rank === 2) {
                if (this.dataFormat === 'channelsFirst') {
                    inputs = tfc.transpose(inputs, [0, 2, 3, 1]); // NCHW -> NHWC.
                }
                output = tfc.separableConv2d(inputs, this.depthwiseKernel.read(), this.pointwiseKernel.read(), this.strides, this.padding, this.dilationRate, 'NHWC');
            }
            if (this.useBias) {
                output = K.biasAdd(output, this.bias.read(), this.dataFormat);
            }
            if (this.activation != null) {
                output = this.activation.apply(output);
            }
            if (this.dataFormat === 'channelsFirst') {
                output = tfc.transpose(output, [0, 3, 1, 2]); // NHWC -> NCHW.
            }
            return output;
        });
    }
    getConfig() {
        const config = super.getConfig();
        delete config['rank'];
        delete config['kernelInitializer'];
        delete config['kernelRegularizer'];
        delete config['kernelConstraint'];
        config['depthwiseInitializer'] =
            serializeInitializer(this.depthwiseInitializer);
        config['pointwiseInitializer'] =
            serializeInitializer(this.pointwiseInitializer);
        config['depthwiseRegularizer'] =
            serializeRegularizer(this.depthwiseRegularizer);
        config['pointwiseRegularizer'] =
            serializeRegularizer(this.pointwiseRegularizer);
        config['depthwiseConstraint'] =
            serializeConstraint(this.depthwiseConstraint);
        config['pointwiseConstraint'] =
            serializeConstraint(this.pointwiseConstraint);
        return config;
    }
}
/** @nocollapse */
SeparableConv.className = 'SeparableConv';
export { SeparableConv };
class SeparableConv2D extends SeparableConv {
    constructor(args) {
        super(2, args);
    }
}
/** @nocollapse */
SeparableConv2D.className = 'SeparableConv2D';
export { SeparableConv2D };
serialization.registerClass(SeparableConv2D);
class Conv1D extends Conv {
    constructor(args) {
        super(1, args);
        Conv1D.verifyArgs(args);
        this.inputSpec = [{ ndim: 3 }];
    }
    getConfig() {
        const config = super.getConfig();
        delete config['rank'];
        delete config['dataFormat'];
        return config;
    }
    static verifyArgs(args) {
        // config.kernelSize must be a number or array of numbers.
        if (typeof args.kernelSize !== 'number' &&
            !generic_utils.checkArrayTypeAndLength(args.kernelSize, 'number', 1, 1)) {
            throw new ValueError(`Conv1D expects config.kernelSize to be number or number[] with ` +
                `length 1, but received ${JSON.stringify(args.kernelSize)}.`);
        }
    }
}
/** @nocollapse */
Conv1D.className = 'Conv1D';
export { Conv1D };
serialization.registerClass(Conv1D);
class Cropping2D extends Layer {
    constructor(args) {
        super(args);
        if (typeof args.cropping === 'number') {
            this.cropping =
                [[args.cropping, args.cropping], [args.cropping, args.cropping]];
        }
        else if (typeof args.cropping[0] === 'number') {
            this.cropping = [
                [args.cropping[0], args.cropping[0]],
                [args.cropping[1], args.cropping[1]]
            ];
        }
        else {
            this.cropping = args.cropping;
        }
        this.dataFormat =
            args.dataFormat === undefined ? 'channelsLast' : args.dataFormat;
        this.inputSpec = [{ ndim: 4 }];
    }
    computeOutputShape(inputShape) {
        if (this.dataFormat === 'channelsFirst') {
            return [
                inputShape[0], inputShape[1],
                inputShape[2] - this.cropping[0][0] - this.cropping[0][1],
                inputShape[3] - this.cropping[1][0] - this.cropping[1][1]
            ];
        }
        else {
            return [
                inputShape[0],
                inputShape[1] - this.cropping[0][0] - this.cropping[0][1],
                inputShape[2] - this.cropping[1][0] - this.cropping[1][1], inputShape[3]
            ];
        }
    }
    call(inputs, kwargs) {
        return tidy(() => {
            inputs = getExactlyOneTensor(inputs);
            if (this.dataFormat === 'channelsLast') {
                const hSliced = K.sliceAlongAxis(inputs, this.cropping[0][0], inputs.shape[1] - this.cropping[0][0] - this.cropping[0][1], 2);
                return K.sliceAlongAxis(hSliced, this.cropping[1][0], inputs.shape[2] - this.cropping[1][1] - this.cropping[1][0], 3);
            }
            else {
                const hSliced = K.sliceAlongAxis(inputs, this.cropping[0][0], inputs.shape[2] - this.cropping[0][0] - this.cropping[0][1], 3);
                return K.sliceAlongAxis(hSliced, this.cropping[1][0], inputs.shape[3] - this.cropping[1][1] - this.cropping[1][0], 4);
            }
        });
    }
    getConfig() {
        const config = { cropping: this.cropping, dataFormat: this.dataFormat };
        const baseConfig = super.getConfig();
        Object.assign(config, baseConfig);
        return config;
    }
}
/** @nocollapse */
Cropping2D.className = 'Cropping2D';
export { Cropping2D };
serialization.registerClass(Cropping2D);
class UpSampling2D extends Layer {
    constructor(args) {
        super(args);
        this.DEFAULT_SIZE = [2, 2];
        this.inputSpec = [{ ndim: 4 }];
        this.size = args.size == null ? this.DEFAULT_SIZE : args.size;
        this.dataFormat =
            args.dataFormat == null ? 'channelsLast' : args.dataFormat;
        checkDataFormat(this.dataFormat);
        this.interpolation =
            args.interpolation == null ? 'nearest' : args.interpolation;
        checkInterpolationFormat(this.interpolation);
    }
    computeOutputShape(inputShape) {
        if (this.dataFormat === 'channelsFirst') {
            const height = inputShape[2] == null ? null : this.size[0] * inputShape[2];
            const width = inputShape[3] == null ? null : this.size[1] * inputShape[3];
            return [inputShape[0], inputShape[1], height, width];
        }
        else {
            const height = inputShape[1] == null ? null : this.size[0] * inputShape[1];
            const width = inputShape[2] == null ? null : this.size[1] * inputShape[2];
            return [inputShape[0], height, width, inputShape[3]];
        }
    }
    call(inputs, kwargs) {
        return tfc.tidy(() => {
            let input = getExactlyOneTensor(inputs);
            const inputShape = input.shape;
            if (this.dataFormat === 'channelsFirst') {
                input = tfc.transpose(input, [0, 2, 3, 1]);
                const height = this.size[0] * inputShape[2];
                const width = this.size[1] * inputShape[3];
                const resized = this.interpolation === 'nearest' ?
                    tfc.image.resizeNearestNeighbor(input, [height, width]) :
                    tfc.image.resizeBilinear(input, [height, width]);
                return tfc.transpose(resized, [0, 3, 1, 2]);
            }
            else {
                const height = this.size[0] * inputShape[1];
                const width = this.size[1] * inputShape[2];
                return this.interpolation === 'nearest' ?
                    tfc.image.resizeNearestNeighbor(input, [height, width]) :
                    tfc.image.resizeBilinear(input, [height, width]);
            }
        });
    }
    getConfig() {
        const config = {
            size: this.size,
            dataFormat: this.dataFormat,
            interpolation: this.interpolation
        };
        const baseConfig = super.getConfig();
        Object.assign(config, baseConfig);
        return config;
    }
}
/** @nocollapse */
UpSampling2D.className = 'UpSampling2D';
export { UpSampling2D };
serialization.registerClass(UpSampling2D);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udm9sdXRpb25hbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtbGF5ZXJzL3NyYy9sYXllcnMvY29udm9sdXRpb25hbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUVIOztHQUVHO0FBRUgsT0FBTyxLQUFLLEdBQUcsTUFBTSx1QkFBdUIsQ0FBQztBQUM3QyxPQUFPLEVBQVEsYUFBYSxFQUE0RCxJQUFJLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUUzSCxPQUFPLEVBQWEsYUFBYSxFQUFFLG1CQUFtQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUUsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBQ2xELE9BQU8sS0FBSyxDQUFDLE1BQU0seUJBQXlCLENBQUM7QUFDN0MsT0FBTyxFQUFDLGVBQWUsRUFBRSx3QkFBd0IsRUFBRSxnQkFBZ0IsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUN0RixPQUFPLEVBQW1DLGFBQWEsRUFBRSxtQkFBbUIsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3BHLE9BQU8sRUFBQyxTQUFTLEVBQUUsS0FBSyxFQUFZLE1BQU0sb0JBQW9CLENBQUM7QUFDL0QsT0FBTyxFQUFDLG1CQUFtQixFQUFFLFVBQVUsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUMxRCxPQUFPLEVBQUMsY0FBYyxFQUFzQyxvQkFBb0IsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBR3pHLE9BQU8sRUFBQyxjQUFjLEVBQXNDLG9CQUFvQixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFFekcsT0FBTyxFQUFDLGdCQUFnQixFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUNuRixPQUFPLEtBQUssYUFBYSxNQUFNLHdCQUF3QixDQUFDO0FBQ3hELE9BQU8sRUFBQyxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBQyxNQUFNLHNCQUFzQixD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TyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQzVCLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO2FBQ3JFO2lCQUFNO2dCQUNMLE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQyxjQUFjLENBQzVCLE1BQU0sRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUMzQixNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDcEUsT0FBTyxDQUFDLENBQUMsY0FBYyxDQUNuQixPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFDNUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7YUFDckU7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFUSxTQUFTO1FBQ2hCLE1BQU0sTUFBTSxHQUFHLEVBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUMsQ0FBQztRQUN0RSxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUM7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LEVBQUUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUN6RCxHQUFHLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQzthQUN0RDtRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVRLFNBQVM7UUFDaEIsTUFBTSxNQUFNLEdBQUc7WUFDWCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7WUFDZixVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVU7WUFDM0IsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO1NBQ3BDLENBQUM7UUFDRixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDckMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDbEMsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQzs7QUFsRUQsa0JBQWtCO0FBQ1gsc0JBQVMsR0FBRyxjQUFjLEFBQWpCLENBQWtCO1NBRnZCLFlBQVk7QUFxRXpCLGFBQWEsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAxOCBHb29nbGUgTExDXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlXG4gKiBsaWNlbnNlIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgb3IgYXRcbiAqIGh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlULlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG4vKipcbiAqIFRlbnNvckZsb3cuanMgTGF5ZXJzOiBDb252b2x1dGlvbmFsIExheWVyc1xuICovXG5cbmltcG9ydCAqIGFzIHRmYyBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuaW1wb3J0IHtmdXNlZCwgc2VyaWFsaXphdGlvbiwgVGVuc29yLCBUZW5zb3IxRCwgVGVuc29yMkQsIFRlbnNvcjNELCBUZW5zb3I0RCwgVGVuc29yNUQsIHRpZHl9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCB7QWN0aXZhdGlvbiwgZ2V0QWN0aXZhdGlvbiwgc2VyaWFsaXplQWN0aXZhdGlvbn0gZnJvbSAnLi4vYWN0aXZhdGlvbnMnO1xuaW1wb3J0IHtpbWFnZURhdGFGb3JtYXR9IGZyb20gJy4uL2JhY2tlbmQvY29tbW9uJztcbmltcG9ydCAqIGFzIEsgZnJvbSAnLi4vYmFja2VuZC90ZmpzX2JhY2tlbmQnO1xuaW1wb3J0IHtjaGVja0RhdGFGb3JtYXQsIGNoZWNrSW50ZXJwb2xhdGlvbkZvcm1hdCwgY2hlY2tQYWRkaW5nTW9kZX0gZnJvbSAnLi4vY29tbW9uJztcbmltcG9ydCB7Q29uc3RyYWludCwgQ29uc3RyYWludElkZW50aWZpZXIsIGdldENvbnN0cmFpbnQsIHNlcmlhbGl6ZUNvbnN0cmFpbnR9IGZyb20gJy4uL2NvbnN0cmFpbnRzJztcbmltcG9ydCB7SW5wdXRTcGVjLCBMYXllciwgTGF5ZXJBcmdzfSBmcm9tICcuLi9lbmdpbmUvdG9wb2xvZ3knO1xuaW1wb3J0IHtOb3RJbXBsZW1lbnRlZEVycm9yLCBWYWx1ZUVycm9yfSBmcm9tICcuLi9lcnJvcnMnO1xuaW1wb3J0IHtnZXRJbml0aWFsaXplciwgSW5pdGlhbGl6ZXIsIEluaXRpYWxpemVySWRlbnRpZmllciwgc2VyaWFsaXplSW5pdGlhbGl6ZXJ9IGZyb20gJy4uL2luaXRpYWxpemVycyc7XG5pbXBvcnQge0FjdGl2YXRpb25JZGVudGlmaWVyfSBmcm9tICcuLi9rZXJhc19mb3JtYXQvYWN0aXZhdGlvbl9jb25maWcnO1xuaW1wb3J0IHtEYXRhRm9ybWF0LCBJbnRlcnBvbGF0aW9uRm9ybWF0LCBQYWRkaW5nTW9kZSwgU2hhcGV9IGZyb20gJy4uL2tlcmFzX2Zvcm1hdC9jb21tb24nO1xuaW1wb3J0IHtnZXRSZWd1bGFyaXplciwgUmVndWxhcml6ZXIsIFJlZ3VsYXJpemVySWRlbnRpZmllciwgc2VyaWFsaXplUmVndWxhcml6ZXJ9IGZyb20gJy4uL3JlZ3VsYXJpemVycyc7XG5pbXBvcnQge0t3YXJnc30gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHtjb252T3V0cHV0TGVuZ3RoLCBkZWNvbnZMZW5ndGgsIG5vcm1hbGl6ZUFycmF5fSBmcm9tICcuLi91dGlscy9jb252X3V0aWxzJztcbmltcG9ydCAqIGFzIGdlbmVyaWNfdXRpbHMgZnJvbSAnLi4vdXRpbHMvZ2VuZXJpY191dGlscyc7XG5pbXBvcnQge2dldEV4YWN0bHlPbmVTaGFwZSwgZ2V0RXhhY3RseU9uZVRlbnNvcn0gZnJvbSAnLi4vdXRpbHMvdHlwZXNfdXRpbHMnO1xuaW1wb3J0IHtMYXllclZhcmlhYmxlfSBmcm9tICcuLi92YXJpYWJsZXMnO1xuXG4vKipcbiAqIFRyYW5zcG9zZSBhbmQgY2FzdCB0aGUgaW5wdXQgYmVmb3JlIHRoZSBjb252MmQuXG4gKiBAcGFyYW0geCBJbnB1dCBpbWFnZSB0ZW5zb3IuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdFxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJlcHJvY2Vzc0NvbnYyRElucHV0KFxuICAgIHg6IFRlbnNvciwgZGF0YUZvcm1hdDogRGF0YUZvcm1hdCk6IFRlbnNvciB7XG4gIC8vIFRPRE8oY2Fpcyk6IENhc3QgdHlwZSB0byBmbG9hdDMyIGlmIG5vdC5cbiAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgIGNoZWNrRGF0YUZvcm1hdChkYXRhRm9ybWF0KTtcbiAgICBpZiAoZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnKSB7XG4gICAgICByZXR1cm4gdGZjLnRyYW5zcG9zZSh4LCBbMCwgMiwgMywgMV0pOyAgLy8gTkNIVyAtPiBOSFdDLlxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4geDtcbiAgICB9XG4gIH0pO1xufVxuXG4vKipcbiAqIFRyYW5zcG9zZSBhbmQgY2FzdCB0aGUgaW5wdXQgYmVmb3JlIHRoZSBjb252M2QuXG4gKiBAcGFyYW0geCBJbnB1dCBpbWFnZSB0ZW5zb3IuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdFxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJlcHJvY2Vzc0NvbnYzRElucHV0KFxuICAgIHg6IFRlbnNvciwgZGF0YUZvcm1hdDogRGF0YUZvcm1hdCk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBjaGVja0RhdGFGb3JtYXQoZGF0YUZvcm1hdCk7XG4gICAgaWYgKGRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgcmV0dXJuIHRmYy50cmFuc3Bvc2UoeCwgWzAsIDIsIDMsIDQsIDFdKTsgIC8vIE5DREhXIC0+IE5ESFdDLlxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4geDtcbiAgICB9XG4gIH0pO1xufVxuXG4vKipcbiAqIDFELWNvbnZvbHV0aW9uIHdpdGggYmlhcyBhZGRlZC5cbiAqXG4gKiBQb3J0aW5nIE5vdGU6IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgZXhpc3QgaW4gdGhlIFB5dGhvbiBLZXJhcyBiYWNrZW5kLlxuICogICBJdCBpcyBleGFjdGx5IHRoZSBzYW1lIGFzIGBjb252MmRgLCBleGNlcHQgdGhlIGFkZGVkIGBiaWFzYC5cbiAqXG4gKiBAcGFyYW0geCBJbnB1dCB0ZW5zb3IsIHJhbmstMywgb2Ygc2hhcGUgYFtiYXRjaFNpemUsIHdpZHRoLCBpbkNoYW5uZWxzXWAuXG4gKiBAcGFyYW0ga2VybmVsIEtlcm5lbCwgcmFuay0zLCBvZiBzaGFwZSBgW2ZpbHRlcldpZHRoLCBpbkRlcHRoLCBvdXREZXB0aF1gLlxuICogQHBhcmFtIGJpYXMgQmlhcywgcmFuay0zLCBvZiBzaGFwZSBgW291dERlcHRoXWAuXG4gKiBAcGFyYW0gc3RyaWRlc1xuICogQHBhcmFtIHBhZGRpbmcgUGFkZGluZyBtb2RlLlxuICogQHBhcmFtIGRhdGFGb3JtYXQgRGF0YSBmb3JtYXQuXG4gKiBAcGFyYW0gZGlsYXRpb25SYXRlXG4gKiBAcmV0dXJucyBUaGUgcmVzdWx0IG9mIHRoZSAxRCBjb252b2x1dGlvbi5cbiAqIEB0aHJvd3MgVmFsdWVFcnJvciwgaWYgYHhgLCBga2VybmVsYCBvciBgYmlhc2AgaXMgbm90IG9mIHRoZSBjb3JyZWN0IHJhbmsuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252MWRXaXRoQmlhcyhcbiAgICB4OiBUZW5zb3IsIGtlcm5lbDogVGVuc29yLCBiaWFzOiBUZW5zb3IsIHN0cmlkZXMgPSAxLCBwYWRkaW5nID0gJ3ZhbGlkJyxcbiAgICBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdCwgZGlsYXRpb25SYXRlID0gMSk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBpZiAoZGF0YUZvcm1hdCA9PSBudWxsKSB7XG4gICAgICBkYXRhRm9ybWF0ID0gaW1hZ2VEYXRhRm9ybWF0KCk7XG4gICAgfVxuICAgIGNoZWNrRGF0YUZvcm1hdChkYXRhRm9ybWF0KTtcbiAgICAvLyBDaGVjayB0aGUgcmFua3Mgb2YgeCwga2VybmVsIGFuZCBiaWFzLlxuICAgIGlmICh4LnNoYXBlLmxlbmd0aCAhPT0gMykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFRoZSBpbnB1dCBvZiBhIGNvbnYxZFdpdGhCaWFzIG9wZXJhdGlvbiBzaG91bGQgYmUgMywgYnV0IGlzIGAgK1xuICAgICAgICAgIGAke3guc2hhcGUubGVuZ3RofSBpbnN0ZWFkLmApO1xuICAgIH1cbiAgICBpZiAoa2VybmVsLnNoYXBlLmxlbmd0aCAhPT0gMykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFRoZSBrZXJuZWwgZm9yIGEgY29udjFkV2l0aEJpYXMgb3BlcmF0aW9uIHNob3VsZCBiZSAzLCBidXQgaXMgYCArXG4gICAgICAgICAgYCR7a2VybmVsLnNoYXBlLmxlbmd0aH0gaW5zdGVhZGApO1xuICAgIH1cbiAgICBpZiAoYmlhcyAhPSBudWxsICYmIGJpYXMuc2hhcGUubGVuZ3RoICE9PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgVGhlIGJpYXMgZm9yIGEgY29udjFkV2l0aEJpYXMgb3BlcmF0aW9uIHNob3VsZCBiZSAxLCBidXQgaXMgYCArXG4gICAgICAgICAgYCR7a2VybmVsLnNoYXBlLmxlbmd0aH0gaW5zdGVhZGApO1xuICAgIH1cbiAgICAvLyBUT0RPKGNhaXMpOiBTdXBwb3J0IENBVVNBTCBwYWRkaW5nIG1vZGUuXG4gICAgaWYgKGRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgeCA9IHRmYy50cmFuc3Bvc2UoeCwgWzAsIDIsIDFdKTsgIC8vIE5DVyAtPiBOV0MuXG4gICAgfVxuICAgIGlmIChwYWRkaW5nID09PSAnY2F1c2FsJykge1xuICAgICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoXG4gICAgICAgICAgJ1RoZSBzdXBwb3J0IGZvciBDQVVTQUwgcGFkZGluZyBtb2RlIGluIGNvbnYxZFdpdGhCaWFzIGlzIG5vdCAnICtcbiAgICAgICAgICAnaW1wbGVtZW50ZWQgeWV0LicpO1xuICAgIH1cbiAgICBsZXQgeTogVGVuc29yID0gdGZjLmNvbnYxZChcbiAgICAgICAgeCBhcyBUZW5zb3IyRCB8IFRlbnNvcjNELCBrZXJuZWwgYXMgVGVuc29yM0QsIHN0cmlkZXMsXG4gICAgICAgIHBhZGRpbmcgPT09ICdzYW1lJyA/ICdzYW1lJyA6ICd2YWxpZCcsICdOV0MnLCBkaWxhdGlvblJhdGUpO1xuICAgIGlmIChiaWFzICE9IG51bGwpIHtcbiAgICAgIHkgPSBLLmJpYXNBZGQoeSwgYmlhcyk7XG4gICAgfVxuICAgIHJldHVybiB5O1xuICB9KTtcbn1cblxuLyoqXG4gKiAxRC1jb252b2x1dGlvbi5cbiAqXG4gKiBAcGFyYW0geCBJbnB1dCB0ZW5zb3IsIHJhbmstMywgb2Ygc2hhcGUgYFtiYXRjaFNpemUsIHdpZHRoLCBpbkNoYW5uZWxzXWAuXG4gKiBAcGFyYW0ga2VybmVsIEtlcm5lbCwgcmFuay0zLCBvZiBzaGFwZSBgW2ZpbHRlcldpZHRoLCBpbkRlcHRoLCBvdXREZXB0aF1gLnNcbiAqIEBwYXJhbSBzdHJpZGVzXG4gKiBAcGFyYW0gcGFkZGluZyBQYWRkaW5nIG1vZGUuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdCBEYXRhIGZvcm1hdC5cbiAqIEBwYXJhbSBkaWxhdGlvblJhdGVcbiAqIEByZXR1cm5zIFRoZSByZXN1bHQgb2YgdGhlIDFEIGNvbnZvbHV0aW9uLlxuICogQHRocm93cyBWYWx1ZUVycm9yLCBpZiBgeGAsIGBrZXJuZWxgIG9yIGBiaWFzYCBpcyBub3Qgb2YgdGhlIGNvcnJlY3QgcmFuay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnYxZChcbiAgICB4OiBUZW5zb3IsIGtlcm5lbDogVGVuc29yLCBzdHJpZGVzID0gMSwgcGFkZGluZyA9ICd2YWxpZCcsXG4gICAgZGF0YUZvcm1hdD86IERhdGFGb3JtYXQsIGRpbGF0aW9uUmF0ZSA9IDEpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgY2hlY2tEYXRhRm9ybWF0KGRhdGFGb3JtYXQpO1xuICAgIHJldHVybiBjb252MWRXaXRoQmlhcyhcbiAgICAgICAgeCwga2VybmVsLCBudWxsLCBzdHJpZGVzLCBwYWRkaW5nLCBkYXRhRm9ybWF0LCBkaWxhdGlvblJhdGUpO1xuICB9KTtcbn1cblxuLyoqXG4gKiAyRCBDb252b2x1dGlvblxuICogQHBhcmFtIHhcbiAqIEBwYXJhbSBrZXJuZWwga2VybmVsIG9mIHRoZSBjb252b2x1dGlvbi5cbiAqIEBwYXJhbSBzdHJpZGVzIHN0cmlkZXMgYXJyYXkuXG4gKiBAcGFyYW0gcGFkZGluZyBwYWRkaW5nIG1vZGUuIERlZmF1bHQgdG8gJ3ZhbGlkJy5cbiAqIEBwYXJhbSBkYXRhRm9ybWF0IGRhdGEgZm9ybWF0LiBEZWZhdWx0cyB0byAnY2hhbm5lbHNMYXN0Jy5cbiAqIEBwYXJhbSBkaWxhdGlvblJhdGUgZGlsYXRpb24gcmF0ZSBhcnJheS5cbiAqIEByZXR1cm5zIFJlc3VsdCBvZiB0aGUgMkQgcG9vbGluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnYyZChcbiAgICB4OiBUZW5zb3IsIGtlcm5lbDogVGVuc29yLCBzdHJpZGVzID0gWzEsIDFdLCBwYWRkaW5nID0gJ3ZhbGlkJyxcbiAgICBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdCwgZGlsYXRpb25SYXRlPzogW251bWJlciwgbnVtYmVyXSk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBjaGVja0RhdGFGb3JtYXQoZGF0YUZvcm1hdCk7XG4gICAgcmV0dXJuIGNvbnYyZFdpdGhCaWFzQWN0aXZhdGlvbihcbiAgICAgICAgeCwga2VybmVsLCBudWxsLCBzdHJpZGVzLCBwYWRkaW5nLCBkYXRhRm9ybWF0LCBkaWxhdGlvblJhdGUpO1xuICB9KTtcbn1cblxuLyoqXG4gKiAyRCBDb252b2x1dGlvbiB3aXRoIGFuIGFkZGVkIGJpYXMgYW5kIG9wdGlvbmFsIGFjdGl2YXRpb24uXG4gKiBOb3RlOiBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IGV4aXN0IGluIHRoZSBQeXRob24gS2VyYXMgQmFja2VuZC4gVGhpcyBmdW5jdGlvblxuICogaXMgZXhhY3RseSB0aGUgc2FtZSBhcyBgY29udjJkYCwgZXhjZXB0IHRoZSBhZGRlZCBgYmlhc2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252MmRXaXRoQmlhc0FjdGl2YXRpb24oXG4gICAgeDogVGVuc29yLCBrZXJuZWw6IFRlbnNvciwgYmlhczogVGVuc29yLCBzdHJpZGVzID0gWzEsIDFdLFxuICAgIHBhZGRpbmcgPSAndmFsaWQnLCBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdCwgZGlsYXRpb25SYXRlPzogW251bWJlciwgbnVtYmVyXSxcbiAgICBhY3RpdmF0aW9uOiBmdXNlZC5BY3RpdmF0aW9uID0gbnVsbCk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBpZiAoZGF0YUZvcm1hdCA9PSBudWxsKSB7XG4gICAgICBkYXRhRm9ybWF0ID0gaW1hZ2VEYXRhRm9ybWF0KCk7XG4gICAgfVxuICAgIGNoZWNrRGF0YUZvcm1hdChkYXRhRm9ybWF0KTtcbiAgICBpZiAoeC5yYW5rICE9PSAzICYmIHgucmFuayAhPT0gNCkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYGNvbnYyZFdpdGhCaWFzQWN0aXZhdGlvbiBleHBlY3RzIGlucHV0IHRvIGJlIG9mIHJhbmsgMyBvciA0LCBgICtcbiAgICAgICAgICBgYnV0IHJlY2VpdmVkICR7eC5yYW5rfS5gKTtcbiAgICB9XG4gICAgaWYgKGtlcm5lbC5yYW5rICE9PSAzICYmIGtlcm5lbC5yYW5rICE9PSA0KSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgY29udjJkV2l0aEJpYXNBY3RpdmF0aW9uIGV4cGVjdHMga2VybmVsIHRvIGJlIG9mIHJhbmsgMyBvciA0LCBgICtcbiAgICAgICAgICBgYnV0IHJlY2VpdmVkICR7eC5yYW5rfS5gKTtcbiAgICB9XG4gICAgbGV0IHkgPSBwcmVwcm9jZXNzQ29udjJESW5wdXQoeCwgZGF0YUZvcm1hdCk7XG4gICAgaWYgKHBhZGRpbmcgPT09ICdjYXVzYWwnKSB7XG4gICAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcihcbiAgICAgICAgICAnVGhlIHN1cHBvcnQgZm9yIENBVVNBTCBwYWRkaW5nIG1vZGUgaW4gY29udjFkV2l0aEJpYXMgaXMgbm90ICcgK1xuICAgICAgICAgICdpbXBsZW1lbnRlZCB5ZXQuJyk7XG4gICAgfVxuICAgIHkgPSB0ZmMuZnVzZWQuY29udjJkKHtcbiAgICAgIHg6IHkgYXMgVGVuc29yM0QgfCBUZW5zb3I0RCxcbiAgICAgIGZpbHRlcjoga2VybmVsIGFzIFRlbnNvcjRELFxuICAgICAgc3RyaWRlczogc3RyaWRlcyBhcyBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgcGFkOiBwYWRkaW5nID09PSAnc2FtZScgPyAnc2FtZScgOiAndmFsaWQnLFxuICAgICAgZGlsYXRpb25zOiBkaWxhdGlvblJhdGUsXG4gICAgICBkYXRhRm9ybWF0OiAnTkhXQycsXG4gICAgICBiaWFzLFxuICAgICAgYWN0aXZhdGlvblxuICAgIH0pO1xuICAgIGlmIChkYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgIHkgPSB0ZmMudHJhbnNwb3NlKHksIFswLCAzLCAxLCAyXSk7XG4gICAgfVxuICAgIHJldHVybiB5O1xuICB9KTtcbn1cblxuLyoqXG4gKiAzRCBDb252b2x1dGlvbi5cbiAqIEBwYXJhbSB4XG4gKiBAcGFyYW0ga2VybmVsIGtlcm5lbCBvZiB0aGUgY29udm9sdXRpb24uXG4gKiBAcGFyYW0gc3RyaWRlcyBzdHJpZGVzIGFycmF5LlxuICogQHBhcmFtIHBhZGRpbmcgcGFkZGluZyBtb2RlLiBEZWZhdWx0IHRvICd2YWxpZCcuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdCBkYXRhIGZvcm1hdC4gRGVmYXVsdHMgdG8gJ2NoYW5uZWxzTGFzdCcuXG4gKiBAcGFyYW0gZGlsYXRpb25SYXRlIGRpbGF0aW9uIHJhdGUgYXJyYXkuXG4gKiBAcmV0dXJucyBSZXN1bHQgb2YgdGhlIDNEIGNvbnZvbHV0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29udjNkKFxuICAgIHg6IFRlbnNvciwga2VybmVsOiBUZW5zb3IsIHN0cmlkZXMgPSBbMSwgMSwgMV0sIHBhZGRpbmcgPSAndmFsaWQnLFxuICAgIGRhdGFGb3JtYXQ/OiBEYXRhRm9ybWF0LCBkaWxhdGlvblJhdGU/OiBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0pOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgY2hlY2tEYXRhRm9ybWF0KGRhdGFGb3JtYXQpO1xuICAgIHJldHVybiBjb252M2RXaXRoQmlhcyhcbiAgICAgICAgeCwga2VybmVsLCBudWxsLCBzdHJpZGVzLCBwYWRkaW5nLCBkYXRhRm9ybWF0LCBkaWxhdGlvblJhdGUpO1xuICB9KTtcbn1cblxuLyoqXG4gKiAzRCBDb252b2x1dGlvbiB3aXRoIGFuIGFkZGVkIGJpYXMuXG4gKiBOb3RlOiBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IGV4aXN0IGluIHRoZSBQeXRob24gS2VyYXMgQmFja2VuZC4gVGhpcyBmdW5jdGlvblxuICogaXMgZXhhY3RseSB0aGUgc2FtZSBhcyBgY29udjNkYCwgZXhjZXB0IHRoZSBhZGRlZCBgYmlhc2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252M2RXaXRoQmlhcyhcbiAgICB4OiBUZW5zb3IsIGtlcm5lbDogVGVuc29yLCBiaWFzOiBUZW5zb3IsIHN0cmlkZXMgPSBbMSwgMSwgMV0sXG4gICAgcGFkZGluZyA9ICd2YWxpZCcsIGRhdGFGb3JtYXQ/OiBEYXRhRm9ybWF0LFxuICAgIGRpbGF0aW9uUmF0ZT86IFtudW1iZXIsIG51bWJlciwgbnVtYmVyXSk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBpZiAoZGF0YUZvcm1hdCA9PSBudWxsKSB7XG4gICAgICBkYXRhRm9ybWF0ID0gaW1hZ2VEYXRhRm9ybWF0KCk7XG4gICAgfVxuICAgIGNoZWNrRGF0YUZvcm1hdChkYXRhRm9ybWF0KTtcbiAgICBpZiAoeC5yYW5rICE9PSA0ICYmIHgucmFuayAhPT0gNSkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYGNvbnYzZFdpdGhCaWFzIGV4cGVjdHMgaW5wdXQgdG8gYmUgb2YgcmFuayA0IG9yIDUsIGJ1dCByZWNlaXZlZCBgICtcbiAgICAgICAgICBgJHt4LnJhbmt9LmApO1xuICAgIH1cbiAgICBpZiAoa2VybmVsLnJhbmsgIT09IDQgJiYga2VybmVsLnJhbmsgIT09IDUpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBjb252M2RXaXRoQmlhcyBleHBlY3RzIGtlcm5lbCB0byBiZSBvZiByYW5rIDQgb3IgNSwgYnV0IHJlY2VpdmVkIGAgK1xuICAgICAgICAgIGAke3gucmFua30uYCk7XG4gICAgfVxuICAgIGxldCB5ID0gcHJlcHJvY2Vzc0NvbnYzRElucHV0KHgsIGRhdGFGb3JtYXQpO1xuICAgIGlmIChwYWRkaW5nID09PSAnY2F1c2FsJykge1xuICAgICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoXG4gICAgICAgICAgJ1RoZSBzdXBwb3J0IGZvciBDQVVTQUwgcGFkZGluZyBtb2RlIGluIGNvbnYzZFdpdGhCaWFzIGlzIG5vdCAnICtcbiAgICAgICAgICAnaW1wbGVtZW50ZWQgeWV0LicpO1xuICAgIH1cbiAgICB5ID0gdGZjLmNvbnYzZChcbiAgICAgICAgeSBhcyBUZW5zb3I0RCB8IHRmYy5UZW5zb3I8dGZjLlJhbmsuUjU+LFxuICAgICAgICBrZXJuZWwgYXMgdGZjLlRlbnNvcjx0ZmMuUmFuay5SNT4sIHN0cmlkZXMgYXMgW251bWJlciwgbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICBwYWRkaW5nID09PSAnc2FtZScgPyAnc2FtZScgOiAndmFsaWQnLCAnTkRIV0MnLCBkaWxhdGlvblJhdGUpO1xuICAgIGlmIChiaWFzICE9IG51bGwpIHtcbiAgICAgIHkgPSBLLmJpYXNBZGQoeSwgYmlhcyBhcyBUZW5zb3IxRCk7XG4gICAgfVxuICAgIGlmIChkYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgIHkgPSB0ZmMudHJhbnNwb3NlKHksIFswLCA0LCAxLCAyLCAzXSk7XG4gICAgfVxuICAgIHJldHVybiB5O1xuICB9KTtcbn1cblxuLyoqXG4gKiBCYXNlIExheWVyQ29uZmlnIGZvciBkZXB0aHdpc2UgYW5kIG5vbi1kZXB0aHdpc2UgY29udm9sdXRpb25hbCBsYXllcnMuXG4gKi9cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBCYXNlQ29udkxheWVyQXJncyBleHRlbmRzIExheWVyQXJncyB7XG4gIC8qKlxuICAgKiBUaGUgZGltZW5zaW9ucyBvZiB0aGUgY29udm9sdXRpb24gd2luZG93LiBJZiBrZXJuZWxTaXplIGlzIGEgbnVtYmVyLCB0aGVcbiAgICogY29udm9sdXRpb25hbCB3aW5kb3cgd2lsbCBiZSBzcXVhcmUuXG4gICAqL1xuICBrZXJuZWxTaXplOiBudW1iZXJ8bnVtYmVyW107XG5cbiAgLyoqXG4gICAqIFRoZSBzdHJpZGVzIG9mIHRoZSBjb252b2x1dGlvbiBpbiBlYWNoIGRpbWVuc2lvbi4gSWYgc3RyaWRlcyBpcyBhIG51bWJlcixcbiAgICogc3RyaWRlcyBpbiBib3RoIGRpbWVuc2lvbnMgYXJlIGVxdWFsLlxuICAgKlxuICAgKiBTcGVjaWZ5aW5nIGFueSBzdHJpZGUgdmFsdWUgIT0gMSBpcyBpbmNvbXBhdGlibGUgd2l0aCBzcGVjaWZ5aW5nIGFueVxuICAgKiBgZGlsYXRpb25SYXRlYCB2YWx1ZSAhPSAxLlxuICAgKi9cbiAgc3RyaWRlcz86IG51bWJlcnxudW1iZXJbXTtcblxuICAvKipcbiAgICogUGFkZGluZyBtb2RlLlxuICAgKi9cbiAgcGFkZGluZz86IFBhZGRpbmdNb2RlO1xuXG4gIC8qKlxuICAgKiBGb3JtYXQgb2YgdGhlIGRhdGEsIHdoaWNoIGRldGVybWluZXMgdGhlIG9yZGVyaW5nIG9mIHRoZSBkaW1lbnNpb25zIGluXG4gICAqIHRoZSBpbnB1dHMuXG4gICAqXG4gICAqIGBjaGFubmVsc19sYXN0YCBjb3JyZXNwb25kcyB0byBpbnB1dHMgd2l0aCBzaGFwZVxuICAgKiAgIGAoYmF0Y2gsIC4uLiwgY2hhbm5lbHMpYFxuICAgKlxuICAgKiAgYGNoYW5uZWxzX2ZpcnN0YCBjb3JyZXNwb25kcyB0byBpbnB1dHMgd2l0aCBzaGFwZSBgKGJhdGNoLCBjaGFubmVscyxcbiAgICogLi4uKWAuXG4gICAqXG4gICAqIERlZmF1bHRzIHRvIGBjaGFubmVsc19sYXN0YC5cbiAgICovXG4gIGRhdGFGb3JtYXQ/OiBEYXRhRm9ybWF0O1xuXG4gIC8qKlxuICAgKiBUaGUgZGlsYXRpb24gcmF0ZSB0byB1c2UgZm9yIHRoZSBkaWxhdGVkIGNvbnZvbHV0aW9uIGluIGVhY2ggZGltZW5zaW9uLlxuICAgKiBTaG91bGQgYmUgYW4gaW50ZWdlciBvciBhcnJheSBvZiB0d28gb3IgdGhyZWUgaW50ZWdlcnMuXG4gICAqXG4gICAqIEN1cnJlbnRseSwgc3BlY2lmeWluZyBhbnkgYGRpbGF0aW9uUmF0ZWAgdmFsdWUgIT0gMSBpcyBpbmNvbXBhdGlibGUgd2l0aFxuICAgKiBzcGVjaWZ5aW5nIGFueSBgc3RyaWRlc2AgdmFsdWUgIT0gMS5cbiAgICovXG4gIGRpbGF0aW9uUmF0ZT86IG51bWJlcnxbbnVtYmVyXXxbbnVtYmVyLCBudW1iZXJdfFtudW1iZXIsIG51bWJlciwgbnVtYmVyXTtcblxuICAvKipcbiAgICogQWN0aXZhdGlvbiBmdW5jdGlvbiBvZiB0aGUgbGF5ZXIuXG4gICAqXG4gICAqIElmIHlvdSBkb24ndCBzcGVjaWZ5IHRoZSBhY3RpdmF0aW9uLCBub25lIGlzIGFwcGxpZWQuXG4gICAqL1xuICBhY3RpdmF0aW9uPzogQWN0aXZhdGlvbklkZW50aWZpZXI7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGxheWVyIHVzZXMgYSBiaWFzIHZlY3Rvci4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgKi9cbiAgdXNlQmlhcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVyIGZvciB0aGUgY29udm9sdXRpb25hbCBrZXJuZWwgd2VpZ2h0cyBtYXRyaXguXG4gICAqL1xuICBrZXJuZWxJbml0aWFsaXplcj86IEluaXRpYWxpemVySWRlbnRpZmllcnxJbml0aWFsaXplcjtcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXIgZm9yIHRoZSBiaWFzIHZlY3Rvci5cbiAgICovXG4gIGJpYXNJbml0aWFsaXplcj86IEluaXRpYWxpemVySWRlbnRpZmllcnxJbml0aWFsaXplcjtcblxuICAvKipcbiAgICogQ29uc3RyYWludCBmb3IgdGhlIGNvbnZvbHV0aW9uYWwga2VybmVsIHdlaWdodHMuXG4gICAqL1xuICBrZXJuZWxDb25zdHJhaW50PzogQ29uc3RyYWludElkZW50aWZpZXJ8Q29uc3RyYWludDtcblxuICAvKipcbiAgICogQ29uc3RyYWludCBmb3IgdGhlIGJpYXMgdmVjdG9yLlxuICAgKi9cbiAgYmlhc0NvbnN0cmFpbnQ/OiBDb25zdHJhaW50SWRlbnRpZmllcnxDb25zdHJhaW50O1xuXG4gIC8qKlxuICAgKiBSZWd1bGFyaXplciBmdW5jdGlvbiBhcHBsaWVkIHRvIHRoZSBrZXJuZWwgd2VpZ2h0cyBtYXRyaXguXG4gICAqL1xuICBrZXJuZWxSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVySWRlbnRpZmllcnxSZWd1bGFyaXplcjtcblxuICAvKipcbiAgICogUmVndWxhcml6ZXIgZnVuY3Rpb24gYXBwbGllZCB0byB0aGUgYmlhcyB2ZWN0b3IuXG4gICAqL1xuICBiaWFzUmVndWxhcml6ZXI/OiBSZWd1bGFyaXplcklkZW50aWZpZXJ8UmVndWxhcml6ZXI7XG5cbiAgLyoqXG4gICAqIFJlZ3VsYXJpemVyIGZ1bmN0aW9uIGFwcGxpZWQgdG8gdGhlIGFjdGl2YXRpb24uXG4gICAqL1xuICBhY3Rpdml0eVJlZ3VsYXJpemVyPzogUmVndWxhcml6ZXJJZGVudGlmaWVyfFJlZ3VsYXJpemVyO1xufVxuXG4vKipcbiAqIExheWVyQ29uZmlnIGZvciBub24tZGVwdGh3aXNlIGNvbnZvbHV0aW9uYWwgbGF5ZXJzLlxuICogQXBwbGllcyB0byBub24tZGVwdGh3aXNlIGNvbnZvbHV0aW9uIG9mIGFsbCByYW5rcyAoZS5nLCBDb252MUQsIENvbnYyRCxcbiAqIENvbnYzRCkuXG4gKi9cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBDb252TGF5ZXJBcmdzIGV4dGVuZHMgQmFzZUNvbnZMYXllckFyZ3Mge1xuICAvKipcbiAgICogVGhlIGRpbWVuc2lvbmFsaXR5IG9mIHRoZSBvdXRwdXQgc3BhY2UgKGkuZS4gdGhlIG51bWJlciBvZiBmaWx0ZXJzIGluIHRoZVxuICAgKiBjb252b2x1dGlvbikuXG4gICAqL1xuICBmaWx0ZXJzOiBudW1iZXI7XG59XG5cbi8qKlxuICogQWJzdHJhY3QgY29udm9sdXRpb24gbGF5ZXIuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlQ29udiBleHRlbmRzIExheWVyIHtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHJhbms6IG51bWJlcjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGtlcm5lbFNpemU6IG51bWJlcltdO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc3RyaWRlczogbnVtYmVyW107XG4gIHByb3RlY3RlZCByZWFkb25seSBwYWRkaW5nOiBQYWRkaW5nTW9kZTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRhdGFGb3JtYXQ6IERhdGFGb3JtYXQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBhY3RpdmF0aW9uOiBBY3RpdmF0aW9uO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdXNlQmlhczogYm9vbGVhbjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRpbGF0aW9uUmF0ZTogbnVtYmVyW107XG5cbiAgLy8gQmlhcy1yZWxhdGVkIG1lbWJlcnMgYXJlIGhlcmUgYmVjYXVzZSBhbGwgY29udm9sdXRpb24gc3ViY2xhc3NlcyB1c2UgdGhlXG4gIC8vIHNhbWUgY29uZmlndXJhdGlvbiBwYXJtZXRlcnMgdG8gY29udHJvbCBiaWFzLiAgS2VybmVsLXJlbGF0ZWQgbWVtYmVyc1xuICAvLyBhcmUgaW4gc3ViY2xhc3MgYENvbnZgIGJlY2F1c2Ugc29tZSBzdWJjbGFzc2VzIHVzZSBkaWZmZXJlbnQgcGFyYW1ldGVycyB0b1xuICAvLyBjb250cm9sIGtlcm5lbCBwcm9wZXJ0aWVzLCBmb3IgaW5zdGFuY2UsIGBEZXB0aHdpc2VDb252MkRgIHVzZXNcbiAgLy8gYGRlcHRod2lzZUluaXRpYWxpemVyYCBpbnN0ZWFkIG9mIGBrZXJuZWxJbml0aWFsaXplcmAuXG4gIHByb3RlY3RlZCByZWFkb25seSBiaWFzSW5pdGlhbGl6ZXI/OiBJbml0aWFsaXplcjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGJpYXNDb25zdHJhaW50PzogQ29uc3RyYWludDtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGJpYXNSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVyO1xuXG4gIHByb3RlY3RlZCBiaWFzOiBMYXllclZhcmlhYmxlID0gbnVsbDtcblxuICByZWFkb25seSBERUZBVUxUX0tFUk5FTF9JTklUSUFMSVpFUjogSW5pdGlhbGl6ZXJJZGVudGlmaWVyID0gJ2dsb3JvdE5vcm1hbCc7XG4gIHJlYWRvbmx5IERFRkFVTFRfQklBU19JTklUSUFMSVpFUjogSW5pdGlhbGl6ZXJJZGVudGlmaWVyID0gJ3plcm9zJztcblxuICBjb25zdHJ1Y3RvcihyYW5rOiBudW1iZXIsIGFyZ3M6IEJhc2VDb252TGF5ZXJBcmdzKSB7XG4gICAgc3VwZXIoYXJncyBhcyBMYXllckFyZ3MpO1xuICAgIEJhc2VDb252LnZlcmlmeUFyZ3MoYXJncyk7XG4gICAgdGhpcy5yYW5rID0gcmFuaztcbiAgICBnZW5lcmljX3V0aWxzLmFzc2VydFBvc2l0aXZlSW50ZWdlcih0aGlzLnJhbmssICdyYW5rJyk7XG4gICAgaWYgKHRoaXMucmFuayAhPT0gMSAmJiB0aGlzLnJhbmsgIT09IDIgJiYgdGhpcy5yYW5rICE9PSAzKSB7XG4gICAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcihcbiAgICAgICAgICBgQ29udm9sdXRpb24gbGF5ZXIgZm9yIHJhbmsgb3RoZXIgdGhhbiAxLCAyLCBvciAzICgke1xuICAgICAgICAgICAgICB0aGlzLnJhbmt9KSBpcyBgICtcbiAgICAgICAgICBgbm90IGltcGxlbWVudGVkIHlldC5gKTtcbiAgICB9XG4gICAgdGhpcy5rZXJuZWxTaXplID0gbm9ybWFsaXplQXJyYXkoYXJncy5rZXJuZWxTaXplLCByYW5rLCAna2VybmVsU2l6ZScpO1xuICAgIHRoaXMuc3RyaWRlcyA9IG5vcm1hbGl6ZUFycmF5KFxuICAgICAgICBhcmdzLnN0cmlkZXMgPT0gbnVsbCA/IDEgOiBhcmdzLnN0cmlkZXMsIHJhbmssICdzdHJpZGVzJyk7XG4gICAgdGhpcy5wYWRkaW5nID0gYXJncy5wYWRkaW5nID09IG51bGwgPyAndmFsaWQnIDogYXJncy5wYWRkaW5nO1xuICAgIGNoZWNrUGFkZGluZ01vZGUodGhpcy5wYWRkaW5nKTtcbiAgICB0aGlzLmRhdGFGb3JtYXQgPVxuICAgICAgICBhcmdzLmRhdGFGb3JtYXQgPT0gbnVsbCA/ICdjaGFubmVsc0xhc3QnIDogYXJncy5kYXRhRm9ybWF0O1xuICAgIGNoZWNrRGF0YUZvcm1hdCh0aGlzLmRhdGFGb3JtYXQpO1xuICAgIHRoaXMuYWN0aXZhdGlvbiA9IGdldEFjdGl2YXRpb24oYXJncy5hY3RpdmF0aW9uKTtcbiAgICB0aGlzLnVzZUJpYXMgPSBhcmdzLnVzZUJpYXMgPT0gbnVsbCA/IHRydWUgOiBhcmdzLnVzZUJpYXM7XG4gICAgdGhpcy5iaWFzSW5pdGlhbGl6ZXIgPVxuICAgICAgICBnZXRJbml0aWFsaXplcihhcmdzLmJpYXNJbml0aWFsaXplciB8fCB0aGlzLkRFRkFVTFRfQklBU19JTklUSUFMSVpFUik7XG4gICAgdGhpcy5iaWFzQ29uc3RyYWludCA9IGdldENvbnN0cmFpbnQoYXJncy5iaWFzQ29uc3RyYWludCk7XG4gICAgdGhpcy5iaWFzUmVndWxhcml6ZXIgPSBnZXRSZWd1bGFyaXplcihhcmdzLmJpYXNSZWd1bGFyaXplcik7XG4gICAgdGhpcy5hY3Rpdml0eVJlZ3VsYXJpemVyID0gZ2V0UmVndWxhcml6ZXIoYXJncy5hY3Rpdml0eVJlZ3VsYXJpemVyKTtcbiAgICB0aGlzLmRpbGF0aW9uUmF0ZSA9IG5vcm1hbGl6ZUFycmF5KFxuICAgICAgICBhcmdzLmRpbGF0aW9uUmF0ZSA9PSBudWxsID8gMSA6IGFyZ3MuZGlsYXRpb25SYXRlLCByYW5rLFxuICAgICAgICAnZGlsYXRpb25SYXRlJyk7XG4gICAgaWYgKHRoaXMucmFuayA9PT0gMSAmJlxuICAgICAgICAoQXJyYXkuaXNBcnJheSh0aGlzLmRpbGF0aW9uUmF0ZSkgJiYgdGhpcy5kaWxhdGlvblJhdGUubGVuZ3RoICE9PSAxKSkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYGRpbGF0aW9uUmF0ZSBtdXN0IGJlIGEgbnVtYmVyIG9yIGFuIGFycmF5IG9mIGEgc2luZ2xlIG51bWJlciBgICtcbiAgICAgICAgICBgZm9yIDFEIGNvbnZvbHV0aW9uLCBidXQgcmVjZWl2ZWQgYCArXG4gICAgICAgICAgYCR7SlNPTi5zdHJpbmdpZnkodGhpcy5kaWxhdGlvblJhdGUpfWApO1xuICAgIH0gZWxzZSBpZiAodGhpcy5yYW5rID09PSAyKSB7XG4gICAgICBpZiAodHlwZW9mIHRoaXMuZGlsYXRpb25SYXRlID09PSAnbnVtYmVyJykge1xuICAgICAgICB0aGlzLmRpbGF0aW9uUmF0ZSA9IFt0aGlzLmRpbGF0aW9uUmF0ZSwgdGhpcy5kaWxhdGlvblJhdGVdO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLmRpbGF0aW9uUmF0ZS5sZW5ndGggIT09IDIpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgICBgZGlsYXRpb25SYXRlIG11c3QgYmUgYSBudW1iZXIgb3IgYXJyYXkgb2YgdHdvIG51bWJlcnMgZm9yIDJEIGAgK1xuICAgICAgICAgICAgYGNvbnZvbHV0aW9uLCBidXQgcmVjZWl2ZWQgJHtKU09OLnN0cmluZ2lmeSh0aGlzLmRpbGF0aW9uUmF0ZSl9YCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0aGlzLnJhbmsgPT09IDMpIHtcbiAgICAgIGlmICh0eXBlb2YgdGhpcy5kaWxhdGlvblJhdGUgPT09ICdudW1iZXInKSB7XG4gICAgICAgIHRoaXMuZGlsYXRpb25SYXRlID1cbiAgICAgICAgICAgIFt0aGlzLmRpbGF0aW9uUmF0ZSwgdGhpcy5kaWxhdGlvblJhdGUsIHRoaXMuZGlsYXRpb25SYXRlXTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5kaWxhdGlvblJhdGUubGVuZ3RoICE9PSAzKSB7XG4gICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICAgYGRpbGF0aW9uUmF0ZSBtdXN0IGJlIGEgbnVtYmVyIG9yIGFycmF5IG9mIHRocmVlIG51bWJlcnMgZm9yIDNEIGAgK1xuICAgICAgICAgICAgYGNvbnZvbHV0aW9uLCBidXQgcmVjZWl2ZWQgJHtKU09OLnN0cmluZ2lmeSh0aGlzLmRpbGF0aW9uUmF0ZSl9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyB2ZXJpZnlBcmdzKGFyZ3M6IEJhc2VDb252TGF5ZXJBcmdzKSB7XG4gICAgLy8gQ2hlY2sgY29uZmlnLmtlcm5lbFNpemUgdHlwZSBhbmQgc2hhcGUuXG4gICAgZ2VuZXJpY191dGlscy5hc3NlcnQoXG4gICAgICAgICdrZXJuZWxTaXplJyBpbiBhcmdzLCBgcmVxdWlyZWQga2V5ICdrZXJuZWxTaXplJyBub3QgaW4gY29uZmlnYCk7XG4gICAgaWYgKHR5cGVvZiBhcmdzLmtlcm5lbFNpemUgIT09ICdudW1iZXInICYmXG4gICAgICAgICFnZW5lcmljX3V0aWxzLmNoZWNrQXJyYXlUeXBlQW5kTGVuZ3RoKFxuICAgICAgICAgICAgYXJncy5rZXJuZWxTaXplLCAnbnVtYmVyJywgMSwgMykpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBCYXNlQ29udiBleHBlY3RzIGNvbmZpZy5rZXJuZWxTaXplIHRvIGJlIG51bWJlciBvciBudW1iZXJbXSB3aXRoIGAgK1xuICAgICAgICAgIGBsZW5ndGggMSwgMiwgb3IgMywgYnV0IHJlY2VpdmVkICR7XG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGFyZ3Mua2VybmVsU2l6ZSl9LmApO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGdldENvbmZpZygpOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3Qge1xuICAgIGNvbnN0IGNvbmZpZzogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0ID0ge1xuICAgICAga2VybmVsU2l6ZTogdGhpcy5rZXJuZWxTaXplLFxuICAgICAgc3RyaWRlczogdGhpcy5zdHJpZGVzLFxuICAgICAgcGFkZGluZzogdGhpcy5wYWRkaW5nLFxuICAgICAgZGF0YUZvcm1hdDogdGhpcy5kYXRhRm9ybWF0LFxuICAgICAgZGlsYXRpb25SYXRlOiB0aGlzLmRpbGF0aW9uUmF0ZSxcbiAgICAgIGFjdGl2YXRpb246IHNlcmlhbGl6ZUFjdGl2YXRpb24odGhpcy5hY3RpdmF0aW9uKSxcbiAgICAgIHVzZUJpYXM6IHRoaXMudXNlQmlhcyxcbiAgICAgIGJpYXNJbml0aWFsaXplcjogc2VyaWFsaXplSW5pdGlhbGl6ZXIodGhpcy5iaWFzSW5pdGlhbGl6ZXIpLFxuICAgICAgYmlhc1JlZ3VsYXJpemVyOiBzZXJpYWxpemVSZWd1bGFyaXplcih0aGlzLmJpYXNSZWd1bGFyaXplciksXG4gICAgICBhY3Rpdml0eVJlZ3VsYXJpemVyOiBzZXJpYWxpemVSZWd1bGFyaXplcih0aGlzLmFjdGl2aXR5UmVndWxhcml6ZXIpLFxuICAgICAgYmlhc0NvbnN0cmFpbnQ6IHNlcmlhbGl6ZUNvbnN0cmFpbnQodGhpcy5iaWFzQ29uc3RyYWludClcbiAgICB9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuXG4vKipcbiAqIEFic3RyYWN0IG5EIGNvbnZvbHV0aW9uIGxheWVyLiAgQW5jZXN0b3Igb2YgY29udm9sdXRpb24gbGF5ZXJzIHdoaWNoIHJlZHVjZVxuICogYWNyb3NzIGNoYW5uZWxzLCBpLmUuLCBDb252MUQgYW5kIENvbnYyRCwgYnV0IG5vdCBEZXB0aHdpc2VDb252MkQuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBDb252IGV4dGVuZHMgQmFzZUNvbnYge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZmlsdGVyczogbnVtYmVyO1xuXG4gIHByb3RlY3RlZCBrZXJuZWw6IExheWVyVmFyaWFibGUgPSBudWxsO1xuXG4gIC8vIEJpYXMtcmVsYXRlZCBwcm9wZXJ0aWVzIGFyZSBzdG9yZWQgaW4gdGhlIHN1cGVyY2xhc3MgYEJhc2VDb252YCBiZWNhdXNlIGFsbFxuICAvLyBjb252b2x1dGlvbiBzdWJjbGFzc2VzIHVzZSB0aGUgc2FtZSBjb25maWd1cmF0aW9uIHBhcmFtZXRlcnMgdG8gY29udHJvbFxuICAvLyBiaWFzLiBLZXJuZWwtcmVsYXRlZCBwcm9wZXJ0aWVzIGFyZSBkZWZpbmVkIGhlcmUgcmF0aGVyIHRoYW4gaW4gdGhlXG4gIC8vIHN1cGVyY2xhc3MgYmVjYXVzZSBzb21lIGNvbnZvbHV0aW9uIHN1YmNsYXNzZXMgdXNlIGRpZmZlcmVudCBuYW1lcyBhbmRcbiAgLy8gY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJzIGZvciB0aGVpciBpbnRlcm5hbCBrZXJuZWwgc3RhdGUuXG4gIHByb3RlY3RlZCByZWFkb25seSBrZXJuZWxJbml0aWFsaXplcj86IEluaXRpYWxpemVyO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkga2VybmVsQ29uc3RyYWludD86IENvbnN0cmFpbnQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBrZXJuZWxSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVyO1xuXG4gIGNvbnN0cnVjdG9yKHJhbms6IG51bWJlciwgYXJnczogQ29udkxheWVyQXJncykge1xuICAgIHN1cGVyKHJhbmssIGFyZ3MgYXMgQmFzZUNvbnZMYXllckFyZ3MpO1xuICAgIENvbnYudmVyaWZ5QXJncyhhcmdzKTtcbiAgICB0aGlzLmZpbHRlcnMgPSBhcmdzLmZpbHRlcnM7XG4gICAgZ2VuZXJpY191dGlscy5hc3NlcnRQb3NpdGl2ZUludGVnZXIodGhpcy5maWx0ZXJzLCAnZmlsdGVycycpO1xuICAgIHRoaXMua2VybmVsSW5pdGlhbGl6ZXIgPSBnZXRJbml0aWFsaXplcihcbiAgICAgICAgYXJncy5rZXJuZWxJbml0aWFsaXplciB8fCB0aGlzLkRFRkFVTFRfS0VSTkVMX0lOSVRJQUxJWkVSKTtcbiAgICB0aGlzLmtlcm5lbENvbnN0cmFpbnQgPSBnZXRDb25zdHJhaW50KGFyZ3Mua2VybmVsQ29uc3RyYWludCk7XG4gICAgdGhpcy5rZXJuZWxSZWd1bGFyaXplciA9IGdldFJlZ3VsYXJpemVyKGFyZ3Mua2VybmVsUmVndWxhcml6ZXIpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYnVpbGQoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IHZvaWQge1xuICAgIGlucHV0U2hhcGUgPSBnZXRFeGFjdGx5T25lU2hhcGUoaW5wdXRTaGFwZSk7XG4gICAgY29uc3QgY2hhbm5lbEF4aXMgPVxuICAgICAgICB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/IDEgOiBpbnB1dFNoYXBlLmxlbmd0aCAtIDE7XG4gICAgaWYgKGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdID09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBUaGUgY2hhbm5lbCBkaW1lbnNpb24gb2YgdGhlIGlucHV0IHNob3VsZCBiZSBkZWZpbmVkLiBgICtcbiAgICAgICAgICBgRm91bmQgJHtpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXX1gKTtcbiAgICB9XG4gICAgY29uc3QgaW5wdXREaW0gPSBpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXTtcblxuICAgIGNvbnN0IGtlcm5lbFNoYXBlID0gdGhpcy5rZXJuZWxTaXplLmNvbmNhdChbaW5wdXREaW0sIHRoaXMuZmlsdGVyc10pO1xuXG4gICAgdGhpcy5rZXJuZWwgPSB0aGlzLmFkZFdlaWdodChcbiAgICAgICAgJ2tlcm5lbCcsIGtlcm5lbFNoYXBlLCBudWxsLCB0aGlzLmtlcm5lbEluaXRpYWxpemVyLFxuICAgICAgICB0aGlzLmtlcm5lbFJlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmtlcm5lbENvbnN0cmFpbnQpO1xuICAgIGlmICh0aGlzLnVzZUJpYXMpIHtcbiAgICAgIHRoaXMuYmlhcyA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAgICdiaWFzJywgW3RoaXMuZmlsdGVyc10sIG51bGwsIHRoaXMuYmlhc0luaXRpYWxpemVyLFxuICAgICAgICAgIHRoaXMuYmlhc1JlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmJpYXNDb25zdHJhaW50KTtcbiAgICB9XG5cbiAgICB0aGlzLmlucHV0U3BlYyA9IFt7bmRpbTogdGhpcy5yYW5rICsgMiwgYXhlczoge1tjaGFubmVsQXhpc106IGlucHV0RGltfX1dO1xuICAgIHRoaXMuYnVpbHQgPSB0cnVlO1xuICB9XG5cbiAgb3ZlcnJpZGUgY2FsbChpbnB1dHM6IFRlbnNvcnxUZW5zb3JbXSwga3dhcmdzOiBLd2FyZ3MpOiBUZW5zb3J8VGVuc29yW10ge1xuICAgIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICAgIGlucHV0cyA9IGdldEV4YWN0bHlPbmVUZW5zb3IoaW5wdXRzKTtcbiAgICAgIGxldCBvdXRwdXRzOiBUZW5zb3I7XG4gICAgICBjb25zdCBiaWFzVmFsdWUgPSB0aGlzLmJpYXMgPT0gbnVsbCA/IG51bGwgOiB0aGlzLmJpYXMucmVhZCgpO1xuICAgICAgY29uc3QgZnVzZWRBY3RpdmF0aW9uTmFtZSA9IGdlbmVyaWNfdXRpbHMubWFwQWN0aXZhdGlvblRvRnVzZWRLZXJuZWwoXG4gICAgICAgICAgdGhpcy5hY3RpdmF0aW9uLmdldENsYXNzTmFtZSgpKTtcblxuICAgICAgaWYgKGZ1c2VkQWN0aXZhdGlvbk5hbWUgIT0gbnVsbCAmJiB0aGlzLnJhbmsgPT09IDIpIHtcbiAgICAgICAgb3V0cHV0cyA9IGNvbnYyZFdpdGhCaWFzQWN0aXZhdGlvbihcbiAgICAgICAgICAgIGlucHV0cywgdGhpcy5rZXJuZWwucmVhZCgpLCBiaWFzVmFsdWUsIHRoaXMuc3RyaWRlcywgdGhpcy5wYWRkaW5nLFxuICAgICAgICAgICAgdGhpcy5kYXRhRm9ybWF0LCB0aGlzLmRpbGF0aW9uUmF0ZSBhcyBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICAgICAgZnVzZWRBY3RpdmF0aW9uTmFtZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAodGhpcy5yYW5rID09PSAxKSB7XG4gICAgICAgICAgb3V0cHV0cyA9IGNvbnYxZFdpdGhCaWFzKFxuICAgICAgICAgICAgICBpbnB1dHMsIHRoaXMua2VybmVsLnJlYWQoKSwgYmlhc1ZhbHVlLCB0aGlzLnN0cmlkZXNbMF0sXG4gICAgICAgICAgICAgIHRoaXMucGFkZGluZywgdGhpcy5kYXRhRm9ybWF0LCB0aGlzLmRpbGF0aW9uUmF0ZVswXSk7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5yYW5rID09PSAyKSB7XG4gICAgICAgICAgLy8gVE9ETyhjYWlzKTogTW92ZSB1cCB0byBjb25zdHJ1Y3Rvci5cbiAgICAgICAgICBvdXRwdXRzID0gY29udjJkV2l0aEJpYXNBY3RpdmF0aW9uKFxuICAgICAgICAgICAgICBpbnB1dHMsIHRoaXMua2VybmVsLnJlYWQoKSwgYmlhc1ZhbHVlLCB0aGlzLnN0cmlkZXMsIHRoaXMucGFkZGluZyxcbiAgICAgICAgICAgICAgdGhpcy5kYXRhRm9ybWF0LCB0aGlzLmRpbGF0aW9uUmF0ZSBhcyBbbnVtYmVyLCBudW1iZXJdKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnJhbmsgPT09IDMpIHtcbiAgICAgICAgICBvdXRwdXRzID0gY29udjNkV2l0aEJpYXMoXG4gICAgICAgICAgICAgIGlucHV0cywgdGhpcy5rZXJuZWwucmVhZCgpLCBiaWFzVmFsdWUsIHRoaXMuc3RyaWRlcywgdGhpcy5wYWRkaW5nLFxuICAgICAgICAgICAgICB0aGlzLmRhdGFGb3JtYXQsIHRoaXMuZGlsYXRpb25SYXRlIGFzIFtudW1iZXIsIG51bWJlciwgbnVtYmVyXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoXG4gICAgICAgICAgICAgICdjb252b2x1dGlvbnMgZ3JlYXRlciB0aGFuIDNEIGFyZSBub3QgaW1wbGVtZW50ZWQgeWV0LicpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPSBudWxsKSB7XG4gICAgICAgICAgb3V0cHV0cyA9IHRoaXMuYWN0aXZhdGlvbi5hcHBseShvdXRwdXRzKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gb3V0cHV0cztcbiAgICB9KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogU2hhcGV8U2hhcGVbXSB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBjb25zdCBuZXdTcGFjZTogbnVtYmVyW10gPSBbXTtcbiAgICBjb25zdCBzcGFjZSA9ICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0xhc3QnKSA/XG4gICAgICAgIGlucHV0U2hhcGUuc2xpY2UoMSwgaW5wdXRTaGFwZS5sZW5ndGggLSAxKSA6XG4gICAgICAgIGlucHV0U2hhcGUuc2xpY2UoMik7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzcGFjZS5sZW5ndGg7ICsraSkge1xuICAgICAgY29uc3QgbmV3RGltID0gY29udk91dHB1dExlbmd0aChcbiAgICAgICAgICBzcGFjZVtpXSwgdGhpcy5rZXJuZWxTaXplW2ldLCB0aGlzLnBhZGRpbmcsIHRoaXMuc3RyaWRlc1tpXSxcbiAgICAgICAgICB0eXBlb2YgdGhpcy5kaWxhdGlvblJhdGUgPT09ICdudW1iZXInID8gdGhpcy5kaWxhdGlvblJhdGUgOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRpbGF0aW9uUmF0ZVtpXSk7XG4gICAgICBuZXdTcGFjZS5wdXNoKG5ld0RpbSk7XG4gICAgfVxuXG4gICAgbGV0IG91dHB1dFNoYXBlID0gW2lucHV0U2hhcGVbMF1dO1xuICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0xhc3QnKSB7XG4gICAgICBvdXRwdXRTaGFwZSA9IG91dHB1dFNoYXBlLmNvbmNhdChuZXdTcGFjZSk7XG4gICAgICBvdXRwdXRTaGFwZS5wdXNoKHRoaXMuZmlsdGVycyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG91dHB1dFNoYXBlLnB1c2godGhpcy5maWx0ZXJzKTtcbiAgICAgIG91dHB1dFNoYXBlID0gb3V0cHV0U2hhcGUuY29uY2F0KG5ld1NwYWNlKTtcbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dFNoYXBlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0ge1xuICAgICAgZmlsdGVyczogdGhpcy5maWx0ZXJzLFxuICAgICAga2VybmVsSW5pdGlhbGl6ZXI6IHNlcmlhbGl6ZUluaXRpYWxpemVyKHRoaXMua2VybmVsSW5pdGlhbGl6ZXIpLFxuICAgICAga2VybmVsUmVndWxhcml6ZXI6IHNlcmlhbGl6ZVJlZ3VsYXJpemVyKHRoaXMua2VybmVsUmVndWxhcml6ZXIpLFxuICAgICAga2VybmVsQ29uc3RyYWludDogc2VyaWFsaXplQ29uc3RyYWludCh0aGlzLmtlcm5lbENvbnN0cmFpbnQpXG4gICAgfTtcbiAgICBjb25zdCBiYXNlQ29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgT2JqZWN0LmFzc2lnbihjb25maWcsIGJhc2VDb25maWcpO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIG92ZXJyaWRlIHZlcmlmeUFyZ3MoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIC8vIENoZWNrIGNvbmZpZy5maWx0ZXJzIHR5cGUsIHNoYXBlLCBhbmQgdmFsdWUuXG4gICAgaWYgKCEoJ2ZpbHRlcnMnIGluIGFyZ3MpIHx8IHR5cGVvZiBhcmdzLmZpbHRlcnMgIT09ICdudW1iZXInIHx8XG4gICAgICAgIGFyZ3MuZmlsdGVycyA8IDEpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBDb252b2x1dGlvbiBsYXllciBleHBlY3RlZCBjb25maWcuZmlsdGVycyB0byBiZSBhICdudW1iZXInID4gMCBgICtcbiAgICAgICAgICBgYnV0IGdvdCAke0pTT04uc3RyaW5naWZ5KGFyZ3MuZmlsdGVycyl9YCk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBDb252MkQgZXh0ZW5kcyBDb252IHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBjbGFzc05hbWUgPSAnQ29udjJEJztcbiAgY29uc3RydWN0b3IoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIHN1cGVyKDIsIGFyZ3MpO1xuICAgIENvbnYyRC52ZXJpZnlBcmdzKGFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1sncmFuayddO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIG92ZXJyaWRlIHZlcmlmeUFyZ3MoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIC8vIGNvbmZpZy5rZXJuZWxTaXplIG11c3QgYmUgYSBudW1iZXIgb3IgYXJyYXkgb2YgbnVtYmVycy5cbiAgICBpZiAoKHR5cGVvZiBhcmdzLmtlcm5lbFNpemUgIT09ICdudW1iZXInKSAmJlxuICAgICAgICAhZ2VuZXJpY191dGlscy5jaGVja0FycmF5VHlwZUFuZExlbmd0aChcbiAgICAgICAgICAgIGFyZ3Mua2VybmVsU2l6ZSwgJ251bWJlcicsIDEsIDIpKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgQ29udjJEIGV4cGVjdHMgY29uZmlnLmtlcm5lbFNpemUgdG8gYmUgbnVtYmVyIG9yIG51bWJlcltdIHdpdGggYCArXG4gICAgICAgICAgYGxlbmd0aCAxIG9yIDIsIGJ1dCByZWNlaXZlZCAke0pTT04uc3RyaW5naWZ5KGFyZ3Mua2VybmVsU2l6ZSl9LmApO1xuICAgIH1cbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYyRCk7XG5cbmV4cG9ydCBjbGFzcyBDb252M0QgZXh0ZW5kcyBDb252IHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBjbGFzc05hbWUgPSAnQ29udjNEJztcbiAgY29uc3RydWN0b3IoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIHN1cGVyKDMsIGFyZ3MpO1xuICAgIENvbnYzRC52ZXJpZnlBcmdzKGFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1sncmFuayddO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIG92ZXJyaWRlIHZlcmlmeUFyZ3MoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIC8vIGNvbmZpZy5rZXJuZWxTaXplIG11c3QgYmUgYSBudW1iZXIgb3IgYXJyYXkgb2YgbnVtYmVycy5cbiAgICBpZiAodHlwZW9mIGFyZ3Mua2VybmVsU2l6ZSAhPT0gJ251bWJlcicpIHtcbiAgICAgIGlmICghKEFycmF5LmlzQXJyYXkoYXJncy5rZXJuZWxTaXplKSAmJlxuICAgICAgICAgICAgKGFyZ3Mua2VybmVsU2l6ZS5sZW5ndGggPT09IDEgfHwgYXJncy5rZXJuZWxTaXplLmxlbmd0aCA9PT0gMykpKSB7XG4gICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICAgYENvbnYzRCBleHBlY3RzIGNvbmZpZy5rZXJuZWxTaXplIHRvIGJlIG51bWJlciBvcmAgK1xuICAgICAgICAgICAgYCBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0sIGJ1dCByZWNlaXZlZCAke1xuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGFyZ3Mua2VybmVsU2l6ZSl9LmApO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYzRCk7XG5cbmV4cG9ydCBjbGFzcyBDb252MkRUcmFuc3Bvc2UgZXh0ZW5kcyBDb252MkQge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIG92ZXJyaWRlIGNsYXNzTmFtZSA9ICdDb252MkRUcmFuc3Bvc2UnO1xuXG4gIGNvbnN0cnVjdG9yKGFyZ3M6IENvbnZMYXllckFyZ3MpIHtcbiAgICBzdXBlcihhcmdzKTtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFtuZXcgSW5wdXRTcGVjKHtuZGltOiA0fSldO1xuXG4gICAgaWYgKHRoaXMucGFkZGluZyAhPT0gJ3NhbWUnICYmIHRoaXMucGFkZGluZyAhPT0gJ3ZhbGlkJykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYENvbnYyRFRyYW5zcG9zZSBjdXJyZW50bHkgc3VwcG9ydHMgb25seSBwYWRkaW5nIG1vZGVzICdzYW1lJyBgICtcbiAgICAgICAgICBgYW5kICd2YWxpZCcsIGJ1dCByZWNlaXZlZCBwYWRkaW5nIG1vZGUgJHt0aGlzLnBhZGRpbmd9YCk7XG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgYnVpbGQoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IHZvaWQge1xuICAgIGlucHV0U2hhcGUgPSBnZXRFeGFjdGx5T25lU2hhcGUoaW5wdXRTaGFwZSk7XG5cbiAgICBpZiAoaW5wdXRTaGFwZS5sZW5ndGggIT09IDQpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICdJbnB1dCBzaG91bGQgaGF2ZSByYW5rIDQ7IFJlY2VpdmVkIGlucHV0IHNoYXBlOiAnICtcbiAgICAgICAgICBKU09OLnN0cmluZ2lmeShpbnB1dFNoYXBlKSk7XG4gICAgfVxuXG4gICAgY29uc3QgY2hhbm5lbEF4aXMgPVxuICAgICAgICB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/IDEgOiBpbnB1dFNoYXBlLmxlbmd0aCAtIDE7XG4gICAgaWYgKGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdID09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICdUaGUgY2hhbm5lbCBkaW1lbnNpb24gb2YgdGhlIGlucHV0cyBzaG91bGQgYmUgZGVmaW5lZC4gJyArXG4gICAgICAgICAgJ0ZvdW5kIGBOb25lYC4nKTtcbiAgICB9XG4gICAgY29uc3QgaW5wdXREaW0gPSBpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXTtcbiAgICBjb25zdCBrZXJuZWxTaGFwZSA9IHRoaXMua2VybmVsU2l6ZS5jb25jYXQoW3RoaXMuZmlsdGVycywgaW5wdXREaW1dKTtcblxuICAgIHRoaXMua2VybmVsID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICdrZXJuZWwnLCBrZXJuZWxTaGFwZSwgJ2Zsb2F0MzInLCB0aGlzLmtlcm5lbEluaXRpYWxpemVyLFxuICAgICAgICB0aGlzLmtlcm5lbFJlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmtlcm5lbENvbnN0cmFpbnQpO1xuICAgIGlmICh0aGlzLnVzZUJpYXMpIHtcbiAgICAgIHRoaXMuYmlhcyA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAgICdiaWFzJywgW3RoaXMuZmlsdGVyc10sICdmbG9hdDMyJywgdGhpcy5iaWFzSW5pdGlhbGl6ZXIsXG4gICAgICAgICAgdGhpcy5iaWFzUmVndWxhcml6ZXIsIHRydWUsIHRoaXMuYmlhc0NvbnN0cmFpbnQpO1xuICAgIH1cblxuICAgIC8vIFNldCBpbnB1dCBzcGVjLlxuICAgIHRoaXMuaW5wdXRTcGVjID1cbiAgICAgICAgW25ldyBJbnB1dFNwZWMoe25kaW06IDQsIGF4ZXM6IHtbY2hhbm5lbEF4aXNdOiBpbnB1dERpbX19KV07XG4gICAgdGhpcy5idWlsdCA9IHRydWU7XG4gIH1cblxuICBvdmVycmlkZSBjYWxsKGlucHV0czogVGVuc29yfFRlbnNvcltdLCBrd2FyZ3M6IEt3YXJncyk6IFRlbnNvcnxUZW5zb3JbXSB7XG4gICAgcmV0dXJuIHRmYy50aWR5KCgpID0+IHtcbiAgICAgIGxldCBpbnB1dCA9IGdldEV4YWN0bHlPbmVUZW5zb3IoaW5wdXRzKTtcbiAgICAgIGlmIChpbnB1dC5zaGFwZS5sZW5ndGggIT09IDQpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgICBgQ29udjJEVHJhbnNwb3NlLmNhbGwoKSBleHBlY3RzIGlucHV0IHRlbnNvciB0byBiZSByYW5rLTQsIGJ1dCBgICtcbiAgICAgICAgICAgIGByZWNlaXZlZCBhIHRlbnNvciBvZiByYW5rLSR7aW5wdXQuc2hhcGUubGVuZ3RofWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbnB1dFNoYXBlID0gaW5wdXQuc2hhcGU7XG4gICAgICBjb25zdCBiYXRjaFNpemUgPSBpbnB1dFNoYXBlWzBdO1xuXG4gICAgICBsZXQgaEF4aXM6IG51bWJlcjtcbiAgICAgIGxldCB3QXhpczogbnVtYmVyO1xuICAgICAgaWYgKHRoaXMuZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnKSB7XG4gICAgICAgIGhBeGlzID0gMjtcbiAgICAgICAgd0F4aXMgPSAzO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaEF4aXMgPSAxO1xuICAgICAgICB3QXhpcyA9IDI7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhlaWdodCA9IGlucHV0U2hhcGVbaEF4aXNdO1xuICAgICAgY29uc3Qgd2lkdGggPSBpbnB1dFNoYXBlW3dBeGlzXTtcbiAgICAgIGNvbnN0IGtlcm5lbEggPSB0aGlzLmtlcm5lbFNpemVbMF07XG4gICAgICBjb25zdCBrZXJuZWxXID0gdGhpcy5rZXJuZWxTaXplWzFdO1xuICAgICAgY29uc3Qgc3RyaWRlSCA9IHRoaXMuc3RyaWRlc1swXTtcbiAgICAgIGNvbnN0IHN0cmlkZVcgPSB0aGlzLnN0cmlkZXNbMV07XG5cbiAgICAgIC8vIEluZmVyIHRoZSBkeW5hbWljIG91dHB1dCBzaGFwZS5cbiAgICAgIGNvbnN0IG91dEhlaWdodCA9IGRlY29udkxlbmd0aChoZWlnaHQsIHN0cmlkZUgsIGtlcm5lbEgsIHRoaXMucGFkZGluZyk7XG4gICAgICBjb25zdCBvdXRXaWR0aCA9IGRlY29udkxlbmd0aCh3aWR0aCwgc3RyaWRlVywga2VybmVsVywgdGhpcy5wYWRkaW5nKTtcblxuICAgICAgLy8gUG9ydGluZyBOb3RlOiBXZSBkb24ndCBicmFuY2ggYmFzZWQgb24gYHRoaXMuZGF0YUZvcm1hdGAgaGVyZSxcbiAgICAgIC8vIGJlY2F1c2VcbiAgICAgIC8vICAgdGhlIHRqZnMtY29yZSBmdW5jdGlvbiBgY29udjJkVHJhbnNwb3NlYCBjYWxsZWQgYmVsb3cgYWx3YXlzXG4gICAgICAvLyAgIGFzc3VtZXMgY2hhbm5lbHNMYXN0LlxuICAgICAgY29uc3Qgb3V0cHV0U2hhcGU6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXJdID1cbiAgICAgICAgICBbYmF0Y2hTaXplLCBvdXRIZWlnaHQsIG91dFdpZHRoLCB0aGlzLmZpbHRlcnNdO1xuXG4gICAgICBpZiAodGhpcy5kYXRhRm9ybWF0ICE9PSAnY2hhbm5lbHNMYXN0Jykge1xuICAgICAgICBpbnB1dCA9IHRmYy50cmFuc3Bvc2UoaW5wdXQsIFswLCAyLCAzLCAxXSk7XG4gICAgICB9XG4gICAgICBsZXQgb3V0cHV0cyA9IHRmYy5jb252MmRUcmFuc3Bvc2UoXG4gICAgICAgICAgaW5wdXQgYXMgVGVuc29yNEQsIHRoaXMua2VybmVsLnJlYWQoKSBhcyBUZW5zb3I0RCwgb3V0cHV0U2hhcGUsXG4gICAgICAgICAgdGhpcy5zdHJpZGVzIGFzIFtudW1iZXIsIG51bWJlcl0sIHRoaXMucGFkZGluZyBhcyAnc2FtZScgfCAndmFsaWQnKTtcbiAgICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgIT09ICdjaGFubmVsc0xhc3QnKSB7XG4gICAgICAgIG91dHB1dHMgPSB0ZmMudHJhbnNwb3NlKG91dHB1dHMsIFswLCAzLCAxLCAyXSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmJpYXMgIT0gbnVsbCkge1xuICAgICAgICBvdXRwdXRzID1cbiAgICAgICAgICAgIEsuYmlhc0FkZChvdXRwdXRzLCB0aGlzLmJpYXMucmVhZCgpLCB0aGlzLmRhdGFGb3JtYXQpIGFzIFRlbnNvcjREO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPSBudWxsKSB7XG4gICAgICAgIG91dHB1dHMgPSB0aGlzLmFjdGl2YXRpb24uYXBwbHkob3V0cHV0cykgYXMgVGVuc29yNEQ7XG4gICAgICB9XG4gICAgICByZXR1cm4gb3V0cHV0cztcbiAgICB9KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogU2hhcGV8U2hhcGVbXSB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBjb25zdCBvdXRwdXRTaGFwZSA9IGlucHV0U2hhcGUuc2xpY2UoKTtcblxuICAgIGxldCBjaGFubmVsQXhpczogbnVtYmVyO1xuICAgIGxldCBoZWlnaHRBeGlzOiBudW1iZXI7XG4gICAgbGV0IHdpZHRoQXhpczogbnVtYmVyO1xuICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgY2hhbm5lbEF4aXMgPSAxO1xuICAgICAgaGVpZ2h0QXhpcyA9IDI7XG4gICAgICB3aWR0aEF4aXMgPSAzO1xuICAgIH0gZWxzZSB7XG4gICAgICBjaGFubmVsQXhpcyA9IDM7XG4gICAgICBoZWlnaHRBeGlzID0gMTtcbiAgICAgIHdpZHRoQXhpcyA9IDI7XG4gICAgfVxuXG4gICAgY29uc3Qga2VybmVsSCA9IHRoaXMua2VybmVsU2l6ZVswXTtcbiAgICBjb25zdCBrZXJuZWxXID0gdGhpcy5rZXJuZWxTaXplWzFdO1xuICAgIGNvbnN0IHN0cmlkZUggPSB0aGlzLnN0cmlkZXNbMF07XG4gICAgY29uc3Qgc3RyaWRlVyA9IHRoaXMuc3RyaWRlc1sxXTtcblxuICAgIG91dHB1dFNoYXBlW2NoYW5uZWxBeGlzXSA9IHRoaXMuZmlsdGVycztcbiAgICBvdXRwdXRTaGFwZVtoZWlnaHRBeGlzXSA9XG4gICAgICAgIGRlY29udkxlbmd0aChvdXRwdXRTaGFwZVtoZWlnaHRBeGlzXSwgc3RyaWRlSCwga2VybmVsSCwgdGhpcy5wYWRkaW5nKTtcbiAgICBvdXRwdXRTaGFwZVt3aWR0aEF4aXNdID1cbiAgICAgICAgZGVjb252TGVuZ3RoKG91dHB1dFNoYXBlW3dpZHRoQXhpc10sIHN0cmlkZVcsIGtlcm5lbFcsIHRoaXMucGFkZGluZyk7XG4gICAgcmV0dXJuIG91dHB1dFNoYXBlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1snZGlsYXRpb25SYXRlJ107XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYyRFRyYW5zcG9zZSk7XG5cbmV4cG9ydCBjbGFzcyBDb252M0RUcmFuc3Bvc2UgZXh0ZW5kcyBDb252M0Qge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIG92ZXJyaWRlIGNsYXNzTmFtZSA9ICdDb252M0RUcmFuc3Bvc2UnO1xuXG4gIGNvbnN0cnVjdG9yKGFyZ3M6IENvbnZMYXllckFyZ3MpIHtcbiAgICBzdXBlcihhcmdzKTtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFtuZXcgSW5wdXRTcGVjKHtuZGltOiA1fSldO1xuXG4gICAgaWYgKHRoaXMucGFkZGluZyAhPT0gJ3NhbWUnICYmIHRoaXMucGFkZGluZyAhPT0gJ3ZhbGlkJykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYENvbnYzRFRyYW5zcG9zZSBjdXJyZW50bHkgc3VwcG9ydHMgb25seSBwYWRkaW5nIG1vZGVzICdzYW1lJyBgICtcbiAgICAgICAgICBgYW5kICd2YWxpZCcsIGJ1dCByZWNlaXZlZCBwYWRkaW5nIG1vZGUgJHt0aGlzLnBhZGRpbmd9YCk7XG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgYnVpbGQoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IHZvaWQge1xuICAgIGlucHV0U2hhcGUgPSBnZXRFeGFjdGx5T25lU2hhcGUoaW5wdXRTaGFwZSk7XG5cbiAgICBpZiAoaW5wdXRTaGFwZS5sZW5ndGggIT09IDUpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICdJbnB1dCBzaG91bGQgaGF2ZSByYW5rIDU7IFJlY2VpdmVkIGlucHV0IHNoYXBlOiAnICtcbiAgICAgICAgICBKU09OLnN0cmluZ2lmeShpbnB1dFNoYXBlKSk7XG4gICAgfVxuXG4gICAgY29uc3QgY2hhbm5lbEF4aXMgPVxuICAgICAgICB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/IDEgOiBpbnB1dFNoYXBlLmxlbmd0aCAtIDE7XG4gICAgaWYgKGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdID09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICdUaGUgY2hhbm5lbCBkaW1lbnNpb24gb2YgdGhlIGlucHV0cyBzaG91bGQgYmUgZGVmaW5lZC4gJyArXG4gICAgICAgICAgJ0ZvdW5kIGBOb25lYC4nKTtcbiAgICB9XG4gICAgY29uc3QgaW5wdXREaW0gPSBpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXTtcbiAgICBjb25zdCBrZXJuZWxTaGFwZSA9IHRoaXMua2VybmVsU2l6ZS5jb25jYXQoW3RoaXMuZmlsdGVycywgaW5wdXREaW1dKTtcblxuICAgIHRoaXMua2VybmVsID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICdrZXJuZWwnLCBrZXJuZWxTaGFwZSwgJ2Zsb2F0MzInLCB0aGlzLmtlcm5lbEluaXRpYWxpemVyLFxuICAgICAgICB0aGlzLmtlcm5lbFJlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmtlcm5lbENvbnN0cmFpbnQpO1xuICAgIGlmICh0aGlzLnVzZUJpYXMpIHtcbiAgICAgIHRoaXMuYmlhcyA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAgICdiaWFzJywgW3RoaXMuZmlsdGVyc10sICdmbG9hdDMyJywgdGhpcy5iaWFzSW5pdGlhbGl6ZXIsXG4gICAgICAgICAgdGhpcy5iaWFzUmVndWxhcml6ZXIsIHRydWUsIHRoaXMuYmlhc0NvbnN0cmFpbnQpO1xuICAgIH1cblxuICAgIC8vIFNldCBpbnB1dCBzcGVjLlxuICAgIHRoaXMuaW5wdXRTcGVjID1cbiAgICAgICAgW25ldyBJbnB1dFNwZWMoe25kaW06IDUsIGF4ZXM6IHtbY2hhbm5lbEF4aXNdOiBpbnB1dERpbX19KV07XG4gICAgdGhpcy5idWlsdCA9IHRydWU7XG4gIH1cblxuICBvdmVycmlkZSBjYWxsKGlucHV0czogVGVuc29yfFRlbnNvcltdLCBrd2FyZ3M6IEt3YXJncyk6IFRlbnNvcnxUZW5zb3JbXSB7XG4gICAgcmV0dXJuIHRmYy50aWR5PHRmYy5UZW5zb3I1RD4oKCkgPT4ge1xuICAgICAgbGV0IGlucHV0ID0gZ2V0RXhhY3RseU9uZVRlbnNvcihpbnB1dHMpO1xuICAgICAgaWYgKGlucHV0LnNoYXBlLmxlbmd0aCAhPT0gNSkge1xuICAgICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICAgIGBDb252M0RUcmFuc3Bvc2UuY2FsbCgpIGV4cGVjdHMgaW5wdXQgdGVuc29yIHRvIGJlIHJhbmstNCwgYnV0IGAgK1xuICAgICAgICAgICAgYHJlY2VpdmVkIGEgdGVuc29yIG9mIHJhbmstJHtpbnB1dC5zaGFwZS5sZW5ndGh9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGlucHV0U2hhcGUgPSBpbnB1dC5zaGFwZTtcbiAgICAgIGNvbnN0IGJhdGNoU2l6ZSA9IGlucHV0U2hhcGVbMF07XG5cbiAgICAgIGxldCBoQXhpczogbnVtYmVyO1xuICAgICAgbGV0IHdBeGlzOiBudW1iZXI7XG4gICAgICBsZXQgZEF4aXM6IG51bWJlcjtcblxuICAgICAgaWYgKHRoaXMuZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnKSB7XG4gICAgICAgIGRBeGlzID0gMjtcbiAgICAgICAgaEF4aXMgPSAzO1xuICAgICAgICB3QXhpcyA9IDQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkQXhpcyA9IDE7XG4gICAgICAgIGhBeGlzID0gMjtcbiAgICAgICAgd0F4aXMgPSAzO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBkZXB0aCA9IGlucHV0U2hhcGVbZEF4aXNdO1xuICAgICAgY29uc3QgaGVpZ2h0ID0gaW5wdXRTaGFwZVtoQXhpc107XG4gICAgICBjb25zdCB3aWR0aCA9IGlucHV0U2hhcGVbd0F4aXNdO1xuICAgICAgY29uc3Qga2VybmVsRCA9IHRoaXMua2VybmVsU2l6ZVswXTtcbiAgICAgIGNvbnN0IGtlcm5lbEggPSB0aGlzLmtlcm5lbFNpemVbMV07XG4gICAgICBjb25zdCBrZXJuZWxXID0gdGhpcy5rZXJuZWxTaXplWzJdO1xuICAgICAgY29uc3Qgc3RyaWRlRCA9IHRoaXMuc3RyaWRlc1swXTtcbiAgICAgIGNvbnN0IHN0cmlkZUggPSB0aGlzLnN0cmlkZXNbMV07XG4gICAgICBjb25zdCBzdHJpZGVXID0gdGhpcy5zdHJpZGVzWzJdO1xuXG4gICAgICAvLyBJbmZlciB0aGUgZHluYW1pYyBvdXRwdXQgc2hhcGUuXG4gICAgICBjb25zdCBvdXREZXB0aCA9IGRlY29udkxlbmd0aChkZXB0aCwgc3RyaWRlRCwga2VybmVsRCwgdGhpcy5wYWRkaW5nKTtcbiAgICAgIGNvbnN0IG91dEhlaWdodCA9IGRlY29udkxlbmd0aChoZWlnaHQsIHN0cmlkZUgsIGtlcm5lbEgsIHRoaXMucGFkZGluZyk7XG4gICAgICBjb25zdCBvdXRXaWR0aCA9IGRlY29udkxlbmd0aCh3aWR0aCwgc3RyaWRlVywga2VybmVsVywgdGhpcy5wYWRkaW5nKTtcblxuICAgICAgLy8gU2FtZSBhcyBgY29udjJkVHJhbnNwb3NlYC4gV2UgYWx3YXlzIGFzc3VtZXMgY2hhbm5lbHNMYXN0LlxuICAgICAgY29uc3Qgb3V0cHV0U2hhcGU6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXIsIG51bWJlcl0gPVxuICAgICAgICAgIFtiYXRjaFNpemUsIG91dERlcHRoLCBvdXRIZWlnaHQsIG91dFdpZHRoLCB0aGlzLmZpbHRlcnNdO1xuICAgICAgaWYgKHRoaXMuZGF0YUZvcm1hdCAhPT0gJ2NoYW5uZWxzTGFzdCcpIHtcbiAgICAgICAgaW5wdXQgPSB0ZmMudHJhbnNwb3NlKGlucHV0LCBbMCwgMiwgMywgNCwgMV0pO1xuICAgICAgfVxuICAgICAgbGV0IG91dHB1dHMgPSB0ZmMuY29udjNkVHJhbnNwb3NlKFxuICAgICAgICAgIGlucHV0IGFzIFRlbnNvcjVELCB0aGlzLmtlcm5lbC5yZWFkKCkgYXMgVGVuc29yNUQsIG91dHB1dFNoYXBlLFxuICAgICAgICAgIHRoaXMuc3RyaWRlcyBhcyBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0sXG4gICAgICAgICAgdGhpcy5wYWRkaW5nIGFzICdzYW1lJyB8ICd2YWxpZCcpO1xuICAgICAgaWYgKHRoaXMuZGF0YUZvcm1hdCAhPT0gJ2NoYW5uZWxzTGFzdCcpIHtcbiAgICAgICAgb3V0cHV0cyA9IHRmYy50cmFuc3Bvc2Uob3V0cHV0cywgWzAsIDQsIDEsIDIsIDNdKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuYmlhcyAhPT0gbnVsbCkge1xuICAgICAgICBvdXRwdXRzID1cbiAgICAgICAgICAgIEsuYmlhc0FkZChvdXRwdXRzLCB0aGlzLmJpYXMucmVhZCgpLCB0aGlzLmRhdGFGb3JtYXQpIGFzIFRlbnNvcjVEO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPT0gbnVsbCkge1xuICAgICAgICBvdXRwdXRzID0gdGhpcy5hY3RpdmF0aW9uLmFwcGx5KG91dHB1dHMpIGFzIFRlbnNvcjVEO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG91dHB1dHM7XG4gICAgfSk7XG4gIH1cblxuICBvdmVycmlkZSBjb21wdXRlT3V0cHV0U2hhcGUoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IFNoYXBlfFNoYXBlW10ge1xuICAgIGlucHV0U2hhcGUgPSBnZXRFeGFjdGx5T25lU2hhcGUoaW5wdXRTaGFwZSk7XG4gICAgY29uc3Qgb3V0cHV0U2hhcGUgPSBpbnB1dFNoYXBlLnNsaWNlKCk7XG5cbiAgICBsZXQgY2hhbm5lbEF4aXM6IG51bWJlcjtcbiAgICBsZXQgZGVwdGhBeGlzOiBudW1iZXI7XG4gICAgbGV0IGhlaWdodEF4aXM6IG51bWJlcjtcbiAgICBsZXQgd2lkdGhBeGlzOiBudW1iZXI7XG4gICAgaWYgKHRoaXMuZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnKSB7XG4gICAgICBjaGFubmVsQXhpcyA9IDE7XG4gICAgICBkZXB0aEF4aXMgPSAyO1xuICAgICAgaGVpZ2h0QXhpcyA9IDM7XG4gICAgICB3aWR0aEF4aXMgPSA0O1xuICAgIH0gZWxzZSB7XG4gICAgICBjaGFubmVsQXhpcyA9IDQ7XG4gICAgICBkZXB0aEF4aXMgPSAxO1xuICAgICAgaGVpZ2h0QXhpcyA9IDI7XG4gICAgICB3aWR0aEF4aXMgPSAzO1xuICAgIH1cblxuICAgIGNvbnN0IGtlcm5lbEQgPSB0aGlzLmtlcm5lbFNpemVbMF07XG4gICAgY29uc3Qga2VybmVsSCA9IHRoaXMua2VybmVsU2l6ZVsxXTtcbiAgICBjb25zdCBrZXJuZWxXID0gdGhpcy5rZXJuZWxTaXplWzJdO1xuICAgIGNvbnN0IHN0cmlkZUQgPSB0aGlzLnN0cmlkZXNbMF07XG4gICAgY29uc3Qgc3RyaWRlSCA9IHRoaXMuc3RyaWRlc1sxXTtcbiAgICBjb25zdCBzdHJpZGVXID0gdGhpcy5zdHJpZGVzWzJdO1xuXG4gICAgb3V0cHV0U2hhcGVbY2hhbm5lbEF4aXNdID0gdGhpcy5maWx0ZXJzO1xuICAgIG91dHB1dFNoYXBlW2RlcHRoQXhpc10gPVxuICAgICAgICBkZWNvbnZMZW5ndGgob3V0cHV0U2hhcGVbZGVwdGhBeGlzXSwgc3RyaWRlRCwga2VybmVsRCwgdGhpcy5wYWRkaW5nKTtcbiAgICBvdXRwdXRTaGFwZVtoZWlnaHRBeGlzXSA9XG4gICAgICAgIGRlY29udkxlbmd0aChvdXRwdXRTaGFwZVtoZWlnaHRBeGlzXSwgc3RyaWRlSCwga2VybmVsSCwgdGhpcy5wYWRkaW5nKTtcbiAgICBvdXRwdXRTaGFwZVt3aWR0aEF4aXNdID1cbiAgICAgICAgZGVjb252TGVuZ3RoKG91dHB1dFNoYXBlW3dpZHRoQXhpc10sIHN0cmlkZVcsIGtlcm5lbFcsIHRoaXMucGFkZGluZyk7XG4gICAgcmV0dXJuIG91dHB1dFNoYXBlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1snZGlsYXRpb25SYXRlJ107XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYzRFRyYW5zcG9zZSk7XG5cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBTZXBhcmFibGVDb252TGF5ZXJBcmdzIGV4dGVuZHMgQ29udkxheWVyQXJncyB7XG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIGRlcHRod2lzZSBjb252b2x1dGlvbiBvdXRwdXQgY2hhbm5lbHMgZm9yIGVhY2ggaW5wdXRcbiAgICogY2hhbm5lbC5cbiAgICogVGhlIHRvdGFsIG51bWJlciBvZiBkZXB0aHdpc2UgY29udm9sdXRpb24gb3V0cHV0IGNoYW5uZWxzIHdpbGwgYmUgZXF1YWxcbiAgICogdG8gYGZpbHRlcnNJbiAqIGRlcHRoTXVsdGlwbGllcmAuIERlZmF1bHQ6IDEuXG4gICAqL1xuICBkZXB0aE11bHRpcGxpZXI/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVyIGZvciB0aGUgZGVwdGh3aXNlIGtlcm5lbCBtYXRyaXguXG4gICAqL1xuICBkZXB0aHdpc2VJbml0aWFsaXplcj86IEluaXRpYWxpemVySWRlbnRpZmllcnxJbml0aWFsaXplcjtcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXIgZm9yIHRoZSBwb2ludHdpc2Uga2VybmVsIG1hdHJpeC5cbiAgICovXG4gIHBvaW50d2lzZUluaXRpYWxpemVyPzogSW5pdGlhbGl6ZXJJZGVudGlmaWVyfEluaXRpYWxpemVyO1xuXG4gIC8qKlxuICAgKiBSZWd1bGFyaXplciBmdW5jdGlvbiBhcHBsaWVkIHRvIHRoZSBkZXB0aHdpc2Uga2VybmVsIG1hdHJpeC5cbiAgICovXG4gIGRlcHRod2lzZVJlZ3VsYXJpemVyPzogUmVndWxhcml6ZXJJZGVudGlmaWVyfFJlZ3VsYXJpemVyO1xuXG4gIC8qKlxuICAgKiBSZWd1bGFyaXplciBmdW5jdGlvbiBhcHBsaWVkIHRvIHRoZSBwb2ludHdpc2Uga2VybmVsIG1hdHJpeC5cbiAgICovXG4gIHBvaW50d2lzZVJlZ3VsYXJpemVyPzogUmVndWxhcml6ZXJJZGVudGlmaWVyfFJlZ3VsYXJpemVyO1xuXG4gIC8qKlxuICAgKiBDb25zdHJhaW50IGZ1bmN0aW9uIGFwcGxpZWQgdG8gdGhlIGRlcHRod2lzZSBrZXJuZWwgbWF0cml4LlxuICAgKi9cbiAgZGVwdGh3aXNlQ29uc3RyYWludD86IENvbnN0cmFpbnRJZGVudGlmaWVyfENvbnN0cmFpbnQ7XG5cbiAgLyoqXG4gICAqIENvbnN0cmFpbnQgZnVuY3Rpb24gYXBwbGllZCB0byB0aGUgcG9pbnR3aXNlIGtlcm5lbCBtYXRyaXguXG4gICAqL1xuICBwb2ludHdpc2VDb25zdHJhaW50PzogQ29uc3RyYWludElkZW50aWZpZXJ8Q29uc3RyYWludDtcbn1cblxuZXhwb3J0IGNsYXNzIFNlcGFyYWJsZUNvbnYgZXh0ZW5kcyBDb252IHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBjbGFzc05hbWUgPSAnU2VwYXJhYmxlQ29udic7XG5cbiAgcmVhZG9ubHkgZGVwdGhNdWx0aXBsaWVyOiBudW1iZXI7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRlcHRod2lzZUluaXRpYWxpemVyPzogSW5pdGlhbGl6ZXI7XG4gIHByb3RlY3RlZCByZWFkb25seSBkZXB0aHdpc2VSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVyO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZGVwdGh3aXNlQ29uc3RyYWludD86IENvbnN0cmFpbnQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBwb2ludHdpc2VJbml0aWFsaXplcj86IEluaXRpYWxpemVyO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcG9pbnR3aXNlUmVndWxhcml6ZXI/OiBSZWd1bGFyaXplcjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHBvaW50d2lzZUNvbnN0cmFpbnQ/OiBDb25zdHJhaW50O1xuXG4gIHJlYWRvbmx5IERFRkFVTFRfREVQVEhXSVNFX0lOSVRJQUxJWkVSOiBJbml0aWFsaXplcklkZW50aWZpZXIgPVxuICAgICAgJ2dsb3JvdFVuaWZvcm0nO1xuICByZWFkb25seSBERUZBVUxUX1BPSU5UV0lTRV9JTklUSUFMSVpFUjogSW5pdGlhbGl6ZXJJZGVudGlmaWVyID1cbiAgICAgICdnbG9yb3RVbmlmb3JtJztcblxuICBwcm90ZWN0ZWQgZGVwdGh3aXNlS2VybmVsOiBMYXllclZhcmlhYmxlID0gbnVsbDtcbiAgcHJvdGVjdGVkIHBvaW50d2lzZUtlcm5lbDogTGF5ZXJWYXJpYWJsZSA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IocmFuazogbnVtYmVyLCBjb25maWc/OiBTZXBhcmFibGVDb252TGF5ZXJBcmdzKSB7XG4gICAgc3VwZXIocmFuaywgY29uZmlnKTtcblxuICAgIGlmIChjb25maWcuZmlsdGVycyA9PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICAnVGhlIGBmaWx0ZXJzYCBjb25maWd1cmF0aW9uIGZpZWxkIGlzIHJlcXVpcmVkIGJ5IFNlcGFyYWJsZUNvbnYsICcgK1xuICAgICAgICAgICdidXQgaXMgdW5zcGVjaWZpZWQuJyk7XG4gICAgfVxuICAgIGlmIChjb25maWcua2VybmVsSW5pdGlhbGl6ZXIgIT0gbnVsbCB8fCBjb25maWcua2VybmVsUmVndWxhcml6ZXIgIT0gbnVsbCB8fFxuICAgICAgICBjb25maWcua2VybmVsQ29uc3RyYWludCAhPSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICAnRmllbGRzIGtlcm5lbEluaXRpYWxpemVyLCBrZXJuZWxSZWd1bGFyaXplciBhbmQga2VybmVsQ29uc3RyYWludCAnICtcbiAgICAgICAgICAnYXJlIGludmFsaWQgZm9yIFNlcGFyYWJsZUNvbnYyRC4gVXNlIGRlcHRod2lzZUluaXRpYWxpemVyLCAnICtcbiAgICAgICAgICAnZGVwdGh3aXNlUmVndWxhcml6ZXIsIGRlcHRod2lzZUNvbnN0cmFpbnQsIHBvaW50d2lzZUluaXRpYWxpemVyLCAnICtcbiAgICAgICAgICAncG9pbnR3aXNlUmVndWxhcml6ZXIgYW5kIHBvaW50d2lzZUNvbnN0cmFpbnQgaW5zdGVhZC4nKTtcbiAgICB9XG4gICAgaWYgKGNvbmZpZy5wYWRkaW5nICE9IG51bGwgJiYgY29uZmlnLnBhZGRpbmcgIT09ICdzYW1lJyAmJlxuICAgICAgICBjb25maWcucGFkZGluZyAhPT0gJ3ZhbGlkJykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFNlcGFyYWJsZUNvbnYke3RoaXMucmFua31EIHN1cHBvcnRzIG9ubHkgcGFkZGluZyBtb2RlczogYCArXG4gICAgICAgICAgYCdzYW1lJyBhbmQgJ3ZhbGlkJywgYnV0IHJlY2VpdmVkICR7SlNPTi5zdHJpbmdpZnkoY29uZmlnLnBhZGRpbmcpfWApO1xuICAgIH1cblxuICAgIHRoaXMuZGVwdGhNdWx0aXBsaWVyID1cbiAgICAgICAgY29uZmlnLmRlcHRoTXVsdGlwbGllciA9PSBudWxsID8gMSA6IGNvbmZpZy5kZXB0aE11bHRpcGxpZXI7XG4gICAgdGhpcy5kZXB0aHdpc2VJbml0aWFsaXplciA9IGdldEluaXRpYWxpemVyKFxuICAgICAgICBjb25maWcuZGVwdGh3aXNlSW5pdGlhbGl6ZXIgfHwgdGhpcy5ERUZBVUxUX0RFUFRIV0lTRV9JTklUSUFMSVpFUik7XG4gICAgdGhpcy5kZXB0aHdpc2VSZWd1bGFyaXplciA9IGdldFJlZ3VsYXJpemVyKGNvbmZpZy5kZXB0aHdpc2VSZWd1bGFyaXplcik7XG4gICAgdGhpcy5kZXB0aHdpc2VDb25zdHJhaW50ID0gZ2V0Q29uc3RyYWludChjb25maWcuZGVwdGh3aXNlQ29uc3RyYWludCk7XG4gICAgdGhpcy5wb2ludHdpc2VJbml0aWFsaXplciA9IGdldEluaXRpYWxpemVyKFxuICAgICAgICBjb25maWcuZGVwdGh3aXNlSW5pdGlhbGl6ZXIgfHwgdGhpcy5ERUZBVUxUX1BPSU5UV0lTRV9JTklUSUFMSVpFUik7XG4gICAgdGhpcy5wb2ludHdpc2VSZWd1bGFyaXplciA9IGdldFJlZ3VsYXJpemVyKGNvbmZpZy5wb2ludHdpc2VSZWd1bGFyaXplcik7XG4gICAgdGhpcy5wb2ludHdpc2VDb25zdHJhaW50ID0gZ2V0Q29uc3RyYWludChjb25maWcucG9pbnR3aXNlQ29uc3RyYWludCk7XG4gIH1cblxuICBvdmVycmlkZSBidWlsZChpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogdm9pZCB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBpZiAoaW5wdXRTaGFwZS5sZW5ndGggPCB0aGlzLnJhbmsgKyAyKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgSW5wdXRzIHRvIFNlcGFyYWJsZUNvbnYke3RoaXMucmFua31EIHNob3VsZCBoYXZlIHJhbmsgYCArXG4gICAgICAgICAgYCR7dGhpcy5yYW5rICsgMn0sIGJ1dCByZWNlaXZlZCBpbnB1dCBzaGFwZTogYCArXG4gICAgICAgICAgYCR7SlNPTi5zdHJpbmdpZnkoaW5wdXRTaGFwZSl9YCk7XG4gICAgfVxuICAgIGNvbnN0IGNoYW5uZWxBeGlzID1cbiAgICAgICAgdGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcgPyAxIDogaW5wdXRTaGFwZS5sZW5ndGggLSAxO1xuICAgIGlmIChpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXSA9PSBudWxsIHx8IGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdIDwgMCkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFRoZSBjaGFubmVsIGRpbWVuc2lvbiBvZiB0aGUgaW5wdXRzIHNob3VsZCBiZSBkZWZpbmVkLCBgICtcbiAgICAgICAgICBgYnV0IGZvdW5kICR7SlNPTi5zdHJpbmdpZnkoaW5wdXRTaGFwZVtjaGFubmVsQXhpc10pfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGlucHV0RGltID0gaW5wdXRTaGFwZVtjaGFubmVsQXhpc107XG4gICAgY29uc3QgZGVwdGh3aXNlS2VybmVsU2hhcGUgPVxuICAgICAgICB0aGlzLmtlcm5lbFNpemUuY29uY2F0KFtpbnB1dERpbSwgdGhpcy5kZXB0aE11bHRpcGxpZXJdKTtcbiAgICBjb25zdCBwb2ludHdpc2VLZXJuZWxTaGFwZSA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5yYW5rOyArK2kpIHtcbiAgICAgIHBvaW50d2lzZUtlcm5lbFNoYXBlLnB1c2goMSk7XG4gICAgfVxuICAgIHBvaW50d2lzZUtlcm5lbFNoYXBlLnB1c2goaW5wdXREaW0gKiB0aGlzLmRlcHRoTXVsdGlwbGllciwgdGhpcy5maWx0ZXJzKTtcblxuICAgIGNvbnN0IHRyYWluYWJsZSA9IHRydWU7XG4gICAgdGhpcy5kZXB0aHdpc2VLZXJuZWwgPSB0aGlzLmFkZFdlaWdodChcbiAgICAgICAgJ2RlcHRod2lzZV9rZXJuZWwnLCBkZXB0aHdpc2VLZXJuZWxTaGFwZSwgJ2Zsb2F0MzInLFxuICAgICAgICB0aGlzLmRlcHRod2lzZUluaXRpYWxpemVyLCB0aGlzLmRlcHRod2lzZVJlZ3VsYXJpemVyLCB0cmFpbmFibGUsXG4gICAgICAgIHRoaXMuZGVwdGh3aXNlQ29uc3RyYWludCk7XG4gICAgdGhpcy5wb2ludHdpc2VLZXJuZWwgPSB0aGlzLmFkZFdlaWdodChcbiAgICAgICAgJ3BvaW50d2lzZV9rZXJuZWwnLCBwb2ludHdpc2VLZXJuZWxTaGFwZSwgJ2Zsb2F0MzInLFxuICAgICAgICB0aGlzLnBvaW50d2lzZUluaXRpYWxpemVyLCB0aGlzLnBvaW50d2lzZVJlZ3VsYXJpemVyLCB0cmFpbmFibGUsXG4gICAgICAgIHRoaXMucG9pbnR3aXNlQ29uc3RyYWludCk7XG4gICAgaWYgKHRoaXMudXNlQmlhcykge1xuICAgICAgdGhpcy5iaWFzID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICAgJ2JpYXMnLCBbdGhpcy5maWx0ZXJzXSwgJ2Zsb2F0MzInLCB0aGlzLmJpYXNJbml0aWFsaXplcixcbiAgICAgICAgICB0aGlzLmJpYXNSZWd1bGFyaXplciwgdHJhaW5hYmxlLCB0aGlzLmJpYXNDb25zdHJhaW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5iaWFzID0gbnVsbDtcbiAgICB9XG5cbiAgICB0aGlzLmlucHV0U3BlYyA9XG4gICAgICAgIFtuZXcgSW5wdXRTcGVjKHtuZGltOiB0aGlzLnJhbmsgKyAyLCBheGVzOiB7W2NoYW5uZWxBeGlzXTogaW5wdXREaW19fSldO1xuICAgIHRoaXMuYnVpbHQgPSB0cnVlO1xuICB9XG5cbiAgb3ZlcnJpZGUgY2FsbChpbnB1dHM6IFRlbnNvcnxUZW5zb3JbXSwga3dhcmdzOiBLd2FyZ3MpOiBUZW5zb3J8VGVuc29yW10ge1xuICAgIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICAgIGlucHV0cyA9IGdldEV4YWN0bHlPbmVUZW5zb3IoaW5wdXRzKTtcblxuICAgICAgbGV0IG91dHB1dDogVGVuc29yO1xuICAgICAgaWYgKHRoaXMucmFuayA9PT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcihcbiAgICAgICAgICAgICcxRCBzZXBhcmFibGUgY29udm9sdXRpb24gaXMgbm90IGltcGxlbWVudGVkIHlldC4nKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5yYW5rID09PSAyKSB7XG4gICAgICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgICAgIGlucHV0cyA9IHRmYy50cmFuc3Bvc2UoaW5wdXRzLCBbMCwgMiwgMywgMV0pOyAgLy8gTkNIVyAtPiBOSFdDLlxuICAgICAgICB9XG5cbiAgICAgICAgb3V0cHV0ID0gdGZjLnNlcGFyYWJsZUNvbnYyZChcbiAgICAgICAgICAgIGlucHV0cyBhcyBUZW5zb3I0RCwgdGhpcy5kZXB0aHdpc2VLZXJuZWwucmVhZCgpIGFzIFRlbnNvcjRELFxuICAgICAgICAgICAgdGhpcy5wb2ludHdpc2VLZXJuZWwucmVhZCgpIGFzIFRlbnNvcjRELFxuICAgICAgICAgICAgdGhpcy5zdHJpZGVzIGFzIFtudW1iZXIsIG51bWJlcl0sIHRoaXMucGFkZGluZyBhcyAnc2FtZScgfCAndmFsaWQnLFxuICAgICAgICAgICAgdGhpcy5kaWxhdGlvblJhdGUgYXMgW251bWJlciwgbnVtYmVyXSwgJ05IV0MnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMudXNlQmlhcykge1xuICAgICAgICBvdXRwdXQgPSBLLmJpYXNBZGQob3V0cHV0LCB0aGlzLmJpYXMucmVhZCgpLCB0aGlzLmRhdGFGb3JtYXQpO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPSBudWxsKSB7XG4gICAgICAgIG91dHB1dCA9IHRoaXMuYWN0aXZhdGlvbi5hcHBseShvdXRwdXQpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgICAgb3V0cHV0ID0gdGZjLnRyYW5zcG9zZShvdXRwdXQsIFswLCAzLCAxLCAyXSk7ICAvLyBOSFdDIC0+IE5DSFcuXG4gICAgICB9XG4gICAgICByZXR1cm4gb3V0cHV0O1xuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1sncmFuayddO1xuICAgIGRlbGV0ZSBjb25maWdbJ2tlcm5lbEluaXRpYWxpemVyJ107XG4gICAgZGVsZXRlIGNvbmZpZ1sna2VybmVsUmVndWxhcml6ZXInXTtcbiAgICBkZWxldGUgY29uZmlnWydrZXJuZWxDb25zdHJhaW50J107XG4gICAgY29uZmlnWydkZXB0aHdpc2VJbml0aWFsaXplciddID1cbiAgICAgICAgc2VyaWFsaXplSW5pdGlhbGl6ZXIodGhpcy5kZXB0aHdpc2VJbml0aWFsaXplcik7XG4gICAgY29uZmlnWydwb2ludHdpc2VJbml0aWFsaXplciddID1cbiAgICAgICAgc2VyaWFsaXplSW5pdGlhbGl6ZXIodGhpcy5wb2ludHdpc2VJbml0aWFsaXplcik7XG4gICAgY29uZmlnWydkZXB0aHdpc2VSZWd1bGFyaXplciddID1cbiAgICAgICAgc2VyaWFsaXplUmVndWxhcml6ZXIodGhpcy5kZXB0aHdpc2VSZWd1bGFyaXplcik7XG4gICAgY29uZmlnWydwb2ludHdpc2VSZWd1bGFyaXplciddID1cbiAgICAgICAgc2VyaWFsaXplUmVndWxhcml6ZXIodGhpcy5wb2ludHdpc2VSZWd1bGFyaXplcik7XG4gICAgY29uZmlnWydkZXB0aHdpc2VDb25zdHJhaW50J10gPVxuICAgICAgICBzZXJpYWxpemVDb25zdHJhaW50KHRoaXMuZGVwdGh3aXNlQ29uc3RyYWludCk7XG4gICAgY29uZmlnWydwb2ludHdpc2VDb25zdHJhaW50J10gPVxuICAgICAgICBzZXJpYWxpemVDb25zdHJhaW50KHRoaXMucG9pbnR3aXNlQ29uc3RyYWludCk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgU2VwYXJhYmxlQ29udjJEIGV4dGVuZHMgU2VwYXJhYmxlQ29udiB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgb3ZlcnJpZGUgY2xhc3NOYW1lID0gJ1NlcGFyYWJsZUNvbnYyRCc7XG4gIGNvbnN0cnVjdG9yKGFyZ3M/OiBTZXBhcmFibGVDb252TGF5ZXJBcmdzKSB7XG4gICAgc3VwZXIoMiwgYXJncyk7XG4gIH1cbn1cbnNlcmlhbGl6YXRpb24ucmVnaXN0ZXJDbGFzcyhTZXBhcmFibGVDb252MkQpO1xuXG5leHBvcnQgY2xhc3MgQ29udjFEIGV4dGVuZHMgQ29udiB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgY2xhc3NOYW1lID0gJ0NvbnYxRCc7XG4gIGNvbnN0cnVjdG9yKGFyZ3M6IENvbnZMYXllckFyZ3MpIHtcbiAgICBzdXBlcigxLCBhcmdzKTtcbiAgICBDb252MUQudmVyaWZ5QXJncyhhcmdzKTtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFt7bmRpbTogM31dO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1sncmFuayddO1xuICAgIGRlbGV0ZSBjb25maWdbJ2RhdGFGb3JtYXQnXTtcbiAgICByZXR1cm4gY29uZmlnO1xuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBvdmVycmlkZSB2ZXJpZnlBcmdzKGFyZ3M6IENvbnZMYXllckFyZ3MpIHtcbiAgICAvLyBjb25maWcua2VybmVsU2l6ZSBtdXN0IGJlIGEgbnVtYmVyIG9yIGFycmF5IG9mIG51bWJlcnMuXG4gICAgaWYgKHR5cGVvZiBhcmdzLmtlcm5lbFNpemUgIT09ICdudW1iZXInICYmXG4gICAgICAgICFnZW5lcmljX3V0aWxzLmNoZWNrQXJyYXlUeXBlQW5kTGVuZ3RoKFxuICAgICAgICAgICAgYXJncy5rZXJuZWxTaXplLCAnbnVtYmVyJywgMSwgMSkpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBDb252MUQgZXhwZWN0cyBjb25maWcua2VybmVsU2l6ZSB0byBiZSBudW1iZXIgb3IgbnVtYmVyW10gd2l0aCBgICtcbiAgICAgICAgICBgbGVuZ3RoIDEsIGJ1dCByZWNlaXZlZCAke0pTT04uc3RyaW5naWZ5KGFyZ3Mua2VybmVsU2l6ZSl9LmApO1xuICAgIH1cbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYxRCk7XG5cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBDcm9wcGluZzJETGF5ZXJBcmdzIGV4dGVuZHMgTGF5ZXJBcmdzIHtcbiAgLyoqXG4gICAqIERpbWVuc2lvbiBvZiB0aGUgY3JvcHBpbmcgYWxvbmcgdGhlIHdpZHRoIGFuZCB0aGUgaGVpZ2h0LlxuICAgKiAtIElmIGludGVnZXI6IHRoZSBzYW1lIHN5bW1ldHJpYyBjcm9wcGluZ1xuICAgKiAgaXMgYXBwbGllZCB0byB3aWR0aCBhbmQgaGVpZ2h0LlxuICAgKiAtIElmIGxpc3Qgb2YgMiBpbnRlZ2VyczpcbiAgICogICBpbnRlcnByZXRlZCBhcyB0d28gZGlmZmVyZW50XG4gICAqICAgc3ltbWV0cmljIGNyb3BwaW5nIHZhbHVlcyBmb3IgaGVpZ2h0IGFuZCB3aWR0aDpcbiAgICogICBgW3N5bW1ldHJpY19oZWlnaHRfY3JvcCwgc3ltbWV0cmljX3dpZHRoX2Nyb3BdYC5cbiAgICogLSBJZiBhIGxpc3Qgb2YgMiBsaXN0cyBvZiAyIGludGVnZXJzOlxuICAgKiAgIGludGVycHJldGVkIGFzXG4gICAqICAgYFtbdG9wX2Nyb3AsIGJvdHRvbV9jcm9wXSwgW2xlZnRfY3JvcCwgcmlnaHRfY3JvcF1dYFxuICAgKi9cbiAgY3JvcHBpbmc6IG51bWJlcnxbbnVtYmVyLCBudW1iZXJdfFtbbnVtYmVyLCBudW1iZXJdLCBbbnVtYmVyLCBudW1iZXJdXTtcblxuICAvKipcbiAgICogRm9ybWF0IG9mIHRoZSBkYXRhLCB3aGljaCBkZXRlcm1pbmVzIHRoZSBvcmRlcmluZyBvZiB0aGUgZGltZW5zaW9ucyBpblxuICAgKiB0aGUgaW5wdXRzLlxuICAgKlxuICAgKiBgY2hhbm5lbHNfbGFzdGAgY29ycmVzcG9uZHMgdG8gaW5wdXRzIHdpdGggc2hhcGVcbiAgICogICBgKGJhdGNoLCAuLi4sIGNoYW5uZWxzKWBcbiAgICpcbiAgICogYGNoYW5uZWxzX2ZpcnN0YCBjb3JyZXNwb25kcyB0byBpbnB1dHMgd2l0aCBzaGFwZVxuICAgKiAgIGAoYmF0Y2gsIGNoYW5uZWxzLCAuLi4pYFxuICAgKlxuICAgKiBEZWZhdWx0cyB0byBgY2hhbm5lbHNfbGFzdGAuXG4gICAqL1xuICBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdDtcbn1cblxuZXhwb3J0IGNsYXNzIENyb3BwaW5nMkQgZXh0ZW5kcyBMYXllciB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgY2xhc3NOYW1lID0gJ0Nyb3BwaW5nMkQnO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY3JvcHBpbmc6IFtbbnVtYmVyLCBudW1iZXJdLCBbbnVtYmVyLCBudW1iZXJdXTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRhdGFGb3JtYXQ6IERhdGFGb3JtYXQ7XG5cbiAgY29uc3RydWN0b3IoYXJnczogQ3JvcHBpbmcyRExheWVyQXJncykge1xuICAgIHN1cGVyKGFyZ3MpO1xuICAgIGlmICh0eXBlb2YgYXJncy5jcm9wcGluZyA9PT0gJ251bWJlcicpIHtcbiAgICAgIHRoaXMuY3JvcHBpbmcgPVxuICAgICAgICAgIFtbYXJncy5jcm9wcGluZywgYXJncy5jcm9wcGluZ10sIFthcmdzLmNyb3BwaW5nLCBhcmdzLmNyb3BwaW5nXV07XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgYXJncy5jcm9wcGluZ1swXSA9PT0gJ251bWJlcicpIHtcbiAgICAgIHRoaXMuY3JvcHBpbmcgPSBbXG4gICAgICAgIFthcmdzLmNyb3BwaW5nWzBdLCBhcmdzLmNyb3BwaW5nWzBdXSxcbiAgICAgICAgW2FyZ3MuY3JvcHBpbmdbMV0gYXMgbnVtYmVyLCBhcmdzLmNyb3BwaW5nWzFdIGFzIG51bWJlcl1cbiAgICAgIF07XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY3JvcHBpbmcgPSBhcmdzLmNyb3BwaW5nIGFzIFtbbnVtYmVyLCBudW1iZXJdLCBbbnVtYmVyLCBudW1iZXJdXTtcbiAgICB9XG4gICAgdGhpcy5kYXRhRm9ybWF0ID1cbiAgICAgICAgYXJncy5kYXRhRm9ybWF0ID09PSB1bmRlZmluZWQgPyAnY2hhbm5lbHNMYXN0JyA6IGFyZ3MuZGF0YUZvcm1hdDtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFt7bmRpbTogNH1dO1xuICB9XG5cbiAgb3ZlcnJpZGUgY29tcHV0ZU91dHB1dFNoYXBlKGlucHV0U2hhcGU6IFNoYXBlKTogU2hhcGUge1xuICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgcmV0dXJuIFtcbiAgICAgICAgaW5wdXRTaGFwZVswXSwgaW5wdXRTaGFwZVsxXSxcbiAgICAgICAgaW5wdXRTaGFwZVsyXSAtIHRoaXMuY3JvcHBpbmdbMF1bMF0gLSB0aGlzLmNyb3BwaW5nWzBdWzFdLFxuICAgICAgICBpbnB1dFNoYXBlWzNdIC0gdGhpcy5jcm9wcGluZ1sxXVswXSAtIHRoaXMuY3JvcHBpbmdbMV1bMV1cbiAgICAgIF07XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBbXG4gICAgICAgIGlucHV0U2hhcGVbMF0sXG4gICAgICAgIGlucHV0U2hhcGVbMV0gLSB0aGlzLmNyb3BwaW5nWzBdWzBdIC0gdGhpcy5jcm9wcGluZ1swXVsxXSxcbiAgICAgICAgaW5wdXRTaGFwZVsyXSAtIHRoaXMuY3JvcHBpbmdbMV1bMF0gLSB0aGlzLmNyb3BwaW5nWzFdWzFdLCBpbnB1dFNoYXBlWzNdXG4gICAgICBdO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgICBpbnB1dHMgPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG5cbiAgICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0xhc3QnKSB7XG4gICAgICAgIGNvbnN0IGhTbGljZWQgPSBLLnNsaWNlQWxvbmdBeGlzKFxuICAgICAgICAgICAgaW5wdXRzLCB0aGlzLmNyb3BwaW5nWzBdWzBdLFxuICAgICAgICAgICAgaW5wdXRzLnNoYXBlWzFdIC0gdGhpcy5jcm9wcGluZ1swXVswXSAtIHRoaXMuY3JvcHBpbmdbMF1bMV0sIDIpO1xuICAgICAgICByZXR1cm4gSy5zbGljZUFsb25nQXhpcyhcbiAgICAgICAgICAgIGhTbGljZWQsIHRoaXMuY3JvcHBpbmdbMV1bMF0sXG4gICAgICAgICAgICBpbnB1dHMuc2hhcGVbMl0gLSB0aGlzLmNyb3BwaW5nWzFdWzFdIC0gdGhpcy5jcm9wcGluZ1sxXVswXSwgMyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBoU2xpY2VkID0gSy5zbGljZUFsb25nQXhpcyhcbiAgICAgICAgICAgIGlucHV0cywgdGhpcy5jcm9wcGluZ1swXVswXSxcbiAgICAgICAgICAgIGlucHV0cy5zaGFwZVsyXSAtIHRoaXMuY3JvcHBpbmdbMF1bMF0gLSB0aGlzLmNyb3BwaW5nWzBdWzFdLCAzKTtcbiAgICAgICAgcmV0dXJuIEsuc2xpY2VBbG9uZ0F4aXMoXG4gICAgICAgICAgICBoU2xpY2VkLCB0aGlzLmNyb3BwaW5nWzFdWzBdLFxuICAgICAgICAgICAgaW5wdXRzLnNoYXBlWzNdIC0gdGhpcy5jcm9wcGluZ1sxXVsxXSAtIHRoaXMuY3JvcHBpbmdbMV1bMF0sIDQpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0ge2Nyb3BwaW5nOiB0aGlzLmNyb3BwaW5nLCBkYXRhRm9ybWF0OiB0aGlzLmRhdGFGb3JtYXR9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENyb3BwaW5nMkQpO1xuXG5leHBvcnQgZGVjbGFyZSBpbnRlcmZhY2UgVXBTYW1wbGluZzJETGF5ZXJBcmdzIGV4dGVuZHMgTGF5ZXJBcmdzIHtcbiAgLyoqXG4gICAqIFRoZSB1cHNhbXBsaW5nIGZhY3RvcnMgZm9yIHJvd3MgYW5kIGNvbHVtbnMuXG4gICAqXG4gICAqIERlZmF1bHRzIHRvIGBbMiwgMl1gLlxuICAgKi9cbiAgc2l6ZT86IG51bWJlcltdO1xuICAvKipcbiAgICogRm9ybWF0IG9mIHRoZSBkYXRhLCB3aGljaCBkZXRlcm1pbmVzIHRoZSBvcmRlcmluZyBvZiB0aGUgZGltZW5zaW9ucyBpblxuICAgKiB0aGUgaW5wdXRzLlxuICAgKlxuICAgKiBgXCJjaGFubmVsc0xhc3RcImAgY29ycmVzcG9uZHMgdG8gaW5wdXRzIHdpdGggc2hhcGVcbiAgICogICBgW2JhdGNoLCAuLi4sIGNoYW5uZWxzXWBcbiAgICpcbiAgICogIGBcImNoYW5uZWxzRmlyc3RcImAgY29ycmVzcG9uZHMgdG8gaW5wdXRzIHdpdGggc2hhcGUgYFtiYXRjaCwgY2hhbm5lbHMsXG4gICAqIC4uLl1gLlxuICAgKlxuICAgKiBEZWZhdWx0cyB0byBgXCJjaGFubmVsc0xhc3RcImAuXG4gICAqL1xuICBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdDtcbiAgLyoqXG4gICAqIFRoZSBpbnRlcnBvbGF0aW9uIG1lY2hhbmlzbSwgb25lIG9mIGBcIm5lYXJlc3RcImAgb3IgYFwiYmlsaW5lYXJcImAsIGRlZmF1bHRcbiAgICogdG8gYFwibmVhcmVzdFwiYC5cbiAgICovXG4gIGludGVycG9sYXRpb24/OiBJbnRlcnBvbGF0aW9uRm9ybWF0O1xufVxuXG5leHBvcnQgY2xhc3MgVXBTYW1wbGluZzJEIGV4dGVuZHMgTGF5ZXIge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIGNsYXNzTmFtZSA9ICdVcFNhbXBsaW5nMkQnO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgREVGQVVMVF9TSVpFID0gWzIsIDJdO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2l6ZTogbnVtYmVyW107XG4gIHByb3RlY3RlZCByZWFkb25seSBkYXRhRm9ybWF0OiBEYXRhRm9ybWF0O1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgaW50ZXJwb2xhdGlvbjogSW50ZXJwb2xhdGlvbkZvcm1hdDtcblxuICBjb25zdHJ1Y3RvcihhcmdzOiBVcFNhbXBsaW5nMkRMYXllckFyZ3MpIHtcbiAgICBzdXBlcihhcmdzKTtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFt7bmRpbTogNH1dO1xuICAgIHRoaXMuc2l6ZSA9IGFyZ3Muc2l6ZSA9PSBudWxsID8gdGhpcy5ERUZBVUxUX1NJWkUgOiBhcmdzLnNpemU7XG4gICAgdGhpcy5kYXRhRm9ybWF0ID1cbiAgICAgICAgYXJncy5kYXRhRm9ybWF0ID09IG51bGwgPyAnY2hhbm5lbHNMYXN0JyA6IGFyZ3MuZGF0YUZvcm1hdDtcbiAgICBjaGVja0RhdGFGb3JtYXQodGhpcy5kYXRhRm9ybWF0KTtcbiAgICB0aGlzLmludGVycG9sYXRpb24gPVxuICAgICAgICBhcmdzLmludGVycG9sYXRpb24gPT0gbnVsbCA/ICduZWFyZXN0JyA6IGFyZ3MuaW50ZXJwb2xhdGlvbjtcbiAgICBjaGVja0ludGVycG9sYXRpb25Gb3JtYXQodGhpcy5pbnRlcnBvbGF0aW9uKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZSk6IFNoYXBlIHtcbiAgICBpZiAodGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgIGNvbnN0IGhlaWdodCA9XG4gICAgICAgICAgaW5wdXRTaGFwZVsyXSA9PSBudWxsID8gbnVsbCA6IHRoaXMuc2l6ZVswXSAqIGlucHV0U2hhcGVbMl07XG4gICAgICBjb25zdCB3aWR0aCA9IGlucHV0U2hhcGVbM10gPT0gbnVsbCA/IG51bGwgOiB0aGlzLnNpemVbMV0gKiBpbnB1dFNoYXBlWzNdO1xuICAgICAgcmV0dXJuIFtpbnB1dFNoYXBlWzBdLCBpbnB1dFNoYXBlWzFdLCBoZWlnaHQsIHdpZHRoXTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgaGVpZ2h0ID1cbiAgICAgICAgICBpbnB1dFNoYXBlWzFdID09IG51bGwgPyBudWxsIDogdGhpcy5zaXplWzBdICogaW5wdXRTaGFwZVsxXTtcbiAgICAgIGNvbnN0IHdpZHRoID0gaW5wdXRTaGFwZVsyXSA9PSBudWxsID8gbnVsbCA6IHRoaXMuc2l6ZVsxXSAqIGlucHV0U2hhcGVbMl07XG4gICAgICByZXR1cm4gW2lucHV0U2hhcGVbMF0sIGhlaWdodCwgd2lkdGgsIGlucHV0U2hhcGVbM11dO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICByZXR1cm4gdGZjLnRpZHkoKCkgPT4ge1xuICAgICAgbGV0IGlucHV0ID0gZ2V0RXhhY3RseU9uZVRlbnNvcihpbnB1dHMpIGFzIFRlbnNvcjREO1xuICAgICAgY29uc3QgaW5wdXRTaGFwZSA9IGlucHV0LnNoYXBlO1xuXG4gICAgICBpZiAodGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgICAgaW5wdXQgPSB0ZmMudHJhbnNwb3NlKGlucHV0LCBbMCwgMiwgMywgMV0pO1xuICAgICAgICBjb25zdCBoZWlnaHQgPSB0aGlzLnNpemVbMF0gKiBpbnB1dFNoYXBlWzJdO1xuICAgICAgICBjb25zdCB3aWR0aCA9IHRoaXMuc2l6ZVsxXSAqIGlucHV0U2hhcGVbM107XG5cbiAgICAgICAgY29uc3QgcmVzaXplZCA9IHRoaXMuaW50ZXJwb2xhdGlvbiA9PT0gJ25lYXJlc3QnID9cbiAgICAgICAgICAgIHRmYy5pbWFnZS5yZXNpemVOZWFyZXN0TmVpZ2hib3IoaW5wdXQsIFtoZWlnaHQsIHdpZHRoXSkgOlxuICAgICAgICAgICAgdGZjLmltYWdlLnJlc2l6ZUJpbGluZWFyKGlucHV0LCBbaGVpZ2h0LCB3aWR0aF0pO1xuICAgICAgICByZXR1cm4gdGZjLnRyYW5zcG9zZShyZXNpemVkLCBbMCwgMywgMSwgMl0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgaGVpZ2h0ID0gdGhpcy5zaXplWzBdICogaW5wdXRTaGFwZVsxXTtcbiAgICAgICAgY29uc3Qgd2lkdGggPSB0aGlzLnNpemVbMV0gKiBpbnB1dFNoYXBlWzJdO1xuICAgICAgICByZXR1cm4gdGhpcy5pbnRlcnBvbGF0aW9uID09PSAnbmVhcmVzdCcgP1xuICAgICAgICAgICAgdGZjLmltYWdlLnJlc2l6ZU5lYXJlc3ROZWlnaGJvcihpbnB1dCwgW2hlaWdodCwgd2lkdGhdKSA6XG4gICAgICAgICAgICB0ZmMuaW1hZ2UucmVzaXplQmlsaW5lYXIoaW5wdXQsIFtoZWlnaHQsIHdpZHRoXSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBvdmVycmlkZSBnZXRDb25maWcoKTogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0IHtcbiAgICBjb25zdCBjb25maWcgPSB7XG4gICAgICAgIHNpemU6IHRoaXMuc2l6ZSxcbiAgICAgICAgZGF0YUZvcm1hdDogdGhpcy5kYXRhRm9ybWF0LFxuICAgICAgICBpbnRlcnBvbGF0aW9uOiB0aGlzLmludGVycG9sYXRpb25cbiAgICB9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKFVwU2FtcGxpbmcyRCk7XG4iXX0=