From 86d9028a8d111af400e256832d6b00c350c0c302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Sun, 20 Jul 2025 16:16:55 -0300 Subject: [PATCH 1/3] Add more unit tests for Util::formatNumber() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- phpstan-baseline.neon | 6 ------ src/Util.php | 20 +++++++------------- tests/unit/UtilTest.php | 20 ++++++++++++++++++-- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 9ac292fdc6..e2e5395f78 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -19140,12 +19140,6 @@ parameters: count: 4 path: tests/unit/UtilTest.php - - - message: '#^Casting to string something that''s already string\.$#' - identifier: cast.useless - count: 1 - path: tests/unit/UtilTest.php - - message: '#^Parameter \#2 \$array of static method PHPUnit\\Framework\\Assert\:\:assertArrayNotHasKey\(\) expects array\\|ArrayAccess\<\(int\|string\), mixed\>, mixed given\.$#' identifier: argument.type diff --git a/src/Util.php b/src/Util.php index 4ed2ff3005..01b19a9418 100644 --- a/src/Util.php +++ b/src/Util.php @@ -389,19 +389,17 @@ class Util $value = (float) $value; } + /* l10n: Decimal separator */ + $decimalSep = __('.'); + /* l10n: Thousands separator */ + $thousandsSep = __(','); + $originalValue = $value; //number_format is not multibyte safe, str_replace is safe if ($digitsLeft === 0) { - $value = number_format( - (float) $value, - $digitsRight, - /* l10n: Decimal separator */ - __('.'), - /* l10n: Thousands separator */ - __(','), - ); + $value = number_format((float) $value, $digitsRight, $decimalSep, $thousandsSep); if ($originalValue != 0 && (float) $value == 0) { - return ' <' . (1 / 10 ** $digitsRight); + return ' <' . number_format((1 / 10 ** $digitsRight), $digitsRight, $decimalSep, $thousandsSep); } return $value; @@ -427,10 +425,6 @@ class Util 7 => 'Z', 8 => 'Y', ]; - /* l10n: Decimal separator */ - $decimalSep = __('.'); - /* l10n: Thousands separator */ - $thousandsSep = __(','); // check for negative value to retain sign if ($value < 0) { diff --git a/tests/unit/UtilTest.php b/tests/unit/UtilTest.php index 91175f47b3..aa91497de7 100644 --- a/tests/unit/UtilTest.php +++ b/tests/unit/UtilTest.php @@ -554,7 +554,6 @@ class UtilTest extends AbstractTestCase $a, $b, $c, - false, ), ); } @@ -573,7 +572,7 @@ class UtilTest extends AbstractTestCase $this->assertFormatNumber($a, $b, $c, $d); // Test with various precisions - $oldPrecision = (string) ini_get('precision'); + $oldPrecision = ini_get('precision'); try { ini_set('precision', '20'); $this->assertFormatNumber($a, $b, $c, $d); @@ -637,6 +636,23 @@ class UtilTest extends AbstractTestCase [123456789, 6, 0, '123,457 k'], [-123456789, 4, 2, '-123.46 M'], [0, 6, 0, '0'], + [0.000001, 0, 3, ' <0.001'], + [0.005, 3, 0, '5 m'], + [0.000005, 3, 0, '5 µ'], + [0.000000005, 3, 0, '5 n'], + [0.000000000005, 3, 0, '5 p'], + [0.000000000000005, 3, 0, '5 f'], + [0.000000000000000005, 3, 0, '5 a'], + [0.000000000000000000005, 3, 0, '5 z'], + [0.000000000000000000000005, 3, 0, '5 y'], + [5000, 3, 0, '5 k'], + [5000000, 3, 0, '5 M'], + [5000000000, 3, 0, '5 G'], + [5000000000000, 3, 0, '5 T'], + [5000000000000000, 3, 0, '5 P'], + [5000000000000000000, 3, 0, '5 E'], + [5000000000000000000000, 3, 0, '5 Z'], + [5000000000000000000000000, 3, 0, '5 Y'], ]; } From ba1743bdc03476f0313acce28646a542fa8b0467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Tue, 22 Jul 2025 19:26:54 -0300 Subject: [PATCH 2/3] Refactor UtilTest::testFormatNumber() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- psalm-baseline.xml | 1 - tests/unit/UtilTest.php | 144 ++++++++++++++++++---------------------- 2 files changed, 65 insertions(+), 80 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 8bd4c043b0..0758571314 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -11924,7 +11924,6 @@ - diff --git a/tests/unit/UtilTest.php b/tests/unit/UtilTest.php index aa91497de7..ab9f887326 100644 --- a/tests/unit/UtilTest.php +++ b/tests/unit/UtilTest.php @@ -538,52 +538,25 @@ class UtilTest extends AbstractTestCase ]; } - /** - * Core test for formatNumber - * - * @param float|int|string $a Value to format - * @param int $b Sensitiveness - * @param int $c Number of decimals to retain - * @param string $d Expected value - */ - private function assertFormatNumber(float|int|string $a, int $b, int $c, string $d): void - { - self::assertSame( - $d, - Util::formatNumber( - $a, - $b, - $c, - ), - ); - } - - /** - * format number test, globals are defined - * - * @param float|int|string $a Value to format - * @param int $b Sensitiveness - * @param int $c Number of decimals to retain - * @param string $d Expected value - */ + /** @psalm-param list{0: float|int|string, 1?: int, 2?: int, 3?: bool, 4?: bool} $arguments */ #[DataProvider('providerFormatNumber')] - public function testFormatNumber(float|int|string $a, int $b, int $c, string $d): void + public function testFormatNumber(string $expected, array $arguments): void { - $this->assertFormatNumber($a, $b, $c, $d); + self::assertSame($expected, Util::formatNumber(...$arguments)); // Test with various precisions $oldPrecision = ini_get('precision'); try { ini_set('precision', '20'); - $this->assertFormatNumber($a, $b, $c, $d); + self::assertSame($expected, Util::formatNumber(...$arguments)); ini_set('precision', '14'); - $this->assertFormatNumber($a, $b, $c, $d); + self::assertSame($expected, Util::formatNumber(...$arguments)); ini_set('precision', '10'); - $this->assertFormatNumber($a, $b, $c, $d); + self::assertSame($expected, Util::formatNumber(...$arguments)); ini_set('precision', '5'); - $this->assertFormatNumber($a, $b, $c, $d); + self::assertSame($expected, Util::formatNumber(...$arguments)); ini_set('precision', '-1'); - $this->assertFormatNumber($a, $b, $c, $d); + self::assertSame($expected, Util::formatNumber(...$arguments)); } finally { ini_set('precision', $oldPrecision); } @@ -592,17 +565,28 @@ class UtilTest extends AbstractTestCase $translator = Loader::getInstance()->getTranslator(); try { + $translator->setTranslation('.', '/'); + self::assertSame( + str_replace('.', '/', $expected), + Util::formatNumber(...$arguments), + 'Decimal separator should be escaped for regex.', + ); + // German $translator->setTranslation(',', '.'); $translator->setTranslation('.', ','); - $expected = str_replace([',', 'X'], ['.', ','], str_replace('.', 'X', $d)); - $this->assertFormatNumber($a, $b, $c, $expected); + self::assertSame( + str_replace([',', 'X'], ['.', ','], str_replace('.', 'X', $expected)), + Util::formatNumber(...$arguments), + ); // Czech $translator->setTranslation(',', ' '); $translator->setTranslation('.', ','); - $expected = str_replace([',', 'X'], [' ', ','], str_replace('.', 'X', $d)); - $this->assertFormatNumber($a, $b, $c, $expected); + self::assertSame( + str_replace([',', 'X'], [' ', ','], str_replace('.', 'X', $expected)), + Util::formatNumber(...$arguments), + ); } finally { // Restore $translator->setTranslation(',', ','); @@ -610,49 +594,51 @@ class UtilTest extends AbstractTestCase } } - /** - * format number data provider - * - * @return mixed[] - */ + /** @psalm-return array */ public static function providerFormatNumber(): array { return [ - [10, 2, 2, '10 '], - [100, 2, 0, '100 '], - [100, 2, 2, '100 '], - ['100', 2, 2, '100 '], - [-1000.454, 4, 2, '-1,000.45 '], - ['-1000.454', 4, 2, '-1,000.45 '], - [0.00003, 3, 2, '30 µ'], - [0.003, 3, 3, '3 m'], - [-0.003, 6, 0, '-3,000 µ'], - [100.98, 0, 2, '100.98'], - [21010101, 0, 2, '21,010,101.00'], - [1100000000, 5, 0, '1,100 M'], - ['1100000000', 5, 0, '1,100 M'], - [20000, 2, 2, '20 k'], - [20011, 2, 2, '20.01 k'], - [123456789, 6, 0, '123,457 k'], - [-123456789, 4, 2, '-123.46 M'], - [0, 6, 0, '0'], - [0.000001, 0, 3, ' <0.001'], - [0.005, 3, 0, '5 m'], - [0.000005, 3, 0, '5 µ'], - [0.000000005, 3, 0, '5 n'], - [0.000000000005, 3, 0, '5 p'], - [0.000000000000005, 3, 0, '5 f'], - [0.000000000000000005, 3, 0, '5 a'], - [0.000000000000000000005, 3, 0, '5 z'], - [0.000000000000000000000005, 3, 0, '5 y'], - [5000, 3, 0, '5 k'], - [5000000, 3, 0, '5 M'], - [5000000000, 3, 0, '5 G'], - [5000000000000, 3, 0, '5 T'], - [5000000000000000, 3, 0, '5 P'], - [5000000000000000000, 3, 0, '5 E'], - [5000000000000000000000, 3, 0, '5 Z'], - [5000000000000000000000000, 3, 0, '5 Y'], + ['10 ', [10, 2, 2]], + ['100 ', [100, 2, 0]], + ['100 ', [100, 2, 2]], + ['100 ', ['100', 2, 2]], + ['-1,000.45 ', [-1000.454, 4, 2]], + ['-1,000.45 ', ['-1000.454', 4, 2]], + ['30 µ', [0.00003, 3, 2]], + ['3 m', [0.003, 3, 3]], + ['-3,000 µ', [-0.003, 6, 0]], + ['100.98', [100.98, 0, 2]], + ['21,010,101.00', [21010101, 0, 2]], + ['1,100 M', [1100000000, 5, 0]], + ['1,100 M', ['1100000000', 5, 0]], + ['20 k', [20000, 2, 2]], + ['20.01 k', [20011, 2, 2]], + ['123,457 k', [123456789, 6, 0]], + ['-123.46 M', [-123456789, 4, 2]], + ['0', [0]], + ['0', [0.0]], + ['0', ['0']], + ['0', ['0.0']], + [' <0.001', [0.000001, 0, 3]], + ['5 m', [0.005]], + ['5 µ', [0.000005]], + ['5 n', [0.000000005]], + ['5 p', [0.000000000005]], + ['5 f', [0.000000000000005]], + ['5 a', [0.000000000000000005]], + ['5 z', [0.000000000000000000005]], + ['5 y', [0.000000000000000000000005]], + ['5 k', [5000]], + ['5 M', [5000000]], + ['5 G', [5000000000]], + ['5 T', [5000000000000]], + ['5 P', [5000000000000000]], + ['5 E', [5000000000000000000]], + ['5 Z', [5000000000000000000000]], + ['5 Y', [5000000000000000000000000]], + ['100 m', [0.1, 3, 0]], + [' <1 ', [0.1, 3, 0, true]], + ['1.000 k', [1000, 3, 3, false, false]], ]; } From 09e8144e97238f81decdf9ffbf9eb0718f1024a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 24 Jul 2025 10:41:36 -0300 Subject: [PATCH 3/3] Refactor Util::formatNumber() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trim whitespace and add more unit prefixes. Signed-off-by: Maurício Meneghini Fauth --- phpstan-baseline.neon | 26 ++++------ psalm-baseline.xml | 16 +++--- src/Util.php | 84 ++++++++++++++++--------------- tests/unit/Engines/InnodbTest.php | 2 +- tests/unit/UtilTest.php | 26 ++++++---- 5 files changed, 81 insertions(+), 73 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e2e5395f78..3519835579 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2884,7 +2884,13 @@ parameters: path: src/Controllers/Server/Status/StatusController.php - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|string, mixed given\.$#' + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, float\|int\|string given\.$#' + identifier: argument.type + count: 4 + path: src/Controllers/Server/Status/StatusController.php + + - + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' identifier: argument.type count: 5 path: src/Controllers/Server/Status/StatusController.php @@ -6058,7 +6064,7 @@ parameters: path: src/Engines/Innodb.php - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|string, mixed given\.$#' + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' identifier: argument.type count: 11 path: src/Engines/Innodb.php @@ -13888,7 +13894,7 @@ parameters: path: src/StorageEngine.php - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|string, mixed given\.$#' + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' identifier: argument.type count: 1 path: src/StorageEngine.php @@ -15012,18 +15018,6 @@ parameters: count: 1 path: src/Util.php - - - message: '#^Loose comparison via "\!\=" is not allowed\.$#' - identifier: notEqual.notAllowed - count: 2 - path: src/Util.php - - - - message: '#^Loose comparison via "\=\=" is not allowed\.$#' - identifier: equal.notAllowed - count: 3 - path: src/Util.php - - message: '#^Method PhpMyAdmin\\Util\:\:getDbInfo\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -16888,7 +16882,7 @@ parameters: path: tests/unit/Controllers/Server/Status/QueriesControllerTest.php - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|string, mixed given\.$#' + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' identifier: argument.type count: 1 path: tests/unit/Controllers/Server/Status/QueriesControllerTest.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 0758571314..e7c301345b 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1925,6 +1925,12 @@ + + data->status['Aborted_clients']]]> + data->status['Aborted_connects']]]> + data->status['Connections']]]> + data->status['Max_used_connections']]]> + data->status['Aborted_clients']]]> data->status['Aborted_clients']]]> @@ -9256,6 +9262,10 @@ + + + + @@ -9275,9 +9285,6 @@ - - - @@ -9296,12 +9303,9 @@ - - - diff --git a/src/Util.php b/src/Util.php index 01b19a9418..e577cc621a 100644 --- a/src/Util.php +++ b/src/Util.php @@ -47,6 +47,7 @@ use function is_object; use function is_scalar; use function is_string; use function log10; +use function max; use function mb_detect_encoding; use function mb_strlen; use function mb_strpos; @@ -365,11 +366,11 @@ class Util * echo formatNumber(0, 6); // 0 * * - * @param float|int|string $value the value to format - * @param int $digitsLeft number of digits left of the comma - * @param int $digitsRight number of digits right of the comma - * @param bool $onlyDown do not reformat numbers below 1 - * @param bool $noTrailingZero removes trailing zeros right of the comma (default: true) + * @param float|int|numeric-string $value the value to format + * @param int $digitsLeft number of digits left of the comma + * @param int $digitsRight number of digits right of the comma + * @param bool $onlyDown do not reformat numbers below 1 + * @param bool $noTrailingZero removes trailing zeros right of the comma (default: true) * * @return string the formatted value and its unit */ @@ -381,51 +382,26 @@ class Util bool $onlyDown = false, bool $noTrailingZero = true, ): string { - if ($value == 0) { + $value = (float) $value; + if ($value === 0.0) { return '0'; } - if (is_string($value)) { - $value = (float) $value; - } - /* l10n: Decimal separator */ $decimalSep = __('.'); /* l10n: Thousands separator */ $thousandsSep = __(','); - $originalValue = $value; //number_format is not multibyte safe, str_replace is safe if ($digitsLeft === 0) { - $value = number_format((float) $value, $digitsRight, $decimalSep, $thousandsSep); - if ($originalValue != 0 && (float) $value == 0) { - return ' <' . number_format((1 / 10 ** $digitsRight), $digitsRight, $decimalSep, $thousandsSep); + $value = number_format($value, $digitsRight, $decimalSep, $thousandsSep); + if ((float) $value === 0.0) { + return '<' . number_format((1 / 10 ** $digitsRight), $digitsRight, $decimalSep, $thousandsSep); } return $value; } - // this units needs no translation, ISO - $units = [ - -8 => 'y', - -7 => 'z', - -6 => 'a', - -5 => 'f', - -4 => 'p', - -3 => 'n', - -2 => 'µ', - -1 => 'm', - 0 => ' ', - 1 => 'k', - 2 => 'M', - 3 => 'G', - 4 => 'T', - 5 => 'P', - 6 => 'E', - 7 => 'Z', - 8 => 'Y', - ]; - // check for negative value to retain sign if ($value < 0) { $sign = '-'; @@ -437,9 +413,9 @@ class Util $dh = 10 ** $digitsRight; // This gives us the right SI prefix already, but $digits_left parameter not incorporated - $d = floor(log10((float) $value) / 3); + $d = floor(log10($value) / 3); // Lowering the SI prefix by 1 gives us an additional 3 zeros - // So if we have 3,6,9,12.. free digits ($digits_left - $cur_digits) to use, then lower the SI prefix + // So if we have 3,6,9,12... free digits ($digits_left - $cur_digits) to use, then lower the SI prefix $curDigits = floor(log10($value / 1000 ** $d) + 1); if ($digitsLeft > $curDigits) { $d -= floor(($digitsLeft - $curDigits) / 3); @@ -449,6 +425,32 @@ class Util $d = 0; } + // SI unit prefixes need no translation + $units = [ + -10 => 'q', // quecto + -9 => 'r', // ronto + -8 => 'y', // yocto + -7 => 'z', // zepto + -6 => 'a', // atto + -5 => 'f', // femto + -4 => 'p', // pico + -3 => 'n', // nano + -2 => 'µ', // micro + -1 => 'm', // milli + 0 => '', + 1 => 'k', // kilo + 2 => 'M', // mega + 3 => 'G', // giga + 4 => 'T', // tera + 5 => 'P', // peta + 6 => 'E', // exa + 7 => 'Z', // zetta + 8 => 'Y', // yotta + 9 => 'R', // ronna + 10 => 'Q', // quetta + ]; + + $d = min(max((int) $d, -10), 10); $value = round($value / (1000 ** $d / $dh)) / $dh; $unit = $units[$d]; @@ -459,11 +461,13 @@ class Util $formattedValue = preg_replace('/' . preg_quote($decimalSep, '/') . '?0+$/', '', $formattedValue); } - if ($originalValue != 0 && $value == 0) { - return ' <' . number_format(1 / 10 ** $digitsRight, $digitsRight, $decimalSep, $thousandsSep) . ' ' . $unit; + if ($value === 0.0) { + return '<' + . number_format(1 / 10 ** $digitsRight, $digitsRight, $decimalSep, $thousandsSep) + . ($unit === '' ? '' : ' ' . $unit); } - return $sign . $formattedValue . ' ' . $unit; + return $sign . $formattedValue . ($unit === '' ? '' : ' ' . $unit); } /** diff --git a/tests/unit/Engines/InnodbTest.php b/tests/unit/Engines/InnodbTest.php index b1a66c4bdd..a7a6b927a9 100644 --- a/tests/unit/Engines/InnodbTest.php +++ b/tests/unit/Engines/InnodbTest.php @@ -194,7 +194,7 @@ class InnodbTest extends AbstractTestCase ' ' . "\n" . ' ' . "\n" . ' Read misses in %' . "\n" . - ' 50 %' . "\n" . + ' 50 %' . "\n" . '' . "\n" . ' ' . "\n" . ' ' . "\n" . diff --git a/tests/unit/UtilTest.php b/tests/unit/UtilTest.php index ab9f887326..396f75e515 100644 --- a/tests/unit/UtilTest.php +++ b/tests/unit/UtilTest.php @@ -538,7 +538,7 @@ class UtilTest extends AbstractTestCase ]; } - /** @psalm-param list{0: float|int|string, 1?: int, 2?: int, 3?: bool, 4?: bool} $arguments */ + /** @psalm-param list{0: float|int|numeric-string, 1?: int, 2?: int, 3?: bool, 4?: bool} $arguments */ #[DataProvider('providerFormatNumber')] public function testFormatNumber(string $expected, array $arguments): void { @@ -594,16 +594,16 @@ class UtilTest extends AbstractTestCase } } - /** @psalm-return array */ + /** @psalm-return array */ public static function providerFormatNumber(): array { return [ - ['10 ', [10, 2, 2]], - ['100 ', [100, 2, 0]], - ['100 ', [100, 2, 2]], - ['100 ', ['100', 2, 2]], - ['-1,000.45 ', [-1000.454, 4, 2]], - ['-1,000.45 ', ['-1000.454', 4, 2]], + ['10', [10, 2, 2]], + ['100', [100, 2, 0]], + ['100', [100, 2, 2]], + ['100', ['100', 2, 2]], + ['-1,000.45', [-1000.454, 4, 2]], + ['-1,000.45', ['-1000.454', 4, 2]], ['30 µ', [0.00003, 3, 2]], ['3 m', [0.003, 3, 3]], ['-3,000 µ', [-0.003, 6, 0]], @@ -619,7 +619,7 @@ class UtilTest extends AbstractTestCase ['0', [0.0]], ['0', ['0']], ['0', ['0.0']], - [' <0.001', [0.000001, 0, 3]], + ['<0.001', [0.000001, 0, 3]], ['5 m', [0.005]], ['5 µ', [0.000005]], ['5 n', [0.000000005]], @@ -628,6 +628,9 @@ class UtilTest extends AbstractTestCase ['5 a', [0.000000000000000005]], ['5 z', [0.000000000000000000005]], ['5 y', [0.000000000000000000000005]], + ['5 r', [0.000000000000000000000000005]], + ['5 q', [0.000000000000000000000000000005]], + ['<1 q', [0.000000000000000000000000000000005]], ['5 k', [5000]], ['5 M', [5000000]], ['5 G', [5000000000]], @@ -636,8 +639,11 @@ class UtilTest extends AbstractTestCase ['5 E', [5000000000000000000]], ['5 Z', [5000000000000000000000]], ['5 Y', [5000000000000000000000000]], + ['5 R', [5000000000000000000000000000]], + ['5 Q', [5000000000000000000000000000000]], + ['5,000 Q', [5000000000000000000000000000000000]], ['100 m', [0.1, 3, 0]], - [' <1 ', [0.1, 3, 0, true]], + ['<1', [0.1, 3, 0, true]], ['1.000 k', [1000, 3, 3, false, false]], ]; }