1 | /**
|
2 | * @license
|
3 | * Copyright 2020 Google LLC. All Rights Reserved.
|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | * you may not use this file except in compliance with the License.
|
6 | * You may obtain a copy of the License at
|
7 | *
|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
9 | *
|
10 | * Unless required by applicable law or agreed to in writing, software
|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 | * See the License for the specific language governing permissions and
|
14 | * limitations under the License.
|
15 | * =============================================================================
|
16 | */
|
17 | import * as tf from '../../index';
|
18 | import { ALL_ENVS, describeWithFlags } from '../../jasmine_util';
|
19 | import { expectArraysClose, expectArraysEqual } from '../../test_util';
|
20 | describeWithFlags('nonMaxSuppression', ALL_ENVS, () => {
|
21 | describe('NonMaxSuppression Basic', () => {
|
22 | it('select from three clusters', async () => {
|
23 | const boxes = tf.tensor2d([
|
24 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
25 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
26 | ], [6, 4]);
|
27 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5, 0.3]);
|
28 | const maxOutputSize = 3;
|
29 | const iouThreshold = 0.5;
|
30 | const scoreThreshold = 0;
|
31 | const indices = tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold);
|
32 | expect(indices.shape).toEqual([3]);
|
33 | expectArraysEqual(await indices.data(), [3, 0, 5]);
|
34 | });
|
35 | it('select from three clusters flipped coordinates', async () => {
|
36 | const boxes = tf.tensor2d([
|
37 | 1, 1, 0, 0, 0, 0.1, 1, 1.1, 0, .9, 1, -0.1,
|
38 | 0, 10, 1, 11, 1, 10.1, 0, 11.1, 1, 101, 0, 100
|
39 | ], [6, 4]);
|
40 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5, 0.3]);
|
41 | const maxOutputSize = 3;
|
42 | const iouThreshold = 0.5;
|
43 | const scoreThreshold = 0;
|
44 | const indices = tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold);
|
45 | expect(indices.shape).toEqual([3]);
|
46 | expectArraysEqual(await indices.data(), [3, 0, 5]);
|
47 | });
|
48 | it('select at most two boxes from three clusters', async () => {
|
49 | const boxes = tf.tensor2d([
|
50 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
51 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
52 | ], [6, 4]);
|
53 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5, 0.3]);
|
54 | const maxOutputSize = 2;
|
55 | const iouThreshold = 0.5;
|
56 | const scoreThreshold = 0;
|
57 | const indices = tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold);
|
58 | expect(indices.shape).toEqual([2]);
|
59 | expectArraysEqual(await indices.data(), [3, 0]);
|
60 | });
|
61 | it('select at most thirty boxes from three clusters', async () => {
|
62 | const boxes = tf.tensor2d([
|
63 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
64 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
65 | ], [6, 4]);
|
66 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5, 0.3]);
|
67 | const maxOutputSize = 30;
|
68 | const iouThreshold = 0.5;
|
69 | const scoreThreshold = 0;
|
70 | const indices = tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold);
|
71 | expect(indices.shape).toEqual([3]);
|
72 | expectArraysEqual(await indices.data(), [3, 0, 5]);
|
73 | });
|
74 | it('select single box', async () => {
|
75 | const boxes = tf.tensor2d([0, 0, 1, 1], [1, 4]);
|
76 | const scores = tf.tensor1d([0.9]);
|
77 | const maxOutputSize = 3;
|
78 | const iouThreshold = 0.5;
|
79 | const scoreThreshold = 0;
|
80 | const indices = tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold);
|
81 | expect(indices.shape).toEqual([1]);
|
82 | expectArraysEqual(await indices.data(), [0]);
|
83 | });
|
84 | it('select from ten identical boxes', async () => {
|
85 | const numBoxes = 10;
|
86 | const corners = new Array(numBoxes)
|
87 | .fill(0)
|
88 | .map(_ => [0, 0, 1, 1])
|
89 | .reduce((arr, curr) => arr.concat(curr));
|
90 | const boxes = tf.tensor2d(corners, [numBoxes, 4]);
|
91 | const scores = tf.tensor1d(Array(numBoxes).fill(0.9));
|
92 | const maxOutputSize = 3;
|
93 | const iouThreshold = 0.5;
|
94 | const scoreThreshold = 0;
|
95 | const indices = tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold);
|
96 | expect(indices.shape).toEqual([1]);
|
97 | expectArraysEqual(await indices.data(), [0]);
|
98 | });
|
99 | it('inconsistent box and score shapes', () => {
|
100 | const boxes = tf.tensor2d([
|
101 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
102 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
103 | ], [6, 4]);
|
104 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5]);
|
105 | const maxOutputSize = 30;
|
106 | const iouThreshold = 0.5;
|
107 | const scoreThreshold = 0;
|
108 | expect(() => tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold))
|
109 | .toThrowError(/scores has incompatible shape with boxes/);
|
110 | });
|
111 | it('invalid iou threshold', () => {
|
112 | const boxes = tf.tensor2d([0, 0, 1, 1], [1, 4]);
|
113 | const scores = tf.tensor1d([0.9]);
|
114 | const maxOutputSize = 3;
|
115 | const iouThreshold = 1.2;
|
116 | const scoreThreshold = 0;
|
117 | expect(() => tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold))
|
118 | .toThrowError(/iouThreshold must be in \[0, 1\]/);
|
119 | });
|
120 | it('empty input', async () => {
|
121 | const boxes = tf.tensor2d([], [0, 4]);
|
122 | const scores = tf.tensor1d([]);
|
123 | const maxOutputSize = 3;
|
124 | const iouThreshold = 0.5;
|
125 | const scoreThreshold = 0;
|
126 | const indices = tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold);
|
127 | expect(indices.shape).toEqual([0]);
|
128 | expectArraysEqual(await indices.data(), []);
|
129 | });
|
130 | it('accepts a tensor-like object', async () => {
|
131 | const boxes = [[0, 0, 1, 1], [0, 1, 1, 2]];
|
132 | const scores = [1, 2];
|
133 | const indices = tf.image.nonMaxSuppression(boxes, scores, 10);
|
134 | expect(indices.shape).toEqual([2]);
|
135 | expect(indices.dtype).toEqual('int32');
|
136 | expectArraysEqual(await indices.data(), [1, 0]);
|
137 | });
|
138 | it('throws when boxes is int32', async () => {
|
139 | const boxes = tf.tensor2d([[0, 0, 1, 1], [0, 1, 1, 2]], [2, 4], 'int32');
|
140 | const scores = [1, 2];
|
141 | expect(() => tf.image.nonMaxSuppression(boxes, scores, 10))
|
142 | .toThrowError(/Argument 'boxes' passed to 'nonMaxSuppression' must be float32/);
|
143 | });
|
144 | it('throws when scores is int32', async () => {
|
145 | const boxes = [[0, 0, 1, 1], [0, 1, 1, 2]];
|
146 | const scores = tf.tensor1d([1, 2], 'int32');
|
147 | const errRegex = /Argument 'scores' passed to 'nonMaxSuppression' must be float32/;
|
148 | expect(() => tf.image.nonMaxSuppression(boxes, scores, 10))
|
149 | .toThrowError(errRegex);
|
150 | });
|
151 | it('works when inputs are not explicitly initialized on the CPU', async () => {
|
152 | // This test ensures that asynchronous backends work with NMS, which
|
153 | // requires inputs to reside on the CPU.
|
154 | const boxes = tf.tensor2d([
|
155 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
156 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
157 | ], [6, 4]);
|
158 | const a = tf.tensor1d([0, 1, -2, -4, 4, -4]);
|
159 | const b = tf.tensor1d([0.15, 0.2, 0.25, 0.5, 0.7, 1.2]);
|
160 | const scores = a.div(b);
|
161 | const maxOutputSize = 2;
|
162 | const iouThreshold = 0.5;
|
163 | const scoreThreshold = 0;
|
164 | await scores.data();
|
165 | const indices = tf.image.nonMaxSuppression(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold);
|
166 | expect(indices.shape).toEqual([2]);
|
167 | expectArraysEqual(await indices.data(), [4, 1]);
|
168 | });
|
169 | });
|
170 | describe('NonMaxSuppressionWithScore', () => {
|
171 | it('select from three clusters with SoftNMS', async () => {
|
172 | const boxes = tf.tensor2d([
|
173 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
174 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
175 | ], [6, 4]);
|
176 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5, 0.3]);
|
177 | const maxOutputSize = 6;
|
178 | const iouThreshold = 1.0;
|
179 | const scoreThreshold = 0;
|
180 | const softNmsSigma = 0.5;
|
181 | const { selectedIndices, selectedScores } = tf.image.nonMaxSuppressionWithScore(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold, softNmsSigma);
|
182 | expectArraysEqual(await selectedIndices.data(), [3, 0, 1, 5, 4, 2]);
|
183 | expectArraysClose(await selectedScores.data(), [0.95, 0.9, 0.384, 0.3, 0.256, 0.197]);
|
184 | });
|
185 | });
|
186 | describe('NonMaxSuppressionPadded', () => {
|
187 | it('select from three clusters with pad five.', async () => {
|
188 | const boxes = tf.tensor2d([
|
189 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
190 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
191 | ], [6, 4]);
|
192 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5, 0.3]);
|
193 | const maxOutputSize = 5;
|
194 | const iouThreshold = 0.5;
|
195 | const scoreThreshold = 0;
|
196 | const before = tf.memory().numTensors;
|
197 | const { selectedIndices, validOutputs } = tf.image.nonMaxSuppressionPadded(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold, true);
|
198 | const after = tf.memory().numTensors;
|
199 | expectArraysEqual(await selectedIndices.data(), [3, 0, 5, 0, 0]);
|
200 | expectArraysEqual(await validOutputs.data(), 3);
|
201 | expect(after).toEqual(before + 2);
|
202 | });
|
203 | it('select from three clusters with pad five and score threshold.', async () => {
|
204 | const boxes = tf.tensor2d([
|
205 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
206 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
207 | ], [6, 4]);
|
208 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5, 0.3]);
|
209 | const maxOutputSize = 6;
|
210 | const iouThreshold = 0.5;
|
211 | const scoreThreshold = 0.4;
|
212 | const before = tf.memory().numTensors;
|
213 | const { selectedIndices, validOutputs } = tf.image.nonMaxSuppressionPadded(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold, true);
|
214 | const after = tf.memory().numTensors;
|
215 | expectArraysEqual(await selectedIndices.data(), [3, 0, 0, 0, 0, 0]);
|
216 | expectArraysEqual(await validOutputs.data(), 2);
|
217 | expect(after).toEqual(before + 2);
|
218 | });
|
219 | it('select from three clusters with no padding when pad option is false.', async () => {
|
220 | const boxes = tf.tensor2d([
|
221 | 0, 0, 1, 1, 0, 0.1, 1, 1.1, 0, -0.1, 1, 0.9,
|
222 | 0, 10, 1, 11, 0, 10.1, 1, 11.1, 0, 100, 1, 101
|
223 | ], [6, 4]);
|
224 | const scores = tf.tensor1d([0.9, 0.75, 0.6, 0.95, 0.5, 0.3]);
|
225 | const maxOutputSize = 5;
|
226 | const iouThreshold = 0.5;
|
227 | const scoreThreshold = 0.0;
|
228 | const { selectedIndices, validOutputs } = tf.image.nonMaxSuppressionPadded(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold, false);
|
229 | expectArraysEqual(await selectedIndices.data(), [3, 0, 5]);
|
230 | expectArraysEqual(await validOutputs.data(), 3);
|
231 | });
|
232 | });
|
233 | });
|
234 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9uX21heF9zdXBwcmVzc2lvbl90ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vdGZqcy1jb3JlL3NyYy9vcHMvaW1hZ2Uvbm9uX21heF9zdXBwcmVzc2lvbl90ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sRUFBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQztBQUMvRCxPQUFPLEVBQUMsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUVyRSxpQkFBaUIsQ0FBQyxtQkFBbUIsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFO0lBQ3BELFFBQVEsQ0FBQyx5QkFBeUIsRUFBRSxHQUFHLEVBQUU7UUFDdkMsRUFBRSxDQUFDLDRCQUE0QixFQUFFLEtBQUssSUFBSSxFQUFFO1lBQzFDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQ3JCO2dCQUNFLENBQUMsRUFBRSxDQUFDLEVBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRyxDQUFDLEVBQUUsR0FBRyxFQUFHLENBQUMsRUFBRSxHQUFHLEVBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxHQUFHO2dCQUMvQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUcsQ0FBQyxFQUFFLEdBQUc7YUFDaEQsRUFDRCxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ1osTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxH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QUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDWixNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQzdELE1BQU0sYUFBYSxHQUFHLENBQUMsQ0FBQztZQUN4QixNQUFNLFlBQVksR0FBRyxHQUFHLENBQUM7WUFDekIsTUFBTSxjQUFjLEdBQUcsR0FBRyxDQUFDO1lBRTNCLE1BQU0sRUFBQyxlQUFlLEVBQUUsWUFBWSxFQUFDLEdBQ2pDLEVBQUUsQ0FBQyxLQUFLLENBQUMsdUJBQXVCLENBQzVCLEtBQUssRUFBRSxNQUFNLEVBQUUsYUFBYSxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQzFELEtBQUssQ0FBQyxDQUFDO1lBRWYsaUJBQWlCLENBQUMsTUFBTSxlQUFlLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDM0QsaUJBQWlCLENBQUMsTUFBTSxZQUFZLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDbEQsQ0FBQyxDQUFDLENBQUM7SUFDUixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMjAgR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuaW1wb3J0ICogYXMgdGYgZnJvbSAnLi4vLi4vaW5kZXgnO1xuaW1wb3J0IHtBTExfRU5WUywgZGVzY3JpYmVXaXRoRmxhZ3N9IGZyb20gJy4uLy4uL2phc21pbmVfdXRpbCc7XG5pbXBvcnQge2V4cGVjdEFycmF5c0Nsb3NlLCBleHBlY3RBcnJheXNFcXVhbH0gZnJvbSAnLi4vLi4vdGVzdF91dGlsJztcblxuZGVzY3JpYmVXaXRoRmxhZ3MoJ25vbk1heFN1cHByZXNzaW9uJywgQUxMX0VOVlMsICgpID0+IHtcbiAgZGVzY3JpYmUoJ05vbk1heFN1cHByZXNzaW9uIEJhc2ljJywgKCkgPT4ge1xuICAgIGl0KCdzZWxlY3QgZnJvbSB0aHJlZSBjbHVzdGVycycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGJveGVzID0gdGYudGVuc29yMmQoXG4gICAgICAgICAgW1xuICAgICAgICAgICAgMCwgMCwgIDEsIDEsICAwLCAwLjEsICAxLCAxLjEsICAwLCAtMC4xLCAxLCAwLjksXG4gICAgICAgICAgICAwLCAxMCwgMSwgMTEsIDAsIDEwLjEsIDEsIDExLjEsIDAsIDEwMCwgIDEsIDEwMVxuICAgICAgICAgIF0sXG4gICAgICAgICAgWzYsIDRdKTtcbiAgICAgIGNvbnN0IHNjb3JlcyA9IHRmLnRlbnNvcjFkKFswLjksIDAuNzUsIDAuNiwgMC45NSwgMC41LCAwLjNdKTtcbiAgICAgIGNvbnN0IG1heE91dHB1dFNpemUgPSAzO1xuICAgICAgY29uc3QgaW91VGhyZXNob2xkID0gMC41O1xuICAgICAgY29uc3Qgc2NvcmVUaHJlc2hvbGQgPSAwO1xuICAgICAgY29uc3QgaW5kaWNlcyA9IHRmLmltYWdlLm5vbk1heFN1cHByZXNzaW9uKFxuICAgICAgICAgIGJveGVzLCBzY29yZXMsIG1heE91dHB1dFNpemUsIGlvdVRocmVzaG9sZCwgc2NvcmVUaHJlc2hvbGQpO1xuXG4gICAgICBleHBlY3QoaW5kaWNlcy5zaGFwZSkudG9FcXVhbChbM10pO1xuICAgICAgZXhwZWN0QXJyYXlzRXF1YWwoYXdhaXQgaW5kaWNlcy5kYXRhKCksIFszLCAwLCA1XSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2VsZWN0IGZyb20gdGhyZWUgY2x1c3RlcnMgZmxpcHBlZCBjb29yZGluYXRlcycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGJveGVzID0gdGYudGVuc29yMmQoXG4gICAgICAgICAgW1xuICAgICAgICAgICAgMSwgMSwgIDAsIDAsICAwLCAwLjEsICAxLCAxLjEsICAwLCAuOSwgIDEsIC0wLjEsXG4gICAgICAgICAgICAwLCAxMCwgMSwgMTEsIDEsIDEwLjEsIDAsIDExLjEsIDEsIDEwMSwgMCwgMTAwXG4gICAgICAgICAgXSxcbiAgICAgICAgICBbNiwgNF0pO1xuICAgICAgY29uc3Qgc2NvcmVzID0gdGYudGVuc29yMWQoWzAuOSwgMC43NSwgMC42LCAwLjk1LCAwLjUsIDAuM10pO1xuICAgICAgY29uc3QgbWF4T3V0cHV0U2l6ZSA9IDM7XG4gICAgICBjb25zdCBpb3VUaHJlc2hvbGQgPSAwLjU7XG4gICAgICBjb25zdCBzY29yZVRocmVzaG9sZCA9IDA7XG4gICAgICBjb25zdCBpbmRpY2VzID0gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oXG4gICAgICAgICAgYm94ZXMsIHNjb3JlcywgbWF4T3V0cHV0U2l6ZSwgaW91VGhyZXNob2xkLCBzY29yZVRocmVzaG9sZCk7XG5cbiAgICAgIGV4cGVjdChpbmRpY2VzLnNoYXBlKS50b0VxdWFsKFszXSk7XG4gICAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCBpbmRpY2VzLmRhdGEoKSwgWzMsIDAsIDVdKTtcbiAgICB9KTtcblxuICAgIGl0KCdzZWxlY3QgYXQgbW9zdCB0d28gYm94ZXMgZnJvbSB0aHJlZSBjbHVzdGVycycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGJveGVzID0gdGYudGVuc29yMmQoXG4gICAgICAgICAgW1xuICAgICAgICAgICAgMCwgMCwgIDEsIDEsICAwLCAwLjEsICAxLCAxLjEsICAwLCAtMC4xLCAxLCAwLjksXG4gICAgICAgICAgICAwLCAxMCwgMSwgMTEsIDAsIDEwLjEsIDEsIDExLjEsIDAsIDEwMCwgIDEsIDEwMVxuICAgICAgICAgIF0sXG4gICAgICAgICAgWzYsIDRdKTtcbiAgICAgIGNvbnN0IHNjb3JlcyA9IHRmLnRlbnNvcjFkKFswLjksIDAuNzUsIDAuNiwgMC45NSwgMC41LCAwLjNdKTtcbiAgICAgIGNvbnN0IG1heE91dHB1dFNpemUgPSAyO1xuICAgICAgY29uc3QgaW91VGhyZXNob2xkID0gMC41O1xuICAgICAgY29uc3Qgc2NvcmVUaHJlc2hvbGQgPSAwO1xuICAgICAgY29uc3QgaW5kaWNlcyA9IHRmLmltYWdlLm5vbk1heFN1cHByZXNzaW9uKFxuICAgICAgICAgIGJveGVzLCBzY29yZXMsIG1heE91dHB1dFNpemUsIGlvdVRocmVzaG9sZCwgc2NvcmVUaHJlc2hvbGQpO1xuXG4gICAgICBleHBlY3QoaW5kaWNlcy5zaGFwZSkudG9FcXVhbChbMl0pO1xuICAgICAgZXhwZWN0QXJyYXlzRXF1YWwoYXdhaXQgaW5kaWNlcy5kYXRhKCksIFszLCAwXSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2VsZWN0IGF0IG1vc3QgdGhpcnR5IGJveGVzIGZyb20gdGhyZWUgY2x1c3RlcnMnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBib3hlcyA9IHRmLnRlbnNvcjJkKFxuICAgICAgICAgIFtcbiAgICAgICAgICAgIDAsIDAsICAxLCAxLCAgMCwgMC4xLCAgMSwgMS4xLCAgMCwgLTAuMSwgMSwgMC45LFxuICAgICAgICAgICAgMCwgMTAsIDEsIDExLCAwLCAxMC4xLCAxLCAxMS4xLCAwLCAxMDAsICAxLCAxMDFcbiAgICAgICAgICBdLFxuICAgICAgICAgIFs2LCA0XSk7XG4gICAgICBjb25zdCBzY29yZXMgPSB0Zi50ZW5zb3IxZChbMC45LCAwLjc1LCAwLjYsIDAuOTUsIDAuNSwgMC4zXSk7XG4gICAgICBjb25zdCBtYXhPdXRwdXRTaXplID0gMzA7XG4gICAgICBjb25zdCBpb3VUaHJlc2hvbGQgPSAwLjU7XG4gICAgICBjb25zdCBzY29yZVRocmVzaG9sZCA9IDA7XG4gICAgICBjb25zdCBpbmRpY2VzID0gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oXG4gICAgICAgICAgYm94ZXMsIHNjb3JlcywgbWF4T3V0cHV0U2l6ZSwgaW91VGhyZXNob2xkLCBzY29yZVRocmVzaG9sZCk7XG5cbiAgICAgIGV4cGVjdChpbmRpY2VzLnNoYXBlKS50b0VxdWFsKFszXSk7XG4gICAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCBpbmRpY2VzLmRhdGEoKSwgWzMsIDAsIDVdKTtcbiAgICB9KTtcblxuICAgIGl0KCdzZWxlY3Qgc2luZ2xlIGJveCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGJveGVzID0gdGYudGVuc29yMmQoWzAsIDAsIDEsIDFdLCBbMSwgNF0pO1xuICAgICAgY29uc3Qgc2NvcmVzID0gdGYudGVuc29yMWQoWzAuOV0pO1xuICAgICAgY29uc3QgbWF4T3V0cHV0U2l6ZSA9IDM7XG4gICAgICBjb25zdCBpb3VUaHJlc2hvbGQgPSAwLjU7XG4gICAgICBjb25zdCBzY29yZVRocmVzaG9sZCA9IDA7XG4gICAgICBjb25zdCBpbmRpY2VzID0gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oXG4gICAgICAgICAgYm94ZXMsIHNjb3JlcywgbWF4T3V0cHV0U2l6ZSwgaW91VGhyZXNob2xkLCBzY29yZVRocmVzaG9sZCk7XG5cbiAgICAgIGV4cGVjdChpbmRpY2VzLnNoYXBlKS50b0VxdWFsKFsxXSk7XG4gICAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCBpbmRpY2VzLmRhdGEoKSwgWzBdKTtcbiAgICB9KTtcblxuICAgIGl0KCdzZWxlY3QgZnJvbSB0ZW4gaWRlbnRpY2FsIGJveGVzJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbnVtQm94ZXMgPSAxMDtcbiAgICAgIGNvbnN0IGNvcm5lcnMgPSBuZXcgQXJyYXkobnVtQm94ZXMpXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC5maWxsKDApXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoXyA9PiBbMCwgMCwgMSwgMV0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC5yZWR1Y2UoKGFyciwgY3VycikgPT4gYXJyLmNvbmNhdChjdXJyKSk7XG4gICAgICBjb25zdCBib3hlcyA9IHRmLnRlbnNvcjJkKGNvcm5lcnMsIFtudW1Cb3hlcywgNF0pO1xuICAgICAgY29uc3Qgc2NvcmVzID0gdGYudGVuc29yMWQoQXJyYXkobnVtQm94ZXMpLmZpbGwoMC45KSk7XG4gICAgICBjb25zdCBtYXhPdXRwdXRTaXplID0gMztcbiAgICAgIGNvbnN0IGlvdVRocmVzaG9sZCA9IDAuNTtcbiAgICAgIGNvbnN0IHNjb3JlVGhyZXNob2xkID0gMDtcbiAgICAgIGNvbnN0IGluZGljZXMgPSB0Zi5pbWFnZS5ub25NYXhTdXBwcmVzc2lvbihcbiAgICAgICAgICBib3hlcywgc2NvcmVzLCBtYXhPdXRwdXRTaXplLCBpb3VUaHJlc2hvbGQsIHNjb3JlVGhyZXNob2xkKTtcblxuICAgICAgZXhwZWN0KGluZGljZXMuc2hhcGUpLnRvRXF1YWwoWzFdKTtcbiAgICAgIGV4cGVjdEFycmF5c0VxdWFsKGF3YWl0IGluZGljZXMuZGF0YSgpLCBbMF0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2luY29uc2lzdGVudCBib3ggYW5kIHNjb3JlIHNoYXBlcycsICgpID0+IHtcbiAgICAgIGNvbnN0IGJveGVzID0gdGYudGVuc29yMmQoXG4gICAgICAgICAgW1xuICAgICAgICAgICAgMCwgMCwgIDEsIDEsICAwLCAwLjEsICAxLCAxLjEsICAwLCAtMC4xLCAxLCAwLjksXG4gICAgICAgICAgICAwLCAxMCwgMSwgMTEsIDAsIDEwLjEsIDEsIDExLjEsIDAsIDEwMCwgIDEsIDEwMVxuICAgICAgICAgIF0sXG4gICAgICAgICAgWzYsIDRdKTtcbiAgICAgIGNvbnN0IHNjb3JlcyA9IHRmLnRlbnNvcjFkKFswLjksIDAuNzUsIDAuNiwgMC45NSwgMC41XSk7XG4gICAgICBjb25zdCBtYXhPdXRwdXRTaXplID0gMzA7XG4gICAgICBjb25zdCBpb3VUaHJlc2hvbGQgPSAwLjU7XG4gICAgICBjb25zdCBzY29yZVRocmVzaG9sZCA9IDA7XG4gICAgICBleHBlY3QoXG4gICAgICAgICAgKCkgPT4gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oXG4gICAgICAgICAgICAgIGJveGVzLCBzY29yZXMsIG1heE91dHB1dFNpemUsIGlvdVRocmVzaG9sZCwgc2NvcmVUaHJlc2hvbGQpKVxuICAgICAgICAgIC50b1Rocm93RXJyb3IoL3Njb3JlcyBoYXMgaW5jb21wYXRpYmxlIHNoYXBlIHdpdGggYm94ZXMvKTtcbiAgICB9KTtcblxuICAgIGl0KCdpbnZhbGlkIGlvdSB0aHJlc2hvbGQnLCAoKSA9PiB7XG4gICAgICBjb25zdCBib3hlcyA9IHRmLnRlbnNvcjJkKFswLCAwLCAxLCAxXSwgWzEsIDRdKTtcbiAgICAgIGNvbnN0IHNjb3JlcyA9IHRmLnRlbnNvcjFkKFswLjldKTtcbiAgICAgIGNvbnN0IG1heE91dHB1dFNpemUgPSAzO1xuICAgICAgY29uc3QgaW91VGhyZXNob2xkID0gMS4yO1xuICAgICAgY29uc3Qgc2NvcmVUaHJlc2hvbGQgPSAwO1xuICAgICAgZXhwZWN0KFxuICAgICAgICAgICgpID0+IHRmLmltYWdlLm5vbk1heFN1cHByZXNzaW9uKFxuICAgICAgICAgICAgICBib3hlcywgc2NvcmVzLCBtYXhPdXRwdXRTaXplLCBpb3VUaHJlc2hvbGQsIHNjb3JlVGhyZXNob2xkKSlcbiAgICAgICAgICAudG9UaHJvd0Vycm9yKC9pb3VUaHJlc2hvbGQgbXVzdCBiZSBpbiBcXFswLCAxXFxdLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnZW1wdHkgaW5wdXQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBib3hlcyA9IHRmLnRlbnNvcjJkKFtdLCBbMCwgNF0pO1xuICAgICAgY29uc3Qgc2NvcmVzID0gdGYudGVuc29yMWQoW10pO1xuICAgICAgY29uc3QgbWF4T3V0cHV0U2l6ZSA9IDM7XG4gICAgICBjb25zdCBpb3VUaHJlc2hvbGQgPSAwLjU7XG4gICAgICBjb25zdCBzY29yZVRocmVzaG9sZCA9IDA7XG4gICAgICBjb25zdCBpbmRpY2VzID0gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oXG4gICAgICAgICAgYm94ZXMsIHNjb3JlcywgbWF4T3V0cHV0U2l6ZSwgaW91VGhyZXNob2xkLCBzY29yZVRocmVzaG9sZCk7XG5cbiAgICAgIGV4cGVjdChpbmRpY2VzLnNoYXBlKS50b0VxdWFsKFswXSk7XG4gICAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCBpbmRpY2VzLmRhdGEoKSwgW10pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2FjY2VwdHMgYSB0ZW5zb3ItbGlrZSBvYmplY3QnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBib3hlcyA9IFtbMCwgMCwgMSwgMV0sIFswLCAxLCAxLCAyXV07XG4gICAgICBjb25zdCBzY29yZXMgPSBbMSwgMl07XG4gICAgICBjb25zdCBpbmRpY2VzID0gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oYm94ZXMsIHNjb3JlcywgMTApO1xuICAgICAgZXhwZWN0KGluZGljZXMuc2hhcGUpLnRvRXF1YWwoWzJdKTtcbiAgICAgIGV4cGVjdChpbmRpY2VzLmR0eXBlKS50b0VxdWFsKCdpbnQzMicpO1xuICAgICAgZXhwZWN0QXJyYXlzRXF1YWwoYXdhaXQgaW5kaWNlcy5kYXRhKCksIFsxLCAwXSk7XG4gICAgfSk7XG5cbiAgICBpdCgndGhyb3dzIHdoZW4gYm94ZXMgaXMgaW50MzInLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBib3hlcyA9IHRmLnRlbnNvcjJkKFtbMCwgMCwgMSwgMV0sIFswLCAxLCAxLCAyXV0sIFsyLCA0XSwgJ2ludDMyJyk7XG4gICAgICBjb25zdCBzY29yZXMgPSBbMSwgMl07XG4gICAgICBleHBlY3QoKCkgPT4gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oYm94ZXMsIHNjb3JlcywgMTApKVxuICAgICAgICAgIC50b1Rocm93RXJyb3IoXG4gICAgICAgICAgICAgIC9Bcmd1bWVudCAnYm94ZXMnIHBhc3NlZCB0byAnbm9uTWF4U3VwcHJlc3Npb24nIG11c3QgYmUgZmxvYXQzMi8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Rocm93cyB3aGVuIHNjb3JlcyBpcyBpbnQzMicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGJveGVzID0gW1swLCAwLCAxLCAxXSwgWzAsIDEsIDEsIDJdXTtcbiAgICAgIGNvbnN0IHNjb3JlcyA9IHRmLnRlbnNvcjFkKFsxLCAyXSwgJ2ludDMyJyk7XG4gICAgICBjb25zdCBlcnJSZWdleCA9XG4gICAgICAgICAgL0FyZ3VtZW50ICdzY29yZXMnIHBhc3NlZCB0byAnbm9uTWF4U3VwcHJlc3Npb24nIG11c3QgYmUgZmxvYXQzMi87XG4gICAgICBleHBlY3QoKCkgPT4gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oYm94ZXMsIHNjb3JlcywgMTApKVxuICAgICAgICAgIC50b1Rocm93RXJyb3IoZXJyUmVnZXgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3dvcmtzIHdoZW4gaW5wdXRzIGFyZSBub3QgZXhwbGljaXRseSBpbml0aWFsaXplZCBvbiB0aGUgQ1BVJyxcbiAgICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgICAvLyBUaGlzIHRlc3QgZW5zdXJlcyB0aGF0IGFzeW5jaHJvbm91cyBiYWNrZW5kcyB3b3JrIHdpdGggTk1TLCB3aGljaFxuICAgICAgICAgLy8gcmVxdWlyZXMgaW5wdXRzIHRvIHJlc2lkZSBvbiB0aGUgQ1BVLlxuICAgICAgICAgY29uc3QgYm94ZXMgPSB0Zi50ZW5zb3IyZChcbiAgICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAwLCAwLCAgMSwgMSwgIDAsIDAuMSwgIDEsIDEuMSwgIDAsIC0wLjEsIDEsIDAuOSxcbiAgICAgICAgICAgICAgIDAsIDEwLCAxLCAxMSwgMCwgMTAuMSwgMSwgMTEuMSwgMCwgMTAwLCAgMSwgMTAxXG4gICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICBbNiwgNF0pO1xuICAgICAgICAgY29uc3QgYSA9IHRmLnRlbnNvcjFkKFswLCAxLCAtMiwgLTQsIDQsIC00XSk7XG4gICAgICAgICBjb25zdCBiID0gdGYudGVuc29yMWQoWzAuMTUsIDAuMiwgMC4yNSwgMC41LCAwLjcsIDEuMl0pO1xuICAgICAgICAgY29uc3Qgc2NvcmVzID0gYS5kaXYoYik7XG4gICAgICAgICBjb25zdCBtYXhPdXRwdXRTaXplID0gMjtcbiAgICAgICAgIGNvbnN0IGlvdVRocmVzaG9sZCA9IDAuNTtcbiAgICAgICAgIGNvbnN0IHNjb3JlVGhyZXNob2xkID0gMDtcbiAgICAgICAgIGF3YWl0IHNjb3Jlcy5kYXRhKCk7XG4gICAgICAgICBjb25zdCBpbmRpY2VzID0gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb24oXG4gICAgICAgICAgICAgYm94ZXMsIHNjb3JlcyBhcyB0Zi5UZW5zb3IxRCwgbWF4T3V0cHV0U2l6ZSwgaW91VGhyZXNob2xkLFxuICAgICAgICAgICAgIHNjb3JlVGhyZXNob2xkKTtcblxuICAgICAgICAgZXhwZWN0KGluZGljZXMuc2hhcGUpLnRvRXF1YWwoWzJdKTtcbiAgICAgICAgIGV4cGVjdEFycmF5c0VxdWFsKGF3YWl0IGluZGljZXMuZGF0YSgpLCBbNCwgMV0pO1xuICAgICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnTm9uTWF4U3VwcHJlc3Npb25XaXRoU2NvcmUnLCAoKSA9PiB7XG4gICAgaXQoJ3NlbGVjdCBmcm9tIHRocmVlIGNsdXN0ZXJzIHdpdGggU29mdE5NUycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGJveGVzID0gdGYudGVuc29yMmQoXG4gICAgICAgICAgW1xuICAgICAgICAgICAgMCwgMCwgIDEsIDEsICAwLCAwLjEsICAxLCAxLjEsICAwLCAtMC4xLCAxLCAwLjksXG4gICAgICAgICAgICAwLCAxMCwgMSwgMTEsIDAsIDEwLjEsIDEsIDExLjEsIDAsIDEwMCwgIDEsIDEwMVxuICAgICAgICAgIF0sXG4gICAgICAgICAgWzYsIDRdKTtcbiAgICAgIGNvbnN0IHNjb3JlcyA9IHRmLnRlbnNvcjFkKFswLjksIDAuNzUsIDAuNiwgMC45NSwgMC41LCAwLjNdKTtcbiAgICAgIGNvbnN0IG1heE91dHB1dFNpemUgPSA2O1xuICAgICAgY29uc3QgaW91VGhyZXNob2xkID0gMS4wO1xuICAgICAgY29uc3Qgc2NvcmVUaHJlc2hvbGQgPSAwO1xuICAgICAgY29uc3Qgc29mdE5tc1NpZ21hID0gMC41O1xuXG4gICAgICBjb25zdCB7c2VsZWN0ZWRJbmRpY2VzLCBzZWxlY3RlZFNjb3Jlc30gPVxuICAgICAgICAgIHRmLmltYWdlLm5vbk1heFN1cHByZXNzaW9uV2l0aFNjb3JlKFxuICAgICAgICAgICAgICBib3hlcywgc2NvcmVzLCBtYXhPdXRwdXRTaXplLCBpb3VUaHJlc2hvbGQsIHNjb3JlVGhyZXNob2xkLFxuICAgICAgICAgICAgICBzb2Z0Tm1zU2lnbWEpO1xuXG4gICAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCBzZWxlY3RlZEluZGljZXMuZGF0YSgpLCBbMywgMCwgMSwgNSwgNCwgMl0pO1xuXG4gICAgICBleHBlY3RBcnJheXNDbG9zZShcbiAgICAgICAgICBhd2FpdCBzZWxlY3RlZFNjb3Jlcy5kYXRhKCksIFswLjk1LCAwLjksIDAuMzg0LCAwLjMsIDAuMjU2LCAwLjE5N10pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnTm9uTWF4U3VwcHJlc3Npb25QYWRkZWQnLCAoKSA9PiB7XG4gICAgaXQoJ3NlbGVjdCBmcm9tIHRocmVlIGNsdXN0ZXJzIHdpdGggcGFkIGZpdmUuJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgYm94ZXMgPSB0Zi50ZW5zb3IyZChcbiAgICAgICAgICBbXG4gICAgICAgICAgICAwLCAwLCAgMSwgMSwgIDAsIDAuMSwgIDEsIDEuMSwgIDAsIC0wLjEsIDEsIDAuOSxcbiAgICAgICAgICAgIDAsIDEwLCAxLCAxMSwgMCwgMTAuMSwgMSwgMTEuMSwgMCwgMTAwLCAgMSwgMTAxXG4gICAgICAgICAgXSxcbiAgICAgICAgICBbNiwgNF0pO1xuICAgICAgY29uc3Qgc2NvcmVzID0gdGYudGVuc29yMWQoWzAuOSwgMC43NSwgMC42LCAwLjk1LCAwLjUsIDAuM10pO1xuICAgICAgY29uc3QgbWF4T3V0cHV0U2l6ZSA9IDU7XG4gICAgICBjb25zdCBpb3VUaHJlc2hvbGQgPSAwLjU7XG4gICAgICBjb25zdCBzY29yZVRocmVzaG9sZCA9IDA7XG5cbiAgICAgIGNvbnN0IGJlZm9yZSA9IHRmLm1lbW9yeSgpLm51bVRlbnNvcnM7XG4gICAgICBjb25zdCB7c2VsZWN0ZWRJbmRpY2VzLCB2YWxpZE91dHB1dHN9ID0gdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb25QYWRkZWQoXG4gICAgICAgICAgYm94ZXMsIHNjb3JlcywgbWF4T3V0cHV0U2l6ZSwgaW91VGhyZXNob2xkLCBzY29yZVRocmVzaG9sZCwgdHJ1ZSk7XG4gICAgICBjb25zdCBhZnRlciA9IHRmLm1lbW9yeSgpLm51bVRlbnNvcnM7XG5cbiAgICAgIGV4cGVjdEFycmF5c0VxdWFsKGF3YWl0IHNlbGVjdGVkSW5kaWNlcy5kYXRhKCksIFszLCAwLCA1LCAwLCAwXSk7XG4gICAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCB2YWxpZE91dHB1dHMuZGF0YSgpLCAzKTtcbiAgICAgIGV4cGVjdChhZnRlcikudG9FcXVhbChiZWZvcmUgKyAyKTtcbiAgICB9KTtcblxuICAgIGl0KCdzZWxlY3QgZnJvbSB0aHJlZSBjbHVzdGVycyB3aXRoIHBhZCBmaXZlIGFuZCBzY29yZSB0aHJlc2hvbGQuJyxcbiAgICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgICBjb25zdCBib3hlcyA9IHRmLnRlbnNvcjJkKFxuICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgIDAsIDAsICAxLCAxLCAgMCwgMC4xLCAgMSwgMS4xLCAgMCwgLTAuMSwgMSwgMC45LFxuICAgICAgICAgICAgICAgMCwgMTAsIDEsIDExLCAwLCAxMC4xLCAxLCAxMS4xLCAwLCAxMDAsICAxLCAxMDFcbiAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgIFs2LCA0XSk7XG4gICAgICAgICBjb25zdCBzY29yZXMgPSB0Zi50ZW5zb3IxZChbMC45LCAwLjc1LCAwLjYsIDAuOTUsIDAuNSwgMC4zXSk7XG4gICAgICAgICBjb25zdCBtYXhPdXRwdXRTaXplID0gNjtcbiAgICAgICAgIGNvbnN0IGlvdVRocmVzaG9sZCA9IDAuNTtcbiAgICAgICAgIGNvbnN0IHNjb3JlVGhyZXNob2xkID0gMC40O1xuXG4gICAgICAgICBjb25zdCBiZWZvcmUgPSB0Zi5tZW1vcnkoKS5udW1UZW5zb3JzO1xuICAgICAgICAgY29uc3Qge3NlbGVjdGVkSW5kaWNlcywgdmFsaWRPdXRwdXRzfSA9XG4gICAgICAgICAgICAgdGYuaW1hZ2Uubm9uTWF4U3VwcHJlc3Npb25QYWRkZWQoXG4gICAgICAgICAgICAgICAgIGJveGVzLCBzY29yZXMsIG1heE91dHB1dFNpemUsIGlvdVRocmVzaG9sZCwgc2NvcmVUaHJlc2hvbGQsXG4gICAgICAgICAgICAgICAgIHRydWUpO1xuICAgICAgICAgY29uc3QgYWZ0ZXIgPSB0Zi5tZW1vcnkoKS5udW1UZW5zb3JzO1xuXG4gICAgICAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCBzZWxlY3RlZEluZGljZXMuZGF0YSgpLCBbMywgMCwgMCwgMCwgMCwgMF0pO1xuICAgICAgICAgZXhwZWN0QXJyYXlzRXF1YWwoYXdhaXQgdmFsaWRPdXRwdXRzLmRhdGEoKSwgMik7XG4gICAgICAgICBleHBlY3QoYWZ0ZXIpLnRvRXF1YWwoYmVmb3JlICsgMik7XG4gICAgICAgfSk7XG5cbiAgICBpdCgnc2VsZWN0IGZyb20gdGhyZWUgY2x1c3RlcnMgd2l0aCBubyBwYWRkaW5nIHdoZW4gcGFkIG9wdGlvbiBpcyBmYWxzZS4nLFxuICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgIGNvbnN0IGJveGVzID0gdGYudGVuc29yMmQoXG4gICAgICAgICAgICAgW1xuICAgICAgICAgICAgICAgMCwgMCwgIDEsIDEsICAwLCAwLjEsICAxLCAxLjEsICAwLCAtMC4xLCAxLCAwLjksXG4gICAgICAgICAgICAgICAwLCAxMCwgMSwgMTEsIDAsIDEwLjEsIDEsIDExLjEsIDAsIDEwMCwgIDEsIDEwMVxuICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgWzYsIDRdKTtcbiAgICAgICAgIGNvbnN0IHNjb3JlcyA9IHRmLnRlbnNvcjFkKFswLjksIDAuNzUsIDAuNiwgMC45NSwgMC41LCAwLjNdKTtcbiAgICAgICAgIGNvbnN0IG1heE91dHB1dFNpemUgPSA1O1xuICAgICAgICAgY29uc3QgaW91VGhyZXNob2xkID0gMC41O1xuICAgICAgICAgY29uc3Qgc2NvcmVUaHJlc2hvbGQgPSAwLjA7XG5cbiAgICAgICAgIGNvbnN0IHtzZWxlY3RlZEluZGljZXMsIHZhbGlkT3V0cHV0c30gPVxuICAgICAgICAgICAgIHRmLmltYWdlLm5vbk1heFN1cHByZXNzaW9uUGFkZGVkKFxuICAgICAgICAgICAgICAgICBib3hlcywgc2NvcmVzLCBtYXhPdXRwdXRTaXplLCBpb3VUaHJlc2hvbGQsIHNjb3JlVGhyZXNob2xkLFxuICAgICAgICAgICAgICAgICBmYWxzZSk7XG5cbiAgICAgICAgIGV4cGVjdEFycmF5c0VxdWFsKGF3YWl0IHNlbGVjdGVkSW5kaWNlcy5kYXRhKCksIFszLCAwLCA1XSk7XG4gICAgICAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCB2YWxpZE91dHB1dHMuZGF0YSgpLCAzKTtcbiAgICAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ== |
\ | No newline at end of file |