UNPKG

47.4 kBJavaScriptView Raw
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 */
17import * as tf from '../../index';
18import { ALL_ENVS, describeWithFlags } from '../../jasmine_util';
19import { expectArraysClose, expectArraysEqual } from '../../test_util';
20describeWithFlags('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