/** * @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