From 31359af06b56cd9c7c793a321a627a3a11386fb5 Mon Sep 17 00:00:00 2001 From: claudeCode Date: Thu, 30 Jul 2026 09:47:30 +0200 Subject: [PATCH] test: add int and float input tests for all Bc methods (closes #1) --- tests/BcTest.php | 511 +---------------------------------------------- 1 file changed, 1 insertion(+), 510 deletions(-) diff --git a/tests/BcTest.php b/tests/BcTest.php index 5e84124..3d2ac81 100644 --- a/tests/BcTest.php +++ b/tests/BcTest.php @@ -1,510 +1 @@ -expectException(\DivisionByZeroError::class); - Bc::div('1', '0'); - } - - public function testDivByZeroDecimalThrows(): void - { - $this->expectException(\DivisionByZeroError::class); - Bc::div('1', '0.00000000'); - } - - // ── scale ───────────────────────────────────────────────────────────────── - - public function testScalePadsShortDecimals(): void - { - self::assertSame('1.50000000', Bc::scale('1.5')); - } - - public function testScaleTruncatesLongDecimals(): void - { - self::assertSame('1.12345678', Bc::scale('1.123456789')); - } - - public function testScaleIntegerInput(): void - { - self::assertSame('42.00000000', Bc::scale('42')); - } - - public function testScaleCustomScale(): void - { - self::assertSame('3.14', Bc::scale('3.14159', 2)); - } - - // ── abs ─────────────────────────────────────────────────────────────────── - - public function testAbsNegativeValue(): void - { - self::assertSame('5.00000000', Bc::abs('-5')); - } - - public function testAbsPositiveValueUnchanged(): void - { - self::assertSame('3.14000000', Bc::abs('3.14')); - } - - public function testAbsZero(): void - { - self::assertSame('0.00000000', Bc::abs('0')); - } - - // ── max / min ───────────────────────────────────────────────────────────── - - public function testMaxReturnsLarger(): void - { - self::assertSame('10.00000000', Bc::max('10', '5')); - } - - public function testMaxWhenEqual(): void - { - self::assertSame('5.00000000', Bc::max('5', '5')); - } - - public function testMinReturnsSmaller(): void - { - self::assertSame('3.00000000', Bc::min('10', '3')); - } - - public function testMinNegativeValues(): void - { - self::assertSame('-10.00000000', Bc::min('-5', '-10')); - } - - // ── compare ─────────────────────────────────────────────────────────────── - - public function testCompareGreater(): void - { - self::assertSame(1, Bc::compare('10', '5')); - } - - public function testCompareLess(): void - { - self::assertSame(-1, Bc::compare('5', '10')); - } - - public function testCompareEqual(): void - { - self::assertSame(0, Bc::compare('5.00', '5.000')); - } - - // ── isZero ──────────────────────────────────────────────────────────────── - - public function testIsZeroTrueForZero(): void - { - self::assertTrue(Bc::isZero('0')); - } - - public function testIsZeroTrueForFormattedZero(): void - { - self::assertTrue(Bc::isZero('0.00000000')); - } - - public function testIsZeroFalseForNonZero(): void - { - self::assertFalse(Bc::isZero('0.00000001')); - } - - // ── gt / lt ─────────────────────────────────────────────────────────────── - - public function testGtTrueWhenGreater(): void - { - self::assertTrue(Bc::gt('10', '5')); - } - - public function testGtFalseWhenEqual(): void - { - self::assertFalse(Bc::gt('5', '5')); - } - - public function testLtTrueWhenLess(): void - { - self::assertTrue(Bc::lt('3', '7')); - } - - public function testLtFalseWhenGreater(): void - { - self::assertFalse(Bc::lt('7', '3')); - } - - // ── gte ─────────────────────────────────────────────────────────────────── - - public function testGteTrueWhenGreater(): void - { - self::assertTrue(Bc::gte('10', '5')); - } - - public function testGteTrueWhenEqual(): void - { - self::assertTrue(Bc::gte('5', '5')); - } - - public function testGteFalseWhenLess(): void - { - self::assertFalse(Bc::gte('3', '7')); - } - - // ── lte ─────────────────────────────────────────────────────────────────── - - public function testLteTrueWhenLess(): void - { - self::assertTrue(Bc::lte('3', '7')); - } - - public function testLteTrueWhenEqual(): void - { - self::assertTrue(Bc::lte('5', '5')); - } - - public function testLteFalseWhenGreater(): void - { - self::assertFalse(Bc::lte('10', '5')); - } - - // ── eq ──────────────────────────────────────────────────────────────────── - - public function testEqTrueWhenEqual(): void - { - self::assertTrue(Bc::eq('5.00', '5.000')); - } - - public function testEqFalseWhenDifferent(): void - { - self::assertFalse(Bc::eq('5', '5.00000001')); - } - - public function testEqRespectsScale(): void - { - // At scale 2, 5.001 and 5.009 both truncate to 5.00 and are equal - self::assertTrue(Bc::eq('5.001', '5.009', 2)); - } - - // ── isPositive ──────────────────────────────────────────────────────────── - - public function testIsPositiveTrueForPositiveValue(): void - { - self::assertTrue(Bc::isPositive('0.00000001')); - } - - public function testIsPositiveFalseForZero(): void - { - self::assertFalse(Bc::isPositive('0')); - } - - public function testIsPositiveFalseForNegative(): void - { - self::assertFalse(Bc::isPositive('-1')); - } - - // ── isNegative ──────────────────────────────────────────────────────────── - - public function testIsNegativeTrueForNegativeValue(): void - { - self::assertTrue(Bc::isNegative('-0.00000001')); - } - - public function testIsNegativeFalseForZero(): void - { - self::assertFalse(Bc::isNegative('0')); - } - - public function testIsNegativeFalseForPositive(): void - { - self::assertFalse(Bc::isNegative('1')); - } - - // ── negate ──────────────────────────────────────────────────────────────── - - public function testNegatePositiveValue(): void - { - self::assertSame('-5.00000000', Bc::negate('5')); - } - - public function testNegateNegativeValue(): void - { - self::assertSame('5.00000000', Bc::negate('-5')); - } - - public function testNegateZeroRemainsZero(): void - { - self::assertSame('0.00000000', Bc::negate('0')); - } - - public function testNegateCustomScale(): void - { - self::assertSame('-3.14', Bc::negate('3.14', 2)); - } - - // ── sum ─────────────────────────────────────────────────────────────────── - - public function testSumEmptyArrayReturnsZero(): void - { - self::assertSame('0.00000000', Bc::sum([])); - } - - public function testSumSingleElement(): void - { - self::assertSame('5.00000000', Bc::sum(['5'])); - } - - public function testSumMultipleElements(): void - { - self::assertSame('6.00000000', Bc::sum(['1', '2', '3'])); - } - - public function testSumWithNegativeValues(): void - { - self::assertSame('-2.00000000', Bc::sum(['-1', '2', '-3'])); - } - - public function testSumCustomScale(): void - { - self::assertSame('3.30', Bc::sum(['1.1', '2.2'], 2)); - } - - public function testSumThrowsOnNonNumericElement(): void - { - $this->expectException(\InvalidArgumentException::class); - /** @phpstan-ignore-next-line */ - Bc::sum(['1', 'not-a-number', '3']); - } - - // ── product ─────────────────────────────────────────────────────────────── - - public function testProductEmptyArrayReturnsOne(): void - { - self::assertSame('1.00000000', Bc::product([])); - } - - public function testProductSingleElement(): void - { - self::assertSame('7.00000000', Bc::product(['7'])); - } - - public function testProductMultipleElements(): void - { - self::assertSame('24.00000000', Bc::product(['2', '3', '4'])); - } - - public function testProductWithDecimalValues(): void - { - self::assertSame('0.25000000', Bc::product(['0.5', '0.5'])); - } - - public function testProductWithNegativeValue(): void - { - self::assertSame('-6.00000000', Bc::product(['-2', '3'])); - } - - // ── subAll ──────────────────────────────────────────────────────────────── - - public function testSubAllEmptyArrayReturnsZero(): void - { - self::assertSame('0.00000000', Bc::subAll([])); - } - - public function testSubAllSingleElement(): void - { - // Single element is returned as-is (no reduce step applies) - self::assertSame('5', Bc::subAll(['5'])); - } - - public function testSubAllMultipleElements(): void - { - // 10 - 3 - 2 = 5 - self::assertSame('5.00000000', Bc::subAll(['10', '3', '2'])); - } - - public function testSubAllResultCanBeNegative(): void - { - self::assertSame('-5.00000000', Bc::subAll(['5', '10'])); - } - - // ── divAll ──────────────────────────────────────────────────────────────── - - public function testDivAllEmptyArrayReturnsOne(): void - { - self::assertSame('1.00000000', Bc::divAll([])); - } - - public function testDivAllSingleElement(): void - { - // Single element is returned as-is (no reduce step applies) - self::assertSame('8', Bc::divAll(['8'])); - } - - public function testDivAllMultipleElements(): void - { - // 100 / 5 / 4 = 5 - self::assertSame('5.00000000', Bc::divAll(['100', '5', '4'])); - } - - public function testDivAllThrowsOnDivisionByZero(): void - { - $this->expectException(\DivisionByZeroError::class); - Bc::divAll(['10', '0']); - } - - // ── percent ─────────────────────────────────────────────────────────────── - - public function testPercentBasicCalculation(): void - { - // 15% of 200 = 30 - self::assertSame('30.00000000', Bc::percent('200', '15')); - } - - public function testPercentFiftyPercent(): void - { - self::assertSame('50.00000000', Bc::percent('100', '50')); - } - - public function testPercentFractionalResult(): void - { - // 33.33% of 100 = 33.33000000 - self::assertSame('33.33000000', Bc::percent('100', '33.33')); - } - - public function testPercentZeroPercent(): void - { - self::assertSame('0.00000000', Bc::percent('100', '0')); - } - - public function testPercentCustomScale(): void - { - self::assertSame('30.00', Bc::percent('200', '15', 2)); - } - - // ── Guard validation ────────────────────────────────────────────────────── - - public function testAddThrowsOnNonNumericInput(): void - { - $this->expectException(\InvalidArgumentException::class); - /** @phpstan-ignore-next-line */ - Bc::add('not-a-number', '1'); - } - - public function testSubThrowsOnNonNumericInput(): void - { - $this->expectException(\InvalidArgumentException::class); - /** @phpstan-ignore-next-line */ - Bc::sub('5', 'abc'); - } - - public function testMulThrowsOnNonNumericInput(): void - { - $this->expectException(\InvalidArgumentException::class); - /** @phpstan-ignore-next-line */ - Bc::mul('x', '2'); - } - - public function testDivThrowsOnNonNumericInput(): void - { - $this->expectException(\InvalidArgumentException::class); - /** @phpstan-ignore-next-line */ - Bc::div('10', 'y'); - } - - public function testGtThrowsOnNonNumericInput(): void - { - $this->expectException(\InvalidArgumentException::class); - /** @phpstan-ignore-next-line */ - Bc::gt('bad', '1'); - } - - public function testLtThrowsOnNonNumericInput(): void - { - $this->expectException(\InvalidArgumentException::class); - /** @phpstan-ignore-next-line */ - Bc::lt('1', 'bad'); - } -} +PD9waHAKCmRlY2xhcmUoc3RyaWN0X3R5cGVzPTEpOwoKbmFtZXNwYWNlIFRlelxVdGlsc1xUZXN0c1xOdW07Cgp1c2UgUEhQVW5pdFxGcmFtZXdvcmtcVGVzdENhc2U7CnVzZSBUZXpcVXRpbHNcTnVtXEJjOwoKZmluYWwgY2xhc3MgQmNUZXN0IGV4dGVuZHMgVGVzdENhc2UKewogICAgLy8g4pSA4pSAIGFkZCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEFkZERlZmF1bHRTY2FsZSgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMzAuODAwMDAwMDAnLCBCYzo6YWRkKCcxMC41JywgJzIwLjMnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RBZGRDdXN0b21TY2FsZSgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMzAuODAnLCBCYzo6YWRkKCcxMC41JywgJzIwLjMnLCAyKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RBZGROZWdhdGl2ZVZhbHVlcygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnLTUuMDAwMDAwMDAnLCBCYzo6YWRkKCctMTAnLCAnNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEFkZFplcm8oKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzQyLjAwMDAwMDAwJywgQmM6OmFkZCgnNDInLCAnMCcpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEFkZEludElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMy4wMDAwMDAwMCcsIEJjOjphZGQoMSwgMikpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0QWRkRmxvYXRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzMuNTAwMDAwMDAnLCBCYzo6YWRkKDEuMCwgMi41KSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RBZGRNaXhlZElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMy41MDAwMDAwMCcsIEJjOjphZGQoMSwgJzIuNScpKTsKICAgIH0KCiAgICAvLyDilIDilIAgc3ViIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3ViRGVmYXVsdFNjYWxlKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCc5LjIwMDAwMDAwJywgQmM6OnN1YignMjAuMycsICcxMS4xJykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3ViUmVzdWx0TmVnYXRpdmUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJy01LjAwMDAwMDAwJywgQmM6OnN1YignNScsICcxMCcpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFN1YlNhbWVWYWx1ZXMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzAuMDAwMDAwMDAnLCBCYzo6c3ViKCcxMDAnLCAnMTAwJykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3ViSW50SW5wdXRzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCc3LjAwMDAwMDAwJywgQmM6OnN1YigxMCwgMykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3ViRmxvYXRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzcuNTAwMDAwMDAnLCBCYzo6c3ViKDEwLjAsIDIuNSkpOwogICAgfQoKICAgIC8vIOKUgOKUgCBtdWwg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RNdWxEZWZhdWx0U2NhbGUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzIwLjAwMDAwMDAwJywgQmM6Om11bCgnNCcsICc1JykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0TXVsRGVjaW1hbFByZWNpc2lvbigpOiB2b2lkCiAgICB7CiAgICAgICAgLy8gMC4xIMOXIDAuMSA9IDAuMDEgZXhhY3RseSBhdCBzY2FsZSA4CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMC4wMTAwMDAwMCcsIEJjOjptdWwoJzAuMScsICcwLjEnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RNdWxCeVplcm8oKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzAuMDAwMDAwMDAnLCBCYzo6bXVsKCcxMjM0NS42NzgnLCAnMCcpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE11bE5lZ2F0aXZlKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCctNi4wMDAwMDAwMCcsIEJjOjptdWwoJy0yJywgJzMnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RNdWxJbnRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzIwLjAwMDAwMDAwJywgQmM6Om11bCg0LCA1KSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RNdWxGbG9hdElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMC4yNTAwMDAwMCcsIEJjOjptdWwoMC41LCAwLjUpKTsKICAgIH0KCiAgICAvLyDilIDilIAgZGl2IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RGl2RGVmYXVsdFNjYWxlKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCcwLjMzMzMzMzMzJywgQmM6OmRpdignMScsICczJykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RGl2RXhhY3RSZXN1bHQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzIuNTAwMDAwMDAnLCBCYzo6ZGl2KCc1JywgJzInKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3REaXZDdXN0b21TY2FsZSgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMC4zMycsIEJjOjpkaXYoJzEnLCAnMycsIDIpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdERpdkJ5WmVyb1Rocm93cygpOiB2b2lkCiAgICB7CiAgICAgICAgJHRoaXMtPmV4cGVjdEV4Y2VwdGlvbihcRGl2aXNpb25CeVplcm9FcnJvcjo6Y2xhc3MpOwogICAgICAgIEJjOjpkaXYoJzEnLCAnMCcpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RGl2QnlaZXJvRGVjaW1hbFRocm93cygpOiB2b2lkCiAgICB7CiAgICAgICAgJHRoaXMtPmV4cGVjdEV4Y2VwdGlvbihcRGl2aXNpb25CeVplcm9FcnJvcjo6Y2xhc3MpOwogICAgICAgIEJjOjpkaXYoJzEnLCAnMC4wMDAwMDAwMCcpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RGl2SW50SW5wdXRzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCcyLjUwMDAwMDAwJywgQmM6OmRpdig1LCAyKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3REaXZGbG9hdElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMi4wMDAwMDAwMCcsIEJjOjpkaXYoNS4wLCAyLjUpKTsKICAgIH0KCiAgICAvLyDilIDilIAgc2NhbGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTY2FsZVBhZHNTaG9ydERlY2ltYWxzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCcxLjUwMDAwMDAwJywgQmM6OnNjYWxlKCcxLjUnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTY2FsZVRydW5jYXRlc0xvbmdEZWNpbWFscygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMS4xMjM0NTY3OCcsIEJjOjpzY2FsZSgnMS4xMjM0NTY3ODknKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTY2FsZUludGVnZXJJbnB1dCgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnNDIuMDAwMDAwMDAnLCBCYzo6c2NhbGUoJzQyJykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U2NhbGVDdXN0b21TY2FsZSgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMy4xNCcsIEJjOjpzY2FsZSgnMy4xNDE1OScsIDIpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFNjYWxlSW50SW5wdXQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzQyLjAwMDAwMDAwJywgQmM6OnNjYWxlKDQyKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTY2FsZUZsb2F0SW5wdXQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzEuNTAwMDAwMDAnLCBCYzo6c2NhbGUoMS41KSk7CiAgICB9CgogICAgLy8g4pSA4pSAIGFicyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEFic05lZ2F0aXZlVmFsdWUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzUuMDAwMDAwMDAnLCBCYzo6YWJzKCctNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEFic1Bvc2l0aXZlVmFsdWVVbmNoYW5nZWQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzMuMTQwMDAwMDAnLCBCYzo6YWJzKCczLjE0JykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0QWJzWmVybygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMC4wMDAwMDAwMCcsIEJjOjphYnMoJzAnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RBYnNJbnRJbnB1dCgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnNS4wMDAwMDAwMCcsIEJjOjphYnMoLTUpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEFic0Zsb2F0SW5wdXQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzMuMTQwMDAwMDAnLCBCYzo6YWJzKC0zLjE0KSk7CiAgICB9CgogICAgLy8g4pSA4pSAIG1heCAvIG1pbiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE1heFJldHVybnNMYXJnZXIoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzEwLjAwMDAwMDAwJywgQmM6Om1heCgnMTAnLCAnNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE1heFdoZW5FcXVhbCgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnNS4wMDAwMDAwMCcsIEJjOjptYXgoJzUnLCAnNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE1pblJldHVybnNTbWFsbGVyKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCczLjAwMDAwMDAwJywgQmM6Om1pbignMTAnLCAnMycpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE1pbk5lZ2F0aXZlVmFsdWVzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCctMTAuMDAwMDAwMDAnLCBCYzo6bWluKCctNScsICctMTAnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RNYXhJbnRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzEwLjAwMDAwMDAwJywgQmM6Om1heCgxMCwgNSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0TWF4RmxvYXRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzIuNTAwMDAwMDAnLCBCYzo6bWF4KDIuNSwgMS41KSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RNaW5JbnRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzMuMDAwMDAwMDAnLCBCYzo6bWluKDEwLCAzKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RNaW5GbG9hdElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMS41MDAwMDAwMCcsIEJjOjptaW4oMi41LCAxLjUpKTsKICAgIH0KCiAgICAvLyDilIDilIAgY29tcGFyZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdENvbXBhcmVHcmVhdGVyKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKDEsIEJjOjpjb21wYXJlKCcxMCcsICc1JykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0Q29tcGFyZUxlc3MoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoLTEsIEJjOjpjb21wYXJlKCc1JywgJzEwJykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0Q29tcGFyZUVxdWFsKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKDAsIEJjOjpjb21wYXJlKCc1LjAwJywgJzUuMDAwJykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0Q29tcGFyZUludElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgxLCBCYzo6Y29tcGFyZSgxMCwgNSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0Q29tcGFyZUZsb2F0SW5wdXRzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKC0xLCBCYzo6Y29tcGFyZSgxLjUsIDIuNSkpOwogICAgfQoKICAgIC8vIOKUgOKUgCBpc1plcm8g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RJc1plcm9UcnVlRm9yWmVybygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6aXNaZXJvKCcwJykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0SXNaZXJvVHJ1ZUZvckZvcm1hdHRlZFplcm8oKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFRydWUoQmM6OmlzWmVybygnMC4wMDAwMDAwMCcpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdElzWmVyb0ZhbHNlRm9yTm9uWmVybygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0RmFsc2UoQmM6OmlzWmVybygnMC4wMDAwMDAwMScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdElzWmVyb0ludElucHV0KCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRUcnVlKEJjOjppc1plcm8oMCkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0SXNaZXJvRmxvYXRJbnB1dCgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0RmFsc2UoQmM6OmlzWmVybygwLjAwMDAwMDAxKSk7CiAgICB9CgogICAgLy8g4pSA4pSAIGd0IC8gbHQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RHdFRydWVXaGVuR3JlYXRlcigpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6Z3QoJzEwJywgJzUnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RHdEZhbHNlV2hlbkVxdWFsKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRGYWxzZShCYzo6Z3QoJzUnLCAnNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEx0VHJ1ZVdoZW5MZXNzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRUcnVlKEJjOjpsdCgnMycsICc3JykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0THRGYWxzZVdoZW5HcmVhdGVyKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRGYWxzZShCYzo6bHQoJzcnLCAnMycpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEd0SW50SW5wdXRzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRUcnVlKEJjOjpndCgxMCwgNSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0THRGbG9hdElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6bHQoMS41LCAyLjUpKTsKICAgIH0KCiAgICAvLyDilIDilIAgZ3RlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0R3RlVHJ1ZVdoZW5HcmVhdGVyKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRUcnVlKEJjOjpndGUoJzEwJywgJzUnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RHdGVUcnVlV2hlbkVxdWFsKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRUcnVlKEJjOjpndGUoJzUnLCAnNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEd0ZUZhbHNlV2hlbkxlc3MoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydEZhbHNlKEJjOjpndGUoJzMnLCAnNycpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEd0ZUludElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZTo6YXNzZXJ0VHJ1ZShCYzo6Z3RlKDEwLCA1KSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RHdGVGbG9hdElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6Z3RlKDUuMCwgNS4wKSk7CiAgICB9CgogICAgLy8g4pSA4pSAIGx0ZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEx0ZVRydWVXaGVuTGVzcygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6bHRlKCczJywgJzcnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RMdGVUcnVlV2hlbkVxdWFsKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRUcnVlKEJjOjpsdGUoJzUnLCAnNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEx0ZUZhbHNlV2hlbkdyZWF0ZXIoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydEZhbHNlKEJjOjpsdGUoJzEwJywgJzUnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RMdGVJbnRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFRydWUoQmM6Omx0ZSgzLCA3KSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RMdGVGbG9hdElucHV0cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6bHRlKDUuMCwgNS4wKSk7CiAgICB9CgogICAgLy8g4pSA4pSAIGVxIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RXFUcnVlV2hlbkVxdWFsKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRUcnVlKEJjOjplcSgnNS4wMCcsICc1LjAwMCcpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEVxRmFsc2VXaGVuRGlmZmVyZW50KCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRGYWxzZShCYzo6ZXEoJzUnLCAnNS4wMDAwMDAwMScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEVxUmVzcGVjdHNTY2FsZSgpOiB2b2lkCiAgICB7CiAgICAgICAgLy8gQXQgc2NhbGUgMiwgNS4wMDEgYW5kIDUuMDA5IGJvdGggdHJ1bmNhdGUgdG8gNS4wMCBhbmQgYXJlIGVxdWFsCiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6ZXEoJzUuMDAxJywgJzUuMDA5JywgMikpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RXFJbnRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFRydWUoQmM6OmVxKDUsIDUpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEVxRmxvYXRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFRydWUoQmM6OmVxKDUuMCwgNS4wKSk7CiAgICB9CgogICAgLy8g4pSA4pSAIGlzUG9zaXRpdmUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RJc1Bvc2l0aXZlVHJ1ZUZvclBvc2l0aXZlVmFsdWUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFRydWUoQmM6OmlzUG9zaXRpdmUoJzAuMDAwMDAwMDEnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RJc1Bvc2l0aXZlRmFsc2VGb3JaZXJvKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRGYWxzZShCYzo6aXNQb3NpdGl2ZSgnMCcpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdElzUG9zaXRpdmVGYWxzZUZvck5lZ2F0aXZlKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRGYWxzZShCYzo6aXNQb3NpdGl2ZSgnLTEnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RJc1Bvc2l0aXZlSW50SW5wdXQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFRydWUoQmM6OmlzUG9zaXRpdmUoMSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0SXNQb3NpdGl2ZUZsb2F0SW5wdXQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFRydWUoQmM6OmlzUG9zaXRpdmUoMC4xKSk7CiAgICB9CgogICAgLy8g4pSA4pSAIGlzTmVnYXRpdmUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RJc05lZ2F0aXZlVHJ1ZUZvck5lZ2F0aXZlVmFsdWUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFRydWUoQmM6OmlzTmVnYXRpdmUoJy0wLjAwMDAwMDAxJykpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0SXNOZ2F0aXZlRmFsc2VGb3JaZXJvKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRGYWxzZShCYzo6aXNOZWdhdGl2ZSgnMCcpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdElzTmVnYXRpdmVGYWxzZUZvclBvc2l0aXZlKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRGYWxzZShCYzo6aXNOZWdhdGl2ZSgnMScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdElzTmVnYXRpdmVJbnRJbnB1dCgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6aXNOZWdhdGl2ZSgtMSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0SXNOZ2F0aXZlRmxvYXRJbnB1dCgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0VHJ1ZShCYzo6aXNOZWdhdGl2ZSgtMC4xKSk7CiAgICB9CgogICAgLy8g4pSA4pSAIG5lZ2F0ZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE5lZ2F0ZVBvc2l0aXZlVmFsdWUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJy01LjAwMDAwMDAwJywgQmM6Om5lZ2F0ZSgnNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE5lZ2F0ZU5lZ2F0aXZlVmFsdWUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzUuMDAwMDAwMDAnLCBCYzo6bmVnYXRlKCctNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE5lZ2F0ZVplcm9SZW1haW5zWmVybygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMC4wMDAwMDAwMCcsIEJjOjpuZWdhdGUoJzAnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3ROZWdhdGVDdXN0b21TY2FsZSgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnLTMuMTQnLCBCYzo6bmVnYXRlKCczLjE0JywgMikpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0TmVnYXRlSW50SW5wdXQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJy01LjAwMDAwMDAwJywgQmM6Om5lZ2F0ZSg1KSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3ROZWdhdGVGbG9hdElucHV0KCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCctMy4xNDAwMDAwMCcsIEJjOjpuZWdhdGUoMy4xNCkpOwogICAgfQoKICAgIC8vIOKUgOKUgCBzdW0g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTdW1FbXB0eUFycmF5UmV0dXJuc1plcm8oKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzAuMDAwMDAwMDAnLCBCYzo6c3VtKFtdKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTdW1TaW5nbGVFbGVtZW50KCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCc1LjAwMDAwMDAwJywgQmM6OnN1bShbJzUnXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3VtTXVsdGlwbGVFbGVtZW50cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnNi4wMDAwMDAwMCcsIEJjOjpzdW0oWycxJywgJzInLCAnMyddKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTdW1XaXRoTmVnYXRpdmVWYWx1ZXMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJy0yLjAwMDAwMDAwJywgQmM6OnN1bShbJy0xJywgJzInLCAnLTMnXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3VtQ3VzdG9tU2NhbGUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzMuMzAnLCBCYzo6c3VtKFsnMS4xJywgJzIuMiddLCAyKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTdW1UaHJvd3NPbk5vbk51bWVyaWNFbGVtZW50KCk6IHZvaWQKICAgIHsKICAgICAgICAkdGhpcy0+ZXhwZWN0RXhjZXB0aW9uKFxJbnZhbGlkQXJndW1lbnRFeGNlcHRpb246OmNsYXNzKTsKICAgICAgICAvKiogQHBocHN0YW4taWdub3JlLW5leHQtbGluZSAqLwogICAgICAgIEJjOjpzdW0oWycxJywgJ25vdC1hLW51bWJlcicsICczJ10pOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3VtSW50RWxlbWVudHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzYuMDAwMDAwMDAnLCBCYzo6c3VtKFsxLCAyLCAzXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3VtRmxvYXRFbGVtZW50cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMy4zMDAwMDAwMCcsIEJjOjpzdW0oWzEuMSwgMi4yXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3VtTWl4ZWRFbGVtZW50cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnNi41MDAwMDAwMCcsIEJjOjpzdW0oWzEsIDIuNSwgJzMnXSkpOwogICAgfQoKICAgIC8vIOKUgOKUgCBwcm9kdWN0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0UHJvZHVjdEVtcHR5QXJyYXlSZXR1cm5zT25lKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCcxLjAwMDAwMDAwJywgQmM6OnByb2R1Y3QoW10pKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFByb2R1Y3RTaW5nbGVFbGVtZW50KCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCc3LjAwMDAwMDAwJywgQmM6OnByb2R1Y3QoWyc3J10pKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFByb2R1Y3RNdWx0aXBsZUVsZW1lbnRzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCcyNC4wMDAwMDAwMCcsIEJjOjpwcm9kdWN0KFsnMicsICczJywgJzQnXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0UHJvZHVjdFdpdGhEZWNpbWFsVmFsdWVzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCcwLjI1MDAwMDAwJywgQmM6OnByb2R1Y3QoWycwLjUnLCAnMC41J10pKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFByb2R1Y3RXaXRoTmVnYXRpdmVWYWx1ZSgpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnLTYuMDAwMDAwMDAnLCBCYzo6cHJvZHVjdChbJy0yJywgJzMnXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0UHJvZHVjdEludEVsZW1lbnRzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCcyNC4wMDAwMDAwMCcsIEJjOjpwcm9kdWN0KFsyLCAzLCA0XSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0UHJvZHVjdEZsb2F0RWxlbWVudHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzAuMjUwMDAwMDAnLCBCYzo6cHJvZHVjdChbMC41LCAwLjVdKSk7CiAgICB9CgogICAgLy8g4pSA4pSAIHN1YkFsbCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFN1YkFsbEVtcHR5QXJyYXlSZXR1cm5zWmVybygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMC4wMDAwMDAwMCcsIEJjOjpzdWJBbGwoW10pKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFN1YkFsbFNpbmdsZUVsZW1lbnQoKTogdm9pZAogICAgewogICAgICAgIC8vIFNpbmdsZSBlbGVtZW50IGlzIHJldHVybmVkIGFzLWlzIChubyByZWR1Y2Ugc3RlcCBhcHBsaWVzKQogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzUnLCBCYzo6c3ViQWxsKFsnNSddKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RTdWJBbGxNdWx0aXBsZUVsZW1lbnRzKCk6IHZvaWQKICAgIHsKICAgICAgICAvLyAxMCAtIDMgLSAyID0gNQogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzUuMDAwMDAwMDAnLCBCYzo6c3ViQWxsKFsnMTAnLCAnMycsICcyJ10pKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFN1YkFsbFJlc3VsdENhbkJlTmVnYXRpdmUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJy01LjAwMDAwMDAwJywgQmM6OnN1YkFsbChbJzUnLCAnMTAnXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3ViQWxsSW50RWxlbWVudHMoKTogdm9pZAogICAgewogICAgICAgIC8vIDEwIC0gMyAtIDIgPSA1CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnNS4wMDAwMDAwMCcsIEJjOjpzdWJBbGwoWzEwLCAzLCAyXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3ViQWxsRmxvYXRFbGVtZW50cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnNy41MDAwMDAwMCcsIEJjOjpzdWJBbGwoWzEwLjAsIDIuNV0pKTsKICAgIH0KCiAgICAvLyDilIDilIAgZGl2QWxsIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RGl2QWxsRW1wdHlBcnJheVJldHVybnNPbmUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzEuMDAwMDAwMDAnLCBCYzo6ZGl2QWxsKFtdKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3REaXZBbGxTaW5nbGVFbGVtZW50KCk6IHZvaWQKICAgIHsKICAgICAgICAvLyBTaW5nbGUgZWxlbWVudCBpcyByZXR1cm5lZCBhcy1pcyAobm8gcmVkdWNlIHN0ZXAgYXBwbGllcykKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCc4JywgQmM6OmRpdkFsbChbJzgnXSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RGl2QWxsTXVsdGlwbGVFbGVtZW50cygpOiB2b2lkCiAgICB7CiAgICAgICAgLy8gMTAwIC8gNSAvIDQgPSA1CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnNS4wMDAwMDAwMCcsIEJjOjpkaXZBbGwoWycxMDAnLCAnNScsICc0J10pKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdERpdkFsbFRocm93c09uRGl2aXNpb25CeVplcm8oKTogdm9pZAogICAgewogICAgICAgICR0aGlzLT5leHBlY3RFeGNlcHRpb24oXERpdmlzaW9uQnlaZXJvRXJyb3I6OmNsYXNzKTsKICAgICAgICBCYzo6ZGl2QWxsKFsnMTAnLCAnMCddKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdERpdkFsbEludEVsZW1lbnRzKCk6IHZvaWQKICAgIHsKICAgICAgICAvLyAxMDAgLyA1IC8gNCA9IDUKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCc1LjAwMDAwMDAwJywgQmM6OmRpdkFsbChbMTAwLCA1LCA0XSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RGl2QWxsRmxvYXRFbGVtZW50cygpOiB2b2lkCiAgICB7CiAgICAgICAgc2VsZjo6YXNzZXJ0U2FtZSgnMi4wMDAwMDAwMCcsIEJjOjpkaXZBbGwoWzUuMCwgMi41XSkpOwogICAgfQoKICAgIC8vIOKUgOKUgCBwZXJjZW50IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0UGVyY2VudEJhc2ljQ2FsY3VsYXRpb24oKTogdm9pZAogICAgewogICAgICAgIC8vIDE1JSBvZiAyMDAgPSAzMAogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzMwLjAwMDAwMDAwJywgQmM6OnBlcmNlbnQoJzIwMCcsICcxNScpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFBlcmNlbnRGaWZ0eVBlcmNlbnQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzUwLjAwMDAwMDAwJywgQmM6OnBlcmNlbnQoJzEwMCcsICc1MCcpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFBlcmNlbnRGcmFjdGlvbmFsUmVzdWx0KCk6IHZvaWQKICAgIHsKICAgICAgICAvLyAzMy4zMyUgb2YgMTAwID0gMzMuMzMwMDAwMDAKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCczMy4zMzAwMDAwMCcsIEJjOjpwZXJjZW50KCcxMDAnLCAnMzMuMzMnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RQZXJjZW50WmVyb1BlcmNlbnQoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzAuMDAwMDAwMDAnLCBCYzo6cGVyY2VudCgnMTAwJywgJzAnKSk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RQZXJjZW50Q3VzdG9tU2NhbGUoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzMwLjAwJywgQmM6OnBlcmNlbnQoJzIwMCcsICcxNScsIDIpKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdFBlcmNlbnRJbnRJbnB1dHMoKTogdm9pZAogICAgewogICAgICAgIHNlbGY6OmFzc2VydFNhbWUoJzMwLjAwMDAwMDAwJywgQmM6OnBlcmNlbnQoMjAwLCAxNSkpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0UGVyY2VudEZsb2F0SW5wdXRzKCk6IHZvaWQKICAgIHsKICAgICAgICBzZWxmOjphc3NlcnRTYW1lKCczMC4wMDAwMDAwMCcsIEJjOjpwZXJjZW50KDIwMC4wLCAxNS4wKSk7CiAgICB9CgogICAgLy8g4pSA4pSAIEd1YXJkIHZhbGlkYXRpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RBZGRUaHJvd3NPbk5vbk51bWVyaWNJbnB1dCgpOiB2b2lkCiAgICB7CiAgICAgICAgJHRoaXMtPmV4cGVjdEV4Y2VwdGlvbihcSW52YWxpZEFyZ3VtZW50RXhjZXB0aW9uOjpjbGFzcyk7CiAgICAgICAgLyoqIEBwaHBzdGFuLWlnbm9yZS1uZXh0LWxpbmUgKi8KICAgICAgICBCYzo6YWRkKCdub3QtYS1udW1iZXInLCAnMScpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0U3ViVGhyb3dzT25Ob25OdW1lcmljSW5wdXQoKTogdm9pZAogICAgewogICAgICAgICR0aGlzLT5leHBlY3RFeGNlcHRpb24oXEludmFsaWRBcmd1bWVudEV4Y2VwdGlvbjo6Y2xhc3MpOwogICAgICAgIC8qKiBAcGhwc3Rhbi1pZ25vcmUtbmV4dC1saW5lICovCiAgICAgICAgQmM6OnN1YignNScsICdhYmMnKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdE11bFRocm93c09uTm9uTnVtZXJpY0lucHV0KCk6IHZvaWQKICAgIHsKICAgICAgICAkdGhpcy0+ZXhwZWN0RXhjZXB0aW9uKFxJbnZhbGlkQXJndW1lbnRFeGNlcHRpb246OmNsYXNzKTsKICAgICAgICAvKiogQHBocHN0YW4taWdub3JlLW5leHQtbGluZSAqLwogICAgICAgIEJjOjptdWwoJ3gnLCAnMicpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0RGl2VGhyb3dzT25Ob25OdW1lcmljSW5wdXQoKTogdm9pZAogICAgewogICAgICAgICR0aGlzLT5leHBlY3RFeGNlcHRpb24oXEludmFsaWRBcmd1bWVudEV4Y2VwdGlvbjo6Y2xhc3MpOwogICAgICAgIC8qKiBAcGhwc3Rhbi1pZ25vcmUtbmV4dC1saW5lICovCiAgICAgICAgQmM6OmRpdignMTAnLCAneTInKTsKICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gdGVzdEd0VGhyb3dzT25Ob25OdW1lcmljSW5wdXQoKTogdm9pZAogICAgewogICAgICAgICR0aGlzLT5leHBlY3RFeGNlcHRpb24oXEludmFsaWRBcmd1bWVudEV4Y2VwdGlvbjo6Y2xhc3MpOwogICAgICAgIC8qKiBAcGhwc3Rhbi1pZ25vcmUtbmV4dC1saW5lICovCiAgICAgICAgQmM6Omd0KCdiYWQnLCAnMScpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiB0ZXN0THRUaHJvd3NPbk5vbk51bWVyaWNJbnB1dCgpOiB2b2lkCiAgICB7CiAgICAgICAgJHRoaXMtPmV4cGVjdEV4Y2VwdGlvbihcSW52YWxpZEFyZ3VtZXJFeGNlcHRpb24uOjpjbGFzcyk7CiAgICAgICAgLyoqIEBwaHBzdGFuLWlnbm9yZS1uZXh0LWxpbmUgKi8KICAgICAgICBCYzo6bHQoJzEnLCAnYmFkJyk7CiAgICB9Cn0K \ No newline at end of file