Jeroen De Dauw has submitted this change and it was merged. Change subject: (bug #56686) Use exponent to represent sig digits ......................................................................
(bug #56686) Use exponent to represent sig digits Change-Id: Idf91f194dde9748a508ff47495c8b09c110f8a1d --- M DataValuesCommon/src/DataValues/DecimalMath.php M DataValuesCommon/src/DataValues/QuantityValue.php M DataValuesCommon/src/ValueFormatters/QuantityFormatter.php M DataValuesCommon/tests/DataValues/DecimalMathTest.php M DataValuesCommon/tests/DataValues/QuantityValueTest.php 5 files changed, 245 insertions(+), 120 deletions(-) Approvals: Jeroen De Dauw: Looks good to me, approved diff --git a/DataValuesCommon/src/DataValues/DecimalMath.php b/DataValuesCommon/src/DataValues/DecimalMath.php index 12780c6..345d979 100644 --- a/DataValuesCommon/src/DataValues/DecimalMath.php +++ b/DataValuesCommon/src/DataValues/DecimalMath.php @@ -47,23 +47,20 @@ /** * Returns the given value, with any insignificant digits removed or zeroed. + * * Rounding is applied using the "round half away from zero" rule (that is, +0.5 is * rounded to +1 and -0.5 is rounded to -1). * * @since 0.1 * - * @todo: change this (or provide an alternative) to work based on the exponent - * of the least significant digit, instead of its position. E.g. -1 would - * mean "the first digit after the decimal point", 0 would mean "the first - * digit before the decimal point", and so on. - * * @param DecimalValue $decimal - * @param int $significantDigits + * @param int $significantDigits The number of digits to retain, counting the decimal point, + * but not counting the leading sign. * * @throws \InvalidArgumentException * @return DecimalValue */ - public function round( DecimalValue $decimal, $significantDigits ) { + public function roundToDigit( DecimalValue $decimal, $significantDigits ) { $value = $decimal->getValue(); $rounded = $this->roundDigits( $value, $significantDigits ); return new DecimalValue( $rounded ); @@ -71,6 +68,63 @@ /** * Returns the given value, with any insignificant digits removed or zeroed. + * + * Rounding is applied using the "round half away from zero" rule (that is, +0.5 is + * rounded to +1 and -0.5 is rounded to -1). + * + * @since 0.1 + * + * @param DecimalValue $decimal + * @param int $significantExponent The exponent of the last significant digit, + * e.g. -1 for "keep the first digit after the decimal point", or 2 for + * "zero the last two digits before the decimal point". + * + * @throws \InvalidArgumentException + * @return DecimalValue + */ + public function roundToExponent( DecimalValue $decimal, $significantExponent ) { + //NOTE: the number of digits to keep (without the leading sign) + // is the same as the exponent's offset (with the leaqding sign). + $digits = $this->getPositionForExponent( $significantExponent, $decimal ); + return $this->roundToDigit( $decimal, $digits ); + } + + /** + * Returns the (zero based) position for the given exponent in + * the given decimal string, counting the decimal point and the leading sign. + * + * @example: the position of exponent 0 in "+10.03" is 2. + * @example: the position of exponent 1 in "+210.03" is 2. + * @example: the position of exponent -2 in "+1.037" is 4. + * + * @param int $exponent + * @param string $decimal + */ + public function getPositionForExponent( $exponent, DecimalValue $decimal ) { + $decimal = $decimal->getValue(); + + $pointPos = strpos( $decimal, '.' ); + if ( $pointPos === false ) { + $pointPos = strlen( $decimal ); + } + + // account for leading sign + $pointPos--; + + if ( $exponent < 0 ) { + // account for decimal point + $position = $pointPos +1 - $exponent; + } else { + // make sure we don't remove more digits than are there + $position = max( 0, $pointPos - $exponent ); + } + + return $position; + } + + /** + * Returns the given value, with any insignificant digits removed or zeroed. + * * Rounding is applied using the "round half away from zero" rule (that is, +0.5 is * rounded to +1 and -0.5 is rounded to -1). * @@ -79,7 +133,7 @@ * @param string $value * @param int $significantDigits * - * @throws \InvalidArgumentException + * @throws \InvalidArgumentException if $significantDigits is smaller than 0 * @return string */ protected function roundDigits( $value, $significantDigits ) { @@ -87,7 +141,12 @@ throw new \InvalidArgumentException( '$significantDigits must be an integer' ); } - if ( $significantDigits <= 0 ) { + // keeping no digits results in zero. + if ( $significantDigits === 0 ) { + return '+0'; + } + + if ( $significantDigits < 0 ) { throw new \InvalidArgumentException( '$significantDigits must be larger than zero.' ); } diff --git a/DataValuesCommon/src/DataValues/QuantityValue.php b/DataValuesCommon/src/DataValues/QuantityValue.php index f6551d6..ffc460c 100644 --- a/DataValuesCommon/src/DataValues/QuantityValue.php +++ b/DataValuesCommon/src/DataValues/QuantityValue.php @@ -305,105 +305,66 @@ } /** - * Returns the number of significant digits in the amount-string, - * counting the decimal point, but not counting the leading sign. + * Returns the order of magnitude of the uncertainty as the exponent of + * last significant digit in the amount-string. The value returned by this + * is suitable for use with @see DecimalMath::roundToExponent(). * - * Note that this calculation assumes a symmetric uncertainty interval, and can be misleading + * @example: if two digits after the decimal point are significant, this + * returns -2. + * + * @example: if the last two digits before the decimal point are insignificant, + * this returns 2. + * + * Note that this calculation assumes a symmetric uncertainty interval, + * and can be misleading. * * @since 0.1 * - * @todo: implement getSignificantExponent, which can be interpreted without knowing the - * length of the integral and fractional parts of the number. - * * @return int */ - public function getSignificantDigits() { + public function getOrderOfUncertainty() { // the desired precision is given by the distance between the amount and - // whatever is close, the uppoer or lower bound. - //TODO: use bcmath if available + // whatever is closer, the upper or lower bound. + //TODO: use DecimalMath to avoid floating point errors! $amount = $this->getAmount()->getValueFloat(); $upperBound = $this->getUpperBound()->getValueFloat(); $lowerBound = $this->getLowerBound()->getValueFloat(); $precision = min( $amount - $lowerBound, $upperBound - $amount ); if ( $precision === 0.0 ) { - // include the decimal point, but not the sign - $significantDigits = strlen( $this->amount->getValue() ) -1; - return $significantDigits; + // If there is no uncertainty, the order of uncertainty is a bit more than what we have digits for. + return -strlen( $this->amount->getFractionalPart() ); } // e.g. +/- 200 -> 2; +/- 0.02 -> -2 - // note: we really want floor( $orderOfPrecision ), but have to account for - // small errors made in the floating point operations above - $orderOfPrecision = floor( log10( $precision + 0.0000000005 ) ); + // note: we really want floor( log10( $precision ) ), but have to account for + // small errors made in the floating point operations above. + // @todo: use bcmath (via DecimalMath) to avoid this if possible + $orderOfUncertainty = floor( log10( $precision + 0.0000000005 ) ); - // the length of the integer part is the reference point - $significantDigits = strlen( $this->amount->getIntegerPart() ); - - if ( $orderOfPrecision >= 0 ) { - // e.g. 3000 +/- 100 -> 2 digits - $significantDigits -= (int)$orderOfPrecision; - } else { - // e.g. 56.78 +/- 0.01 -> 5 digits - $significantDigits += (int)(-$orderOfPrecision); - $significantDigits += 1; // for the '.' - } - - // assert sane value - if ( $significantDigits <= 0 ) { - throw new LogicException( 'Invalid calculation of significant digits' ); - } - - return $significantDigits; + return (int)$orderOfUncertainty; } /** - * Returns the number of significant digits of the given value in the context - * of this quantity's amount. This can be used to determine the appropriate - * rounding for auxiliary values associated with this quantity, such as the - * uncertainty margin or the upper and lower bounds. + * Returns the number of significant figures in the amount-string, + * counting the decimal point, but not counting the leading sign. * - * @example: if the amount is 1200, with 2 significant digits and a margin - * of +/-222, this method would return 1 for the significant digits - * of the value "222", causing it to be rounded to "200". + * Note that this calculation assumes a symmetric uncertainty interval, and can be misleading * - * @example: if the amount is 2.375, with 4 significant digits (counting the - * decimal point) and a margin of +/-0.036, this method would return 4 for - * the significant digits of the value "0.036", causing it to be rounded to "0.04". - * - * @param DecimalValue $value + * @since 0.1 * * @return int */ - public function getSignificantDigitsOf( DecimalValue $value ) { - $signDigits = $this->getSignificantDigits(); + public function getSignificantFigures() { + $math = new DecimalMath(); - // difference in the length of the integer part, to be subtracted - // (even if negative) - $intDigitDifference = - strlen( $this->amount->getIntegerPart() ) - - strlen( $value->getIntegerPart() ); + // $orderOfUncertainty is +/- 200 -> 2; +/- 0.02 -> -2 + $orderOfUncertainty = $this->getOrderOfUncertainty(); - // get the length of the fractional parts, accounting for any decimal point - $amountFractLength = strlen( $this->amount->getFractionalPart() ); - $valueFractLength = strlen( $value->getFractionalPart() ); + // the number of digits (without the sign) is the same as the position (with the sign). + $significantDigits = $math->getPositionForExponent( $orderOfUncertainty, $this->amount ); - if ( $amountFractLength > 0 ) { - $amountFractLength++; - } - - if ( $valueFractLength > 0 ) { - $valueFractLength++; - } - - // difference in the length of the factional part, to be subtracted - // if greater than 0. - $fractDigitDifference = max( 0, $amountFractLength - $valueFractLength ); - - // subtract the length differences, to apply rounding at the same order of magnitude - // as for the amount. - $signDigits = max( 1, $signDigits - $intDigitDifference - $fractDigitDifference ); - return $signDigits; + return $significantDigits; } /** @@ -481,15 +442,14 @@ // use a preliminary QuantityValue to determine the significant number of digits $transformed = new QuantityValue( $amount, $newUnit, $upperBound, $lowerBound ); - $digits = $transformed->getSignificantDigits(); + $roundingExponent = $transformed->getOrderOfUncertainty(); // apply rounding to the significant digits - $math = new DecimalMath( ); //TODO: Perhaps transform() should go into a QuantityTransformer class. + $math = new DecimalMath(); - //TODO: rounding should be done based on an exponent (needs getSignificantExponent). - $amount = $math->round( $amount, $digits ); - $upperBound = $math->round( $upperBound, $digits ); - $lowerBound = $math->round( $lowerBound, $digits ); + $amount = $math->roundToExponent( $amount, $roundingExponent ); + $upperBound = $math->roundToExponent( $upperBound, $roundingExponent ); + $lowerBound = $math->roundToExponent( $lowerBound, $roundingExponent ); return new QuantityValue( $amount, $newUnit, $upperBound, $lowerBound ); } diff --git a/DataValuesCommon/src/ValueFormatters/QuantityFormatter.php b/DataValuesCommon/src/ValueFormatters/QuantityFormatter.php index 879c26e..9de12cc 100644 --- a/DataValuesCommon/src/ValueFormatters/QuantityFormatter.php +++ b/DataValuesCommon/src/ValueFormatters/QuantityFormatter.php @@ -57,10 +57,10 @@ throw new InvalidArgumentException( 'DataValue is not a QuantityValue.' ); } - $digits = $dataValue->getSignificantDigits(); + $roundingExponent = $dataValue->getOrderOfUncertainty(); $amountValue = $dataValue->getAmount(); - $amountValue = $this->decimalMath->round( $amountValue, $digits ); + $amountValue = $this->decimalMath->roundToExponent( $amountValue, $roundingExponent ); $amount = $this->decimalFormatter->format( $amountValue ); $unit = $dataValue->getUnit(); @@ -71,8 +71,7 @@ || $this->options->getOption( self::OPT_SHOW_UNCERTAINTY_MARGIN ) == true ) { $marginValue = $dataValue->getUncertaintyMargin(); - $marginDigits = $dataValue->getSignificantDigitsOf( $marginValue ); - $marginValue = $this->decimalMath->round( $marginValue, $marginDigits ); + $marginValue = $this->decimalMath->roundToExponent( $marginValue, $roundingExponent ); if ( !$marginValue->isZero() ) { $margin = $this->decimalFormatter->format( $marginValue ); diff --git a/DataValuesCommon/tests/DataValues/DecimalMathTest.php b/DataValuesCommon/tests/DataValues/DecimalMathTest.php index 4156b93..fc0883c 100644 --- a/DataValuesCommon/tests/DataValues/DecimalMathTest.php +++ b/DataValuesCommon/tests/DataValues/DecimalMathTest.php @@ -154,21 +154,23 @@ } /** - * @dataProvider roundProvider + * @dataProvider roundToDigitProvider * * @since 0.1 */ - public function testRound( DecimalValue $value, $digits, $expected ) { + public function testRoundToDigit( DecimalValue $value, $digits, $expected ) { $math = new DecimalMath(); - $actual = $math->round( $value, $digits ); + $actual = $math->roundToDigit( $value, $digits ); $this->assertSame( $expected, $actual->getValue() ); } - public function roundProvider() { + public function roundToDigitProvider() { $argLists = array(); //NOTE: Rounding is applied using the "round half away from zero" logic. + + $argLists[] = array( new DecimalValue( '-2' ), 0, '+0' ); // no digits left $argLists[] = array( new DecimalValue( '+0' ), 1, '+0' ); $argLists[] = array( new DecimalValue( '+0' ), 2, '+0' ); @@ -227,4 +229,100 @@ return $argLists; } + + /** + * @dataProvider getPositionForExponentProvider + * + * @since 0.1 + */ + public function testGetPositionForExponent( $exponent, DecimalValue $decimal, $expected ) { + $math = new DecimalMath(); + + $actual = $math->getPositionForExponent( $exponent, $decimal ); + $this->assertSame( $expected, $actual ); + } + + public function getPositionForExponentProvider() { + $argLists = array(); + + $argLists[] = array( 0, new DecimalValue( '+0' ), 1 ); + $argLists[] = array( 1, new DecimalValue( '+10.25' ), 1 ); + $argLists[] = array( 1, new DecimalValue( '-100.25' ), 2 ); + $argLists[] = array( 2, new DecimalValue( '+100.25' ), 1 ); + $argLists[] = array( -2, new DecimalValue( '+0.234' ), 4 ); + $argLists[] = array( -2, new DecimalValue( '+11.234' ), 5 ); + + return $argLists; + } + /** + * @dataProvider roundToExponentProvider + * + * @since 0.1 + */ + public function testRoundToExponent( DecimalValue $value, $digits, $expected ) { + $math = new DecimalMath(); + + $actual = $math->roundToExponent( $value, $digits ); + $this->assertSame( $expected, $actual->getValue() ); + } + + public function roundToExponentProvider() { + $argLists = array(); + + //NOTE: Rounding is applied using the "round half away from zero" logic. + + $argLists[] = array( new DecimalValue( '+0' ), 0, '+0' ); + $argLists[] = array( new DecimalValue( '+0' ), 1, '+0' ); + $argLists[] = array( new DecimalValue( '+0.0' ), 0, '+0' ); + $argLists[] = array( new DecimalValue( '+0.0' ), 2, '+0' ); + $argLists[] = array( new DecimalValue( '+0.0' ), -5, '+0.0' ); + + $argLists[] = array( new DecimalValue( '-2' ), 0, '-2' ); + $argLists[] = array( new DecimalValue( '-2' ), -1, '-2' ); + $argLists[] = array( new DecimalValue( '-2' ), 1, '+0' ); + + $argLists[] = array( new DecimalValue( '+23' ), 0, '+23' ); + $argLists[] = array( new DecimalValue( '+23' ), 1, '+20' ); + $argLists[] = array( new DecimalValue( '+23' ), 2, '+0' ); + + $argLists[] = array( new DecimalValue( '-234' ), 2, '-200' ); + $argLists[] = array( new DecimalValue( '-234' ), 1, '-230' ); + $argLists[] = array( new DecimalValue( '-234' ), 0, '-234' ); + + $argLists[] = array( new DecimalValue( '-2.0' ), 0, '-2' ); + $argLists[] = array( new DecimalValue( '-2.0' ), -1, '-2.0' ); + $argLists[] = array( new DecimalValue( '-2.0' ), -2, '-2.0' ); // edge case, may change + + $argLists[] = array( new DecimalValue( '-2.000' ), 0, '-2' ); + $argLists[] = array( new DecimalValue( '-2.000' ), -1, '-2.0' ); + $argLists[] = array( new DecimalValue( '-2.000' ), -2, '-2.00' ); + + $argLists[] = array( new DecimalValue( '+2.5' ), 0, '+3' ); // rounded up + $argLists[] = array( new DecimalValue( '+2.5' ), -1, '+2.5' ); + $argLists[] = array( new DecimalValue( '+2.5' ), -2, '+2.5' ); + + $argLists[] = array( new DecimalValue( '+2.05' ), 0, '+2' ); + $argLists[] = array( new DecimalValue( '+2.05' ), -1, '+2.1' ); // rounded up + $argLists[] = array( new DecimalValue( '+2.05' ), -2, '+2.05' ); + + $argLists[] = array( new DecimalValue( '-23.05' ), 1, '-20' ); + $argLists[] = array( new DecimalValue( '-23.05' ), 0, '-23' ); + + $argLists[] = array( new DecimalValue( '-23.05' ), -1, '-23.1' ); // rounded down + $argLists[] = array( new DecimalValue( '-23.05' ), -2, '-23.05' ); + + $argLists[] = array( new DecimalValue( '+9.33' ), 0, '+9' ); // no rounding + $argLists[] = array( new DecimalValue( '+9.87' ), 0, '+10' ); // rounding ripples up + $argLists[] = array( new DecimalValue( '+9.87' ), -1, '+9.9' ); // rounding ripples up + $argLists[] = array( new DecimalValue( '+99' ), 1, '+100' ); // rounding ripples up + $argLists[] = array( new DecimalValue( '+99' ), 0, '+99' ); // rounding ripples up + + $argLists[] = array( new DecimalValue( '-9.33' ), 0, '-9' ); // no rounding + $argLists[] = array( new DecimalValue( '-9.87' ), 0, '-10' ); // rounding ripples down + $argLists[] = array( new DecimalValue( '-9.87' ), -1, '-9.9' ); // rounding ripples down + $argLists[] = array( new DecimalValue( '-99' ), 1, '-100' ); // rounding ripples down + $argLists[] = array( new DecimalValue( '-99' ), 0, '-99' ); // rounding ripples down + + return $argLists; + } } diff --git a/DataValuesCommon/tests/DataValues/QuantityValueTest.php b/DataValuesCommon/tests/DataValues/QuantityValueTest.php index bfe8f56..baa3096 100644 --- a/DataValuesCommon/tests/DataValues/QuantityValueTest.php +++ b/DataValuesCommon/tests/DataValues/QuantityValueTest.php @@ -203,15 +203,45 @@ /** - * @dataProvider getSignificantDigitsProvider + * @dataProvider getOrderOfUncertaintyProvider */ - public function testGetSignificantDigits( QuantityValue $quantity, $expected ) { - $actual = $quantity->getSignificantDigits(); + public function testGetOrderOfUncertainty( QuantityValue $quantity, $expected ) { + $actual = $quantity->getOrderOfUncertainty(); $this->assertEquals( $expected, $actual ); } - public function getSignificantDigitsProvider() { + public function getOrderOfUncertaintyProvider() { + return array( + 0 => array( QuantityValue::newFromNumber( '+0' ), 0 ), + 1 => array( QuantityValue::newFromNumber( '-123' ), 0 ), + 2 => array( QuantityValue::newFromNumber( '-1.23' ), -2 ), + + 10 => array( QuantityValue::newFromNumber( '-100', '1', '-99', '-101' ), 0 ), + 11 => array( QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ), -2 ), + 12 => array( QuantityValue::newFromNumber( '-117.3', '1', '-117.2', '-117.4' ), -1 ), + + 20 => array( QuantityValue::newFromNumber( '+100', '1', '+100.01', '+99.97' ), -2 ), + 21 => array( QuantityValue::newFromNumber( '-0.002', '1', '-0.001', '-0.004' ), -3 ), + 22 => array( QuantityValue::newFromNumber( '-0.002', '1', '+0.001', '-0.06' ), -3 ), + 23 => array( QuantityValue::newFromNumber( '-21', '1', '+1.1', '-120' ), 1 ), + 24 => array( QuantityValue::newFromNumber( '-2', '1', '+1.1', '-120' ), 0 ), + 25 => array( QuantityValue::newFromNumber( '+1000', '1', '+1100', '+900.03' ), 1 ), + 26 => array( QuantityValue::newFromNumber( '+1000', '1', '+1100', '+900' ), 2 ), + ); + } + + + /** + * @dataProvider getSignificantFiguresProvider + */ + public function testGetSignificantFigures( QuantityValue $quantity, $expected ) { + $actual = $quantity->getSignificantFigures(); + + $this->assertEquals( $expected, $actual ); + } + + public function getSignificantFiguresProvider() { return array( 0 => array( QuantityValue::newFromNumber( '+0' ), 1 ), 1 => array( QuantityValue::newFromNumber( '-123' ), 3 ), @@ -228,27 +258,6 @@ 24 => array( QuantityValue::newFromNumber( '-2', '1', '+1.1', '-120' ), 1 ), 25 => array( QuantityValue::newFromNumber( '+1000', '1', '+1100', '+900.03' ), 3 ), 26 => array( QuantityValue::newFromNumber( '+1000', '1', '+1100', '+900' ), 2 ), - ); - } - - /** - * @dataProvider getSignificantDigitsProviderOf - */ - public function testGetSignificantDigitsOf( QuantityValue $quantity, DecimalValue $value, $expected ) { - $actual = $quantity->getSignificantDigitsOf( $value ); - - $this->assertEquals( $expected, $actual ); - } - - public function getSignificantDigitsProviderOf() { - return array( - array( QuantityValue::newFromNumber( '+0' ), new DecimalValue( '+0' ), 1 ), - array( QuantityValue::newFromNumber( '-123', '1', '-123', '-123' ), new DecimalValue( '+10' ), 2 ), - array( QuantityValue::newFromNumber( '-123', '1', '-123', '-123' ), new DecimalValue( '+10.03' ), 2 ), - array( QuantityValue::newFromNumber( '+123', '1', '+143', '+103' ), new DecimalValue( '+13.44' ), 1 ), - array( QuantityValue::newFromNumber( '+12.31', '1', '+12.32', '+12.30' ), new DecimalValue( '+13.03' ), 5 ), - array( QuantityValue::newFromNumber( '+12.31', '1', '+12.32', '+12.30' ), new DecimalValue( '+13' ), 2 ), - array( QuantityValue::newFromNumber( '+12.31', '1', '+12.32', '+12.30' ), new DecimalValue( '+2213' ), 4 ), ); } @@ -287,7 +296,7 @@ 0 => array( QuantityValue::newFromNumber( '+10', '1', '+11', '+9' ), $identity, QuantityValue::newFromNumber( '+10', '?', '+11', '+9' ) ), 1 => array( QuantityValue::newFromNumber( '-0.5', '1', '-0.4', '-0.6' ), $identity, QuantityValue::newFromNumber( '-0.5', '?', '-0.4', '-0.6' ) ), 2 => array( QuantityValue::newFromNumber( '+0', '1', '+1', '-1' ), $square, QuantityValue::newFromNumber( '+0', '?', '+1', '-1' ) ), - 3 => array( QuantityValue::newFromNumber( '+10', '1', '+11', '+9' ), $square, QuantityValue::newFromNumber( '+1000', '?', '+1300', '+730' ) ), // note how rounding applies to bounds + 3 => array( QuantityValue::newFromNumber( '+10', '1', '+11', '+9' ), $square, QuantityValue::newFromNumber( '+1000', '?', '+1300', '+700' ) ), // note how rounding applies to bounds 4 => array( QuantityValue::newFromNumber( '+0.5', '1', '+0.6', '+0.4' ), $scale, QuantityValue::newFromNumber( '+0.25', '?', '+0.3', '+0.2' ), 0.5 ), // note: absolutely exact values require conversion with infinite precision! -- To view, visit https://gerrit.wikimedia.org/r/94385 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Idf91f194dde9748a508ff47495c8b09c110f8a1d Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/DataValues Gerrit-Branch: master Gerrit-Owner: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Addshore <addshorew...@gmail.com> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Henning Snater <henning.sna...@wikimedia.de> Gerrit-Reviewer: Jeroen De Dauw <jeroended...@gmail.com> Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits