chenyc
2025-05-29 92f69c57b920cf62ecc9f15f9ed196fa26dbf2ac
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
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =============================================================================
 */
import * as tf from '../index';
import { ALL_ENVS, describeWithFlags } from '../jasmine_util';
import { expectArraysEqual } from '../test_util';
/**
 * Unit tests for confusionMatrix().
 */
describeWithFlags('confusionMatrix', ALL_ENVS, () => {
    // Reference (Python) TensorFlow code:
    //
    // ```py
    // import tensorflow as tf
    //
    // tf.enable_eager_execution()
    //
    // labels = tf.constant([0, 1, 2, 1, 0])
    // predictions = tf.constant([0, 2, 2, 1, 0])
    // out = tf.confusion_matrix(labels, predictions, 3)
    //
    // print(out)
    // ```
    it('3x3 all cases present in both labels and predictions', async () => {
        const labels = tf.tensor1d([0, 1, 2, 1, 0], 'int32');
        const predictions = tf.tensor1d([0, 2, 2, 1, 0], 'int32');
        const numClasses = 3;
        const out = tf.math.confusionMatrix(labels, predictions, numClasses);
        expectArraysEqual(await out.data(), [2, 0, 0, 0, 1, 1, 0, 0, 1]);
        expect(out.dtype).toBe('int32');
        expect(out.shape).toEqual([3, 3]);
    });
    it('float32 arguments are accepted', async () => {
        const labels = tf.tensor1d([0, 1, 2, 1, 0], 'float32');
        const predictions = tf.tensor1d([0, 2, 2, 1, 0], 'float32');
        const numClasses = 3;
        const out = tf.math.confusionMatrix(labels, predictions, numClasses);
        expectArraysEqual(await out.data(), [2, 0, 0, 0, 1, 1, 0, 0, 1]);
        expect(out.dtype).toBe('int32');
        expect(out.shape).toEqual([3, 3]);
    });
    // Reference (Python) TensorFlow code:
    //
    // ```py
    // import tensorflow as tf
    //
    // tf.enable_eager_execution()
    //
    // labels = tf.constant([3, 3, 2, 2, 1, 1, 0, 0])
    // predictions = tf.constant([2, 2, 2, 2, 0, 0, 0, 0])
    // out = tf.confusion_matrix(labels, predictions, 4)
    //
    // print(out)
    // ```
    it('4x4 all cases present in labels, but not predictions', async () => {
        const labels = tf.tensor1d([3, 3, 2, 2, 1, 1, 0, 0], 'int32');
        const predictions = tf.tensor1d([2, 2, 2, 2, 0, 0, 0, 0], 'int32');
        const numClasses = 4;
        const out = tf.math.confusionMatrix(labels, predictions, numClasses);
        expectArraysEqual(await out.data(), [2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0]);
        expect(out.dtype).toBe('int32');
        expect(out.shape).toEqual([4, 4]);
    });
    it('4x4 all cases present in predictions, but not labels', async () => {
        const labels = tf.tensor1d([2, 2, 2, 2, 0, 0, 0, 0], 'int32');
        const predictions = tf.tensor1d([3, 3, 2, 2, 1, 1, 0, 0], 'int32');
        const numClasses = 4;
        const out = tf.math.confusionMatrix(labels, predictions, numClasses);
        expectArraysEqual(await out.data(), [2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0]);
        expect(out.dtype).toBe('int32');
        expect(out.shape).toEqual([4, 4]);
    });
    it('Plain arrays as inputs', async () => {
        const labels = [3, 3, 2, 2, 1, 1, 0, 0];
        const predictions = [2, 2, 2, 2, 0, 0, 0, 0];
        const numClasses = 4;
        const out = tf.math.confusionMatrix(labels, predictions, numClasses);
        expectArraysEqual(await out.data(), [2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0]);
        expect(out.dtype).toBe('int32');
        expect(out.shape).toEqual([4, 4]);
    });
    it('Int32Arrays as inputs', async () => {
        const labels = new Int32Array([3, 3, 2, 2, 1, 1, 0, 0]);
        const predictions = new Int32Array([2, 2, 2, 2, 0, 0, 0, 0]);
        const numClasses = 4;
        const out = tf.math.confusionMatrix(labels, predictions, numClasses);
        expectArraysEqual(await out.data(), [2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0]);
        expect(out.dtype).toBe('int32');
        expect(out.shape).toEqual([4, 4]);
    });
    // Reference (Python) TensorFlow code:
    //
    // ```py
    // import tensorflow as tf
    //
    // tf.enable_eager_execution()
    //
    // labels = tf.constant([0, 4])
    // predictions = tf.constant([4, 0])
    // out = tf.confusion_matrix(labels, predictions, 5)
    //
    // print(out)
    // ```
    it('5x5 predictions and labels both missing some cases', async () => {
        const labels = tf.tensor1d([0, 4], 'int32');
        const predictions = tf.tensor1d([4, 0], 'int32');
        const numClasses = 5;
        const out = tf.math.confusionMatrix(labels, predictions, numClasses);
        expectArraysEqual(await out.data(), [
            0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
        ]);
        expect(out.dtype).toBe('int32');
        expect(out.shape).toEqual([5, 5]);
    });
    it('Invalid numClasses leads to Error', () => {
        expect(() => tf.math.confusionMatrix(tf.tensor1d([0, 1]), tf.tensor1d([1, 0]), 2.5))
            .toThrowError(/numClasses .* positive integer.* got 2\.5/);
    });
    it('Incorrect tensor rank leads to Error', () => {
        expect(() => tf.math.confusionMatrix(
        // tslint:disable-next-line:no-any
        tf.scalar(0), tf.scalar(0), 1))
            .toThrowError(/rank .* 1.*got 0/);
        expect(() => 
        // tslint:disable-next-line:no-any
        tf.math.confusionMatrix(tf.zeros([3, 3]), tf.zeros([9]), 2))
            .toThrowError(/rank .* 1.*got 2/);
        expect(() => 
        // tslint:disable-next-line:no-any
        tf.math.confusionMatrix(tf.zeros([9]), tf.zeros([3, 3]), 2))
            .toThrowError(/rank .* 1.*got 2/);
    });
    it('Mismatch in lengths leads to Error', () => {
        expect(
        // tslint:disable-next-line:no-any
        () => tf.math.confusionMatrix(tf.zeros([3]), tf.zeros([9]), 2))
            .toThrowError(/Mismatch .* 3 vs.* 9/);
    });
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZnVzaW9uX21hdHJpeF90ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGZqcy1jb3JlL3NyYy9vcHMvY29uZnVzaW9uX21hdHJpeF90ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQy9CLE9BQU8sRUFBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUM1RCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFFL0M7O0dBRUc7QUFFSCxpQkFBaUIsQ0FBQyxpQkFBaUIsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFO0lBQ2xELHNDQUFzQztJQUN0QyxFQUFFO0lBQ0YsUUFBUTtJQUNSLDBCQUEwQjtJQUMxQixFQUFFO0lBQ0YsOEJBQThCO0lBQzlCLEVBQUU7SUFDRix3Q0FBd0M7SUFDeEMsNkNBQTZDO0lBQzdDLG9EQUFvRDtJQUNwRCxFQUFFO0lBQ0YsYUFBYTtJQUNiLE1BQU07SUFDTixFQUFFLENBQUMsc0RBQXNELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDcEUsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNyRCxNQUFNLFdBQVcsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzFELE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQztRQUNyQixNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3JFLGlCQUFpQixDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pFLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsZ0NBQWdDLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDOUMsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUN2RCxNQUFNLFdBQVcsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQzVELE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQztRQUNyQixNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3JFLGlCQUFpQixDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pFLE1BQU0s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LENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3hFLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsd0JBQXdCLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDdEMsTUFBTSxNQUFNLEdBQWEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDbEQsTUFBTSxXQUFXLEdBQWEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDdkQsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBQ3JCLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sRUFBRSxXQUFXLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDckUsaUJBQWlCLENBQ2IsTUFBTSxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3hFLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxHQUFHLENBQUMs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QUFDLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7YUFDbEUsWUFBWSxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFDeEMsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsb0NBQW9DLEVBQUUsR0FBRyxFQUFFO1FBQzVDLE1BQU07UUFDRixrQ0FBa0M7UUFDbEMsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFRLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7YUFDckUsWUFBWSxDQUFDLHNCQUFzQixDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCAyMDE4IEdvb2dsZSBMTEMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuaW1wb3J0ICogYXMgdGYgZnJvbSAnLi4vaW5kZXgnO1xuaW1wb3J0IHtBTExfRU5WUywgZGVzY3JpYmVXaXRoRmxhZ3N9IGZyb20gJy4uL2phc21pbmVfdXRpbCc7XG5pbXBvcnQge2V4cGVjdEFycmF5c0VxdWFsfSBmcm9tICcuLi90ZXN0X3V0aWwnO1xuXG4vKipcbiAqIFVuaXQgdGVzdHMgZm9yIGNvbmZ1c2lvbk1hdHJpeCgpLlxuICovXG5cbmRlc2NyaWJlV2l0aEZsYWdzKCdjb25mdXNpb25NYXRyaXgnLCBBTExfRU5WUywgKCkgPT4ge1xuICAvLyBSZWZlcmVuY2UgKFB5dGhvbikgVGVuc29yRmxvdyBjb2RlOlxuICAvL1xuICAvLyBgYGBweVxuICAvLyBpbXBvcnQgdGVuc29yZmxvdyBhcyB0ZlxuICAvL1xuICAvLyB0Zi5lbmFibGVfZWFnZXJfZXhlY3V0aW9uKClcbiAgLy9cbiAgLy8gbGFiZWxzID0gdGYuY29uc3RhbnQoWzAsIDEsIDIsIDEsIDBdKVxuICAvLyBwcmVkaWN0aW9ucyA9IHRmLmNvbnN0YW50KFswLCAyLCAyLCAxLCAwXSlcbiAgLy8gb3V0ID0gdGYuY29uZnVzaW9uX21hdHJpeChsYWJlbHMsIHByZWRpY3Rpb25zLCAzKVxuICAvL1xuICAvLyBwcmludChvdXQpXG4gIC8vIGBgYFxuICBpdCgnM3gzIGFsbCBjYXNlcyBwcmVzZW50IGluIGJvdGggbGFiZWxzIGFuZCBwcmVkaWN0aW9ucycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBsYWJlbHMgPSB0Zi50ZW5zb3IxZChbMCwgMSwgMiwgMSwgMF0sICdpbnQzMicpO1xuICAgIGNvbnN0IHByZWRpY3Rpb25zID0gdGYudGVuc29yMWQoWzAsIDIsIDIsIDEsIDBdLCAnaW50MzInKTtcbiAgICBjb25zdCBudW1DbGFzc2VzID0gMztcbiAgICBjb25zdCBvdXQgPSB0Zi5tYXRoLmNvbmZ1c2lvbk1hdHJpeChsYWJlbHMsIHByZWRpY3Rpb25zLCBudW1DbGFzc2VzKTtcbiAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCBvdXQuZGF0YSgpLCBbMiwgMCwgMCwgMCwgMSwgMSwgMCwgMCwgMV0pO1xuICAgIGV4cGVjdChvdXQuZHR5cGUpLnRvQmUoJ2ludDMyJyk7XG4gICAgZXhwZWN0KG91dC5zaGFwZSkudG9FcXVhbChbMywgM10pO1xuICB9KTtcblxuICBpdCgnZmxvYXQzMiBhcmd1bWVudHMgYXJlIGFjY2VwdGVkJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGxhYmVscyA9IHRmLnRlbnNvcjFkKFswLCAxLCAyLCAxLCAwXSwgJ2Zsb2F0MzInKTtcbiAgICBjb25zdCBwcmVkaWN0aW9ucyA9IHRmLnRlbnNvcjFkKFswLCAyLCAyLCAxLCAwXSwgJ2Zsb2F0MzInKTtcbiAgICBjb25zdCBudW1DbGFzc2VzID0gMztcbiAgICBjb25zdCBvdXQgPSB0Zi5tYXRoLmNvbmZ1c2lvbk1hdHJpeChsYWJlbHMsIHByZWRpY3Rpb25zLCBudW1DbGFzc2VzKTtcbiAgICBleHBlY3RBcnJheXNFcXVhbChhd2FpdCBvdXQuZGF0YSgpLCBbMiwgMCwgMCwgMCwgMSwgMSwgMCwgMCwgMV0pO1xuICAgIGV4cGVjdChvdXQuZHR5cGUpLnRvQmUoJ2ludDMyJyk7XG4gICAgZXhwZWN0KG91dC5zaGFwZSkudG9FcXVhbChbMywgM10pO1xuICB9KTtcblxuICAvLyBSZWZlcmVuY2UgKFB5dGhvbikgVGVuc29yRmxvdyBjb2RlOlxuICAvL1xuICAvLyBgYGBweVxuICAvLyBpbXBvcnQgdGVuc29yZmxvdyBhcyB0ZlxuICAvL1xuICAvLyB0Zi5lbmFibGVfZWFnZXJfZXhlY3V0aW9uKClcbiAgLy9cbiAgLy8gbGFiZWxzID0gdGYuY29uc3RhbnQoWzMsIDMsIDIsIDIsIDEsIDEsIDAsIDBdKVxuICAvLyBwcmVkaWN0aW9ucyA9IHRmLmNvbnN0YW50KFsyLCAyLCAyLCAyLCAwLCAwLCAwLCAwXSlcbiAgLy8gb3V0ID0gdGYuY29uZnVzaW9uX21hdHJpeChsYWJlbHMsIHByZWRpY3Rpb25zLCA0KVxuICAvL1xuICAvLyBwcmludChvdXQpXG4gIC8vIGBgYFxuICBpdCgnNHg0IGFsbCBjYXNlcyBwcmVzZW50IGluIGxhYmVscywgYnV0IG5vdCBwcmVkaWN0aW9ucycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBsYWJlbHMgPSB0Zi50ZW5zb3IxZChbMywgMywgMiwgMiwgMSwgMSwgMCwgMF0sICdpbnQzMicpO1xuICAgIGNvbnN0IHByZWRpY3Rpb25zID0gdGYudGVuc29yMWQoWzIsIDIsIDIsIDIsIDAsIDAsIDAsIDBdLCAnaW50MzInKTtcbiAgICBjb25zdCBudW1DbGFzc2VzID0gNDtcbiAgICBjb25zdCBvdXQgPSB0Zi5tYXRoLmNvbmZ1c2lvbk1hdHJpeChsYWJlbHMsIHByZWRpY3Rpb25zLCBudW1DbGFzc2VzKTtcbiAgICBleHBlY3RBcnJheXNFcXVhbChcbiAgICAgICAgYXdhaXQgb3V0LmRhdGEoKSwgWzIsIDAsIDAsIDAsIDIsIDAsIDAsIDAsIDAsIDAsIDIsIDAsIDAsIDAsIDIsIDBdKTtcbiAgICBleHBlY3Qob3V0LmR0eXBlKS50b0JlKCdpbnQzMicpO1xuICAgIGV4cGVjdChvdXQuc2hhcGUpLnRvRXF1YWwoWzQsIDRdKTtcbiAgfSk7XG5cbiAgaXQoJzR4NCBhbGwgY2FzZXMgcHJlc2VudCBpbiBwcmVkaWN0aW9ucywgYnV0IG5vdCBsYWJlbHMnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgbGFiZWxzID0gdGYudGVuc29yMWQoWzIsIDIsIDIsIDIsIDAsIDAsIDAsIDBdLCAnaW50MzInKTtcbiAgICBjb25zdCBwcmVkaWN0aW9ucyA9IHRmLnRlbnNvcjFkKFszLCAzLCAyLCAyLCAxLCAxLCAwLCAwXSwgJ2ludDMyJyk7XG4gICAgY29uc3QgbnVtQ2xhc3NlcyA9IDQ7XG4gICAgY29uc3Qgb3V0ID0gdGYubWF0aC5jb25mdXNpb25NYXRyaXgobGFiZWxzLCBwcmVkaWN0aW9ucywgbnVtQ2xhc3Nlcyk7XG4gICAgZXhwZWN0QXJyYXlzRXF1YWwoXG4gICAgICAgIGF3YWl0IG91dC5kYXRhKCksIFsyLCAyLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAyLCAyLCAwLCAwLCAwLCAwXSk7XG4gICAgZXhwZWN0KG91dC5kdHlwZSkudG9CZSgnaW50MzInKTtcbiAgICBleHBlY3Qob3V0LnNoYXBlKS50b0VxdWFsKFs0LCA0XSk7XG4gIH0pO1xuXG4gIGl0KCdQbGFpbiBhcnJheXMgYXMgaW5wdXRzJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGxhYmVsczogbnVtYmVyW10gPSBbMywgMywgMiwgMiwgMSwgMSwgMCwgMF07XG4gICAgY29uc3QgcHJlZGljdGlvbnM6IG51bWJlcltdID0gWzIsIDIsIDIsIDIsIDAsIDAsIDAsIDBdO1xuICAgIGNvbnN0IG51bUNsYXNzZXMgPSA0O1xuICAgIGNvbnN0IG91dCA9IHRmLm1hdGguY29uZnVzaW9uTWF0cml4KGxhYmVscywgcHJlZGljdGlvbnMsIG51bUNsYXNzZXMpO1xuICAgIGV4cGVjdEFycmF5c0VxdWFsKFxuICAgICAgICBhd2FpdCBvdXQuZGF0YSgpLCBbMiwgMCwgMCwgMCwgMiwgMCwgMCwgMCwgMCwgMCwgMiwgMCwgMCwgMCwgMiwgMF0pO1xuICAgIGV4cGVjdChvdXQuZHR5cGUpLnRvQmUoJ2ludDMyJyk7XG4gICAgZXhwZWN0KG91dC5zaGFwZSkudG9FcXVhbChbNCwgNF0pO1xuICB9KTtcblxuICBpdCgnSW50MzJBcnJheXMgYXMgaW5wdXRzJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGxhYmVscyA9IG5ldyBJbnQzMkFycmF5KFszLCAzLCAyLCAyLCAxLCAxLCAwLCAwXSk7XG4gICAgY29uc3QgcHJlZGljdGlvbnMgPSBuZXcgSW50MzJBcnJheShbMiwgMiwgMiwgMiwgMCwgMCwgMCwgMF0pO1xuICAgIGNvbnN0IG51bUNsYXNzZXMgPSA0O1xuICAgIGNvbnN0IG91dCA9IHRmLm1hdGguY29uZnVzaW9uTWF0cml4KGxhYmVscywgcHJlZGljdGlvbnMsIG51bUNsYXNzZXMpO1xuICAgIGV4cGVjdEFycmF5c0VxdWFsKFxuICAgICAgICBhd2FpdCBvdXQuZGF0YSgpLCBbMiwgMCwgMCwgMCwgMiwgMCwgMCwgMCwgMCwgMCwgMiwgMCwgMCwgMCwgMiwgMF0pO1xuICAgIGV4cGVjdChvdXQuZHR5cGUpLnRvQmUoJ2ludDMyJyk7XG4gICAgZXhwZWN0KG91dC5zaGFwZSkudG9FcXVhbChbNCwgNF0pO1xuICB9KTtcblxuICAvLyBSZWZlcmVuY2UgKFB5dGhvbikgVGVuc29yRmxvdyBjb2RlOlxuICAvL1xuICAvLyBgYGBweVxuICAvLyBpbXBvcnQgdGVuc29yZmxvdyBhcyB0ZlxuICAvL1xuICAvLyB0Zi5lbmFibGVfZWFnZXJfZXhlY3V0aW9uKClcbiAgLy9cbiAgLy8gbGFiZWxzID0gdGYuY29uc3RhbnQoWzAsIDRdKVxuICAvLyBwcmVkaWN0aW9ucyA9IHRmLmNvbnN0YW50KFs0LCAwXSlcbiAgLy8gb3V0ID0gdGYuY29uZnVzaW9uX21hdHJpeChsYWJlbHMsIHByZWRpY3Rpb25zLCA1KVxuICAvL1xuICAvLyBwcmludChvdXQpXG4gIC8vIGBgYFxuICBpdCgnNXg1IHByZWRpY3Rpb25zIGFuZCBsYWJlbHMgYm90aCBtaXNzaW5nIHNvbWUgY2FzZXMnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgbGFiZWxzID0gdGYudGVuc29yMWQoWzAsIDRdLCAnaW50MzInKTtcbiAgICBjb25zdCBwcmVkaWN0aW9ucyA9IHRmLnRlbnNvcjFkKFs0LCAwXSwgJ2ludDMyJyk7XG4gICAgY29uc3QgbnVtQ2xhc3NlcyA9IDU7XG4gICAgY29uc3Qgb3V0ID0gdGYubWF0aC5jb25mdXNpb25NYXRyaXgobGFiZWxzLCBwcmVkaWN0aW9ucywgbnVtQ2xhc3Nlcyk7XG4gICAgZXhwZWN0QXJyYXlzRXF1YWwoYXdhaXQgb3V0LmRhdGEoKSwgW1xuICAgICAgMCwgMCwgMCwgMCwgMSwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCxcbiAgICAgIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDEsIDAsIDAsIDAsIDBcbiAgICBdKTtcbiAgICBleHBlY3Qob3V0LmR0eXBlKS50b0JlKCdpbnQzMicpO1xuICAgIGV4cGVjdChvdXQuc2hhcGUpLnRvRXF1YWwoWzUsIDVdKTtcbiAgfSk7XG5cbiAgaXQoJ0ludmFsaWQgbnVtQ2xhc3NlcyBsZWFkcyB0byBFcnJvcicsICgpID0+IHtcbiAgICBleHBlY3QoXG4gICAgICAgICgpID0+IHRmLm1hdGguY29uZnVzaW9uTWF0cml4KFxuICAgICAgICAgICAgdGYudGVuc29yMWQoWzAsIDFdKSwgdGYudGVuc29yMWQoWzEsIDBdKSwgMi41KSlcbiAgICAgICAgLnRvVGhyb3dFcnJvcigvbnVtQ2xhc3NlcyAuKiBwb3NpdGl2ZSBpbnRlZ2VyLiogZ290IDJcXC41Lyk7XG4gIH0pO1xuXG4gIGl0KCdJbmNvcnJlY3QgdGVuc29yIHJhbmsgbGVhZHMgdG8gRXJyb3InLCAoKSA9PiB7XG4gICAgZXhwZWN0KFxuICAgICAgICAoKSA9PiB0Zi5tYXRoLmNvbmZ1c2lvbk1hdHJpeChcbiAgICAgICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1hbnlcbiAgICAgICAgICAgIHRmLnNjYWxhcigwKSBhcyBhbnksIHRmLnNjYWxhcigwKSBhcyBhbnksIDEpKVxuICAgICAgICAudG9UaHJvd0Vycm9yKC9yYW5rIC4qIDEuKmdvdCAwLyk7XG4gICAgZXhwZWN0KFxuICAgICAgICAoKSA9PlxuICAgICAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWFueVxuICAgICAgICB0Zi5tYXRoLmNvbmZ1c2lvbk1hdHJpeCh0Zi56ZXJvcyhbMywgM10pIGFzIGFueSwgdGYuemVyb3MoWzldKSwgMikpXG4gICAgICAgIC50b1Rocm93RXJyb3IoL3JhbmsgLiogMS4qZ290IDIvKTtcbiAgICBleHBlY3QoXG4gICAgICAgICgpID0+XG4gICAgICAgICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gICAgICAgIHRmLm1hdGguY29uZnVzaW9uTWF0cml4KHRmLnplcm9zKFs5XSksIHRmLnplcm9zKFszLCAzXSkgYXMgYW55LCAyKSlcbiAgICAgICAgLnRvVGhyb3dFcnJvcigvcmFuayAuKiAxLipnb3QgMi8pO1xuICB9KTtcblxuICBpdCgnTWlzbWF0Y2ggaW4gbGVuZ3RocyBsZWFkcyB0byBFcnJvcicsICgpID0+IHtcbiAgICBleHBlY3QoXG4gICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1hbnlcbiAgICAgICAgKCkgPT4gdGYubWF0aC5jb25mdXNpb25NYXRyaXgodGYuemVyb3MoWzNdKSBhcyBhbnksIHRmLnplcm9zKFs5XSksIDIpKVxuICAgICAgICAudG9UaHJvd0Vycm9yKC9NaXNtYXRjaCAuKiAzIHZzLiogOS8pO1xuICB9KTtcbn0pO1xuIl19