diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:30:08 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:30:08 +0000 |
commit | 4ce65d59ca91871cfd126497158200a818720bce (patch) | |
tree | e277def01fc7eba7dbc21c4a4ae5576e8aa2cf1f /vendor | |
parent | Initial commit. (diff) | |
download | icinga-php-library-4ce65d59ca91871cfd126497158200a818720bce.tar.xz icinga-php-library-4ce65d59ca91871cfd126497158200a818720bce.zip |
Adding upstream version 0.13.1.upstream/0.13.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor')
721 files changed, 417820 insertions, 0 deletions
diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000..69318e2 --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,25 @@ +<?php + +// autoload.php @generated by Composer + +if (PHP_VERSION_ID < 50600) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, $err); + } elseif (!headers_sent()) { + echo $err; + } + } + trigger_error( + $err, + E_USER_ERROR + ); +} + +require_once __DIR__ . '/composer/autoload_real.php'; + +return ComposerAutoloaderInit35fbfdaec6c999686b0d3ca7c10db905::getLoader(); diff --git a/vendor/brick/math/LICENSE b/vendor/brick/math/LICENSE new file mode 100644 index 0000000..f9b724f --- /dev/null +++ b/vendor/brick/math/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-present Benjamin Morel + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/brick/math/composer.json b/vendor/brick/math/composer.json new file mode 100644 index 0000000..ec19663 --- /dev/null +++ b/vendor/brick/math/composer.json @@ -0,0 +1,35 @@ +{ + "name": "brick/math", + "description": "Arbitrary-precision arithmetic library", + "type": "library", + "keywords": [ + "Brick", + "Math", + "Arbitrary-precision", + "Arithmetic", + "BigInteger", + "BigDecimal", + "BigRational", + "Bignum" + ], + "license": "MIT", + "require": { + "php": "^7.1 || ^8.0", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "php-coveralls/php-coveralls": "^2.2", + "vimeo/psalm": "4.9.2" + }, + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Brick\\Math\\Tests\\": "tests/" + } + } +} diff --git a/vendor/brick/math/src/BigDecimal.php b/vendor/brick/math/src/BigDecimal.php new file mode 100644 index 0000000..7824650 --- /dev/null +++ b/vendor/brick/math/src/BigDecimal.php @@ -0,0 +1,895 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math; + +use Brick\Math\Exception\DivisionByZeroException; +use Brick\Math\Exception\MathException; +use Brick\Math\Exception\NegativeNumberException; +use Brick\Math\Internal\Calculator; + +/** + * Immutable, arbitrary-precision signed decimal numbers. + * + * @psalm-immutable + */ +final class BigDecimal extends BigNumber +{ + /** + * The unscaled value of this decimal number. + * + * This is a string of digits with an optional leading minus sign. + * No leading zero must be present. + * No leading minus sign must be present if the value is 0. + * + * @var string + */ + private $value; + + /** + * The scale (number of digits after the decimal point) of this decimal number. + * + * This must be zero or more. + * + * @var int + */ + private $scale; + + /** + * Protected constructor. Use a factory method to obtain an instance. + * + * @param string $value The unscaled value, validated. + * @param int $scale The scale, validated. + */ + protected function __construct(string $value, int $scale = 0) + { + $this->value = $value; + $this->scale = $scale; + } + + /** + * Creates a BigDecimal of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigDecimal + * + * @throws MathException If the value cannot be converted to a BigDecimal. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigDecimal(); + } + + /** + * Creates a BigDecimal from an unscaled value and a scale. + * + * Example: `(12345, 3)` will result in the BigDecimal `12.345`. + * + * @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger. + * @param int $scale The scale of the number, positive or zero. + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale is negative. + * + * @psalm-pure + */ + public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal + { + if ($scale < 0) { + throw new \InvalidArgumentException('The scale cannot be negative.'); + } + + return new BigDecimal((string) BigInteger::of($value), $scale); + } + + /** + * Returns a BigDecimal representing zero, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function zero() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigDecimal('0'); + } + + return $zero; + } + + /** + * Returns a BigDecimal representing one, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function one() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $one + */ + static $one; + + if ($one === null) { + $one = new BigDecimal('1'); + } + + return $one; + } + + /** + * Returns a BigDecimal representing ten, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function ten() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigDecimal('10'); + } + + return $ten; + } + + /** + * Returns the sum of this number and the given one. + * + * The result has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. + */ + public function plus($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0' && $that->scale <= $this->scale) { + return $this; + } + + if ($this->value === '0' && $this->scale <= $that->scale) { + return $that; + } + + [$a, $b] = $this->scaleValues($this, $that); + + $value = Calculator::get()->add($a, $b); + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the difference of this number and the given one. + * + * The result has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. + */ + public function minus($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0' && $that->scale <= $this->scale) { + return $this; + } + + [$a, $b] = $this->scaleValues($this, $that); + + $value = Calculator::get()->sub($a, $b); + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the product of this number and the given one. + * + * The result has a scale of `$this->scale + $that->scale`. + * + * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal. + */ + public function multipliedBy($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '1' && $that->scale === 0) { + return $this; + } + + if ($this->value === '1' && $this->scale === 0) { + return $that; + } + + $value = Calculator::get()->mul($this->value, $that->value); + $scale = $this->scale + $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the result of the division of this number by the given one, at the given scale. + * + * @param BigNumber|int|float|string $that The divisor. + * @param int|null $scale The desired scale, or null to use the scale of this number. + * @param int $roundingMode An optional rounding mode. + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale or rounding mode is invalid. + * @throws MathException If the number is invalid, is zero, or rounding was necessary. + */ + public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + if ($scale === null) { + $scale = $this->scale; + } elseif ($scale < 0) { + throw new \InvalidArgumentException('Scale cannot be negative.'); + } + + if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) { + return $this; + } + + $p = $this->valueWithMinScale($that->scale + $scale); + $q = $that->valueWithMinScale($this->scale - $scale); + + $result = Calculator::get()->divRound($p, $q, $roundingMode); + + return new BigDecimal($result, $scale); + } + + /** + * Returns the exact result of the division of this number by the given one. + * + * The scale of the result is automatically calculated to fit all the fraction digits. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero, + * or the result yields an infinite number of digits. + */ + public function exactlyDividedBy($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + [, $b] = $this->scaleValues($this, $that); + + $d = \rtrim($b, '0'); + $scale = \strlen($b) - \strlen($d); + + $calculator = Calculator::get(); + + foreach ([5, 2] as $prime) { + for (;;) { + $lastDigit = (int) $d[-1]; + + if ($lastDigit % $prime !== 0) { + break; + } + + $d = $calculator->divQ($d, (string) $prime); + $scale++; + } + } + + return $this->dividedBy($that, $scale)->stripTrailingZeros(); + } + + /** + * Returns this number exponentiated to the given value. + * + * The result has a scale of `$this->scale * $exponent`. + * + * @param int $exponent The exponent. + * + * @return BigDecimal The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigDecimal + { + if ($exponent === 0) { + return BigDecimal::one(); + } + + if ($exponent === 1) { + return $this; + } + + if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { + throw new \InvalidArgumentException(\sprintf( + 'The exponent %d is not in the range 0 to %d.', + $exponent, + Calculator::MAX_POWER + )); + } + + return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent); + } + + /** + * Returns the quotient of the division of this number by this given one. + * + * The quotient has a scale of `0`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The quotient. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function quotient($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + $quotient = Calculator::get()->divQ($p, $q); + + return new BigDecimal($quotient, 0); + } + + /** + * Returns the remainder of the division of this number by this given one. + * + * The remainder has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The remainder. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function remainder($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + $remainder = Calculator::get()->divR($p, $q); + + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($remainder, $scale); + } + + /** + * Returns the quotient and remainder of the division of this number by the given one. + * + * The quotient has a scale of `0`, and the remainder has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal[] An array containing the quotient and the remainder. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function quotientAndRemainder($that) : array + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + [$quotient, $remainder] = Calculator::get()->divQR($p, $q); + + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + $quotient = new BigDecimal($quotient, 0); + $remainder = new BigDecimal($remainder, $scale); + + return [$quotient, $remainder]; + } + + /** + * Returns the square root of this number, rounded down to the given number of decimals. + * + * @param int $scale + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale is negative. + * @throws NegativeNumberException If this number is negative. + */ + public function sqrt(int $scale) : BigDecimal + { + if ($scale < 0) { + throw new \InvalidArgumentException('Scale cannot be negative.'); + } + + if ($this->value === '0') { + return new BigDecimal('0', $scale); + } + + if ($this->value[0] === '-') { + throw new NegativeNumberException('Cannot calculate the square root of a negative number.'); + } + + $value = $this->value; + $addDigits = 2 * $scale - $this->scale; + + if ($addDigits > 0) { + // add zeros + $value .= \str_repeat('0', $addDigits); + } elseif ($addDigits < 0) { + // trim digits + if (-$addDigits >= \strlen($this->value)) { + // requesting a scale too low, will always yield a zero result + return new BigDecimal('0', $scale); + } + + $value = \substr($value, 0, $addDigits); + } + + $value = Calculator::get()->sqrt($value); + + return new BigDecimal($value, $scale); + } + + /** + * Returns a copy of this BigDecimal with the decimal point moved $n places to the left. + * + * @param int $n + * + * @return BigDecimal + */ + public function withPointMovedLeft(int $n) : BigDecimal + { + if ($n === 0) { + return $this; + } + + if ($n < 0) { + return $this->withPointMovedRight(-$n); + } + + return new BigDecimal($this->value, $this->scale + $n); + } + + /** + * Returns a copy of this BigDecimal with the decimal point moved $n places to the right. + * + * @param int $n + * + * @return BigDecimal + */ + public function withPointMovedRight(int $n) : BigDecimal + { + if ($n === 0) { + return $this; + } + + if ($n < 0) { + return $this->withPointMovedLeft(-$n); + } + + $value = $this->value; + $scale = $this->scale - $n; + + if ($scale < 0) { + if ($value !== '0') { + $value .= \str_repeat('0', -$scale); + } + $scale = 0; + } + + return new BigDecimal($value, $scale); + } + + /** + * Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part. + * + * @return BigDecimal + */ + public function stripTrailingZeros() : BigDecimal + { + if ($this->scale === 0) { + return $this; + } + + $trimmedValue = \rtrim($this->value, '0'); + + if ($trimmedValue === '') { + return BigDecimal::zero(); + } + + $trimmableZeros = \strlen($this->value) - \strlen($trimmedValue); + + if ($trimmableZeros === 0) { + return $this; + } + + if ($trimmableZeros > $this->scale) { + $trimmableZeros = $this->scale; + } + + $value = \substr($this->value, 0, -$trimmableZeros); + $scale = $this->scale - $trimmableZeros; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the absolute value of this number. + * + * @return BigDecimal + */ + public function abs() : BigDecimal + { + return $this->isNegative() ? $this->negated() : $this; + } + + /** + * Returns the negated value of this number. + * + * @return BigDecimal + */ + public function negated() : BigDecimal + { + return new BigDecimal(Calculator::get()->neg($this->value), $this->scale); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + $that = BigNumber::of($that); + + if ($that instanceof BigInteger) { + $that = $that->toBigDecimal(); + } + + if ($that instanceof BigDecimal) { + [$a, $b] = $this->scaleValues($this, $that); + + return Calculator::get()->cmp($a, $b); + } + + return - $that->compareTo($this); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); + } + + /** + * @return BigInteger + */ + public function getUnscaledValue() : BigInteger + { + return BigInteger::create($this->value); + } + + /** + * @return int + */ + public function getScale() : int + { + return $this->scale; + } + + /** + * Returns a string representing the integral part of this decimal number. + * + * Example: `-123.456` => `-123`. + * + * @return string + */ + public function getIntegralPart() : string + { + if ($this->scale === 0) { + return $this->value; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, 0, -$this->scale); + } + + /** + * Returns a string representing the fractional part of this decimal number. + * + * If the scale is zero, an empty string is returned. + * + * Examples: `-123.456` => '456', `123` => ''. + * + * @return string + */ + public function getFractionalPart() : string + { + if ($this->scale === 0) { + return ''; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, -$this->scale); + } + + /** + * Returns whether this decimal number has a non-zero fractional part. + * + * @return bool + */ + public function hasNonZeroFractionalPart() : bool + { + return $this->getFractionalPart() !== \str_repeat('0', $this->scale); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + $zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0); + + return BigInteger::create($zeroScaleDecimal->value); + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + $numerator = BigInteger::create($this->value); + $denominator = BigInteger::create('1' . \str_repeat('0', $this->scale)); + + return BigRational::create($numerator, $denominator, false); + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + if ($scale === $this->scale) { + return $this; + } + + return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + return $this->toBigInteger()->toInt(); + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return (float) (string) $this; + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + if ($this->scale === 0) { + return $this->value; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->scale); + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{value: string, scale: int} + */ + public function __serialize(): array + { + return ['value' => $this->value, 'scale' => $this->scale]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{value: string, scale: int} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->value)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $data['value']; + $this->scale = $data['scale']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->value . ':' . $this->scale; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->value)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + [$value, $scale] = \explode(':', $value); + + $this->value = $value; + $this->scale = (int) $scale; + } + + /** + * Puts the internal values of the given decimal numbers on the same scale. + * + * @param BigDecimal $x The first decimal number. + * @param BigDecimal $y The second decimal number. + * + * @return array{string, string} The scaled integer values of $x and $y. + */ + private function scaleValues(BigDecimal $x, BigDecimal $y) : array + { + $a = $x->value; + $b = $y->value; + + if ($b !== '0' && $x->scale > $y->scale) { + $b .= \str_repeat('0', $x->scale - $y->scale); + } elseif ($a !== '0' && $x->scale < $y->scale) { + $a .= \str_repeat('0', $y->scale - $x->scale); + } + + return [$a, $b]; + } + + /** + * @param int $scale + * + * @return string + */ + private function valueWithMinScale(int $scale) : string + { + $value = $this->value; + + if ($this->value !== '0' && $scale > $this->scale) { + $value .= \str_repeat('0', $scale - $this->scale); + } + + return $value; + } + + /** + * Adds leading zeros if necessary to the unscaled value to represent the full decimal number. + * + * @return string + */ + private function getUnscaledValueWithLeadingZeros() : string + { + $value = $this->value; + $targetLength = $this->scale + 1; + $negative = ($value[0] === '-'); + $length = \strlen($value); + + if ($negative) { + $length--; + } + + if ($length >= $targetLength) { + return $this->value; + } + + if ($negative) { + $value = \substr($value, 1); + } + + $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT); + + if ($negative) { + $value = '-' . $value; + } + + return $value; + } +} diff --git a/vendor/brick/math/src/BigInteger.php b/vendor/brick/math/src/BigInteger.php new file mode 100644 index 0000000..f213fbe --- /dev/null +++ b/vendor/brick/math/src/BigInteger.php @@ -0,0 +1,1184 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math; + +use Brick\Math\Exception\DivisionByZeroException; +use Brick\Math\Exception\IntegerOverflowException; +use Brick\Math\Exception\MathException; +use Brick\Math\Exception\NegativeNumberException; +use Brick\Math\Exception\NumberFormatException; +use Brick\Math\Internal\Calculator; + +/** + * An arbitrary-size integer. + * + * All methods accepting a number as a parameter accept either a BigInteger instance, + * an integer, or a string representing an arbitrary size integer. + * + * @psalm-immutable + */ +final class BigInteger extends BigNumber +{ + /** + * The value, as a string of digits with optional leading minus sign. + * + * No leading zeros must be present. + * No leading minus sign must be present if the number is zero. + * + * @var string + */ + private $value; + + /** + * Protected constructor. Use a factory method to obtain an instance. + * + * @param string $value A string of digits, with optional leading minus sign. + */ + protected function __construct(string $value) + { + $this->value = $value; + } + + /** + * Creates a BigInteger of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigInteger + * + * @throws MathException If the value cannot be converted to a BigInteger. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigInteger(); + } + + /** + * Creates a number from a string in a given base. + * + * The string can optionally be prefixed with the `+` or `-` sign. + * + * Bases greater than 36 are not supported by this method, as there is no clear consensus on which of the lowercase + * or uppercase characters should come first. Instead, this method accepts any base up to 36, and does not + * differentiate lowercase and uppercase characters, which are considered equal. + * + * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method. + * + * @param string $number The number to convert, in the given base. + * @param int $base The base of the number, between 2 and 36. + * + * @return BigInteger + * + * @throws NumberFormatException If the number is empty, or contains invalid chars for the given base. + * @throws \InvalidArgumentException If the base is out of range. + * + * @psalm-pure + */ + public static function fromBase(string $number, int $base) : BigInteger + { + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + if ($base < 2 || $base > 36) { + throw new \InvalidArgumentException(\sprintf('Base %d is not in range 2 to 36.', $base)); + } + + if ($number[0] === '-') { + $sign = '-'; + $number = \substr($number, 1); + } elseif ($number[0] === '+') { + $sign = ''; + $number = \substr($number, 1); + } else { + $sign = ''; + } + + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + $number = \ltrim($number, '0'); + + if ($number === '') { + // The result will be the same in any base, avoid further calculation. + return BigInteger::zero(); + } + + if ($number === '1') { + // The result will be the same in any base, avoid further calculation. + return new BigInteger($sign . '1'); + } + + $pattern = '/[^' . \substr(Calculator::ALPHABET, 0, $base) . ']/'; + + if (\preg_match($pattern, \strtolower($number), $matches) === 1) { + throw new NumberFormatException(\sprintf('"%s" is not a valid character in base %d.', $matches[0], $base)); + } + + if ($base === 10) { + // The number is usable as is, avoid further calculation. + return new BigInteger($sign . $number); + } + + $result = Calculator::get()->fromBase($number, $base); + + return new BigInteger($sign . $result); + } + + /** + * Parses a string containing an integer in an arbitrary base, using a custom alphabet. + * + * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers. + * + * @param string $number The number to parse. + * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8. + * + * @return BigInteger + * + * @throws NumberFormatException If the given number is empty or contains invalid chars for the given alphabet. + * @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars. + * + * @psalm-pure + */ + public static function fromArbitraryBase(string $number, string $alphabet) : BigInteger + { + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + $base = \strlen($alphabet); + + if ($base < 2) { + throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.'); + } + + $pattern = '/[^' . \preg_quote($alphabet, '/') . ']/'; + + if (\preg_match($pattern, $number, $matches) === 1) { + throw NumberFormatException::charNotInAlphabet($matches[0]); + } + + $number = Calculator::get()->fromArbitraryBase($number, $alphabet, $base); + + return new BigInteger($number); + } + + /** + * Translates a string of bytes containing the binary representation of a BigInteger into a BigInteger. + * + * The input string is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element. + * + * If `$signed` is true, the input is assumed to be in two's-complement representation, and the leading bit is + * interpreted as a sign bit. If `$signed` is false, the input is interpreted as an unsigned number, and the + * resulting BigInteger will always be positive or zero. + * + * This method can be used to retrieve a number exported by `toBytes()`, as long as the `$signed` flags match. + * + * @param string $value The byte string. + * @param bool $signed Whether to interpret as a signed number in two's-complement representation with a leading + * sign bit. + * + * @return BigInteger + * + * @throws NumberFormatException If the string is empty. + */ + public static function fromBytes(string $value, bool $signed = true) : BigInteger + { + if ($value === '') { + throw new NumberFormatException('The byte string must not be empty.'); + } + + $twosComplement = false; + + if ($signed) { + $x = \ord($value[0]); + + if (($twosComplement = ($x >= 0x80))) { + $value = ~$value; + } + } + + $number = self::fromBase(\bin2hex($value), 16); + + if ($twosComplement) { + return $number->plus(1)->negated(); + } + + return $number; + } + + /** + * Generates a pseudo-random number in the range 0 to 2^numBits - 1. + * + * Using the default random bytes generator, this method is suitable for cryptographic use. + * + * @psalm-param callable(int): string $randomBytesGenerator + * + * @param int $numBits The number of bits. + * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, and returns a + * string of random bytes of the given length. Defaults to the + * `random_bytes()` function. + * + * @return BigInteger + * + * @throws \InvalidArgumentException If $numBits is negative. + */ + public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger + { + if ($numBits < 0) { + throw new \InvalidArgumentException('The number of bits cannot be negative.'); + } + + if ($numBits === 0) { + return BigInteger::zero(); + } + + if ($randomBytesGenerator === null) { + $randomBytesGenerator = 'random_bytes'; + } + + $byteLength = \intdiv($numBits - 1, 8) + 1; + + $extraBits = ($byteLength * 8 - $numBits); + $bitmask = \chr(0xFF >> $extraBits); + + $randomBytes = $randomBytesGenerator($byteLength); + $randomBytes[0] = $randomBytes[0] & $bitmask; + + return self::fromBytes($randomBytes, false); + } + + /** + * Generates a pseudo-random number between `$min` and `$max`. + * + * Using the default random bytes generator, this method is suitable for cryptographic use. + * + * @psalm-param (callable(int): string)|null $randomBytesGenerator + * + * @param BigNumber|int|float|string $min The lower bound. Must be convertible to a BigInteger. + * @param BigNumber|int|float|string $max The upper bound. Must be convertible to a BigInteger. + * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, + * and returns a string of random bytes of the given length. + * Defaults to the `random_bytes()` function. + * + * @return BigInteger + * + * @throws MathException If one of the parameters cannot be converted to a BigInteger, + * or `$min` is greater than `$max`. + */ + public static function randomRange($min, $max, ?callable $randomBytesGenerator = null) : BigInteger + { + $min = BigInteger::of($min); + $max = BigInteger::of($max); + + if ($min->isGreaterThan($max)) { + throw new MathException('$min cannot be greater than $max.'); + } + + if ($min->isEqualTo($max)) { + return $min; + } + + $diff = $max->minus($min); + $bitLength = $diff->getBitLength(); + + // try until the number is in range (50% to 100% chance of success) + do { + $randomNumber = self::randomBits($bitLength, $randomBytesGenerator); + } while ($randomNumber->isGreaterThan($diff)); + + return $randomNumber->plus($min); + } + + /** + * Returns a BigInteger representing zero. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function zero() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigInteger('0'); + } + + return $zero; + } + + /** + * Returns a BigInteger representing one. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function one() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $one + */ + static $one; + + if ($one === null) { + $one = new BigInteger('1'); + } + + return $one; + } + + /** + * Returns a BigInteger representing ten. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function ten() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigInteger('10'); + } + + return $ten; + } + + /** + * Returns the sum of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigInteger. + */ + public function plus($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + return $this; + } + + if ($this->value === '0') { + return $that; + } + + $value = Calculator::get()->add($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the difference of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigInteger. + */ + public function minus($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + return $this; + } + + $value = Calculator::get()->sub($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the product of this number and the given one. + * + * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger. + */ + public function multipliedBy($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($this->value === '1') { + return $that; + } + + $value = Calculator::get()->mul($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the result of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * @param int $roundingMode An optional rounding mode. + * + * @return BigInteger The result. + * + * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero, + * or RoundingMode::UNNECESSARY is used and the remainder is not zero. + */ + public function dividedBy($that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $result = Calculator::get()->divRound($this->value, $that->value, $roundingMode); + + return new BigInteger($result); + } + + /** + * Returns this number exponentiated to the given value. + * + * @param int $exponent The exponent. + * + * @return BigInteger The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigInteger + { + if ($exponent === 0) { + return BigInteger::one(); + } + + if ($exponent === 1) { + return $this; + } + + if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { + throw new \InvalidArgumentException(\sprintf( + 'The exponent %d is not in the range 0 to %d.', + $exponent, + Calculator::MAX_POWER + )); + } + + return new BigInteger(Calculator::get()->pow($this->value, $exponent)); + } + + /** + * Returns the quotient of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function quotient($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $quotient = Calculator::get()->divQ($this->value, $that->value); + + return new BigInteger($quotient); + } + + /** + * Returns the remainder of the division of this number by the given one. + * + * The remainder, when non-zero, has the same sign as the dividend. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function remainder($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return BigInteger::zero(); + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $remainder = Calculator::get()->divR($this->value, $that->value); + + return new BigInteger($remainder); + } + + /** + * Returns the quotient and remainder of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger[] An array containing the quotient and the remainder. + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function quotientAndRemainder($that) : array + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + [$quotient, $remainder] = Calculator::get()->divQR($this->value, $that->value); + + return [ + new BigInteger($quotient), + new BigInteger($remainder) + ]; + } + + /** + * Returns the modulo of this number and the given one. + * + * The modulo operation yields the same result as the remainder operation when both operands are of the same sign, + * and may differ when signs are different. + * + * The result of the modulo operation, when non-zero, has the same sign as the divisor. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function mod($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + $value = Calculator::get()->mod($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the modular multiplicative inverse of this BigInteger modulo $m. + * + * @param BigInteger $m + * + * @return BigInteger + * + * @throws DivisionByZeroException If $m is zero. + * @throws NegativeNumberException If $m is negative. + * @throws MathException If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger + * is not relatively prime to m). + */ + public function modInverse(BigInteger $m) : BigInteger + { + if ($m->value === '0') { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + if ($m->isNegative()) { + throw new NegativeNumberException('Modulus must not be negative.'); + } + + if ($m->value === '1') { + return BigInteger::zero(); + } + + $value = Calculator::get()->modInverse($this->value, $m->value); + + if ($value === null) { + throw new MathException('Unable to compute the modInverse for the given modulus.'); + } + + return new BigInteger($value); + } + + /** + * Returns this number raised into power with modulo. + * + * This operation only works on positive numbers. + * + * @param BigNumber|int|float|string $exp The exponent. Must be positive or zero. + * @param BigNumber|int|float|string $mod The modulus. Must be strictly positive. + * + * @return BigInteger + * + * @throws NegativeNumberException If any of the operands is negative. + * @throws DivisionByZeroException If the modulus is zero. + */ + public function modPow($exp, $mod) : BigInteger + { + $exp = BigInteger::of($exp); + $mod = BigInteger::of($mod); + + if ($this->isNegative() || $exp->isNegative() || $mod->isNegative()) { + throw new NegativeNumberException('The operands cannot be negative.'); + } + + if ($mod->isZero()) { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + $result = Calculator::get()->modPow($this->value, $exp->value, $mod->value); + + return new BigInteger($result); + } + + /** + * Returns the greatest common divisor of this number and the given one. + * + * The GCD is always positive, unless both operands are zero, in which case it is zero. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function gcd($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0' && $this->value[0] !== '-') { + return $this; + } + + if ($this->value === '0' && $that->value[0] !== '-') { + return $that; + } + + $value = Calculator::get()->gcd($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the integer square root number of this number, rounded down. + * + * The result is the largest x such that x² ≤ n. + * + * @return BigInteger + * + * @throws NegativeNumberException If this number is negative. + */ + public function sqrt() : BigInteger + { + if ($this->value[0] === '-') { + throw new NegativeNumberException('Cannot calculate the square root of a negative number.'); + } + + $value = Calculator::get()->sqrt($this->value); + + return new BigInteger($value); + } + + /** + * Returns the absolute value of this number. + * + * @return BigInteger + */ + public function abs() : BigInteger + { + return $this->isNegative() ? $this->negated() : $this; + } + + /** + * Returns the inverse of this number. + * + * @return BigInteger + */ + public function negated() : BigInteger + { + return new BigInteger(Calculator::get()->neg($this->value)); + } + + /** + * Returns the integer bitwise-and combined with another integer. + * + * This method returns a negative BigInteger if and only if both operands are negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function and($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->and($this->value, $that->value)); + } + + /** + * Returns the integer bitwise-or combined with another integer. + * + * This method returns a negative BigInteger if and only if either of the operands is negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function or($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->or($this->value, $that->value)); + } + + /** + * Returns the integer bitwise-xor combined with another integer. + * + * This method returns a negative BigInteger if and only if exactly one of the operands is negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function xor($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->xor($this->value, $that->value)); + } + + /** + * Returns the bitwise-not of this BigInteger. + * + * @return BigInteger + */ + public function not() : BigInteger + { + return $this->negated()->minus(1); + } + + /** + * Returns the integer left shifted by a given number of bits. + * + * @param int $distance The distance to shift. + * + * @return BigInteger + */ + public function shiftedLeft(int $distance) : BigInteger + { + if ($distance === 0) { + return $this; + } + + if ($distance < 0) { + return $this->shiftedRight(- $distance); + } + + return $this->multipliedBy(BigInteger::of(2)->power($distance)); + } + + /** + * Returns the integer right shifted by a given number of bits. + * + * @param int $distance The distance to shift. + * + * @return BigInteger + */ + public function shiftedRight(int $distance) : BigInteger + { + if ($distance === 0) { + return $this; + } + + if ($distance < 0) { + return $this->shiftedLeft(- $distance); + } + + $operand = BigInteger::of(2)->power($distance); + + if ($this->isPositiveOrZero()) { + return $this->quotient($operand); + } + + return $this->dividedBy($operand, RoundingMode::UP); + } + + /** + * Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit. + * + * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation. + * Computes (ceil(log2(this < 0 ? -this : this+1))). + * + * @return int + */ + public function getBitLength() : int + { + if ($this->value === '0') { + return 0; + } + + if ($this->isNegative()) { + return $this->abs()->minus(1)->getBitLength(); + } + + return \strlen($this->toBase(2)); + } + + /** + * Returns the index of the rightmost (lowest-order) one bit in this BigInteger. + * + * Returns -1 if this BigInteger contains no one bits. + * + * @return int + */ + public function getLowestSetBit() : int + { + $n = $this; + $bitLength = $this->getBitLength(); + + for ($i = 0; $i <= $bitLength; $i++) { + if ($n->isOdd()) { + return $i; + } + + $n = $n->shiftedRight(1); + } + + return -1; + } + + /** + * Returns whether this number is even. + * + * @return bool + */ + public function isEven() : bool + { + return \in_array($this->value[-1], ['0', '2', '4', '6', '8'], true); + } + + /** + * Returns whether this number is odd. + * + * @return bool + */ + public function isOdd() : bool + { + return \in_array($this->value[-1], ['1', '3', '5', '7', '9'], true); + } + + /** + * Returns true if and only if the designated bit is set. + * + * Computes ((this & (1<<n)) != 0). + * + * @param int $n The bit to test, 0-based. + * + * @return bool + * + * @throws \InvalidArgumentException If the bit to test is negative. + */ + public function testBit(int $n) : bool + { + if ($n < 0) { + throw new \InvalidArgumentException('The bit to test cannot be negative.'); + } + + return $this->shiftedRight($n)->isOdd(); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + $that = BigNumber::of($that); + + if ($that instanceof BigInteger) { + return Calculator::get()->cmp($this->value, $that->value); + } + + return - $that->compareTo($this); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return BigDecimal::create($this->value); + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + return BigRational::create($this, BigInteger::one(), false); + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + return $this->toBigDecimal()->toScale($scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + $intValue = (int) $this->value; + + if ($this->value !== (string) $intValue) { + throw IntegerOverflowException::toIntOverflow($this); + } + + return $intValue; + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return (float) $this->value; + } + + /** + * Returns a string representation of this number in the given base. + * + * The output will always be lowercase for bases greater than 10. + * + * @param int $base + * + * @return string + * + * @throws \InvalidArgumentException If the base is out of range. + */ + public function toBase(int $base) : string + { + if ($base === 10) { + return $this->value; + } + + if ($base < 2 || $base > 36) { + throw new \InvalidArgumentException(\sprintf('Base %d is out of range [2, 36]', $base)); + } + + return Calculator::get()->toBase($this->value, $base); + } + + /** + * Returns a string representation of this number in an arbitrary base with a custom alphabet. + * + * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers; + * a NegativeNumberException will be thrown when attempting to call this method on a negative number. + * + * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8. + * + * @return string + * + * @throws NegativeNumberException If this number is negative. + * @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars. + */ + public function toArbitraryBase(string $alphabet) : string + { + $base = \strlen($alphabet); + + if ($base < 2) { + throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.'); + } + + if ($this->value[0] === '-') { + throw new NegativeNumberException(__FUNCTION__ . '() does not support negative numbers.'); + } + + return Calculator::get()->toArbitraryBase($this->value, $alphabet, $base); + } + + /** + * Returns a string of bytes containing the binary representation of this BigInteger. + * + * The string is in big-endian byte-order: the most significant byte is in the zeroth element. + * + * If `$signed` is true, the output will be in two's-complement representation, and a sign bit will be prepended to + * the output. If `$signed` is false, no sign bit will be prepended, and this method will throw an exception if the + * number is negative. + * + * The string will contain the minimum number of bytes required to represent this BigInteger, including a sign bit + * if `$signed` is true. + * + * This representation is compatible with the `fromBytes()` factory method, as long as the `$signed` flags match. + * + * @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit. + * + * @return string + * + * @throws NegativeNumberException If $signed is false, and the number is negative. + */ + public function toBytes(bool $signed = true) : string + { + if (! $signed && $this->isNegative()) { + throw new NegativeNumberException('Cannot convert a negative number to a byte string when $signed is false.'); + } + + $hex = $this->abs()->toBase(16); + + if (\strlen($hex) % 2 !== 0) { + $hex = '0' . $hex; + } + + $baseHexLength = \strlen($hex); + + if ($signed) { + if ($this->isNegative()) { + $bin = \hex2bin($hex); + assert($bin !== false); + + $hex = \bin2hex(~$bin); + $hex = self::fromBase($hex, 16)->plus(1)->toBase(16); + + $hexLength = \strlen($hex); + + if ($hexLength < $baseHexLength) { + $hex = \str_repeat('0', $baseHexLength - $hexLength) . $hex; + } + + if ($hex[0] < '8') { + $hex = 'FF' . $hex; + } + } else { + if ($hex[0] >= '8') { + $hex = '00' . $hex; + } + } + } + + return \hex2bin($hex); + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + return $this->value; + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{value: string} + */ + public function __serialize(): array + { + return ['value' => $this->value]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{value: string} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->value)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $data['value']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->value; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->value)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $value; + } +} diff --git a/vendor/brick/math/src/BigNumber.php b/vendor/brick/math/src/BigNumber.php new file mode 100644 index 0000000..38c8c55 --- /dev/null +++ b/vendor/brick/math/src/BigNumber.php @@ -0,0 +1,572 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math; + +use Brick\Math\Exception\DivisionByZeroException; +use Brick\Math\Exception\MathException; +use Brick\Math\Exception\NumberFormatException; +use Brick\Math\Exception\RoundingNecessaryException; + +/** + * Common interface for arbitrary-precision rational numbers. + * + * @psalm-immutable + */ +abstract class BigNumber implements \Serializable, \JsonSerializable +{ + /** + * The regular expression used to parse integer, decimal and rational numbers. + */ + private const PARSE_REGEXP = + '/^' . + '(?<sign>[\-\+])?' . + '(?:' . + '(?:' . + '(?<integral>[0-9]+)?' . + '(?<point>\.)?' . + '(?<fractional>[0-9]+)?' . + '(?:[eE](?<exponent>[\-\+]?[0-9]+))?' . + ')|(?:' . + '(?<numerator>[0-9]+)' . + '\/?' . + '(?<denominator>[0-9]+)' . + ')' . + ')' . + '$/'; + + /** + * Creates a BigNumber of the given value. + * + * The concrete return type is dependent on the given value, with the following rules: + * + * - BigNumber instances are returned as is + * - integer numbers are returned as BigInteger + * - floating point numbers are converted to a string then parsed as such + * - strings containing a `/` character are returned as BigRational + * - strings containing a `.` character or using an exponential notation are returned as BigDecimal + * - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger + * + * @param BigNumber|int|float|string $value + * + * @return BigNumber + * + * @throws NumberFormatException If the format of the number is not valid. + * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + if ($value instanceof BigNumber) { + return $value; + } + + if (\is_int($value)) { + return new BigInteger((string) $value); + } + + /** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */ + $value = \is_float($value) ? self::floatToString($value) : (string) $value; + + $throw = static function() use ($value) : void { + throw new NumberFormatException(\sprintf( + 'The given value "%s" does not represent a valid number.', + $value + )); + }; + + if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) { + $throw(); + } + + $getMatch = static function(string $value) use ($matches) : ?string { + return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null; + }; + + $sign = $getMatch('sign'); + $numerator = $getMatch('numerator'); + $denominator = $getMatch('denominator'); + + if ($numerator !== null) { + assert($denominator !== null); + + if ($sign !== null) { + $numerator = $sign . $numerator; + } + + $numerator = self::cleanUp($numerator); + $denominator = self::cleanUp($denominator); + + if ($denominator === '0') { + throw DivisionByZeroException::denominatorMustNotBeZero(); + } + + return new BigRational( + new BigInteger($numerator), + new BigInteger($denominator), + false + ); + } + + $point = $getMatch('point'); + $integral = $getMatch('integral'); + $fractional = $getMatch('fractional'); + $exponent = $getMatch('exponent'); + + if ($integral === null && $fractional === null) { + $throw(); + } + + if ($integral === null) { + $integral = '0'; + } + + if ($point !== null || $exponent !== null) { + $fractional = ($fractional ?? ''); + $exponent = ($exponent !== null) ? (int) $exponent : 0; + + if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) { + throw new NumberFormatException('Exponent too large.'); + } + + $unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional); + + $scale = \strlen($fractional) - $exponent; + + if ($scale < 0) { + if ($unscaledValue !== '0') { + $unscaledValue .= \str_repeat('0', - $scale); + } + $scale = 0; + } + + return new BigDecimal($unscaledValue, $scale); + } + + $integral = self::cleanUp(($sign ?? '') . $integral); + + return new BigInteger($integral); + } + + /** + * Safely converts float to string, avoiding locale-dependent issues. + * + * @see https://github.com/brick/math/pull/20 + * + * @param float $float + * + * @return string + * + * @psalm-pure + * @psalm-suppress ImpureFunctionCall + */ + private static function floatToString(float $float) : string + { + $currentLocale = \setlocale(LC_NUMERIC, '0'); + \setlocale(LC_NUMERIC, 'C'); + + $result = (string) $float; + + \setlocale(LC_NUMERIC, $currentLocale); + + return $result; + } + + /** + * Proxy method to access protected constructors from sibling classes. + * + * @internal + * + * @param mixed ...$args The arguments to the constructor. + * + * @return static + * + * @psalm-pure + * @psalm-suppress TooManyArguments + * @psalm-suppress UnsafeInstantiation + */ + protected static function create(... $args) : BigNumber + { + return new static(... $args); + } + + /** + * Returns the minimum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The minimum value. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function min(...$values) : BigNumber + { + $min = null; + + foreach ($values as $value) { + $value = static::of($value); + + if ($min === null || $value->isLessThan($min)) { + $min = $value; + } + } + + if ($min === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $min; + } + + /** + * Returns the maximum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The maximum value. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function max(...$values) : BigNumber + { + $max = null; + + foreach ($values as $value) { + $value = static::of($value); + + if ($max === null || $value->isGreaterThan($max)) { + $max = $value; + } + } + + if ($max === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $max; + } + + /** + * Returns the sum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The sum. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function sum(...$values) : BigNumber + { + /** @var BigNumber|null $sum */ + $sum = null; + + foreach ($values as $value) { + $value = static::of($value); + + $sum = $sum === null ? $value : self::add($sum, $value); + } + + if ($sum === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $sum; + } + + /** + * Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException. + * + * @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to + * concrete classes the responsibility to perform the addition themselves or delegate it to the given number, + * depending on their ability to perform the operation. This will also require a version bump because we're + * potentially breaking custom BigNumber implementations (if any...) + * + * @param BigNumber $a + * @param BigNumber $b + * + * @return BigNumber + * + * @psalm-pure + */ + private static function add(BigNumber $a, BigNumber $b) : BigNumber + { + if ($a instanceof BigRational) { + return $a->plus($b); + } + + if ($b instanceof BigRational) { + return $b->plus($a); + } + + if ($a instanceof BigDecimal) { + return $a->plus($b); + } + + if ($b instanceof BigDecimal) { + return $b->plus($a); + } + + /** @var BigInteger $a */ + + return $a->plus($b); + } + + /** + * Removes optional leading zeros and + sign from the given number. + * + * @param string $number The number, validated as a non-empty string of digits with optional leading sign. + * + * @return string + * + * @psalm-pure + */ + private static function cleanUp(string $number) : string + { + $firstChar = $number[0]; + + if ($firstChar === '+' || $firstChar === '-') { + $number = \substr($number, 1); + } + + $number = \ltrim($number, '0'); + + if ($number === '') { + return '0'; + } + + if ($firstChar === '-') { + return '-' . $number; + } + + return $number; + } + + /** + * Checks if this number is equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isEqualTo($that) : bool + { + return $this->compareTo($that) === 0; + } + + /** + * Checks if this number is strictly lower than the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isLessThan($that) : bool + { + return $this->compareTo($that) < 0; + } + + /** + * Checks if this number is lower than or equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isLessThanOrEqualTo($that) : bool + { + return $this->compareTo($that) <= 0; + } + + /** + * Checks if this number is strictly greater than the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isGreaterThan($that) : bool + { + return $this->compareTo($that) > 0; + } + + /** + * Checks if this number is greater than or equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isGreaterThanOrEqualTo($that) : bool + { + return $this->compareTo($that) >= 0; + } + + /** + * Checks if this number equals zero. + * + * @return bool + */ + public function isZero() : bool + { + return $this->getSign() === 0; + } + + /** + * Checks if this number is strictly negative. + * + * @return bool + */ + public function isNegative() : bool + { + return $this->getSign() < 0; + } + + /** + * Checks if this number is negative or zero. + * + * @return bool + */ + public function isNegativeOrZero() : bool + { + return $this->getSign() <= 0; + } + + /** + * Checks if this number is strictly positive. + * + * @return bool + */ + public function isPositive() : bool + { + return $this->getSign() > 0; + } + + /** + * Checks if this number is positive or zero. + * + * @return bool + */ + public function isPositiveOrZero() : bool + { + return $this->getSign() >= 0; + } + + /** + * Returns the sign of this number. + * + * @return int -1 if the number is negative, 0 if zero, 1 if positive. + */ + abstract public function getSign() : int; + + /** + * Compares this number to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`. + * + * @throws MathException If the number is not valid. + */ + abstract public function compareTo($that) : int; + + /** + * Converts this number to a BigInteger. + * + * @return BigInteger The converted number. + * + * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding. + */ + abstract public function toBigInteger() : BigInteger; + + /** + * Converts this number to a BigDecimal. + * + * @return BigDecimal The converted number. + * + * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding. + */ + abstract public function toBigDecimal() : BigDecimal; + + /** + * Converts this number to a BigRational. + * + * @return BigRational The converted number. + */ + abstract public function toBigRational() : BigRational; + + /** + * Converts this number to a BigDecimal with the given scale, using rounding if necessary. + * + * @param int $scale The scale of the resulting `BigDecimal`. + * @param int $roundingMode A `RoundingMode` constant. + * + * @return BigDecimal + * + * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding. + * This only applies when RoundingMode::UNNECESSARY is used. + */ + abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal; + + /** + * Returns the exact value of this number as a native integer. + * + * If this number cannot be converted to a native integer without losing precision, an exception is thrown. + * Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit. + * + * @return int The converted value. + * + * @throws MathException If this number cannot be exactly converted to a native integer. + */ + abstract public function toInt() : int; + + /** + * Returns an approximation of this number as a floating-point value. + * + * Note that this method can discard information as the precision of a floating-point value + * is inherently limited. + * + * If the number is greater than the largest representable floating point number, positive infinity is returned. + * If the number is less than the smallest representable floating point number, negative infinity is returned. + * + * @return float The converted value. + */ + abstract public function toFloat() : float; + + /** + * Returns a string representation of this number. + * + * The output of this method can be parsed by the `of()` factory method; + * this will yield an object equal to this one, without any information loss. + * + * @return string + */ + abstract public function __toString() : string; + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : string + { + return $this->__toString(); + } +} diff --git a/vendor/brick/math/src/BigRational.php b/vendor/brick/math/src/BigRational.php new file mode 100644 index 0000000..bee094f --- /dev/null +++ b/vendor/brick/math/src/BigRational.php @@ -0,0 +1,523 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math; + +use Brick\Math\Exception\DivisionByZeroException; +use Brick\Math\Exception\MathException; +use Brick\Math\Exception\NumberFormatException; +use Brick\Math\Exception\RoundingNecessaryException; + +/** + * An arbitrarily large rational number. + * + * This class is immutable. + * + * @psalm-immutable + */ +final class BigRational extends BigNumber +{ + /** + * The numerator. + * + * @var BigInteger + */ + private $numerator; + + /** + * The denominator. Always strictly positive. + * + * @var BigInteger + */ + private $denominator; + + /** + * Protected constructor. Use a factory method to obtain an instance. + * + * @param BigInteger $numerator The numerator. + * @param BigInteger $denominator The denominator. + * @param bool $checkDenominator Whether to check the denominator for negative and zero. + * + * @throws DivisionByZeroException If the denominator is zero. + */ + protected function __construct(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) + { + if ($checkDenominator) { + if ($denominator->isZero()) { + throw DivisionByZeroException::denominatorMustNotBeZero(); + } + + if ($denominator->isNegative()) { + $numerator = $numerator->negated(); + $denominator = $denominator->negated(); + } + } + + $this->numerator = $numerator; + $this->denominator = $denominator; + } + + /** + * Creates a BigRational of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigRational + * + * @throws MathException If the value cannot be converted to a BigRational. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigRational(); + } + + /** + * Creates a BigRational out of a numerator and a denominator. + * + * If the denominator is negative, the signs of both the numerator and the denominator + * will be inverted to ensure that the denominator is always positive. + * + * @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger. + * @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger. + * + * @return BigRational + * + * @throws NumberFormatException If an argument does not represent a valid number. + * @throws RoundingNecessaryException If an argument represents a non-integer number. + * @throws DivisionByZeroException If the denominator is zero. + * + * @psalm-pure + */ + public static function nd($numerator, $denominator) : BigRational + { + $numerator = BigInteger::of($numerator); + $denominator = BigInteger::of($denominator); + + return new BigRational($numerator, $denominator, true); + } + + /** + * Returns a BigRational representing zero. + * + * @return BigRational + * + * @psalm-pure + */ + public static function zero() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false); + } + + return $zero; + } + + /** + * Returns a BigRational representing one. + * + * @return BigRational + * + * @psalm-pure + */ + public static function one() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $one + */ + static $one; + + if ($one === null) { + $one = new BigRational(BigInteger::one(), BigInteger::one(), false); + } + + return $one; + } + + /** + * Returns a BigRational representing ten. + * + * @return BigRational + * + * @psalm-pure + */ + public static function ten() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigRational(BigInteger::ten(), BigInteger::one(), false); + } + + return $ten; + } + + /** + * @return BigInteger + */ + public function getNumerator() : BigInteger + { + return $this->numerator; + } + + /** + * @return BigInteger + */ + public function getDenominator() : BigInteger + { + return $this->denominator; + } + + /** + * Returns the quotient of the division of the numerator by the denominator. + * + * @return BigInteger + */ + public function quotient() : BigInteger + { + return $this->numerator->quotient($this->denominator); + } + + /** + * Returns the remainder of the division of the numerator by the denominator. + * + * @return BigInteger + */ + public function remainder() : BigInteger + { + return $this->numerator->remainder($this->denominator); + } + + /** + * Returns the quotient and remainder of the division of the numerator by the denominator. + * + * @return BigInteger[] + */ + public function quotientAndRemainder() : array + { + return $this->numerator->quotientAndRemainder($this->denominator); + } + + /** + * Returns the sum of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to add. + * + * @return BigRational The result. + * + * @throws MathException If the number is not valid. + */ + public function plus($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $numerator = $numerator->plus($that->numerator->multipliedBy($this->denominator)); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the difference of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to subtract. + * + * @return BigRational The result. + * + * @throws MathException If the number is not valid. + */ + public function minus($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $numerator = $numerator->minus($that->numerator->multipliedBy($this->denominator)); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the product of this number and the given one. + * + * @param BigNumber|int|float|string $that The multiplier. + * + * @return BigRational The result. + * + * @throws MathException If the multiplier is not a valid number. + */ + public function multipliedBy($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->numerator); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the result of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. + * + * @return BigRational The result. + * + * @throws MathException If the divisor is not a valid number, or is zero. + */ + public function dividedBy($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $denominator = $this->denominator->multipliedBy($that->numerator); + + return new BigRational($numerator, $denominator, true); + } + + /** + * Returns this number exponentiated to the given value. + * + * @param int $exponent The exponent. + * + * @return BigRational The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigRational + { + if ($exponent === 0) { + $one = BigInteger::one(); + + return new BigRational($one, $one, false); + } + + if ($exponent === 1) { + return $this; + } + + return new BigRational( + $this->numerator->power($exponent), + $this->denominator->power($exponent), + false + ); + } + + /** + * Returns the reciprocal of this BigRational. + * + * The reciprocal has the numerator and denominator swapped. + * + * @return BigRational + * + * @throws DivisionByZeroException If the numerator is zero. + */ + public function reciprocal() : BigRational + { + return new BigRational($this->denominator, $this->numerator, true); + } + + /** + * Returns the absolute value of this BigRational. + * + * @return BigRational + */ + public function abs() : BigRational + { + return new BigRational($this->numerator->abs(), $this->denominator, false); + } + + /** + * Returns the negated value of this BigRational. + * + * @return BigRational + */ + public function negated() : BigRational + { + return new BigRational($this->numerator->negated(), $this->denominator, false); + } + + /** + * Returns the simplified value of this BigRational. + * + * @return BigRational + */ + public function simplified() : BigRational + { + $gcd = $this->numerator->gcd($this->denominator); + + $numerator = $this->numerator->quotient($gcd); + $denominator = $this->denominator->quotient($gcd); + + return new BigRational($numerator, $denominator, false); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + return $this->minus($that)->getSign(); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return $this->numerator->getSign(); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + $simplified = $this->simplified(); + + if (! $simplified->denominator->isEqualTo(1)) { + throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.'); + } + + return $simplified->numerator; + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator); + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + return $this->toBigInteger()->toInt(); + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return $this->numerator->toFloat() / $this->denominator->toFloat(); + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + $numerator = (string) $this->numerator; + $denominator = (string) $this->denominator; + + if ($denominator === '1') { + return $numerator; + } + + return $this->numerator . '/' . $this->denominator; + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{numerator: BigInteger, denominator: BigInteger} + */ + public function __serialize(): array + { + return ['numerator' => $this->numerator, 'denominator' => $this->denominator]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{numerator: BigInteger, denominator: BigInteger} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->numerator)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->numerator = $data['numerator']; + $this->denominator = $data['denominator']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->numerator . '/' . $this->denominator; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->numerator)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + [$numerator, $denominator] = \explode('/', $value); + + $this->numerator = BigInteger::of($numerator); + $this->denominator = BigInteger::of($denominator); + } +} diff --git a/vendor/brick/math/src/Exception/DivisionByZeroException.php b/vendor/brick/math/src/Exception/DivisionByZeroException.php new file mode 100644 index 0000000..a4e4431 --- /dev/null +++ b/vendor/brick/math/src/Exception/DivisionByZeroException.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Exception; + +/** + * Exception thrown when a division by zero occurs. + */ +class DivisionByZeroException extends MathException +{ + /** + * @return DivisionByZeroException + * + * @psalm-pure + */ + public static function divisionByZero() : DivisionByZeroException + { + return new self('Division by zero.'); + } + + /** + * @return DivisionByZeroException + * + * @psalm-pure + */ + public static function modulusMustNotBeZero() : DivisionByZeroException + { + return new self('The modulus must not be zero.'); + } + + /** + * @return DivisionByZeroException + * + * @psalm-pure + */ + public static function denominatorMustNotBeZero() : DivisionByZeroException + { + return new self('The denominator of a rational number cannot be zero.'); + } +} diff --git a/vendor/brick/math/src/Exception/IntegerOverflowException.php b/vendor/brick/math/src/Exception/IntegerOverflowException.php new file mode 100644 index 0000000..e0b07d3 --- /dev/null +++ b/vendor/brick/math/src/Exception/IntegerOverflowException.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Exception; + +use Brick\Math\BigInteger; + +/** + * Exception thrown when an integer overflow occurs. + */ +class IntegerOverflowException extends MathException +{ + /** + * @param BigInteger $value + * + * @return IntegerOverflowException + * + * @psalm-pure + */ + public static function toIntOverflow(BigInteger $value) : IntegerOverflowException + { + $message = '%s is out of range %d to %d and cannot be represented as an integer.'; + + return new self(\sprintf($message, (string) $value, PHP_INT_MIN, PHP_INT_MAX)); + } +} diff --git a/vendor/brick/math/src/Exception/MathException.php b/vendor/brick/math/src/Exception/MathException.php new file mode 100644 index 0000000..21fda90 --- /dev/null +++ b/vendor/brick/math/src/Exception/MathException.php @@ -0,0 +1,14 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Exception; + +/** + * Base class for all math exceptions. + * + * This class is abstract to ensure that only fine-grained exceptions are thrown throughout the code. + */ +class MathException extends \RuntimeException +{ +} diff --git a/vendor/brick/math/src/Exception/NegativeNumberException.php b/vendor/brick/math/src/Exception/NegativeNumberException.php new file mode 100644 index 0000000..4739113 --- /dev/null +++ b/vendor/brick/math/src/Exception/NegativeNumberException.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Exception; + +/** + * Exception thrown when attempting to perform an unsupported operation, such as a square root, on a negative number. + */ +class NegativeNumberException extends MathException +{ +} diff --git a/vendor/brick/math/src/Exception/NumberFormatException.php b/vendor/brick/math/src/Exception/NumberFormatException.php new file mode 100644 index 0000000..2fd0be7 --- /dev/null +++ b/vendor/brick/math/src/Exception/NumberFormatException.php @@ -0,0 +1,35 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Exception; + +/** + * Exception thrown when attempting to create a number from a string with an invalid format. + */ +class NumberFormatException extends MathException +{ + /** + * @param string $char The failing character. + * + * @return NumberFormatException + * + * @psalm-pure + */ + public static function charNotInAlphabet(string $char) : self + { + $ord = \ord($char); + + if ($ord < 32 || $ord > 126) { + $char = \strtoupper(\dechex($ord)); + + if ($ord < 10) { + $char = '0' . $char; + } + } else { + $char = '"' . $char . '"'; + } + + return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char)); + } +} diff --git a/vendor/brick/math/src/Exception/RoundingNecessaryException.php b/vendor/brick/math/src/Exception/RoundingNecessaryException.php new file mode 100644 index 0000000..1c61005 --- /dev/null +++ b/vendor/brick/math/src/Exception/RoundingNecessaryException.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Exception; + +/** + * Exception thrown when a number cannot be represented at the requested scale without rounding. + */ +class RoundingNecessaryException extends MathException +{ + /** + * @return RoundingNecessaryException + * + * @psalm-pure + */ + public static function roundingNecessary() : RoundingNecessaryException + { + return new self('Rounding is necessary to represent the result of the operation at this scale.'); + } +} diff --git a/vendor/brick/math/src/Internal/Calculator.php b/vendor/brick/math/src/Internal/Calculator.php new file mode 100644 index 0000000..a6eac79 --- /dev/null +++ b/vendor/brick/math/src/Internal/Calculator.php @@ -0,0 +1,756 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Internal; + +use Brick\Math\Exception\RoundingNecessaryException; +use Brick\Math\RoundingMode; + +/** + * Performs basic operations on arbitrary size integers. + * + * Unless otherwise specified, all parameters must be validated as non-empty strings of digits, + * without leading zero, and with an optional leading minus sign if the number is not zero. + * + * Any other parameter format will lead to undefined behaviour. + * All methods must return strings respecting this format, unless specified otherwise. + * + * @internal + * + * @psalm-immutable + */ +abstract class Calculator +{ + /** + * The maximum exponent value allowed for the pow() method. + */ + public const MAX_POWER = 1000000; + + /** + * The alphabet for converting from and to base 2 to 36, lowercase. + */ + public const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'; + + /** + * The Calculator instance in use. + * + * @var Calculator|null + */ + private static $instance; + + /** + * Sets the Calculator instance to use. + * + * An instance is typically set only in unit tests: the autodetect is usually the best option. + * + * @param Calculator|null $calculator The calculator instance, or NULL to revert to autodetect. + * + * @return void + */ + final public static function set(?Calculator $calculator) : void + { + self::$instance = $calculator; + } + + /** + * Returns the Calculator instance to use. + * + * If none has been explicitly set, the fastest available implementation will be returned. + * + * @return Calculator + * + * @psalm-pure + * @psalm-suppress ImpureStaticProperty + */ + final public static function get() : Calculator + { + if (self::$instance === null) { + /** @psalm-suppress ImpureMethodCall */ + self::$instance = self::detect(); + } + + return self::$instance; + } + + /** + * Returns the fastest available Calculator implementation. + * + * @codeCoverageIgnore + * + * @return Calculator + */ + private static function detect() : Calculator + { + if (\extension_loaded('gmp')) { + return new Calculator\GmpCalculator(); + } + + if (\extension_loaded('bcmath')) { + return new Calculator\BcMathCalculator(); + } + + return new Calculator\NativeCalculator(); + } + + /** + * Extracts the sign & digits of the operands. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return array{bool, bool, string, string} Whether $a and $b are negative, followed by their digits. + */ + final protected function init(string $a, string $b) : array + { + return [ + $aNeg = ($a[0] === '-'), + $bNeg = ($b[0] === '-'), + + $aNeg ? \substr($a, 1) : $a, + $bNeg ? \substr($b, 1) : $b, + ]; + } + + /** + * Returns the absolute value of a number. + * + * @param string $n The number. + * + * @return string The absolute value. + */ + final public function abs(string $n) : string + { + return ($n[0] === '-') ? \substr($n, 1) : $n; + } + + /** + * Negates a number. + * + * @param string $n The number. + * + * @return string The negated value. + */ + final public function neg(string $n) : string + { + if ($n === '0') { + return '0'; + } + + if ($n[0] === '-') { + return \substr($n, 1); + } + + return '-' . $n; + } + + /** + * Compares two numbers. + * + * @param string $a The first number. + * @param string $b The second number. + * + * @return int [-1, 0, 1] If the first number is less than, equal to, or greater than the second number. + */ + final public function cmp(string $a, string $b) : int + { + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + if ($aNeg && ! $bNeg) { + return -1; + } + + if ($bNeg && ! $aNeg) { + return 1; + } + + $aLen = \strlen($aDig); + $bLen = \strlen($bDig); + + if ($aLen < $bLen) { + $result = -1; + } elseif ($aLen > $bLen) { + $result = 1; + } else { + $result = $aDig <=> $bDig; + } + + return $aNeg ? -$result : $result; + } + + /** + * Adds two numbers. + * + * @param string $a The augend. + * @param string $b The addend. + * + * @return string The sum. + */ + abstract public function add(string $a, string $b) : string; + + /** + * Subtracts two numbers. + * + * @param string $a The minuend. + * @param string $b The subtrahend. + * + * @return string The difference. + */ + abstract public function sub(string $a, string $b) : string; + + /** + * Multiplies two numbers. + * + * @param string $a The multiplicand. + * @param string $b The multiplier. + * + * @return string The product. + */ + abstract public function mul(string $a, string $b) : string; + + /** + * Returns the quotient of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string The quotient. + */ + abstract public function divQ(string $a, string $b) : string; + + /** + * Returns the remainder of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string The remainder. + */ + abstract public function divR(string $a, string $b) : string; + + /** + * Returns the quotient and remainder of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string[] An array containing the quotient and remainder. + */ + abstract public function divQR(string $a, string $b) : array; + + /** + * Exponentiates a number. + * + * @param string $a The base number. + * @param int $e The exponent, validated as an integer between 0 and MAX_POWER. + * + * @return string The power. + */ + abstract public function pow(string $a, int $e) : string; + + /** + * @param string $a + * @param string $b The modulus; must not be zero. + * + * @return string + */ + public function mod(string $a, string $b) : string + { + return $this->divR($this->add($this->divR($a, $b), $b), $b); + } + + /** + * Returns the modular multiplicative inverse of $x modulo $m. + * + * If $x has no multiplicative inverse mod m, this method must return null. + * + * This method can be overridden by the concrete implementation if the underlying library has built-in support. + * + * @param string $x + * @param string $m The modulus; must not be negative or zero. + * + * @return string|null + */ + public function modInverse(string $x, string $m) : ?string + { + if ($m === '1') { + return '0'; + } + + $modVal = $x; + + if ($x[0] === '-' || ($this->cmp($this->abs($x), $m) >= 0)) { + $modVal = $this->mod($x, $m); + } + + $x = '0'; + $y = '0'; + $g = $this->gcdExtended($modVal, $m, $x, $y); + + if ($g !== '1') { + return null; + } + + return $this->mod($this->add($this->mod($x, $m), $m), $m); + } + + /** + * Raises a number into power with modulo. + * + * @param string $base The base number; must be positive or zero. + * @param string $exp The exponent; must be positive or zero. + * @param string $mod The modulus; must be strictly positive. + * + * @return string The power. + */ + abstract public function modPow(string $base, string $exp, string $mod) : string; + + /** + * Returns the greatest common divisor of the two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for GCD calculations. + * + * @param string $a The first number. + * @param string $b The second number. + * + * @return string The GCD, always positive, or zero if both arguments are zero. + */ + public function gcd(string $a, string $b) : string + { + if ($a === '0') { + return $this->abs($b); + } + + if ($b === '0') { + return $this->abs($a); + } + + return $this->gcd($b, $this->divR($a, $b)); + } + + private function gcdExtended(string $a, string $b, string &$x, string &$y) : string + { + if ($a === '0') { + $x = '0'; + $y = '1'; + + return $b; + } + + $x1 = '0'; + $y1 = '0'; + + $gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1); + + $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1)); + $y = $x1; + + return $gcd; + } + + /** + * Returns the square root of the given number, rounded down. + * + * The result is the largest x such that x² ≤ n. + * The input MUST NOT be negative. + * + * @param string $n The number. + * + * @return string The square root. + */ + abstract public function sqrt(string $n) : string; + + /** + * Converts a number from an arbitrary base. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for base conversion. + * + * @param string $number The number, positive or zero, non-empty, case-insensitively validated for the given base. + * @param int $base The base of the number, validated from 2 to 36. + * + * @return string The converted number, following the Calculator conventions. + */ + public function fromBase(string $number, int $base) : string + { + return $this->fromArbitraryBase(\strtolower($number), self::ALPHABET, $base); + } + + /** + * Converts a number to an arbitrary base. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for base conversion. + * + * @param string $number The number to convert, following the Calculator conventions. + * @param int $base The base to convert to, validated from 2 to 36. + * + * @return string The converted number, lowercase. + */ + public function toBase(string $number, int $base) : string + { + $negative = ($number[0] === '-'); + + if ($negative) { + $number = \substr($number, 1); + } + + $number = $this->toArbitraryBase($number, self::ALPHABET, $base); + + if ($negative) { + return '-' . $number; + } + + return $number; + } + + /** + * Converts a non-negative number in an arbitrary base using a custom alphabet, to base 10. + * + * @param string $number The number to convert, validated as a non-empty string, + * containing only chars in the given alphabet/base. + * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum. + * @param int $base The base of the number, validated from 2 to alphabet length. + * + * @return string The number in base 10, following the Calculator conventions. + */ + final public function fromArbitraryBase(string $number, string $alphabet, int $base) : string + { + // remove leading "zeros" + $number = \ltrim($number, $alphabet[0]); + + if ($number === '') { + return '0'; + } + + // optimize for "one" + if ($number === $alphabet[1]) { + return '1'; + } + + $result = '0'; + $power = '1'; + + $base = (string) $base; + + for ($i = \strlen($number) - 1; $i >= 0; $i--) { + $index = \strpos($alphabet, $number[$i]); + + if ($index !== 0) { + $result = $this->add($result, ($index === 1) + ? $power + : $this->mul($power, (string) $index) + ); + } + + if ($i !== 0) { + $power = $this->mul($power, $base); + } + } + + return $result; + } + + /** + * Converts a non-negative number to an arbitrary base using a custom alphabet. + * + * @param string $number The number to convert, positive or zero, following the Calculator conventions. + * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum. + * @param int $base The base to convert to, validated from 2 to alphabet length. + * + * @return string The converted number in the given alphabet. + */ + final public function toArbitraryBase(string $number, string $alphabet, int $base) : string + { + if ($number === '0') { + return $alphabet[0]; + } + + $base = (string) $base; + $result = ''; + + while ($number !== '0') { + [$number, $remainder] = $this->divQR($number, $base); + $remainder = (int) $remainder; + + $result .= $alphabet[$remainder]; + } + + return \strrev($result); + } + + /** + * Performs a rounded division. + * + * Rounding is performed when the remainder of the division is not zero. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * @param int $roundingMode The rounding mode. + * + * @return string + * + * @throws \InvalidArgumentException If the rounding mode is invalid. + * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary. + */ + final public function divRound(string $a, string $b, int $roundingMode) : string + { + [$quotient, $remainder] = $this->divQR($a, $b); + + $hasDiscardedFraction = ($remainder !== '0'); + $isPositiveOrZero = ($a[0] === '-') === ($b[0] === '-'); + + $discardedFractionSign = function() use ($remainder, $b) : int { + $r = $this->abs($this->mul($remainder, '2')); + $b = $this->abs($b); + + return $this->cmp($r, $b); + }; + + $increment = false; + + switch ($roundingMode) { + case RoundingMode::UNNECESSARY: + if ($hasDiscardedFraction) { + throw RoundingNecessaryException::roundingNecessary(); + } + break; + + case RoundingMode::UP: + $increment = $hasDiscardedFraction; + break; + + case RoundingMode::DOWN: + break; + + case RoundingMode::CEILING: + $increment = $hasDiscardedFraction && $isPositiveOrZero; + break; + + case RoundingMode::FLOOR: + $increment = $hasDiscardedFraction && ! $isPositiveOrZero; + break; + + case RoundingMode::HALF_UP: + $increment = $discardedFractionSign() >= 0; + break; + + case RoundingMode::HALF_DOWN: + $increment = $discardedFractionSign() > 0; + break; + + case RoundingMode::HALF_CEILING: + $increment = $isPositiveOrZero ? $discardedFractionSign() >= 0 : $discardedFractionSign() > 0; + break; + + case RoundingMode::HALF_FLOOR: + $increment = $isPositiveOrZero ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0; + break; + + case RoundingMode::HALF_EVEN: + $lastDigit = (int) $quotient[-1]; + $lastDigitIsEven = ($lastDigit % 2 === 0); + $increment = $lastDigitIsEven ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0; + break; + + default: + throw new \InvalidArgumentException('Invalid rounding mode.'); + } + + if ($increment) { + return $this->add($quotient, $isPositiveOrZero ? '1' : '-1'); + } + + return $quotient; + } + + /** + * Calculates bitwise AND of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function and(string $a, string $b) : string + { + return $this->bitwise('and', $a, $b); + } + + /** + * Calculates bitwise OR of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function or(string $a, string $b) : string + { + return $this->bitwise('or', $a, $b); + } + + /** + * Calculates bitwise XOR of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function xor(string $a, string $b) : string + { + return $this->bitwise('xor', $a, $b); + } + + /** + * Performs a bitwise operation on a decimal number. + * + * @param string $operator The operator to use, must be "and", "or" or "xor". + * @param string $a The left operand. + * @param string $b The right operand. + * + * @return string + */ + private function bitwise(string $operator, string $a, string $b) : string + { + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $aBin = $this->toBinary($aDig); + $bBin = $this->toBinary($bDig); + + $aLen = \strlen($aBin); + $bLen = \strlen($bBin); + + if ($aLen > $bLen) { + $bBin = \str_repeat("\x00", $aLen - $bLen) . $bBin; + } elseif ($bLen > $aLen) { + $aBin = \str_repeat("\x00", $bLen - $aLen) . $aBin; + } + + if ($aNeg) { + $aBin = $this->twosComplement($aBin); + } + if ($bNeg) { + $bBin = $this->twosComplement($bBin); + } + + switch ($operator) { + case 'and': + $value = $aBin & $bBin; + $negative = ($aNeg and $bNeg); + break; + + case 'or': + $value = $aBin | $bBin; + $negative = ($aNeg or $bNeg); + break; + + case 'xor': + $value = $aBin ^ $bBin; + $negative = ($aNeg xor $bNeg); + break; + + // @codeCoverageIgnoreStart + default: + throw new \InvalidArgumentException('Invalid bitwise operator.'); + // @codeCoverageIgnoreEnd + } + + if ($negative) { + $value = $this->twosComplement($value); + } + + $result = $this->toDecimal($value); + + return $negative ? $this->neg($result) : $result; + } + + /** + * @param string $number A positive, binary number. + * + * @return string + */ + private function twosComplement(string $number) : string + { + $xor = \str_repeat("\xff", \strlen($number)); + + $number ^= $xor; + + for ($i = \strlen($number) - 1; $i >= 0; $i--) { + $byte = \ord($number[$i]); + + if (++$byte !== 256) { + $number[$i] = \chr($byte); + break; + } + + $number[$i] = "\x00"; + + if ($i === 0) { + $number = "\x01" . $number; + } + } + + return $number; + } + + /** + * Converts a decimal number to a binary string. + * + * @param string $number The number to convert, positive or zero, only digits. + * + * @return string + */ + private function toBinary(string $number) : string + { + $result = ''; + + while ($number !== '0') { + [$number, $remainder] = $this->divQR($number, '256'); + $result .= \chr((int) $remainder); + } + + return \strrev($result); + } + + /** + * Returns the positive decimal representation of a binary number. + * + * @param string $bytes The bytes representing the number. + * + * @return string + */ + private function toDecimal(string $bytes) : string + { + $result = '0'; + $power = '1'; + + for ($i = \strlen($bytes) - 1; $i >= 0; $i--) { + $index = \ord($bytes[$i]); + + if ($index !== 0) { + $result = $this->add($result, ($index === 1) + ? $power + : $this->mul($power, (string) $index) + ); + } + + if ($i !== 0) { + $power = $this->mul($power, '256'); + } + } + + return $result; + } +} diff --git a/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php b/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php new file mode 100644 index 0000000..6632b37 --- /dev/null +++ b/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php @@ -0,0 +1,116 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Internal\Calculator; + +use Brick\Math\Internal\Calculator; + +/** + * Calculator implementation built around the bcmath library. + * + * @internal + * + * @psalm-immutable + */ +class BcMathCalculator extends Calculator +{ + /** + * {@inheritdoc} + */ + public function add(string $a, string $b) : string + { + return \bcadd($a, $b, 0); + } + + /** + * {@inheritdoc} + */ + public function sub(string $a, string $b) : string + { + return \bcsub($a, $b, 0); + } + + /** + * {@inheritdoc} + */ + public function mul(string $a, string $b) : string + { + return \bcmul($a, $b, 0); + } + + /** + * {@inheritdoc} + * + * @psalm-suppress InvalidNullableReturnType + * @psalm-suppress NullableReturnStatement + */ + public function divQ(string $a, string $b) : string + { + return \bcdiv($a, $b, 0); + } + + /** + * {@inheritdoc} + * + * @psalm-suppress InvalidNullableReturnType + * @psalm-suppress NullableReturnStatement + */ + public function divR(string $a, string $b) : string + { + if (version_compare(PHP_VERSION, '7.2') >= 0) { + return \bcmod($a, $b, 0); + } + + return \bcmod($a, $b); + } + + /** + * {@inheritdoc} + */ + public function divQR(string $a, string $b) : array + { + $q = \bcdiv($a, $b, 0); + + if (version_compare(PHP_VERSION, '7.2') >= 0) { + $r = \bcmod($a, $b, 0); + } else { + $r = \bcmod($a, $b); + } + + assert($q !== null); + assert($r !== null); + + return [$q, $r]; + } + + /** + * {@inheritdoc} + */ + public function pow(string $a, int $e) : string + { + return \bcpow($a, (string) $e, 0); + } + + /** + * {@inheritdoc} + * + * @psalm-suppress InvalidNullableReturnType + * @psalm-suppress NullableReturnStatement + */ + public function modPow(string $base, string $exp, string $mod) : string + { + return \bcpowmod($base, $exp, $mod, 0); + } + + /** + * {@inheritDoc} + * + * @psalm-suppress NullableReturnStatement + * @psalm-suppress InvalidNullableReturnType + */ + public function sqrt(string $n) : string + { + return \bcsqrt($n, 0); + } +} diff --git a/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php b/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php new file mode 100644 index 0000000..52d1880 --- /dev/null +++ b/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php @@ -0,0 +1,156 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Internal\Calculator; + +use Brick\Math\Internal\Calculator; + +/** + * Calculator implementation built around the GMP library. + * + * @internal + * + * @psalm-immutable + */ +class GmpCalculator extends Calculator +{ + /** + * {@inheritdoc} + */ + public function add(string $a, string $b) : string + { + return \gmp_strval(\gmp_add($a, $b)); + } + + /** + * {@inheritdoc} + */ + public function sub(string $a, string $b) : string + { + return \gmp_strval(\gmp_sub($a, $b)); + } + + /** + * {@inheritdoc} + */ + public function mul(string $a, string $b) : string + { + return \gmp_strval(\gmp_mul($a, $b)); + } + + /** + * {@inheritdoc} + */ + public function divQ(string $a, string $b) : string + { + return \gmp_strval(\gmp_div_q($a, $b)); + } + + /** + * {@inheritdoc} + */ + public function divR(string $a, string $b) : string + { + return \gmp_strval(\gmp_div_r($a, $b)); + } + + /** + * {@inheritdoc} + */ + public function divQR(string $a, string $b) : array + { + [$q, $r] = \gmp_div_qr($a, $b); + + return [ + \gmp_strval($q), + \gmp_strval($r) + ]; + } + + /** + * {@inheritdoc} + */ + public function pow(string $a, int $e) : string + { + return \gmp_strval(\gmp_pow($a, $e)); + } + + /** + * {@inheritdoc} + */ + public function modInverse(string $x, string $m) : ?string + { + $result = \gmp_invert($x, $m); + + if ($result === false) { + return null; + } + + return \gmp_strval($result); + } + + /** + * {@inheritdoc} + */ + public function modPow(string $base, string $exp, string $mod) : string + { + return \gmp_strval(\gmp_powm($base, $exp, $mod)); + } + + /** + * {@inheritdoc} + */ + public function gcd(string $a, string $b) : string + { + return \gmp_strval(\gmp_gcd($a, $b)); + } + + /** + * {@inheritdoc} + */ + public function fromBase(string $number, int $base) : string + { + return \gmp_strval(\gmp_init($number, $base)); + } + + /** + * {@inheritdoc} + */ + public function toBase(string $number, int $base) : string + { + return \gmp_strval($number, $base); + } + + /** + * {@inheritdoc} + */ + public function and(string $a, string $b) : string + { + return \gmp_strval(\gmp_and($a, $b)); + } + + /** + * {@inheritdoc} + */ + public function or(string $a, string $b) : string + { + return \gmp_strval(\gmp_or($a, $b)); + } + + /** + * {@inheritdoc} + */ + public function xor(string $a, string $b) : string + { + return \gmp_strval(\gmp_xor($a, $b)); + } + + /** + * {@inheritDoc} + */ + public function sqrt(string $n) : string + { + return \gmp_strval(\gmp_sqrt($n)); + } +} diff --git a/vendor/brick/math/src/Internal/Calculator/NativeCalculator.php b/vendor/brick/math/src/Internal/Calculator/NativeCalculator.php new file mode 100644 index 0000000..020a633 --- /dev/null +++ b/vendor/brick/math/src/Internal/Calculator/NativeCalculator.php @@ -0,0 +1,634 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math\Internal\Calculator; + +use Brick\Math\Internal\Calculator; + +/** + * Calculator implementation using only native PHP code. + * + * @internal + * + * @psalm-immutable + */ +class NativeCalculator extends Calculator +{ + /** + * The max number of digits the platform can natively add, subtract, multiply or divide without overflow. + * For multiplication, this represents the max sum of the lengths of both operands. + * + * For addition, it is assumed that an extra digit can hold a carry (1) without overflowing. + * Example: 32-bit: max number 1,999,999,999 (9 digits + carry) + * 64-bit: max number 1,999,999,999,999,999,999 (18 digits + carry) + * + * @var int + */ + private $maxDigits; + + /** + * Class constructor. + * + * @codeCoverageIgnore + */ + public function __construct() + { + switch (PHP_INT_SIZE) { + case 4: + $this->maxDigits = 9; + break; + + case 8: + $this->maxDigits = 18; + break; + + default: + throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.'); + } + } + + /** + * {@inheritdoc} + */ + public function add(string $a, string $b) : string + { + /** + * @psalm-var numeric-string $a + * @psalm-var numeric-string $b + */ + $result = $a + $b; + + if (is_int($result)) { + return (string) $result; + } + + if ($a === '0') { + return $b; + } + + if ($b === '0') { + return $a; + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $result = $aNeg === $bNeg ? $this->doAdd($aDig, $bDig) : $this->doSub($aDig, $bDig); + + if ($aNeg) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function sub(string $a, string $b) : string + { + return $this->add($a, $this->neg($b)); + } + + /** + * {@inheritdoc} + */ + public function mul(string $a, string $b) : string + { + /** + * @psalm-var numeric-string $a + * @psalm-var numeric-string $b + */ + $result = $a * $b; + + if (is_int($result)) { + return (string) $result; + } + + if ($a === '0' || $b === '0') { + return '0'; + } + + if ($a === '1') { + return $b; + } + + if ($b === '1') { + return $a; + } + + if ($a === '-1') { + return $this->neg($b); + } + + if ($b === '-1') { + return $this->neg($a); + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $result = $this->doMul($aDig, $bDig); + + if ($aNeg !== $bNeg) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function divQ(string $a, string $b) : string + { + return $this->divQR($a, $b)[0]; + } + + /** + * {@inheritdoc} + */ + public function divR(string $a, string $b): string + { + return $this->divQR($a, $b)[1]; + } + + /** + * {@inheritdoc} + */ + public function divQR(string $a, string $b) : array + { + if ($a === '0') { + return ['0', '0']; + } + + if ($a === $b) { + return ['1', '0']; + } + + if ($b === '1') { + return [$a, '0']; + } + + if ($b === '-1') { + return [$this->neg($a), '0']; + } + + /** @psalm-var numeric-string $a */ + $na = $a * 1; // cast to number + + if (is_int($na)) { + /** @psalm-var numeric-string $b */ + $nb = $b * 1; + + if (is_int($nb)) { + // the only division that may overflow is PHP_INT_MIN / -1, + // which cannot happen here as we've already handled a divisor of -1 above. + $r = $na % $nb; + $q = ($na - $r) / $nb; + + assert(is_int($q)); + + return [ + (string) $q, + (string) $r + ]; + } + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + [$q, $r] = $this->doDiv($aDig, $bDig); + + if ($aNeg !== $bNeg) { + $q = $this->neg($q); + } + + if ($aNeg) { + $r = $this->neg($r); + } + + return [$q, $r]; + } + + /** + * {@inheritdoc} + */ + public function pow(string $a, int $e) : string + { + if ($e === 0) { + return '1'; + } + + if ($e === 1) { + return $a; + } + + $odd = $e % 2; + $e -= $odd; + + $aa = $this->mul($a, $a); + + /** @psalm-suppress PossiblyInvalidArgument We're sure that $e / 2 is an int now */ + $result = $this->pow($aa, $e / 2); + + if ($odd === 1) { + $result = $this->mul($result, $a); + } + + return $result; + } + + /** + * Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/ + * + * {@inheritdoc} + */ + public function modPow(string $base, string $exp, string $mod) : string + { + // special case: the algorithm below fails with 0 power 0 mod 1 (returns 1 instead of 0) + if ($base === '0' && $exp === '0' && $mod === '1') { + return '0'; + } + + // special case: the algorithm below fails with power 0 mod 1 (returns 1 instead of 0) + if ($exp === '0' && $mod === '1') { + return '0'; + } + + $x = $base; + + $res = '1'; + + // numbers are positive, so we can use remainder instead of modulo + $x = $this->divR($x, $mod); + + while ($exp !== '0') { + if (in_array($exp[-1], ['1', '3', '5', '7', '9'])) { // odd + $res = $this->divR($this->mul($res, $x), $mod); + } + + $exp = $this->divQ($exp, '2'); + $x = $this->divR($this->mul($x, $x), $mod); + } + + return $res; + } + + /** + * Adapted from https://cp-algorithms.com/num_methods/roots_newton.html + * + * {@inheritDoc} + */ + public function sqrt(string $n) : string + { + if ($n === '0') { + return '0'; + } + + // initial approximation + $x = \str_repeat('9', \intdiv(\strlen($n), 2) ?: 1); + + $decreased = false; + + for (;;) { + $nx = $this->divQ($this->add($x, $this->divQ($n, $x)), '2'); + + if ($x === $nx || $this->cmp($nx, $x) > 0 && $decreased) { + break; + } + + $decreased = $this->cmp($nx, $x) < 0; + $x = $nx; + } + + return $x; + } + + /** + * Performs the addition of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doAdd(string $a, string $b) : string + { + [$a, $b, $length] = $this->pad($a, $b); + + $carry = 0; + $result = ''; + + for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) { + $blockLength = $this->maxDigits; + + if ($i < 0) { + $blockLength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + /** @psalm-var numeric-string $blockA */ + $blockA = \substr($a, $i, $blockLength); + + /** @psalm-var numeric-string $blockB */ + $blockB = \substr($b, $i, $blockLength); + + $sum = (string) ($blockA + $blockB + $carry); + $sumLength = \strlen($sum); + + if ($sumLength > $blockLength) { + $sum = \substr($sum, 1); + $carry = 1; + } else { + if ($sumLength < $blockLength) { + $sum = \str_repeat('0', $blockLength - $sumLength) . $sum; + } + $carry = 0; + } + + $result = $sum . $result; + + if ($i === 0) { + break; + } + } + + if ($carry === 1) { + $result = '1' . $result; + } + + return $result; + } + + /** + * Performs the subtraction of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doSub(string $a, string $b) : string + { + if ($a === $b) { + return '0'; + } + + // Ensure that we always subtract to a positive result: biggest minus smallest. + $cmp = $this->doCmp($a, $b); + + $invert = ($cmp === -1); + + if ($invert) { + $c = $a; + $a = $b; + $b = $c; + } + + [$a, $b, $length] = $this->pad($a, $b); + + $carry = 0; + $result = ''; + + $complement = 10 ** $this->maxDigits; + + for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) { + $blockLength = $this->maxDigits; + + if ($i < 0) { + $blockLength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + /** @psalm-var numeric-string $blockA */ + $blockA = \substr($a, $i, $blockLength); + + /** @psalm-var numeric-string $blockB */ + $blockB = \substr($b, $i, $blockLength); + + $sum = $blockA - $blockB - $carry; + + if ($sum < 0) { + $sum += $complement; + $carry = 1; + } else { + $carry = 0; + } + + $sum = (string) $sum; + $sumLength = \strlen($sum); + + if ($sumLength < $blockLength) { + $sum = \str_repeat('0', $blockLength - $sumLength) . $sum; + } + + $result = $sum . $result; + + if ($i === 0) { + break; + } + } + + // Carry cannot be 1 when the loop ends, as a > b + assert($carry === 0); + + $result = \ltrim($result, '0'); + + if ($invert) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * Performs the multiplication of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doMul(string $a, string $b) : string + { + $x = \strlen($a); + $y = \strlen($b); + + $maxDigits = \intdiv($this->maxDigits, 2); + $complement = 10 ** $maxDigits; + + $result = '0'; + + for ($i = $x - $maxDigits;; $i -= $maxDigits) { + $blockALength = $maxDigits; + + if ($i < 0) { + $blockALength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + $blockA = (int) \substr($a, $i, $blockALength); + + $line = ''; + $carry = 0; + + for ($j = $y - $maxDigits;; $j -= $maxDigits) { + $blockBLength = $maxDigits; + + if ($j < 0) { + $blockBLength += $j; + /** @psalm-suppress LoopInvalidation */ + $j = 0; + } + + $blockB = (int) \substr($b, $j, $blockBLength); + + $mul = $blockA * $blockB + $carry; + $value = $mul % $complement; + $carry = ($mul - $value) / $complement; + + $value = (string) $value; + $value = \str_pad($value, $maxDigits, '0', STR_PAD_LEFT); + + $line = $value . $line; + + if ($j === 0) { + break; + } + } + + if ($carry !== 0) { + $line = $carry . $line; + } + + $line = \ltrim($line, '0'); + + if ($line !== '') { + $line .= \str_repeat('0', $x - $blockALength - $i); + $result = $this->add($result, $line); + } + + if ($i === 0) { + break; + } + } + + return $result; + } + + /** + * Performs the division of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string[] The quotient and remainder. + */ + private function doDiv(string $a, string $b) : array + { + $cmp = $this->doCmp($a, $b); + + if ($cmp === -1) { + return ['0', $a]; + } + + $x = \strlen($a); + $y = \strlen($b); + + // we now know that a >= b && x >= y + + $q = '0'; // quotient + $r = $a; // remainder + $z = $y; // focus length, always $y or $y+1 + + for (;;) { + $focus = \substr($a, 0, $z); + + $cmp = $this->doCmp($focus, $b); + + if ($cmp === -1) { + if ($z === $x) { // remainder < dividend + break; + } + + $z++; + } + + $zeros = \str_repeat('0', $x - $z); + + $q = $this->add($q, '1' . $zeros); + $a = $this->sub($a, $b . $zeros); + + $r = $a; + + if ($r === '0') { // remainder == 0 + break; + } + + $x = \strlen($a); + + if ($x < $y) { // remainder < dividend + break; + } + + $z = $y; + } + + return [$q, $r]; + } + + /** + * Compares two non-signed large numbers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return int [-1, 0, 1] + */ + private function doCmp(string $a, string $b) : int + { + $x = \strlen($a); + $y = \strlen($b); + + $cmp = $x <=> $y; + + if ($cmp !== 0) { + return $cmp; + } + + return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1] + } + + /** + * Pads the left of one of the given numbers with zeros if necessary to make both numbers the same length. + * + * The numbers must only consist of digits, without leading minus sign. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return array{string, string, int} + */ + private function pad(string $a, string $b) : array + { + $x = \strlen($a); + $y = \strlen($b); + + if ($x > $y) { + $b = \str_repeat('0', $x - $y) . $b; + + return [$a, $b, $x]; + } + + if ($x < $y) { + $a = \str_repeat('0', $y - $x) . $a; + + return [$a, $b, $y]; + } + + return [$a, $b, $x]; + } +} diff --git a/vendor/brick/math/src/RoundingMode.php b/vendor/brick/math/src/RoundingMode.php new file mode 100644 index 0000000..06936d8 --- /dev/null +++ b/vendor/brick/math/src/RoundingMode.php @@ -0,0 +1,107 @@ +<?php + +declare(strict_types=1); + +namespace Brick\Math; + +/** + * Specifies a rounding behavior for numerical operations capable of discarding precision. + * + * Each rounding mode indicates how the least significant returned digit of a rounded result + * is to be calculated. If fewer digits are returned than the digits needed to represent the + * exact numerical result, the discarded digits will be referred to as the discarded fraction + * regardless the digits' contribution to the value of the number. In other words, considered + * as a numerical value, the discarded fraction could have an absolute value greater than one. + */ +final class RoundingMode +{ + /** + * Private constructor. This class is not instantiable. + * + * @codeCoverageIgnore + */ + private function __construct() + { + } + + /** + * Asserts that the requested operation has an exact result, hence no rounding is necessary. + * + * If this rounding mode is specified on an operation that yields a result that + * cannot be represented at the requested scale, a RoundingNecessaryException is thrown. + */ + public const UNNECESSARY = 0; + + /** + * Rounds away from zero. + * + * Always increments the digit prior to a nonzero discarded fraction. + * Note that this rounding mode never decreases the magnitude of the calculated value. + */ + public const UP = 1; + + /** + * Rounds towards zero. + * + * Never increments the digit prior to a discarded fraction (i.e., truncates). + * Note that this rounding mode never increases the magnitude of the calculated value. + */ + public const DOWN = 2; + + /** + * Rounds towards positive infinity. + * + * If the result is positive, behaves as for UP; if negative, behaves as for DOWN. + * Note that this rounding mode never decreases the calculated value. + */ + public const CEILING = 3; + + /** + * Rounds towards negative infinity. + * + * If the result is positive, behave as for DOWN; if negative, behave as for UP. + * Note that this rounding mode never increases the calculated value. + */ + public const FLOOR = 4; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up. + * + * Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN. + * Note that this is the rounding mode commonly taught at school. + */ + public const HALF_UP = 5; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down. + * + * Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN. + */ + public const HALF_DOWN = 6; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity. + * + * If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN. + */ + public const HALF_CEILING = 7; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity. + * + * If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP. + */ + public const HALF_FLOOR = 8; + + /** + * Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor. + * + * Behaves as for HALF_UP if the digit to the left of the discarded fraction is odd; + * behaves as for HALF_DOWN if it's even. + * + * Note that this is the rounding mode that statistically minimizes + * cumulative error when applied repeatedly over a sequence of calculations. + * It is sometimes known as "Banker's rounding", and is chiefly used in the USA. + */ + public const HALF_EVEN = 9; +} diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php new file mode 100644 index 0000000..7824d8f --- /dev/null +++ b/vendor/composer/ClassLoader.php @@ -0,0 +1,579 @@ +<?php + +/* + * This file is part of Composer. + * + * (c) Nils Adermann <naderman@naderman.de> + * Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Jordi Boggiano <j.boggiano@seld.be> + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array<string, array<string, int>> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array<string, list<string>> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list<string> + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array<string, array<string, list<string>>> + */ + private $prefixesPsr0 = array(); + /** + * @var list<string> + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array<string, string> + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array<string, bool> + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array<string, self> + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array<string, list<string>> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array<string, list<string>> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list<string> + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list<string> + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array<string, string> Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array<string, string> $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list<string>|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list<string>|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list<string>|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list<string>|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array<string, self> + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..51e734a --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,359 @@ +<?php + +/* + * This file is part of Composer. + * + * (c) Nils Adermann <naderman@naderman.de> + * Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list<string> + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list<string> + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } + + return $installed; + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..a16ffbd --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,16 @@ +<?php + +// autoload_classmap.php @generated by Composer + +$vendorDir = dirname(__DIR__); +$baseDir = dirname($vendorDir); + +return array( + 'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', + 'lessc' => $vendorDir . '/wikimedia/less.php/lessc.inc.php', +); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100644 index 0000000..39e9a0d --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,17 @@ +<?php + +// autoload_files.php @generated by Composer + +$vendorDir = dirname(__DIR__); +$baseDir = dirname($vendorDir); + +return array( + 'a2c78434f64e5f5ed402f42eee19c025' => $vendorDir . '/ipl/stdlib/src/functions_include.php', + '6076de347104821999fcfc82c8f19bc5' => $vendorDir . '/ipl/i18n/src/functions_include.php', + '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + 'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php', + 'ad155f8f1cf0d418fe49e248db8c661b' => $vendorDir . '/react/promise/src/functions_include.php', + '8e4ccce73649a2b516ec3b4571432da5' => $vendorDir . '/ipl/scheduler/src/register_cron_aliases.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..999a6d0 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,11 @@ +<?php + +// autoload_namespaces.php @generated by Composer + +$vendorDir = dirname(__DIR__); +$baseDir = dirname($vendorDir); + +return array( + 'Less' => array($vendorDir . '/wikimedia/less.php/lib'), + 'AssetLoader' => array($baseDir . '/'), +); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php new file mode 100644 index 0000000..54a21a1 --- /dev/null +++ b/vendor/composer/autoload_psr4.php @@ -0,0 +1,34 @@ +<?php + +// autoload_psr4.php @generated by Composer + +$vendorDir = dirname(__DIR__); +$baseDir = dirname($vendorDir); + +return array( + 'ipl\\Web\\' => array($vendorDir . '/ipl/web/src'), + 'ipl\\Validator\\' => array($vendorDir . '/ipl/validator/src'), + 'ipl\\Stdlib\\' => array($vendorDir . '/ipl/stdlib/src'), + 'ipl\\Sql\\' => array($vendorDir . '/ipl/sql/src'), + 'ipl\\Scheduler\\' => array($vendorDir . '/ipl/scheduler/src'), + 'ipl\\Orm\\' => array($vendorDir . '/ipl/orm/src'), + 'ipl\\I18n\\' => array($vendorDir . '/ipl/i18n/src'), + 'ipl\\Html\\' => array($vendorDir . '/ipl/html/src'), + 'cweagans\\Composer\\' => array($vendorDir . '/cweagans/composer-patches/src'), + 'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), + 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), + 'Recurr\\' => array($vendorDir . '/simshaun/recurr/src/Recurr'), + 'React\\Promise\\' => array($vendorDir . '/react/promise/src'), + 'React\\EventLoop\\' => array($vendorDir . '/react/event-loop/src'), + 'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'), + 'Ramsey\\Collection\\' => array($vendorDir . '/ramsey/collection/src'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), + 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'), + 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), + 'Evenement\\' => array($vendorDir . '/evenement/evenement/src'), + 'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'), + 'Doctrine\\Common\\Collections\\' => array($vendorDir . '/doctrine/collections/lib/Doctrine/Common/Collections'), + 'Cron\\' => array($vendorDir . '/dragonmantank/cron-expression/src/Cron'), + 'Brick\\Math\\' => array($vendorDir . '/brick/math/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000..1bde463 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,50 @@ +<?php + +// autoload_real.php @generated by Composer + +class ComposerAutoloaderInit35fbfdaec6c999686b0d3ca7c10db905 +{ + private static $loader; + + public static function loadClassLoader($class) + { + if ('Composer\Autoload\ClassLoader' === $class) { + require __DIR__ . '/ClassLoader.php'; + } + } + + /** + * @return \Composer\Autoload\ClassLoader + */ + public static function getLoader() + { + if (null !== self::$loader) { + return self::$loader; + } + + require __DIR__ . '/platform_check.php'; + + spl_autoload_register(array('ComposerAutoloaderInit35fbfdaec6c999686b0d3ca7c10db905', 'loadClassLoader'), true, true); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); + spl_autoload_unregister(array('ComposerAutoloaderInit35fbfdaec6c999686b0d3ca7c10db905', 'loadClassLoader')); + + require __DIR__ . '/autoload_static.php'; + call_user_func(\Composer\Autoload\ComposerStaticInit35fbfdaec6c999686b0d3ca7c10db905::getInitializer($loader)); + + $loader->register(true); + + $filesToLoad = \Composer\Autoload\ComposerStaticInit35fbfdaec6c999686b0d3ca7c10db905::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); + } + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000..464f848 --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,222 @@ +<?php + +// autoload_static.php @generated by Composer + +namespace Composer\Autoload; + +class ComposerStaticInit35fbfdaec6c999686b0d3ca7c10db905 +{ + public static $files = array ( + 'a2c78434f64e5f5ed402f42eee19c025' => __DIR__ . '/..' . '/ipl/stdlib/src/functions_include.php', + '6076de347104821999fcfc82c8f19bc5' => __DIR__ . '/..' . '/ipl/i18n/src/functions_include.php', + '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + 'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php', + 'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php', + '8e4ccce73649a2b516ec3b4571432da5' => __DIR__ . '/..' . '/ipl/scheduler/src/register_cron_aliases.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'i' => + array ( + 'ipl\\Web\\' => 8, + 'ipl\\Validator\\' => 14, + 'ipl\\Stdlib\\' => 11, + 'ipl\\Sql\\' => 8, + 'ipl\\Scheduler\\' => 14, + 'ipl\\Orm\\' => 8, + 'ipl\\I18n\\' => 9, + 'ipl\\Html\\' => 9, + ), + 'c' => + array ( + 'cweagans\\Composer\\' => 18, + ), + 'W' => + array ( + 'Webmozart\\Assert\\' => 17, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Php80\\' => 23, + 'Symfony\\Polyfill\\Ctype\\' => 23, + ), + 'R' => + array ( + 'Recurr\\' => 7, + 'React\\Promise\\' => 14, + 'React\\EventLoop\\' => 16, + 'Ramsey\\Uuid\\' => 12, + 'Ramsey\\Collection\\' => 18, + ), + 'P' => + array ( + 'Psr\\Log\\' => 8, + 'Psr\\Http\\Message\\' => 17, + ), + 'G' => + array ( + 'GuzzleHttp\\Psr7\\' => 16, + ), + 'E' => + array ( + 'Evenement\\' => 10, + ), + 'D' => + array ( + 'Doctrine\\Deprecations\\' => 22, + 'Doctrine\\Common\\Collections\\' => 28, + ), + 'C' => + array ( + 'Cron\\' => 5, + ), + 'B' => + array ( + 'Brick\\Math\\' => 11, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'ipl\\Web\\' => + array ( + 0 => __DIR__ . '/..' . '/ipl/web/src', + ), + 'ipl\\Validator\\' => + array ( + 0 => __DIR__ . '/..' . '/ipl/validator/src', + ), + 'ipl\\Stdlib\\' => + array ( + 0 => __DIR__ . '/..' . '/ipl/stdlib/src', + ), + 'ipl\\Sql\\' => + array ( + 0 => __DIR__ . '/..' . '/ipl/sql/src', + ), + 'ipl\\Scheduler\\' => + array ( + 0 => __DIR__ . '/..' . '/ipl/scheduler/src', + ), + 'ipl\\Orm\\' => + array ( + 0 => __DIR__ . '/..' . '/ipl/orm/src', + ), + 'ipl\\I18n\\' => + array ( + 0 => __DIR__ . '/..' . '/ipl/i18n/src', + ), + 'ipl\\Html\\' => + array ( + 0 => __DIR__ . '/..' . '/ipl/html/src', + ), + 'cweagans\\Composer\\' => + array ( + 0 => __DIR__ . '/..' . '/cweagans/composer-patches/src', + ), + 'Webmozart\\Assert\\' => + array ( + 0 => __DIR__ . '/..' . '/webmozart/assert/src', + ), + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), + 'Symfony\\Polyfill\\Ctype\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', + ), + 'Recurr\\' => + array ( + 0 => __DIR__ . '/..' . '/simshaun/recurr/src/Recurr', + ), + 'React\\Promise\\' => + array ( + 0 => __DIR__ . '/..' . '/react/promise/src', + ), + 'React\\EventLoop\\' => + array ( + 0 => __DIR__ . '/..' . '/react/event-loop/src', + ), + 'Ramsey\\Uuid\\' => + array ( + 0 => __DIR__ . '/..' . '/ramsey/uuid/src', + ), + 'Ramsey\\Collection\\' => + array ( + 0 => __DIR__ . '/..' . '/ramsey/collection/src', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', + ), + 'Psr\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-message/src', + 1 => __DIR__ . '/..' . '/psr/http-factory/src', + ), + 'GuzzleHttp\\Psr7\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', + ), + 'Evenement\\' => + array ( + 0 => __DIR__ . '/..' . '/evenement/evenement/src', + ), + 'Doctrine\\Deprecations\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations', + ), + 'Doctrine\\Common\\Collections\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/collections/lib/Doctrine/Common/Collections', + ), + 'Cron\\' => + array ( + 0 => __DIR__ . '/..' . '/dragonmantank/cron-expression/src/Cron', + ), + 'Brick\\Math\\' => + array ( + 0 => __DIR__ . '/..' . '/brick/math/src', + ), + ); + + public static $prefixesPsr0 = array ( + 'L' => + array ( + 'Less' => + array ( + 0 => __DIR__ . '/..' . '/wikimedia/less.php/lib', + ), + ), + 'A' => + array ( + 'AssetLoader' => + array ( + 0 => __DIR__ . '/../..' . '/', + ), + ), + ); + + public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', + 'lessc' => __DIR__ . '/..' . '/wikimedia/less.php/lessc.inc.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit35fbfdaec6c999686b0d3ca7c10db905::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit35fbfdaec6c999686b0d3ca7c10db905::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit35fbfdaec6c999686b0d3ca7c10db905::$prefixesPsr0; + $loader->classMap = ComposerStaticInit35fbfdaec6c999686b0d3ca7c10db905::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..c1fbdde --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,1855 @@ +{ + "packages": [ + { + "name": "brick/math", + "version": "0.9.3", + "version_normalized": "0.9.3.0", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "vimeo/psalm": "4.9.2" + }, + "time": "2021-08-15T20:50:18+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "brick", + "math" + ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.9.3" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/brick/math", + "type": "tidelift" + } + ], + "install-path": "../brick/math" + }, + { + "name": "cweagans/composer-patches", + "version": "1.7.3", + "version_normalized": "1.7.3.0", + "source": { + "type": "git", + "url": "https://github.com/cweagans/composer-patches.git", + "reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/e190d4466fe2b103a55467dfa83fc2fecfcaf2db", + "reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.3.0" + }, + "require-dev": { + "composer/composer": "~1.0 || ~2.0", + "phpunit/phpunit": "~4.6" + }, + "time": "2022-12-20T22:53:13+00:00", + "type": "composer-plugin", + "extra": { + "class": "cweagans\\Composer\\Patches" + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "cweagans\\Composer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Cameron Eagans", + "email": "me@cweagans.net" + } + ], + "description": "Provides a way to patch Composer packages.", + "support": { + "issues": "https://github.com/cweagans/composer-patches/issues", + "source": "https://github.com/cweagans/composer-patches/tree/1.7.3" + }, + "install-path": "../cweagans/composer-patches" + }, + { + "name": "doctrine/collections", + "version": "1.8.0", + "version_normalized": "1.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "2b44dd4cbca8b5744327de78bafef5945c7e7b5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/2b44dd4cbca8b5744327de78bafef5945c7e7b5e", + "reference": "2b44dd4cbca8b5744327de78bafef5945c7e7b5e", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^0.5.3 || ^1", + "php": "^7.1.3 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0 || ^10.0", + "phpstan/phpstan": "^1.4.8", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.1.5", + "vimeo/psalm": "^4.22" + }, + "time": "2022-09-01T20:12:10+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/collections/issues", + "source": "https://github.com/doctrine/collections/tree/1.8.0" + }, + "install-path": "../doctrine/collections" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.2", + "version_normalized": "1.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "time": "2023-09-27T20:04:15+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.2" + }, + "install-path": "../doctrine/deprecations" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.3.3", + "version_normalized": "3.3.3.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "webmozart/assert": "^1.0" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-webmozart-assert": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0" + }, + "time": "2023-08-10T19:36:49+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "install-path": "../dragonmantank/cron-expression" + }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "version_normalized": "3.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "time": "2023-08-08T05:53:35+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "install-path": "../evenement/evenement" + }, + { + "name": "fortawesome/font-awesome", + "version": "6.4.2", + "version_normalized": "6.4.2.0", + "source": { + "type": "git", + "url": "https://github.com/FortAwesome/Font-Awesome.git", + "reference": "f0c25837a3fe0e03783b939559e088abcbfb3c4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FortAwesome/Font-Awesome/zipball/f0c25837a3fe0e03783b939559e088abcbfb3c4b", + "reference": "f0c25837a3fe0e03783b939559e088abcbfb3c4b", + "shasum": "" + }, + "time": "2023-08-02T20:27:06+00:00", + "type": "library", + "installation-source": "dist", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "CC-BY-4.0", + "OFL-1.1", + "MIT" + ], + "authors": [ + { + "name": "The Font Awesome Team", + "homepage": "https://github.com/orgs/FortAwesome/people" + } + ], + "description": "The iconic font, CSS, and SVG framework", + "homepage": "https://fontawesome.com", + "keywords": [ + "FontAwesome", + "awesome", + "bootstrap", + "font", + "icon", + "svg" + ], + "support": { + "docs": "http://fontawesome.com/docs", + "email": "hello@fontawesome.com", + "issues": "https://github.com/FortAwesome/Font-Awesome/issues", + "source": "https://github.com/FortAwesome/Font-Awesome" + }, + "install-path": "../fortawesome/font-awesome" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.6.1", + "version_normalized": "2.6.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "time": "2023-08-27T10:13:57+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/psr7" + }, + { + "name": "ipl/html", + "version": "v0.8.0", + "version_normalized": "0.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/Icinga/ipl-html.git", + "reference": "ad522bfd34521d4deb147e99e19a6dbf22bc15d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Icinga/ipl-html/zipball/ad522bfd34521d4deb147e99e19a6dbf22bc15d1", + "reference": "ad522bfd34521d4deb147e99e19a6dbf22bc15d1", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "guzzlehttp/psr7": "^2.5", + "ipl/stdlib": ">=0.12.0", + "ipl/validator": ">=0.5.0", + "php": ">=7.2", + "psr/http-message": "^1.1" + }, + "require-dev": { + "ipl/stdlib": "dev-main", + "ipl/validator": "dev-main" + }, + "time": "2023-09-01T14:05:28+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ipl\\Html\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Icinga PHP Library - HTML abstraction layer", + "homepage": "https://github.com/Icinga/ipl-html", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/Icinga/ipl-html/issues", + "source": "https://github.com/Icinga/ipl-html/tree/v0.8.0" + }, + "install-path": "../ipl/html" + }, + { + "name": "ipl/i18n", + "version": "v0.2.1", + "version_normalized": "0.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Icinga/ipl-i18n.git", + "reference": "9803bdd30be1780736a9e0102c41caaf61bcf709" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Icinga/ipl-i18n/zipball/9803bdd30be1780736a9e0102c41caaf61bcf709", + "reference": "9803bdd30be1780736a9e0102c41caaf61bcf709", + "shasum": "" + }, + "require": { + "ext-gettext": "*", + "ext-intl": "*", + "ipl/stdlib": ">=0.12.0", + "php": ">=7.2" + }, + "require-dev": { + "ipl/stdlib": "dev-main" + }, + "time": "2023-08-30T14:13:46+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "ipl\\I18n\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Icinga PHP Library - Internationalization", + "homepage": "https://github.com/Icinga/ipl-i18n", + "keywords": [ + "gettext", + "i18n", + "internationalization", + "localization", + "translation" + ], + "support": { + "issues": "https://github.com/Icinga/ipl-i18n/issues", + "source": "https://github.com/Icinga/ipl-i18n/tree/v0.2.1" + }, + "install-path": "../ipl/i18n" + }, + { + "name": "ipl/orm", + "version": "v0.6.0", + "version_normalized": "0.6.0.0", + "source": { + "type": "git", + "url": "https://github.com/Icinga/ipl-orm.git", + "reference": "ed6d9374c9d72a5dd0bc15ec725f7926bf1853e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Icinga/ipl-orm/zipball/ed6d9374c9d72a5dd0bc15ec725f7926bf1853e0", + "reference": "ed6d9374c9d72a5dd0bc15ec725f7926bf1853e0", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "ipl/sql": ">=0.7.0", + "ipl/stdlib": ">=0.12.0", + "php": ">=7.2" + }, + "require-dev": { + "ext-pdo_sqlite": "*", + "ipl/sql": "dev-main", + "ipl/stdlib": "dev-main" + }, + "time": "2023-09-21T08:27:51+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ipl\\Orm\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Icinga PHP Library - ORM", + "homepage": "https://github.com/Icinga/ipl-orm", + "keywords": [ + "database", + "orm", + "sql" + ], + "support": { + "issues": "https://github.com/Icinga/ipl-orm/issues", + "source": "https://github.com/Icinga/ipl-orm/tree/v0.6.0" + }, + "install-path": "../ipl/orm" + }, + { + "name": "ipl/scheduler", + "version": "v0.1.2", + "version_normalized": "0.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/Icinga/ipl-scheduler.git", + "reference": "6119afdea07b1390bd728e350e0d80b26ec8d6ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Icinga/ipl-scheduler/zipball/6119afdea07b1390bd728e350e0d80b26ec8d6ba", + "reference": "6119afdea07b1390bd728e350e0d80b26ec8d6ba", + "shasum": "" + }, + "require": { + "dragonmantank/cron-expression": "^3", + "ext-json": "*", + "ipl/stdlib": ">=0.12.0", + "php": ">=7.2", + "psr/log": "^1", + "ramsey/uuid": "^4.2.3", + "react/event-loop": "^1.4", + "react/promise": "^2.10", + "simshaun/recurr": "^5" + }, + "require-dev": { + "ipl/stdlib": "dev-main" + }, + "suggest": { + "ext-ev": "Improves performance, efficiency and avoids system limitations. Highly recommended! (See https://www.php.net/manual/en/intro.ev.php for details)" + }, + "time": "2023-08-30T14:14:23+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/register_cron_aliases.php" + ], + "psr-4": { + "ipl\\Scheduler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Icinga PHP Library - Tasks scheduler", + "homepage": "https://github.com/Icinga/ipl-scheduler", + "keywords": [ + "cron", + "job", + "scheduler", + "task" + ], + "support": { + "issues": "https://github.com/Icinga/ipl-scheduler/issues", + "source": "https://github.com/Icinga/ipl-scheduler/tree/v0.1.2" + }, + "install-path": "../ipl/scheduler" + }, + { + "name": "ipl/sql", + "version": "v0.7.0", + "version_normalized": "0.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/Icinga/ipl-sql.git", + "reference": "abcecf3987cec49c57f63f5a51383806408124db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Icinga/ipl-sql/zipball/abcecf3987cec49c57f63f5a51383806408124db", + "reference": "abcecf3987cec49c57f63f5a51383806408124db", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "ipl/stdlib": ">=0.12.0", + "php": ">=7.2" + }, + "require-dev": { + "ipl/stdlib": "dev-main" + }, + "time": "2023-08-30T14:13:28+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ipl\\Sql\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Icinga PHP Library - SQL abstraction layer", + "homepage": "https://github.com/Icinga/ipl-sql", + "keywords": [ + "database", + "sql" + ], + "support": { + "issues": "https://github.com/Icinga/ipl-sql/issues", + "source": "https://github.com/Icinga/ipl-sql/tree/v0.7.0" + }, + "install-path": "../ipl/sql" + }, + { + "name": "ipl/stdlib", + "version": "v0.13.0", + "version_normalized": "0.13.0.0", + "source": { + "type": "git", + "url": "https://github.com/Icinga/ipl-stdlib.git", + "reference": "1150af1155df4fddbd9d8ea3c06e9e5258fdb034" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Icinga/ipl-stdlib/zipball/1150af1155df4fddbd9d8ea3c06e9e5258fdb034", + "reference": "1150af1155df4fddbd9d8ea3c06e9e5258fdb034", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0.1", + "ext-openssl": "*", + "php": ">=7.2" + }, + "time": "2023-09-01T14:09:22+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "ipl\\Stdlib\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "ipl Standard Library", + "support": { + "issues": "https://github.com/Icinga/ipl-stdlib/issues", + "source": "https://github.com/Icinga/ipl-stdlib/tree/v0.13.0" + }, + "install-path": "../ipl/stdlib" + }, + { + "name": "ipl/validator", + "version": "v0.5.0", + "version_normalized": "0.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/Icinga/ipl-validator.git", + "reference": "a601fae0ed330e63cea50e4a2a6659ca1ad97bde" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Icinga/ipl-validator/zipball/a601fae0ed330e63cea50e4a2a6659ca1ad97bde", + "reference": "a601fae0ed330e63cea50e4a2a6659ca1ad97bde", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-openssl": "*", + "ipl/i18n": ">=0.2.0", + "ipl/stdlib": ">=0.12.0", + "php": ">=7.2", + "psr/http-message": "~1.0" + }, + "require-dev": { + "guzzlehttp/psr7": "^1" + }, + "time": "2023-03-21T15:59:00+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ipl\\Validator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Icinga PHP Library - Common validators and validator chaining", + "homepage": "https://github.com/Icinga/ipl-validator", + "support": { + "issues": "https://github.com/Icinga/ipl-validator/issues", + "source": "https://github.com/Icinga/ipl-validator/tree/v0.5.0" + }, + "install-path": "../ipl/validator" + }, + { + "name": "ipl/web", + "version": "v0.9.1", + "version_normalized": "0.9.1.0", + "source": { + "type": "git", + "url": "https://github.com/Icinga/ipl-web.git", + "reference": "1168bff7c995719659018b9b141d01c35c63224f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Icinga/ipl-web/zipball/1168bff7c995719659018b9b141d01c35c63224f", + "reference": "1168bff7c995719659018b9b141d01c35c63224f", + "shasum": "" + }, + "require": { + "ext-json": "*", + "fortawesome/font-awesome": "^6", + "ipl/html": ">=0.8.0", + "ipl/i18n": ">=0.2.0", + "ipl/orm": ">=0.5.2", + "ipl/scheduler": ">=0.1.0", + "ipl/stdlib": ">=0.13.0", + "php": ">=7.2", + "psr/http-message": "^1.1", + "wikimedia/less.php": "^3.2.1" + }, + "require-dev": { + "ipl/html": "dev-main", + "ipl/i18n": "dev-main", + "ipl/orm": "dev-main", + "ipl/scheduler": "dev-main", + "ipl/stdlib": "dev-main", + "shardj/zf1-future": "^1.22" + }, + "time": "2023-10-17T13:10:38+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ipl\\Web\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Icinga PHP Library - Web Components", + "homepage": "https://github.com/Icinga/ipl-web", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/Icinga/ipl-web/issues", + "source": "https://github.com/Icinga/ipl-web/tree/v0.9.1" + }, + "install-path": "../ipl/web" + }, + { + "name": "psr/http-factory", + "version": "1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "e616d01114759c4c489f93b099585439f795fe35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "time": "2023-04-10T20:10:41+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + }, + "install-path": "../psr/http-factory" + }, + { + "name": "psr/http-message", + "version": "1.1", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "time": "2023-04-04T09:50:52+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "install-path": "../psr/http-message" + }, + { + "name": "psr/log", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2021-05-03T11:20:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "install-path": "../psr/log" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "install-path": "../ralouphie/getallheaders" + }, + { + "name": "ramsey/collection", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "ab2237657ad99667a5143e32ba2683c8029563d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/ab2237657ad99667a5143e32ba2683c8029563d4", + "reference": "ab2237657ad99667a5143e32ba2683c8029563d4", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8" + }, + "require-dev": { + "captainhook/captainhook": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "ergebnis/composer-normalize": "^2.6", + "fakerphp/faker": "^1.5", + "hamcrest/hamcrest-php": "^2", + "jangregor/phpstan-prophecy": "^0.8", + "mockery/mockery": "^1.3", + "phpstan/extension-installer": "^1", + "phpstan/phpstan": "^0.12.32", + "phpstan/phpstan-mockery": "^0.12.5", + "phpstan/phpstan-phpunit": "^0.12.11", + "phpunit/phpunit": "^8.5 || ^9", + "psy/psysh": "^0.10.4", + "slevomat/coding-standard": "^6.3", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.4" + }, + "time": "2021-07-30T00:58:27+00:00", + "type": "library", + "extra": { + "patches_applied": { + "Collection: Add PHP 8.1 support": "patches/ramsey-collection.patch" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP 7.2+ library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/1.1.4" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", + "type": "tidelift" + } + ], + "install-path": "../ramsey/collection" + }, + { + "name": "ramsey/uuid", + "version": "4.2.3", + "version_normalized": "4.2.3.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "shasum": "" + }, + "require": { + "brick/math": "^0.8 || ^0.9", + "ext-json": "*", + "php": "^7.2 || ^8.0", + "ramsey/collection": "^1.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php80": "^1.14" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.8", + "ergebnis/composer-normalize": "^2.15", + "mockery/mockery": "^1.3", + "moontoast/math": "^1.1", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", + "php-mock/php-mock-mockery": "^1.3", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-mockery": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-ctype": "Enables faster processing of character classification using ctype functions.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "time": "2021-09-25T23:10:38+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.2.3" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "install-path": "../ramsey/uuid" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "version_normalized": "1.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "time": "2023-11-13T13:48:05+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "install-path": "../react/event-loop" + }, + { + "name": "react/promise", + "version": "v2.10.0", + "version_normalized": "2.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", + "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" + }, + "time": "2023-05-02T15:15:43+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v2.10.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "install-path": "../react/promise" + }, + { + "name": "simshaun/recurr", + "version": "v5.0.2", + "version_normalized": "5.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/simshaun/recurr.git", + "reference": "1aff62e6e0ee875b3f2487352542605123ee9172" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simshaun/recurr/zipball/1aff62e6e0ee875b3f2487352542605123ee9172", + "reference": "1aff62e6e0ee875b3f2487352542605123ee9172", + "shasum": "" + }, + "require": { + "doctrine/collections": "~1.6||^2.0", + "php": "^7.2||^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.16", + "symfony/yaml": "^5.3" + }, + "time": "2023-09-26T20:31:33+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Recurr\\": "src/Recurr/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Shaun Simmons", + "email": "shaun@shaun.pub", + "homepage": "https://shaun.pub" + } + ], + "description": "PHP library for working with recurrence rules", + "homepage": "https://github.com/simshaun/recurr", + "keywords": [ + "dates", + "events", + "recurrence", + "recurring", + "rrule" + ], + "support": { + "issues": "https://github.com/simshaun/recurr/issues", + "source": "https://github.com/simshaun/recurr/tree/v5.0.2" + }, + "install-path": "../simshaun/recurr" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.28.0", + "version_normalized": "1.28.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "time": "2023-01-26T09:26:14+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-ctype" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.28.0", + "version_normalized": "1.28.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2023-01-26T09:26:14+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php80" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "version_normalized": "1.11.0.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "time": "2022-06-03T18:03:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "install-path": "../webmozart/assert" + }, + { + "name": "wikimedia/less.php", + "version": "v3.2.1", + "version_normalized": "3.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/wikimedia/less.php.git", + "reference": "0d5b30ba792bdbf8991a646fc9c30561b38a5559" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wikimedia/less.php/zipball/0d5b30ba792bdbf8991a646fc9c30561b38a5559", + "reference": "0d5b30ba792bdbf8991a646fc9c30561b38a5559", + "shasum": "" + }, + "require": { + "php": ">=7.2.9" + }, + "require-dev": { + "mediawiki/mediawiki-codesniffer": "40.0.1", + "mediawiki/mediawiki-phan-config": "0.12.0", + "mediawiki/minus-x": "1.1.1", + "php-parallel-lint/php-console-highlighter": "1.0.0", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpunit/phpunit": "^8.5" + }, + "time": "2023-02-03T06:43:41+00:00", + "bin": [ + "bin/lessc" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Less": "lib/" + }, + "classmap": [ + "lessc.inc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Timo Tijhof", + "homepage": "https://timotijhof.net" + }, + { + "name": "Josh Schmidt", + "homepage": "https://github.com/oyejorge" + }, + { + "name": "Matt Agar", + "homepage": "https://github.com/agar" + }, + { + "name": "Martin Jantošovič", + "homepage": "https://github.com/Mordred" + } + ], + "description": "PHP port of the LESS processor", + "homepage": "https://gerrit.wikimedia.org/g/mediawiki/libs/less.php", + "keywords": [ + "css", + "less", + "less.js", + "lesscss", + "php", + "stylesheet" + ], + "support": { + "issues": "https://github.com/wikimedia/less.php/issues", + "source": "https://github.com/wikimedia/less.php/tree/v3.2.1" + }, + "install-path": "../wikimedia/less.php" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 0000000..40b832b --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,308 @@ +<?php return array( + 'root' => array( + 'name' => 'icinga/icinga-php-library', + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => '42dff4b0f6279dfd058ef71fce1de5557eb50b07', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + 'brick/math' => array( + 'pretty_version' => '0.9.3', + 'version' => '0.9.3.0', + 'reference' => 'ca57d18f028f84f777b2168cd1911b0dee2343ae', + 'type' => 'library', + 'install_path' => __DIR__ . '/../brick/math', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'cweagans/composer-patches' => array( + 'pretty_version' => '1.7.3', + 'version' => '1.7.3.0', + 'reference' => 'e190d4466fe2b103a55467dfa83fc2fecfcaf2db', + 'type' => 'composer-plugin', + 'install_path' => __DIR__ . '/../cweagans/composer-patches', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/collections' => array( + 'pretty_version' => '1.8.0', + 'version' => '1.8.0.0', + 'reference' => '2b44dd4cbca8b5744327de78bafef5945c7e7b5e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/collections', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/deprecations' => array( + 'pretty_version' => '1.1.2', + 'version' => '1.1.2.0', + 'reference' => '4f2d4f2836e7ec4e7a8625e75c6aa916004db931', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/deprecations', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'dragonmantank/cron-expression' => array( + 'pretty_version' => 'v3.3.3', + 'version' => '3.3.3.0', + 'reference' => 'adfb1f505deb6384dc8b39804c5065dd3c8c8c0a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../dragonmantank/cron-expression', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'evenement/evenement' => array( + 'pretty_version' => 'v3.0.2', + 'version' => '3.0.2.0', + 'reference' => '0a16b0d71ab13284339abb99d9d2bd813640efbc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../evenement/evenement', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'fortawesome/font-awesome' => array( + 'pretty_version' => '6.4.2', + 'version' => '6.4.2.0', + 'reference' => 'f0c25837a3fe0e03783b939559e088abcbfb3c4b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../fortawesome/font-awesome', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/psr7' => array( + 'pretty_version' => '2.6.1', + 'version' => '2.6.1.0', + 'reference' => 'be45764272e8873c72dbe3d2edcfdfcc3bc9f727', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/psr7', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'icinga/icinga-php-library' => array( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => '42dff4b0f6279dfd058ef71fce1de5557eb50b07', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ipl/html' => array( + 'pretty_version' => 'v0.8.0', + 'version' => '0.8.0.0', + 'reference' => 'ad522bfd34521d4deb147e99e19a6dbf22bc15d1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ipl/html', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ipl/i18n' => array( + 'pretty_version' => 'v0.2.1', + 'version' => '0.2.1.0', + 'reference' => '9803bdd30be1780736a9e0102c41caaf61bcf709', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ipl/i18n', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ipl/orm' => array( + 'pretty_version' => 'v0.6.0', + 'version' => '0.6.0.0', + 'reference' => 'ed6d9374c9d72a5dd0bc15ec725f7926bf1853e0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ipl/orm', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ipl/scheduler' => array( + 'pretty_version' => 'v0.1.2', + 'version' => '0.1.2.0', + 'reference' => '6119afdea07b1390bd728e350e0d80b26ec8d6ba', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ipl/scheduler', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ipl/sql' => array( + 'pretty_version' => 'v0.7.0', + 'version' => '0.7.0.0', + 'reference' => 'abcecf3987cec49c57f63f5a51383806408124db', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ipl/sql', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ipl/stdlib' => array( + 'pretty_version' => 'v0.13.0', + 'version' => '0.13.0.0', + 'reference' => '1150af1155df4fddbd9d8ea3c06e9e5258fdb034', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ipl/stdlib', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ipl/validator' => array( + 'pretty_version' => 'v0.5.0', + 'version' => '0.5.0.0', + 'reference' => 'a601fae0ed330e63cea50e4a2a6659ca1ad97bde', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ipl/validator', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ipl/web' => array( + 'pretty_version' => 'v0.9.1', + 'version' => '0.9.1.0', + 'reference' => '1168bff7c995719659018b9b141d01c35c63224f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ipl/web', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'mtdowling/cron-expression' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '^1.0', + ), + ), + 'psr/http-factory' => array( + 'pretty_version' => '1.0.2', + 'version' => '1.0.2.0', + 'reference' => 'e616d01114759c4c489f93b099585439f795fe35', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-factory', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-factory-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/http-message' => array( + 'pretty_version' => '1.1', + 'version' => '1.1.0.0', + 'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-message', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-message-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/log' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ralouphie/getallheaders' => array( + 'pretty_version' => '3.0.3', + 'version' => '3.0.3.0', + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ralouphie/getallheaders', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ramsey/collection' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'reference' => 'ab2237657ad99667a5143e32ba2683c8029563d4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ramsey/collection', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ramsey/uuid' => array( + 'pretty_version' => '4.2.3', + 'version' => '4.2.3.0', + 'reference' => 'fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ramsey/uuid', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'react/event-loop' => array( + 'pretty_version' => 'v1.5.0', + 'version' => '1.5.0.0', + 'reference' => 'bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354', + 'type' => 'library', + 'install_path' => __DIR__ . '/../react/event-loop', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'react/promise' => array( + 'pretty_version' => 'v2.10.0', + 'version' => '2.10.0.0', + 'reference' => 'f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38', + 'type' => 'library', + 'install_path' => __DIR__ . '/../react/promise', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rhumsaa/uuid' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '4.2.3', + ), + ), + 'simshaun/recurr' => array( + 'pretty_version' => 'v5.0.2', + 'version' => '5.0.2.0', + 'reference' => '1aff62e6e0ee875b3f2487352542605123ee9172', + 'type' => 'library', + 'install_path' => __DIR__ . '/../simshaun/recurr', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-ctype' => array( + 'pretty_version' => 'v1.28.0', + 'version' => '1.28.0.0', + 'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.28.0', + 'version' => '1.28.0.0', + 'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'webmozart/assert' => array( + 'pretty_version' => '1.11.0', + 'version' => '1.11.0.0', + 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', + 'type' => 'library', + 'install_path' => __DIR__ . '/../webmozart/assert', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'wikimedia/less.php' => array( + 'pretty_version' => 'v3.2.1', + 'version' => '3.2.1.0', + 'reference' => '0d5b30ba792bdbf8991a646fc9c30561b38a5559', + 'type' => 'library', + 'install_path' => __DIR__ . '/../wikimedia/less.php', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 0000000..5da86a6 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ +<?php + +// platform_check.php @generated by Composer + +$issues = array(); + +if (!(PHP_VERSION_ID >= 70209)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.9". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/cweagans/composer-patches/composer.json b/vendor/cweagans/composer-patches/composer.json new file mode 100644 index 0000000..1565b02 --- /dev/null +++ b/vendor/cweagans/composer-patches/composer.json @@ -0,0 +1,30 @@ +{ + "name": "cweagans/composer-patches", + "description": "Provides a way to patch Composer packages.", + "minimum-stability": "dev", + "license": "BSD-3-Clause", + "type": "composer-plugin", + "extra": { + "class": "cweagans\\Composer\\Patches" + }, + "authors": [ + { + "name": "Cameron Eagans", + "email": "me@cweagans.net" + } + ], + "require": { + "php": ">=5.3.0", + "composer-plugin-api": "^1.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "~1.0 || ~2.0", + "phpunit/phpunit": "~4.6" + }, + "autoload": { + "psr-4": {"cweagans\\Composer\\": "src"} + }, + "autoload-dev": { + "psr-4": {"cweagans\\Composer\\Tests\\": "tests"} + } +} diff --git a/vendor/cweagans/composer-patches/src/PatchEvent.php b/vendor/cweagans/composer-patches/src/PatchEvent.php new file mode 100644 index 0000000..31d36f8 --- /dev/null +++ b/vendor/cweagans/composer-patches/src/PatchEvent.php @@ -0,0 +1,70 @@ +<?php + +/** + * @file + * Dispatch events when patches are applied. + */ + +namespace cweagans\Composer; + +use Composer\EventDispatcher\Event; +use Composer\Package\PackageInterface; + +class PatchEvent extends Event { + + /** + * @var PackageInterface $package + */ + protected $package; + /** + * @var string $url + */ + protected $url; + /** + * @var string $description + */ + protected $description; + + /** + * Constructs a PatchEvent object. + * + * @param string $eventName + * @param PackageInterface $package + * @param string $url + * @param string $description + */ + public function __construct($eventName, PackageInterface $package, $url, $description) { + parent::__construct($eventName); + $this->package = $package; + $this->url = $url; + $this->description = $description; + } + + /** + * Returns the package that is patched. + * + * @return PackageInterface + */ + public function getPackage() { + return $this->package; + } + + /** + * Returns the url of the patch. + * + * @return string + */ + public function getUrl() { + return $this->url; + } + + /** + * Returns the description of the patch. + * + * @return string + */ + public function getDescription() { + return $this->description; + } + +} diff --git a/vendor/cweagans/composer-patches/src/PatchEvents.php b/vendor/cweagans/composer-patches/src/PatchEvents.php new file mode 100644 index 0000000..ecee947 --- /dev/null +++ b/vendor/cweagans/composer-patches/src/PatchEvents.php @@ -0,0 +1,30 @@ +<?php + +/** + * @file + * Dispatch events when patches are applied. + */ + +namespace cweagans\Composer; + +class PatchEvents { + + /** + * The PRE_PATCH_APPLY event occurs before a patch is applied. + * + * The event listener method receives a cweagans\Composer\PatchEvent instance. + * + * @var string + */ + const PRE_PATCH_APPLY = 'pre-patch-apply'; + + /** + * The POST_PATCH_APPLY event occurs after a patch is applied. + * + * The event listener method receives a cweagans\Composer\PatchEvent instance. + * + * @var string + */ + const POST_PATCH_APPLY = 'post-patch-apply'; + +} diff --git a/vendor/cweagans/composer-patches/src/Patches.php b/vendor/cweagans/composer-patches/src/Patches.php new file mode 100644 index 0000000..3d7d864 --- /dev/null +++ b/vendor/cweagans/composer-patches/src/Patches.php @@ -0,0 +1,599 @@ +<?php + +/** + * @file + * Provides a way to patch Composer packages after installation. + */ + +namespace cweagans\Composer; + +use Composer\Composer; +use Composer\DependencyResolver\Operation\InstallOperation; +use Composer\DependencyResolver\Operation\UninstallOperation; +use Composer\DependencyResolver\Operation\UpdateOperation; +use Composer\DependencyResolver\Operation\OperationInterface; +use Composer\EventDispatcher\EventSubscriberInterface; +use Composer\IO\IOInterface; +use Composer\Package\AliasPackage; +use Composer\Package\PackageInterface; +use Composer\Plugin\PluginInterface; +use Composer\Installer\PackageEvents; +use Composer\Script\Event; +use Composer\Script\ScriptEvents; +use Composer\Installer\PackageEvent; +use Composer\Util\ProcessExecutor; +use Composer\Util\RemoteFilesystem; +use Symfony\Component\Process\Process; + +class Patches implements PluginInterface, EventSubscriberInterface { + + /** + * @var Composer $composer + */ + protected $composer; + /** + * @var IOInterface $io + */ + protected $io; + /** + * @var EventDispatcher $eventDispatcher + */ + protected $eventDispatcher; + /** + * @var ProcessExecutor $executor + */ + protected $executor; + /** + * @var array $patches + */ + protected $patches; + + /** + * @var array $installedPatches + */ + protected $installedPatches; + + /** + * Apply plugin modifications to composer + * + * @param Composer $composer + * @param IOInterface $io + */ + public function activate(Composer $composer, IOInterface $io) { + $this->composer = $composer; + $this->io = $io; + $this->eventDispatcher = $composer->getEventDispatcher(); + $this->executor = new ProcessExecutor($this->io); + $this->patches = array(); + $this->installedPatches = array(); + } + + /** + * Returns an array of event names this subscriber wants to listen to. + */ + public static function getSubscribedEvents() { + return array( + ScriptEvents::PRE_INSTALL_CMD => array('checkPatches'), + ScriptEvents::PRE_UPDATE_CMD => array('checkPatches'), + PackageEvents::PRE_PACKAGE_INSTALL => array('gatherPatches'), + PackageEvents::PRE_PACKAGE_UPDATE => array('gatherPatches'), + // The following is a higher weight for compatibility with + // https://github.com/AydinHassan/magento-core-composer-installer and more generally for compatibility with + // every Composer plugin which deploys downloaded packages to other locations. + // In such cases you want that those plugins deploy patched files so they have to run after + // the "composer-patches" plugin. + // @see: https://github.com/cweagans/composer-patches/pull/153 + PackageEvents::POST_PACKAGE_INSTALL => array('postInstall', 10), + PackageEvents::POST_PACKAGE_UPDATE => array('postInstall', 10), + ); + } + + /** + * Before running composer install, + * @param Event $event + */ + public function checkPatches(Event $event) { + if (!$this->isPatchingEnabled()) { + return; + } + + try { + $repositoryManager = $this->composer->getRepositoryManager(); + $localRepository = $repositoryManager->getLocalRepository(); + $installationManager = $this->composer->getInstallationManager(); + $packages = $localRepository->getPackages(); + + $extra = $this->composer->getPackage()->getExtra(); + $patches_ignore = isset($extra['patches-ignore']) ? $extra['patches-ignore'] : array(); + + $tmp_patches = $this->grabPatches(); + foreach ($packages as $package) { + $extra = $package->getExtra(); + if (isset($extra['patches'])) { + if (isset($patches_ignore[$package->getName()])) { + foreach ($patches_ignore[$package->getName()] as $package_name => $patches) { + if (isset($extra['patches'][$package_name])) { + $extra['patches'][$package_name] = array_diff($extra['patches'][$package_name], $patches); + } + } + } + $this->installedPatches[$package->getName()] = $extra['patches']; + } + $patches = isset($extra['patches']) ? $extra['patches'] : array(); + $tmp_patches = $this->arrayMergeRecursiveDistinct($tmp_patches, $patches); + } + + if ($tmp_patches == FALSE) { + $this->io->write('<info>No patches supplied.</info>'); + return; + } + + // Remove packages for which the patch set has changed. + $promises = array(); + foreach ($packages as $package) { + if (!($package instanceof AliasPackage)) { + $package_name = $package->getName(); + $extra = $package->getExtra(); + $has_patches = isset($tmp_patches[$package_name]); + $has_applied_patches = isset($extra['patches_applied']) && count($extra['patches_applied']) > 0; + if (($has_patches && !$has_applied_patches) + || (!$has_patches && $has_applied_patches) + || ($has_patches && $has_applied_patches && $tmp_patches[$package_name] !== $extra['patches_applied'])) { + $uninstallOperation = new UninstallOperation($package, 'Removing package so it can be re-installed and re-patched.'); + $this->io->write('<info>Removing package ' . $package_name . ' so that it can be re-installed and re-patched.</info>'); + $promises[] = $installationManager->uninstall($localRepository, $uninstallOperation); + } + } + } + $promises = array_filter($promises); + if ($promises) { + $this->composer->getLoop()->wait($promises); + } + } + // If the Locker isn't available, then we don't need to do this. + // It's the first time packages have been installed. + catch (\LogicException $e) { + return; + } + } + + /** + * Gather patches from dependencies and store them for later use. + * + * @param PackageEvent $event + */ + public function gatherPatches(PackageEvent $event) { + // If we've already done this, then don't do it again. + if (isset($this->patches['_patchesGathered'])) { + $this->io->write('<info>Patches already gathered. Skipping</info>', TRUE, IOInterface::VERBOSE); + return; + } + // If patching has been disabled, bail out here. + elseif (!$this->isPatchingEnabled()) { + $this->io->write('<info>Patching is disabled. Skipping.</info>', TRUE, IOInterface::VERBOSE); + return; + } + + $this->patches = $this->grabPatches(); + if (empty($this->patches)) { + $this->io->write('<info>No patches supplied.</info>'); + } + + $extra = $this->composer->getPackage()->getExtra(); + $patches_ignore = isset($extra['patches-ignore']) ? $extra['patches-ignore'] : array(); + + // Now add all the patches from dependencies that will be installed. + $operations = $event->getOperations(); + $this->io->write('<info>Gathering patches for dependencies. This might take a minute.</info>'); + foreach ($operations as $operation) { + if ($operation instanceof InstallOperation || $operation instanceof UpdateOperation) { + $package = $this->getPackageFromOperation($operation); + $extra = $package->getExtra(); + if (isset($extra['patches'])) { + if (isset($patches_ignore[$package->getName()])) { + foreach ($patches_ignore[$package->getName()] as $package_name => $patches) { + if (isset($extra['patches'][$package_name])) { + $extra['patches'][$package_name] = array_diff($extra['patches'][$package_name], $patches); + } + } + } + $this->patches = $this->arrayMergeRecursiveDistinct($this->patches, $extra['patches']); + } + // Unset installed patches for this package + if(isset($this->installedPatches[$package->getName()])) { + unset($this->installedPatches[$package->getName()]); + } + } + } + + // Merge installed patches from dependencies that did not receive an update. + foreach ($this->installedPatches as $patches) { + $this->patches = $this->arrayMergeRecursiveDistinct($this->patches, $patches); + } + + // If we're in verbose mode, list the projects we're going to patch. + if ($this->io->isVerbose()) { + foreach ($this->patches as $package => $patches) { + $number = count($patches); + $this->io->write('<info>Found ' . $number . ' patches for ' . $package . '.</info>'); + } + } + + // Make sure we don't gather patches again. Extra keys in $this->patches + // won't hurt anything, so we'll just stash it there. + $this->patches['_patchesGathered'] = TRUE; + } + + /** + * Get the patches from root composer or external file + * @return Patches + * @throws \Exception + */ + public function grabPatches() { + // First, try to get the patches from the root composer.json. + $extra = $this->composer->getPackage()->getExtra(); + if (isset($extra['patches'])) { + $this->io->write('<info>Gathering patches for root package.</info>'); + $patches = $extra['patches']; + return $patches; + } + // If it's not specified there, look for a patches-file definition. + elseif (isset($extra['patches-file'])) { + $this->io->write('<info>Gathering patches from patch file.</info>'); + $patches = file_get_contents($extra['patches-file']); + $patches = json_decode($patches, TRUE); + $error = json_last_error(); + if ($error != 0) { + switch ($error) { + case JSON_ERROR_DEPTH: + $msg = ' - Maximum stack depth exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + $msg = ' - Underflow or the modes mismatch'; + break; + case JSON_ERROR_CTRL_CHAR: + $msg = ' - Unexpected control character found'; + break; + case JSON_ERROR_SYNTAX: + $msg = ' - Syntax error, malformed JSON'; + break; + case JSON_ERROR_UTF8: + $msg = ' - Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + default: + $msg = ' - Unknown error'; + break; + } + throw new \Exception('There was an error in the supplied patches file:' . $msg); + } + if (isset($patches['patches'])) { + $patches = $patches['patches']; + return $patches; + } + elseif(!$patches) { + throw new \Exception('There was an error in the supplied patch file'); + } + } + else { + return array(); + } + } + + /** + * @param PackageEvent $event + * @throws \Exception + */ + public function postInstall(PackageEvent $event) { + + // Check if we should exit in failure. + $extra = $this->composer->getPackage()->getExtra(); + $exitOnFailure = getenv('COMPOSER_EXIT_ON_PATCH_FAILURE') || !empty($extra['composer-exit-on-patch-failure']); + $skipReporting = getenv('COMPOSER_PATCHES_SKIP_REPORTING') || !empty($extra['composer-patches-skip-reporting']); + + // Get the package object for the current operation. + $operation = $event->getOperation(); + /** @var PackageInterface $package */ + $package = $this->getPackageFromOperation($operation); + $package_name = $package->getName(); + + if (!isset($this->patches[$package_name])) { + if ($this->io->isVerbose()) { + $this->io->write('<info>No patches found for ' . $package_name . '.</info>'); + } + return; + } + $this->io->write(' - Applying patches for <info>' . $package_name . '</info>'); + + // Get the install path from the package object. + $manager = $event->getComposer()->getInstallationManager(); + $install_path = $manager->getInstaller($package->getType())->getInstallPath($package); + + // Set up a downloader. + $downloader = new RemoteFilesystem($this->io, $this->composer->getConfig()); + + // Track applied patches in the package info in installed.json + $localRepository = $this->composer->getRepositoryManager()->getLocalRepository(); + $localPackage = $localRepository->findPackage($package_name, $package->getVersion()); + $extra = $localPackage->getExtra(); + $extra['patches_applied'] = array(); + + foreach ($this->patches[$package_name] as $description => $url) { + $this->io->write(' <info>' . $url . '</info> (<comment>' . $description. '</comment>)'); + try { + $this->eventDispatcher->dispatch(NULL, new PatchEvent(PatchEvents::PRE_PATCH_APPLY, $package, $url, $description)); + $this->getAndApplyPatch($downloader, $install_path, $url, $package); + $this->eventDispatcher->dispatch(NULL, new PatchEvent(PatchEvents::POST_PATCH_APPLY, $package, $url, $description)); + $extra['patches_applied'][$description] = $url; + } + catch (\Exception $e) { + $this->io->write(' <error>Could not apply patch! Skipping. The error was: ' . $e->getMessage() . '</error>'); + if ($exitOnFailure) { + throw new \Exception("Cannot apply patch $description ($url)!"); + } + } + } + $localPackage->setExtra($extra); + + $this->io->write(''); + + if (true !== $skipReporting) { + $this->writePatchReport($this->patches[$package_name], $install_path); + } + } + + /** + * Get a Package object from an OperationInterface object. + * + * @param OperationInterface $operation + * @return PackageInterface + * @throws \Exception + */ + protected function getPackageFromOperation(OperationInterface $operation) { + if ($operation instanceof InstallOperation) { + $package = $operation->getPackage(); + } + elseif ($operation instanceof UpdateOperation) { + $package = $operation->getTargetPackage(); + } + else { + throw new \Exception('Unknown operation: ' . get_class($operation)); + } + + return $package; + } + + /** + * Apply a patch on code in the specified directory. + * + * @param RemoteFilesystem $downloader + * @param $install_path + * @param $patch_url + * @param PackageInterface $package + * @throws \Exception + */ + protected function getAndApplyPatch(RemoteFilesystem $downloader, $install_path, $patch_url, PackageInterface $package) { + + // Local patch file. + if (file_exists($patch_url)) { + $filename = realpath($patch_url); + } + else { + // Generate random (but not cryptographically so) filename. + $filename = uniqid(sys_get_temp_dir().'/') . ".patch"; + + // Download file from remote filesystem to this location. + $hostname = parse_url($patch_url, PHP_URL_HOST); + + try { + $downloader->copy($hostname, $patch_url, $filename, false); + } catch (\Exception $e) { + // In case of an exception, retry once as the download might + // have failed due to intermittent network issues. + $downloader->copy($hostname, $patch_url, $filename, false); + } + } + + // The order here is intentional. p1 is most likely to apply with git apply. + // p0 is next likely. p2 is extremely unlikely, but for some special cases, + // it might be useful. p4 is useful for Magento 2 patches + $patch_levels = array('-p1', '-p0', '-p2', '-p4'); + + // Check for specified patch level for this package. + $extra = $this->composer->getPackage()->getExtra(); + if (!empty($extra['patchLevel'][$package->getName()])){ + $patch_levels = array($extra['patchLevel'][$package->getName()]); + } + // Attempt to apply with git apply. + $patched = $this->applyPatchWithGit($install_path, $patch_levels, $filename); + + // In some rare cases, git will fail to apply a patch, fallback to using + // the 'patch' command. + if (!$patched) { + foreach ($patch_levels as $patch_level) { + // --no-backup-if-mismatch here is a hack that fixes some + // differences between how patch works on windows and unix. + if ($patched = $this->executeCommand("patch %s --no-backup-if-mismatch -d %s < %s", $patch_level, $install_path, $filename)) { + break; + } + } + } + + // Clean up the temporary patch file. + if (isset($hostname)) { + unlink($filename); + } + // If the patch *still* isn't applied, then give up and throw an Exception. + // Otherwise, let the user know it worked. + if (!$patched) { + throw new \Exception("Cannot apply patch $patch_url"); + } + } + + /** + * Checks if the root package enables patching. + * + * @return bool + * Whether patching is enabled. Defaults to TRUE. + */ + protected function isPatchingEnabled() { + $extra = $this->composer->getPackage()->getExtra(); + + if (empty($extra['patches']) && empty($extra['patches-ignore']) && !isset($extra['patches-file'])) { + // The root package has no patches of its own, so only allow patching if + // it has specifically opted in. + return isset($extra['enable-patching']) ? $extra['enable-patching'] : FALSE; + } + else { + return TRUE; + } + } + + /** + * Writes a patch report to the target directory. + * + * @param array $patches + * @param string $directory + */ + protected function writePatchReport($patches, $directory) { + $output = "This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches)\n"; + $output .= "Patches applied to this directory:\n\n"; + foreach ($patches as $description => $url) { + $output .= $description . "\n"; + $output .= 'Source: ' . $url . "\n\n\n"; + } + file_put_contents($directory . "/PATCHES.txt", $output); + } + + /** + * Executes a shell command with escaping. + * + * @param string $cmd + * @return bool + */ + protected function executeCommand($cmd) { + // Shell-escape all arguments except the command. + $args = func_get_args(); + foreach ($args as $index => $arg) { + if ($index !== 0) { + $args[$index] = escapeshellarg($arg); + } + } + + // And replace the arguments. + $command = call_user_func_array('sprintf', $args); + $output = ''; + if ($this->io->isVerbose()) { + $this->io->write('<comment>' . $command . '</comment>'); + $io = $this->io; + $output = function ($type, $data) use ($io) { + if ($type == Process::ERR) { + $io->write('<error>' . $data . '</error>'); + } + else { + $io->write('<comment>' . $data . '</comment>'); + } + }; + } + return ($this->executor->execute($command, $output) == 0); + } + + /** + * Recursively merge arrays without changing data types of values. + * + * Does not change the data types of the values in the arrays. Matching keys' + * values in the second array overwrite those in the first array, as is the + * case with array_merge. + * + * @param array $array1 + * The first array. + * @param array $array2 + * The second array. + * @return array + * The merged array. + * + * @see http://php.net/manual/en/function.array-merge-recursive.php#92195 + */ + protected function arrayMergeRecursiveDistinct(array $array1, array $array2) { + $merged = $array1; + + foreach ($array2 as $key => &$value) { + if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { + $merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value); + } + else { + $merged[$key] = $value; + } + } + + return $merged; + } + + /** + * Attempts to apply a patch with git apply. + * + * @param $install_path + * @param $patch_levels + * @param $filename + * + * @return bool + * TRUE if patch was applied, FALSE otherwise. + */ + protected function applyPatchWithGit($install_path, $patch_levels, $filename) { + // Do not use git apply unless the install path is itself a git repo + // @see https://stackoverflow.com/a/27283285 + if (!is_dir($install_path . '/.git')) { + return FALSE; + } + + $patched = FALSE; + foreach ($patch_levels as $patch_level) { + if ($this->io->isVerbose()) { + $comment = 'Testing ability to patch with git apply.'; + $comment .= ' This command may produce errors that can be safely ignored.'; + $this->io->write('<comment>' . $comment . '</comment>'); + } + $checked = $this->executeCommand('git -C %s apply --check -v %s %s', $install_path, $patch_level, $filename); + $output = $this->executor->getErrorOutput(); + if (substr($output, 0, 7) == 'Skipped') { + // Git will indicate success but silently skip patches in some scenarios. + // + // @see https://github.com/cweagans/composer-patches/pull/165 + $checked = FALSE; + } + if ($checked) { + // Apply the first successful style. + $patched = $this->executeCommand('git -C %s apply %s %s', $install_path, $patch_level, $filename); + break; + } + } + return $patched; + } + + /** + * Indicates if a package has been patched. + * + * @param \Composer\Package\PackageInterface $package + * The package to check. + * + * @return bool + * TRUE if the package has been patched. + */ + public static function isPackagePatched(PackageInterface $package) { + return array_key_exists('patches_applied', $package->getExtra()); + } + + /** + * {@inheritDoc} + */ + public function deactivate(Composer $composer, IOInterface $io) + { + } + + /** + * {@inheritDoc} + */ + public function uninstall(Composer $composer, IOInterface $io) + { + } + +} diff --git a/vendor/doctrine/collections/.doctrine-project.json b/vendor/doctrine/collections/.doctrine-project.json new file mode 100644 index 0000000..9c89e50 --- /dev/null +++ b/vendor/doctrine/collections/.doctrine-project.json @@ -0,0 +1,32 @@ +{ + "active": true, + "name": "Collections", + "slug": "collections", + "docsSlug": "doctrine-collections", + "versions": [ + { + "name": "2.0", + "branchName": "2.0.x", + "slug": "latest", + "upcoming": true + }, + { + "name": "1.8", + "branchName": "1.8.x", + "slug": "1.8", + "upcoming": true + }, + { + "name": "1.7", + "branchName": "1.7.x", + "slug": "1.7", + "current": true + }, + { + "name": "1.6", + "branchName": "1.6.x", + "slug": "1.6", + "maintained": false + } + ] +} diff --git a/vendor/doctrine/collections/LICENSE b/vendor/doctrine/collections/LICENSE new file mode 100644 index 0000000..5e781fc --- /dev/null +++ b/vendor/doctrine/collections/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2013 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/collections/composer.json b/vendor/doctrine/collections/composer.json new file mode 100644 index 0000000..d9422dd --- /dev/null +++ b/vendor/doctrine/collections/composer.json @@ -0,0 +1,61 @@ +{ + "name": "doctrine/collections", + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "license": "MIT", + "type": "library", + "keywords": [ + "php", + "collections", + "array", + "iterators" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "require": { + "php": "^7.1.3 || ^8.0", + "doctrine/deprecations": "^0.5.3 || ^1" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0 || ^10.0", + "phpstan/phpstan": "^1.4.8", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.1.5", + "vimeo/psalm": "^4.22" + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "autoload-dev": { + "psr-4": { + "Doctrine\\Tests\\": "tests/Doctrine/Tests" + } + }, + "config": { + "allow-plugins": { + "composer/package-versions-deprecated": true, + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php new file mode 100644 index 0000000..baab4d5 --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php @@ -0,0 +1,389 @@ +<?php + +namespace Doctrine\Common\Collections; + +use Closure; +use LogicException; +use ReturnTypeWillChange; +use Traversable; + +/** + * Lazy collection that is backed by a concrete collection + * + * @psalm-template TKey of array-key + * @psalm-template T + * @template-implements Collection<TKey,T> + */ +abstract class AbstractLazyCollection implements Collection +{ + /** + * The backed collection to use + * + * @psalm-var Collection<TKey,T>|null + * @var Collection<mixed>|null + */ + protected $collection; + + /** @var bool */ + protected $initialized = false; + + /** + * {@inheritDoc} + * + * @return int + */ + #[ReturnTypeWillChange] + public function count() + { + $this->initialize(); + + return $this->collection->count(); + } + + /** + * {@inheritDoc} + */ + public function add($element) + { + $this->initialize(); + + return $this->collection->add($element); + } + + /** + * {@inheritDoc} + */ + public function clear() + { + $this->initialize(); + $this->collection->clear(); + } + + /** + * {@inheritDoc} + * + * @template TMaybeContained + */ + public function contains($element) + { + $this->initialize(); + + return $this->collection->contains($element); + } + + /** + * {@inheritDoc} + */ + public function isEmpty() + { + $this->initialize(); + + return $this->collection->isEmpty(); + } + + /** + * {@inheritDoc} + */ + public function remove($key) + { + $this->initialize(); + + return $this->collection->remove($key); + } + + /** + * {@inheritDoc} + */ + public function removeElement($element) + { + $this->initialize(); + + return $this->collection->removeElement($element); + } + + /** + * {@inheritDoc} + */ + public function containsKey($key) + { + $this->initialize(); + + return $this->collection->containsKey($key); + } + + /** + * {@inheritDoc} + */ + public function get($key) + { + $this->initialize(); + + return $this->collection->get($key); + } + + /** + * {@inheritDoc} + */ + public function getKeys() + { + $this->initialize(); + + return $this->collection->getKeys(); + } + + /** + * {@inheritDoc} + */ + public function getValues() + { + $this->initialize(); + + return $this->collection->getValues(); + } + + /** + * {@inheritDoc} + */ + public function set($key, $value) + { + $this->initialize(); + $this->collection->set($key, $value); + } + + /** + * {@inheritDoc} + */ + public function toArray() + { + $this->initialize(); + + return $this->collection->toArray(); + } + + /** + * {@inheritDoc} + */ + public function first() + { + $this->initialize(); + + return $this->collection->first(); + } + + /** + * {@inheritDoc} + */ + public function last() + { + $this->initialize(); + + return $this->collection->last(); + } + + /** + * {@inheritDoc} + */ + public function key() + { + $this->initialize(); + + return $this->collection->key(); + } + + /** + * {@inheritDoc} + */ + public function current() + { + $this->initialize(); + + return $this->collection->current(); + } + + /** + * {@inheritDoc} + */ + public function next() + { + $this->initialize(); + + return $this->collection->next(); + } + + /** + * {@inheritDoc} + */ + public function exists(Closure $p) + { + $this->initialize(); + + return $this->collection->exists($p); + } + + /** + * {@inheritDoc} + */ + public function filter(Closure $p) + { + $this->initialize(); + + return $this->collection->filter($p); + } + + /** + * {@inheritDoc} + */ + public function forAll(Closure $p) + { + $this->initialize(); + + return $this->collection->forAll($p); + } + + /** + * {@inheritDoc} + */ + public function map(Closure $func) + { + $this->initialize(); + + return $this->collection->map($func); + } + + /** + * {@inheritDoc} + */ + public function partition(Closure $p) + { + $this->initialize(); + + return $this->collection->partition($p); + } + + /** + * {@inheritDoc} + * + * @template TMaybeContained + */ + public function indexOf($element) + { + $this->initialize(); + + return $this->collection->indexOf($element); + } + + /** + * {@inheritDoc} + */ + public function slice($offset, $length = null) + { + $this->initialize(); + + return $this->collection->slice($offset, $length); + } + + /** + * {@inheritDoc} + * + * @return Traversable<int|string, mixed> + * @psalm-return Traversable<TKey,T> + */ + #[ReturnTypeWillChange] + public function getIterator() + { + $this->initialize(); + + return $this->collection->getIterator(); + } + + /** + * @param TKey $offset + * + * @return bool + */ + #[ReturnTypeWillChange] + public function offsetExists($offset) + { + $this->initialize(); + + return $this->collection->offsetExists($offset); + } + + /** + * @param TKey $offset + * + * @return mixed + */ + #[ReturnTypeWillChange] + public function offsetGet($offset) + { + $this->initialize(); + + return $this->collection->offsetGet($offset); + } + + /** + * @param TKey|null $offset + * @param T $value + * + * @return void + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + $this->initialize(); + $this->collection->offsetSet($offset, $value); + } + + /** + * @param TKey $offset + * + * @return void + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset) + { + $this->initialize(); + $this->collection->offsetUnset($offset); + } + + /** + * Is the lazy collection already initialized? + * + * @return bool + * + * @psalm-assert-if-true Collection<TKey,T> $this->collection + */ + public function isInitialized() + { + return $this->initialized; + } + + /** + * Initialize the collection + * + * @return void + * + * @psalm-assert Collection<TKey,T> $this->collection + */ + protected function initialize() + { + if ($this->initialized) { + return; + } + + $this->doInitialize(); + $this->initialized = true; + + if ($this->collection === null) { + throw new LogicException('You must initialize the collection property in the doInitialize() method.'); + } + } + + /** + * Do the initialization logic + * + * @return void + */ + abstract protected function doInitialize(); +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php new file mode 100644 index 0000000..186f6ec --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php @@ -0,0 +1,466 @@ +<?php + +namespace Doctrine\Common\Collections; + +use ArrayIterator; +use Closure; +use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor; +use ReturnTypeWillChange; +use Traversable; + +use function array_filter; +use function array_key_exists; +use function array_keys; +use function array_map; +use function array_reverse; +use function array_search; +use function array_slice; +use function array_values; +use function count; +use function current; +use function end; +use function in_array; +use function key; +use function next; +use function reset; +use function spl_object_hash; +use function uasort; + +use const ARRAY_FILTER_USE_BOTH; + +/** + * An ArrayCollection is a Collection implementation that wraps a regular PHP array. + * + * Warning: Using (un-)serialize() on a collection is not a supported use-case + * and may break when we change the internals in the future. If you need to + * serialize a collection use {@link toArray()} and reconstruct the collection + * manually. + * + * @psalm-template TKey of array-key + * @psalm-template T + * @template-implements Collection<TKey,T> + * @template-implements Selectable<TKey,T> + * @psalm-consistent-constructor + */ +class ArrayCollection implements Collection, Selectable +{ + /** + * An array containing the entries of this collection. + * + * @psalm-var array<TKey,T> + * @var mixed[] + */ + private $elements; + + /** + * Initializes a new ArrayCollection. + * + * @param array $elements + * @psalm-param array<TKey,T> $elements + */ + public function __construct(array $elements = []) + { + $this->elements = $elements; + } + + /** + * {@inheritDoc} + */ + public function toArray() + { + return $this->elements; + } + + /** + * {@inheritDoc} + */ + public function first() + { + return reset($this->elements); + } + + /** + * Creates a new instance from the specified elements. + * + * This method is provided for derived classes to specify how a new + * instance should be created when constructor semantics have changed. + * + * @param array $elements Elements. + * @psalm-param array<K,V> $elements + * + * @return static + * @psalm-return static<K,V> + * + * @psalm-template K of array-key + * @psalm-template V + */ + protected function createFrom(array $elements) + { + return new static($elements); + } + + /** + * {@inheritDoc} + */ + public function last() + { + return end($this->elements); + } + + /** + * {@inheritDoc} + */ + public function key() + { + return key($this->elements); + } + + /** + * {@inheritDoc} + */ + public function next() + { + return next($this->elements); + } + + /** + * {@inheritDoc} + */ + public function current() + { + return current($this->elements); + } + + /** + * {@inheritDoc} + */ + public function remove($key) + { + if (! isset($this->elements[$key]) && ! array_key_exists($key, $this->elements)) { + return null; + } + + $removed = $this->elements[$key]; + unset($this->elements[$key]); + + return $removed; + } + + /** + * {@inheritDoc} + */ + public function removeElement($element) + { + $key = array_search($element, $this->elements, true); + + if ($key === false) { + return false; + } + + unset($this->elements[$key]); + + return true; + } + + /** + * Required by interface ArrayAccess. + * + * @param TKey $offset + * + * @return bool + */ + #[ReturnTypeWillChange] + public function offsetExists($offset) + { + return $this->containsKey($offset); + } + + /** + * Required by interface ArrayAccess. + * + * @param TKey $offset + * + * @return mixed + */ + #[ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->get($offset); + } + + /** + * Required by interface ArrayAccess. + * + * @param TKey|null $offset + * @param T $value + * + * @return void + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + if (! isset($offset)) { + $this->add($value); + + return; + } + + $this->set($offset, $value); + } + + /** + * Required by interface ArrayAccess. + * + * @param TKey $offset + * + * @return void + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset) + { + $this->remove($offset); + } + + /** + * {@inheritDoc} + */ + public function containsKey($key) + { + return isset($this->elements[$key]) || array_key_exists($key, $this->elements); + } + + /** + * {@inheritDoc} + * + * @template TMaybeContained + */ + public function contains($element) + { + return in_array($element, $this->elements, true); + } + + /** + * {@inheritDoc} + */ + public function exists(Closure $p) + { + foreach ($this->elements as $key => $element) { + if ($p($key, $element)) { + return true; + } + } + + return false; + } + + /** + * {@inheritDoc} + * + * @psalm-param TMaybeContained $element + * + * @psalm-return (TMaybeContained is T ? TKey|false : false) + * + * @template TMaybeContained + */ + public function indexOf($element) + { + return array_search($element, $this->elements, true); + } + + /** + * {@inheritDoc} + */ + public function get($key) + { + return $this->elements[$key] ?? null; + } + + /** + * {@inheritDoc} + */ + public function getKeys() + { + return array_keys($this->elements); + } + + /** + * {@inheritDoc} + */ + public function getValues() + { + return array_values($this->elements); + } + + /** + * {@inheritDoc} + * + * @return int + */ + #[ReturnTypeWillChange] + public function count() + { + return count($this->elements); + } + + /** + * {@inheritDoc} + */ + public function set($key, $value) + { + $this->elements[$key] = $value; + } + + /** + * {@inheritDoc} + * + * @psalm-suppress InvalidPropertyAssignmentValue + * + * This breaks assumptions about the template type, but it would + * be a backwards-incompatible change to remove this method + */ + public function add($element) + { + $this->elements[] = $element; + + return true; + } + + /** + * {@inheritDoc} + */ + public function isEmpty() + { + return empty($this->elements); + } + + /** + * {@inheritDoc} + * + * @return Traversable<int|string, mixed> + * @psalm-return Traversable<TKey,T> + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return new ArrayIterator($this->elements); + } + + /** + * {@inheritDoc} + * + * @psalm-param Closure(T):U $func + * + * @return static + * @psalm-return static<TKey, U> + * + * @psalm-template U + */ + public function map(Closure $func) + { + return $this->createFrom(array_map($func, $this->elements)); + } + + /** + * {@inheritDoc} + * + * @return static + * @psalm-return static<TKey,T> + */ + public function filter(Closure $p) + { + return $this->createFrom(array_filter($this->elements, $p, ARRAY_FILTER_USE_BOTH)); + } + + /** + * {@inheritDoc} + */ + public function forAll(Closure $p) + { + foreach ($this->elements as $key => $element) { + if (! $p($key, $element)) { + return false; + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function partition(Closure $p) + { + $matches = $noMatches = []; + + foreach ($this->elements as $key => $element) { + if ($p($key, $element)) { + $matches[$key] = $element; + } else { + $noMatches[$key] = $element; + } + } + + return [$this->createFrom($matches), $this->createFrom($noMatches)]; + } + + /** + * Returns a string representation of this object. + * + * @return string + */ + public function __toString() + { + return self::class . '@' . spl_object_hash($this); + } + + /** + * {@inheritDoc} + */ + public function clear() + { + $this->elements = []; + } + + /** + * {@inheritDoc} + */ + public function slice($offset, $length = null) + { + return array_slice($this->elements, $offset, $length, true); + } + + /** + * {@inheritDoc} + */ + public function matching(Criteria $criteria) + { + $expr = $criteria->getWhereExpression(); + $filtered = $this->elements; + + if ($expr) { + $visitor = new ClosureExpressionVisitor(); + $filter = $visitor->dispatch($expr); + $filtered = array_filter($filtered, $filter); + } + + $orderings = $criteria->getOrderings(); + + if ($orderings) { + $next = null; + foreach (array_reverse($orderings) as $field => $ordering) { + $next = ClosureExpressionVisitor::sortByField($field, $ordering === Criteria::DESC ? -1 : 1, $next); + } + + uasort($filtered, $next); + } + + $offset = $criteria->getFirstResult(); + $length = $criteria->getMaxResults(); + + if ($offset || $length) { + $filtered = array_slice($filtered, (int) $offset, $length); + } + + return $this->createFrom($filtered); + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php new file mode 100644 index 0000000..fb09192 --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php @@ -0,0 +1,99 @@ +<?php + +namespace Doctrine\Common\Collections; + +use ArrayAccess; +use Closure; + +/** + * The missing (SPL) Collection/Array/OrderedMap interface. + * + * A Collection resembles the nature of a regular PHP array. That is, + * it is essentially an <b>ordered map</b> that can also be used + * like a list. + * + * A Collection has an internal iterator just like a PHP array. In addition, + * a Collection can be iterated with external iterators, which is preferable. + * To use an external iterator simply use the foreach language construct to + * iterate over the collection (which calls {@link getIterator()} internally) or + * explicitly retrieve an iterator though {@link getIterator()} which can then be + * used to iterate over the collection. + * You can not rely on the internal iterator of the collection being at a certain + * position unless you explicitly positioned it before. Prefer iteration with + * external iterators. + * + * @psalm-template TKey of array-key + * @psalm-template T + * @template-extends ReadableCollection<TKey, T> + * @template-extends ArrayAccess<TKey, T> + */ +interface Collection extends ReadableCollection, ArrayAccess +{ + /** + * Adds an element at the end of the collection. + * + * @param mixed $element The element to add. + * @psalm-param T $element + * + * @return true Always TRUE. + */ + public function add($element); + + /** + * Clears the collection, removing all elements. + * + * @return void + */ + public function clear(); + + /** + * Removes the element at the specified index from the collection. + * + * @param string|int $key The key/index of the element to remove. + * @psalm-param TKey $key + * + * @return mixed The removed element or NULL, if the collection did not contain the element. + * @psalm-return T|null + */ + public function remove($key); + + /** + * Removes the specified element from the collection, if it is found. + * + * @param mixed $element The element to remove. + * @psalm-param T $element + * + * @return bool TRUE if this collection contained the specified element, FALSE otherwise. + */ + public function removeElement($element); + + /** + * Sets an element in the collection at the specified key/index. + * + * @param string|int $key The key/index of the element to set. + * @param mixed $value The element to set. + * @psalm-param TKey $key + * @psalm-param T $value + * + * @return void + */ + public function set($key, $value); + + /** + * {@inheritdoc} + * + * @return Collection<mixed> A collection with the results of the filter operation. + * @psalm-return Collection<TKey, T> + */ + public function filter(Closure $p); + + /** + * {@inheritdoc} + * + * @return Collection<mixed>[] An array with two elements. The first element contains the collection + * of elements where the predicate returned TRUE, the second element + * contains the collection of elements where the predicate returned FALSE. + * @psalm-return array{0: Collection<TKey, T>, 1: Collection<TKey, T>} + */ + public function partition(Closure $p); +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php new file mode 100644 index 0000000..c1639d3 --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php @@ -0,0 +1,245 @@ +<?php + +namespace Doctrine\Common\Collections; + +use Doctrine\Common\Collections\Expr\CompositeExpression; +use Doctrine\Common\Collections\Expr\Expression; +use Doctrine\Deprecations\Deprecation; + +use function array_map; +use function func_num_args; +use function strtoupper; + +/** + * Criteria for filtering Selectable collections. + * + * @psalm-consistent-constructor + */ +class Criteria +{ + public const ASC = 'ASC'; + + public const DESC = 'DESC'; + + /** @var ExpressionBuilder|null */ + private static $expressionBuilder; + + /** @var Expression|null */ + private $expression; + + /** @var string[] */ + private $orderings = []; + + /** @var int|null */ + private $firstResult; + + /** @var int|null */ + private $maxResults; + + /** + * Creates an instance of the class. + * + * @return Criteria + */ + public static function create() + { + return new static(); + } + + /** + * Returns the expression builder. + * + * @return ExpressionBuilder + */ + public static function expr() + { + if (self::$expressionBuilder === null) { + self::$expressionBuilder = new ExpressionBuilder(); + } + + return self::$expressionBuilder; + } + + /** + * Construct a new Criteria. + * + * @param string[]|null $orderings + * @param int|null $firstResult + * @param int|null $maxResults + */ + public function __construct(?Expression $expression = null, ?array $orderings = null, $firstResult = null, $maxResults = null) + { + $this->expression = $expression; + + if ($firstResult === null && func_num_args() > 2) { + Deprecation::trigger( + 'doctrine/collections', + 'https://github.com/doctrine/collections/pull/311', + 'Passing null as $firstResult to the constructor of %s is deprecated. Pass 0 instead or omit the argument.', + self::class + ); + } + + $this->setFirstResult($firstResult); + $this->setMaxResults($maxResults); + + if ($orderings === null) { + return; + } + + $this->orderBy($orderings); + } + + /** + * Sets the where expression to evaluate when this Criteria is searched for. + * + * @return $this + */ + public function where(Expression $expression) + { + $this->expression = $expression; + + return $this; + } + + /** + * Appends the where expression to evaluate when this Criteria is searched for + * using an AND with previous expression. + * + * @return $this + */ + public function andWhere(Expression $expression) + { + if ($this->expression === null) { + return $this->where($expression); + } + + $this->expression = new CompositeExpression( + CompositeExpression::TYPE_AND, + [$this->expression, $expression] + ); + + return $this; + } + + /** + * Appends the where expression to evaluate when this Criteria is searched for + * using an OR with previous expression. + * + * @return $this + */ + public function orWhere(Expression $expression) + { + if ($this->expression === null) { + return $this->where($expression); + } + + $this->expression = new CompositeExpression( + CompositeExpression::TYPE_OR, + [$this->expression, $expression] + ); + + return $this; + } + + /** + * Gets the expression attached to this Criteria. + * + * @return Expression|null + */ + public function getWhereExpression() + { + return $this->expression; + } + + /** + * Gets the current orderings of this Criteria. + * + * @return string[] + */ + public function getOrderings() + { + return $this->orderings; + } + + /** + * Sets the ordering of the result of this Criteria. + * + * Keys are field and values are the order, being either ASC or DESC. + * + * @see Criteria::ASC + * @see Criteria::DESC + * + * @param string[] $orderings + * + * @return $this + */ + public function orderBy(array $orderings) + { + $this->orderings = array_map( + static function (string $ordering): string { + return strtoupper($ordering) === Criteria::ASC ? Criteria::ASC : Criteria::DESC; + }, + $orderings + ); + + return $this; + } + + /** + * Gets the current first result option of this Criteria. + * + * @return int|null + */ + public function getFirstResult() + { + return $this->firstResult; + } + + /** + * Set the number of first result that this Criteria should return. + * + * @param int|null $firstResult The value to set. + * + * @return $this + */ + public function setFirstResult($firstResult) + { + if ($firstResult === null) { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/collections', + 'https://github.com/doctrine/collections/pull/311', + 'Passing null to %s() is deprecated, pass 0 instead.', + __METHOD__ + ); + } + + $this->firstResult = $firstResult; + + return $this; + } + + /** + * Gets maxResults. + * + * @return int|null + */ + public function getMaxResults() + { + return $this->maxResults; + } + + /** + * Sets maxResults. + * + * @param int|null $maxResults The value to set. + * + * @return $this + */ + public function setMaxResults($maxResults) + { + $this->maxResults = $maxResults; + + return $this; + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php new file mode 100644 index 0000000..c10b8d5 --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php @@ -0,0 +1,269 @@ +<?php + +namespace Doctrine\Common\Collections\Expr; + +use ArrayAccess; +use Closure; +use RuntimeException; + +use function explode; +use function in_array; +use function is_array; +use function is_scalar; +use function iterator_to_array; +use function method_exists; +use function preg_match; +use function preg_replace_callback; +use function strlen; +use function strpos; +use function strtoupper; +use function substr; + +/** + * Walks an expression graph and turns it into a PHP closure. + * + * This closure can be used with {@Collection#filter()} and is used internally + * by {@ArrayCollection#select()}. + */ +class ClosureExpressionVisitor extends ExpressionVisitor +{ + /** + * Accesses the field of a given object. This field has to be public + * directly or indirectly (through an accessor get*, is*, or a magic + * method, __get, __call). + * + * @param object|mixed[] $object + * @param string $field + * + * @return mixed + */ + public static function getObjectFieldValue($object, $field) + { + if (strpos($field, '.') !== false) { + [$field, $subField] = explode('.', $field, 2); + $object = self::getObjectFieldValue($object, $field); + + return self::getObjectFieldValue($object, $subField); + } + + if (is_array($object)) { + return $object[$field]; + } + + $accessors = ['get', 'is', '']; + + foreach ($accessors as $accessor) { + $accessor .= $field; + + if (method_exists($object, $accessor)) { + return $object->$accessor(); + } + } + + if (preg_match('/^is[A-Z]+/', $field) === 1 && method_exists($object, $field)) { + return $object->$field(); + } + + // __call should be triggered for get. + $accessor = $accessors[0] . $field; + + if (method_exists($object, '__call')) { + return $object->$accessor(); + } + + if ($object instanceof ArrayAccess) { + return $object[$field]; + } + + if (isset($object->$field)) { + return $object->$field; + } + + // camelcase field name to support different variable naming conventions + $ccField = preg_replace_callback('/_(.?)/', static function ($matches) { + return strtoupper($matches[1]); + }, $field); + + foreach ($accessors as $accessor) { + $accessor .= $ccField; + + if (method_exists($object, $accessor)) { + return $object->$accessor(); + } + } + + return $object->$field; + } + + /** + * Helper for sorting arrays of objects based on multiple fields + orientations. + * + * @param string $name + * @param int $orientation + * + * @return Closure + */ + public static function sortByField($name, $orientation = 1, ?Closure $next = null) + { + if (! $next) { + $next = static function (): int { + return 0; + }; + } + + return static function ($a, $b) use ($name, $next, $orientation): int { + $aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name); + + $bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name); + + if ($aValue === $bValue) { + return $next($a, $b); + } + + return ($aValue > $bValue ? 1 : -1) * $orientation; + }; + } + + /** + * {@inheritDoc} + */ + public function walkComparison(Comparison $comparison) + { + $field = $comparison->getField(); + $value = $comparison->getValue()->getValue(); // shortcut for walkValue() + + switch ($comparison->getOperator()) { + case Comparison::EQ: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value; + }; + + case Comparison::NEQ: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value; + }; + + case Comparison::LT: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value; + }; + + case Comparison::LTE: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value; + }; + + case Comparison::GT: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value; + }; + + case Comparison::GTE: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value; + }; + + case Comparison::IN: + return static function ($object) use ($field, $value): bool { + $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field); + + return in_array($fieldValue, $value, is_scalar($fieldValue)); + }; + + case Comparison::NIN: + return static function ($object) use ($field, $value): bool { + $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field); + + return ! in_array($fieldValue, $value, is_scalar($fieldValue)); + }; + + case Comparison::CONTAINS: + return static function ($object) use ($field, $value) { + return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) !== false; + }; + + case Comparison::MEMBER_OF: + return static function ($object) use ($field, $value): bool { + $fieldValues = ClosureExpressionVisitor::getObjectFieldValue($object, $field); + + if (! is_array($fieldValues)) { + $fieldValues = iterator_to_array($fieldValues); + } + + return in_array($value, $fieldValues, true); + }; + + case Comparison::STARTS_WITH: + return static function ($object) use ($field, $value): bool { + return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) === 0; + }; + + case Comparison::ENDS_WITH: + return static function ($object) use ($field, $value): bool { + return $value === substr(ClosureExpressionVisitor::getObjectFieldValue($object, $field), -strlen($value)); + }; + + default: + throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator()); + } + } + + /** + * {@inheritDoc} + */ + public function walkValue(Value $value) + { + return $value->getValue(); + } + + /** + * {@inheritDoc} + */ + public function walkCompositeExpression(CompositeExpression $expr) + { + $expressionList = []; + + foreach ($expr->getExpressionList() as $child) { + $expressionList[] = $this->dispatch($child); + } + + switch ($expr->getType()) { + case CompositeExpression::TYPE_AND: + return $this->andExpressions($expressionList); + + case CompositeExpression::TYPE_OR: + return $this->orExpressions($expressionList); + + default: + throw new RuntimeException('Unknown composite ' . $expr->getType()); + } + } + + /** @param callable[] $expressions */ + private function andExpressions(array $expressions): callable + { + return static function ($object) use ($expressions): bool { + foreach ($expressions as $expression) { + if (! $expression($object)) { + return false; + } + } + + return true; + }; + } + + /** @param callable[] $expressions */ + private function orExpressions(array $expressions): callable + { + return static function ($object) use ($expressions): bool { + foreach ($expressions as $expression) { + if ($expression($object)) { + return true; + } + } + + return false; + }; + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php new file mode 100644 index 0000000..6762b8b --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php @@ -0,0 +1,74 @@ +<?php + +namespace Doctrine\Common\Collections\Expr; + +/** + * Comparison of a field with a value by the given operator. + */ +class Comparison implements Expression +{ + public const EQ = '='; + public const NEQ = '<>'; + public const LT = '<'; + public const LTE = '<='; + public const GT = '>'; + public const GTE = '>='; + public const IS = '='; // no difference with EQ + public const IN = 'IN'; + public const NIN = 'NIN'; + public const CONTAINS = 'CONTAINS'; + public const MEMBER_OF = 'MEMBER_OF'; + public const STARTS_WITH = 'STARTS_WITH'; + public const ENDS_WITH = 'ENDS_WITH'; + + /** @var string */ + private $field; + + /** @var string */ + private $op; + + /** @var Value */ + private $value; + + /** + * @param string $field + * @param string $operator + * @param mixed $value + */ + public function __construct($field, $operator, $value) + { + if (! ($value instanceof Value)) { + $value = new Value($value); + } + + $this->field = $field; + $this->op = $operator; + $this->value = $value; + } + + /** @return string */ + public function getField() + { + return $this->field; + } + + /** @return Value */ + public function getValue() + { + return $this->value; + } + + /** @return string */ + public function getOperator() + { + return $this->op; + } + + /** + * {@inheritDoc} + */ + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkComparison($this); + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php new file mode 100644 index 0000000..174b21b --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php @@ -0,0 +1,67 @@ +<?php + +namespace Doctrine\Common\Collections\Expr; + +use RuntimeException; + +/** + * Expression of Expressions combined by AND or OR operation. + */ +class CompositeExpression implements Expression +{ + public const TYPE_AND = 'AND'; + public const TYPE_OR = 'OR'; + + /** @var string */ + private $type; + + /** @var Expression[] */ + private $expressions = []; + + /** + * @param string $type + * @param mixed[] $expressions + * + * @throws RuntimeException + */ + public function __construct($type, array $expressions) + { + $this->type = $type; + + foreach ($expressions as $expr) { + if ($expr instanceof Value) { + throw new RuntimeException('Values are not supported expressions as children of and/or expressions.'); + } + + if (! ($expr instanceof Expression)) { + throw new RuntimeException('No expression given to CompositeExpression.'); + } + + $this->expressions[] = $expr; + } + } + + /** + * Returns the list of expressions nested in this composite. + * + * @return Expression[] + */ + public function getExpressionList() + { + return $this->expressions; + } + + /** @return string */ + public function getType() + { + return $this->type; + } + + /** + * {@inheritDoc} + */ + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkCompositeExpression($this); + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php new file mode 100644 index 0000000..566d6d5 --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php @@ -0,0 +1,12 @@ +<?php + +namespace Doctrine\Common\Collections\Expr; + +/** + * Expression for the {@link Selectable} interface. + */ +interface Expression +{ + /** @return mixed */ + public function visit(ExpressionVisitor $visitor); +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php new file mode 100644 index 0000000..72bb153 --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php @@ -0,0 +1,59 @@ +<?php + +namespace Doctrine\Common\Collections\Expr; + +use RuntimeException; + +use function get_class; + +/** + * An Expression visitor walks a graph of expressions and turns them into a + * query for the underlying implementation. + */ +abstract class ExpressionVisitor +{ + /** + * Converts a comparison expression into the target query language output. + * + * @return mixed + */ + abstract public function walkComparison(Comparison $comparison); + + /** + * Converts a value expression into the target query language part. + * + * @return mixed + */ + abstract public function walkValue(Value $value); + + /** + * Converts a composite expression into the target query language output. + * + * @return mixed + */ + abstract public function walkCompositeExpression(CompositeExpression $expr); + + /** + * Dispatches walking an expression to the appropriate handler. + * + * @return mixed + * + * @throws RuntimeException + */ + public function dispatch(Expression $expr) + { + switch (true) { + case $expr instanceof Comparison: + return $this->walkComparison($expr); + + case $expr instanceof Value: + return $this->walkValue($expr); + + case $expr instanceof CompositeExpression: + return $this->walkCompositeExpression($expr); + + default: + throw new RuntimeException('Unknown Expression ' . get_class($expr)); + } + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php new file mode 100644 index 0000000..693d345 --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php @@ -0,0 +1,29 @@ +<?php + +namespace Doctrine\Common\Collections\Expr; + +class Value implements Expression +{ + /** @var mixed */ + private $value; + + /** @param mixed $value */ + public function __construct($value) + { + $this->value = $value; + } + + /** @return mixed */ + public function getValue() + { + return $this->value; + } + + /** + * {@inheritDoc} + */ + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkValue($this); + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php new file mode 100644 index 0000000..ebb21ca --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php @@ -0,0 +1,181 @@ +<?php + +namespace Doctrine\Common\Collections; + +use Doctrine\Common\Collections\Expr\Comparison; +use Doctrine\Common\Collections\Expr\CompositeExpression; +use Doctrine\Common\Collections\Expr\Value; + +use function func_get_args; + +/** + * Builder for Expressions in the {@link Selectable} interface. + * + * Important Notice for interoperable code: You have to use scalar + * values only for comparisons, otherwise the behavior of the comparison + * may be different between implementations (Array vs ORM vs ODM). + */ +class ExpressionBuilder +{ + /** + * @param mixed ...$x + * + * @return CompositeExpression + */ + public function andX($x = null) + { + return new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); + } + + /** + * @param mixed ...$x + * + * @return CompositeExpression + */ + public function orX($x = null) + { + return new CompositeExpression(CompositeExpression::TYPE_OR, func_get_args()); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function eq($field, $value) + { + return new Comparison($field, Comparison::EQ, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function gt($field, $value) + { + return new Comparison($field, Comparison::GT, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function lt($field, $value) + { + return new Comparison($field, Comparison::LT, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function gte($field, $value) + { + return new Comparison($field, Comparison::GTE, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function lte($field, $value) + { + return new Comparison($field, Comparison::LTE, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function neq($field, $value) + { + return new Comparison($field, Comparison::NEQ, new Value($value)); + } + + /** + * @param string $field + * + * @return Comparison + */ + public function isNull($field) + { + return new Comparison($field, Comparison::EQ, new Value(null)); + } + + /** + * @param string $field + * @param mixed[] $values + * + * @return Comparison + */ + public function in($field, array $values) + { + return new Comparison($field, Comparison::IN, new Value($values)); + } + + /** + * @param string $field + * @param mixed[] $values + * + * @return Comparison + */ + public function notIn($field, array $values) + { + return new Comparison($field, Comparison::NIN, new Value($values)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function contains($field, $value) + { + return new Comparison($field, Comparison::CONTAINS, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function memberOf($field, $value) + { + return new Comparison($field, Comparison::MEMBER_OF, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function startsWith($field, $value) + { + return new Comparison($field, Comparison::STARTS_WITH, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function endsWith($field, $value) + { + return new Comparison($field, Comparison::ENDS_WITH, new Value($value)); + } +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ReadableCollection.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ReadableCollection.php new file mode 100644 index 0000000..44b3749 --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ReadableCollection.php @@ -0,0 +1,213 @@ +<?php + +namespace Doctrine\Common\Collections; + +use Closure; +use Countable; +use IteratorAggregate; + +/** + * @psalm-template TKey of array-key + * @template-covariant T + * @template-extends IteratorAggregate<TKey, T> + */ +interface ReadableCollection extends Countable, IteratorAggregate +{ + /** + * Checks whether an element is contained in the collection. + * This is an O(n) operation, where n is the size of the collection. + * + * @param mixed $element The element to search for. + * @psalm-param TMaybeContained $element + * + * @return bool TRUE if the collection contains the element, FALSE otherwise. + * @psalm-return (TMaybeContained is T ? bool : false) + * + * @template TMaybeContained + */ + public function contains($element); + + /** + * Checks whether the collection is empty (contains no elements). + * + * @return bool TRUE if the collection is empty, FALSE otherwise. + */ + public function isEmpty(); + + /** + * Checks whether the collection contains an element with the specified key/index. + * + * @param string|int $key The key/index to check for. + * @psalm-param TKey $key + * + * @return bool TRUE if the collection contains an element with the specified key/index, + * FALSE otherwise. + */ + public function containsKey($key); + + /** + * Gets the element at the specified key/index. + * + * @param string|int $key The key/index of the element to retrieve. + * @psalm-param TKey $key + * + * @return mixed + * @psalm-return T|null + */ + public function get($key); + + /** + * Gets all keys/indices of the collection. + * + * @return int[]|string[] The keys/indices of the collection, in the order of the corresponding + * elements in the collection. + * @psalm-return list<TKey> + */ + public function getKeys(); + + /** + * Gets all values of the collection. + * + * @return mixed[] The values of all elements in the collection, in the + * order they appear in the collection. + * @psalm-return list<T> + */ + public function getValues(); + + /** + * Gets a native PHP array representation of the collection. + * + * @return mixed[] + * @psalm-return array<TKey,T> + */ + public function toArray(); + + /** + * Sets the internal iterator to the first element in the collection and returns this element. + * + * @return mixed + * @psalm-return T|false + */ + public function first(); + + /** + * Sets the internal iterator to the last element in the collection and returns this element. + * + * @return mixed + * @psalm-return T|false + */ + public function last(); + + /** + * Gets the key/index of the element at the current iterator position. + * + * @return int|string|null + * @psalm-return TKey|null + */ + public function key(); + + /** + * Gets the element of the collection at the current iterator position. + * + * @return mixed + * @psalm-return T|false + */ + public function current(); + + /** + * Moves the internal iterator position to the next element and returns this element. + * + * @return mixed + * @psalm-return T|false + */ + public function next(); + + /** + * Extracts a slice of $length elements starting at position $offset from the Collection. + * + * If $length is null it returns all elements from $offset to the end of the Collection. + * Keys have to be preserved by this method. Calling this method will only return the + * selected slice and NOT change the elements contained in the collection slice is called on. + * + * @param int $offset The offset to start from. + * @param int|null $length The maximum number of elements to return, or null for no limit. + * + * @return mixed[] + * @psalm-return array<TKey,T> + */ + public function slice($offset, $length = null); + + /** + * Tests for the existence of an element that satisfies the given predicate. + * + * @param Closure $p The predicate. + * @psalm-param Closure(TKey, T):bool $p + * + * @return bool TRUE if the predicate is TRUE for at least one element, FALSE otherwise. + */ + public function exists(Closure $p); + + /** + * Returns all the elements of this collection that satisfy the predicate p. + * The order of the elements is preserved. + * + * @param Closure $p The predicate used for filtering. + * @psalm-param Closure(T):bool $p + * + * @return ReadableCollection<mixed> A collection with the results of the filter operation. + * @psalm-return ReadableCollection<TKey, T> + */ + public function filter(Closure $p); + + /** + * Applies the given function to each element in the collection and returns + * a new collection with the elements returned by the function. + * + * @psalm-param Closure(T):U $func + * + * @return Collection<mixed> + * @psalm-return Collection<TKey, U> + * + * @psalm-template U + */ + public function map(Closure $func); + + /** + * Partitions this collection in two collections according to a predicate. + * Keys are preserved in the resulting collections. + * + * @param Closure $p The predicate on which to partition. + * @psalm-param Closure(TKey, T):bool $p + * + * @return ReadableCollection<mixed>[] An array with two elements. The first element contains the collection + * of elements where the predicate returned TRUE, the second element + * contains the collection of elements where the predicate returned FALSE. + * @psalm-return array{0: ReadableCollection<TKey, T>, 1: ReadableCollection<TKey, T>} + */ + public function partition(Closure $p); + + /** + * Tests whether the given predicate p holds for all elements of this collection. + * + * @param Closure $p The predicate. + * @psalm-param Closure(TKey, T):bool $p + * + * @return bool TRUE, if the predicate yields TRUE for all elements, FALSE otherwise. + */ + public function forAll(Closure $p); + + /** + * Gets the index/key of a given element. The comparison of two elements is strict, + * that means not only the value but also the type must match. + * For objects this means reference equality. + * + * @param mixed $element The element to search for. + * @psalm-param TMaybeContained $element + * + * @return int|string|bool The key/index of the element or FALSE if the element was not found. + * @psalm-return (TMaybeContained is T ? TKey|false : false) + * + * @template TMaybeContained + */ + public function indexOf($element); +} diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php new file mode 100644 index 0000000..9f7586d --- /dev/null +++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php @@ -0,0 +1,30 @@ +<?php + +namespace Doctrine\Common\Collections; + +/** + * Interface for collections that allow efficient filtering with an expression API. + * + * Goal of this interface is a backend independent method to fetch elements + * from a collections. {@link Expression} is crafted in a way that you can + * implement queries from both in-memory and database-backed collections. + * + * For database backed collections this allows very efficient access by + * utilizing the query APIs, for example SQL in the ORM. Applications using + * this API can implement efficient database access without having to ask the + * EntityManager or Repositories. + * + * @psalm-template TKey as array-key + * @psalm-template T + */ +interface Selectable +{ + /** + * Selects all elements from a selectable that match the expression and + * returns a new collection containing these elements. + * + * @return Collection<mixed>&Selectable<mixed> + * @psalm-return Collection<TKey,T>&Selectable<TKey,T> + */ + public function matching(Criteria $criteria); +} diff --git a/vendor/doctrine/deprecations/LICENSE b/vendor/doctrine/deprecations/LICENSE new file mode 100644 index 0000000..156905c --- /dev/null +++ b/vendor/doctrine/deprecations/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-2021 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/deprecations/composer.json b/vendor/doctrine/deprecations/composer.json new file mode 100644 index 0000000..f8319f9 --- /dev/null +++ b/vendor/doctrine/deprecations/composer.json @@ -0,0 +1,38 @@ +{ + "name": "doctrine/deprecations", + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "license": "MIT", + "type": "library", + "homepage": "https://www.doctrine-project.org/", + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "autoload-dev": { + "psr-4": { + "DeprecationTests\\": "test_fixtures/src", + "Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo" + } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php new file mode 100644 index 0000000..bad5070 --- /dev/null +++ b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php @@ -0,0 +1,313 @@ +<?php + +declare(strict_types=1); + +namespace Doctrine\Deprecations; + +use Psr\Log\LoggerInterface; + +use function array_key_exists; +use function array_reduce; +use function assert; +use function debug_backtrace; +use function sprintf; +use function str_replace; +use function strpos; +use function strrpos; +use function substr; +use function trigger_error; + +use const DEBUG_BACKTRACE_IGNORE_ARGS; +use const DIRECTORY_SEPARATOR; +use const E_USER_DEPRECATED; + +/** + * Manages Deprecation logging in different ways. + * + * By default triggered exceptions are not logged. + * + * To enable different deprecation logging mechanisms you can call the + * following methods: + * + * - Minimal collection of deprecations via getTriggeredDeprecations() + * \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations(); + * + * - Uses @trigger_error with E_USER_DEPRECATED + * \Doctrine\Deprecations\Deprecation::enableWithTriggerError(); + * + * - Sends deprecation messages via a PSR-3 logger + * \Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger); + * + * Packages that trigger deprecations should use the `trigger()` or + * `triggerIfCalledFromOutside()` methods. + */ +class Deprecation +{ + private const TYPE_NONE = 0; + private const TYPE_TRACK_DEPRECATIONS = 1; + private const TYPE_TRIGGER_ERROR = 2; + private const TYPE_PSR_LOGGER = 4; + + /** @var int-mask-of<self::TYPE_*>|null */ + private static $type; + + /** @var LoggerInterface|null */ + private static $logger; + + /** @var array<string,bool> */ + private static $ignoredPackages = []; + + /** @var array<string,int> */ + private static $triggeredDeprecations = []; + + /** @var array<string,bool> */ + private static $ignoredLinks = []; + + /** @var bool */ + private static $deduplication = true; + + /** + * Trigger a deprecation for the given package and identfier. + * + * The link should point to a Github issue or Wiki entry detailing the + * deprecation. It is additionally used to de-duplicate the trigger of the + * same deprecation during a request. + * + * @param float|int|string $args + */ + public static function trigger(string $package, string $link, string $message, ...$args): void + { + $type = self::$type ?? self::getTypeFromEnv(); + + if ($type === self::TYPE_NONE) { + return; + } + + if (isset(self::$ignoredLinks[$link])) { + return; + } + + if (array_key_exists($link, self::$triggeredDeprecations)) { + self::$triggeredDeprecations[$link]++; + } else { + self::$triggeredDeprecations[$link] = 1; + } + + if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) { + return; + } + + if (isset(self::$ignoredPackages[$package])) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + $message = sprintf($message, ...$args); + + self::delegateTriggerToBackend($message, $backtrace, $link, $package); + } + + /** + * Trigger a deprecation for the given package and identifier when called from outside. + * + * "Outside" means we assume that $package is currently installed as a + * dependency and the caller is not a file in that package. When $package + * is installed as a root package then deprecations triggered from the + * tests folder are also considered "outside". + * + * This deprecation method assumes that you are using Composer to install + * the dependency and are using the default /vendor/ folder and not a + * Composer plugin to change the install location. The assumption is also + * that $package is the exact composer packge name. + * + * Compared to {@link trigger()} this method causes some overhead when + * deprecation tracking is enabled even during deduplication, because it + * needs to call {@link debug_backtrace()} + * + * @param float|int|string $args + */ + public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void + { + $type = self::$type ?? self::getTypeFromEnv(); + + if ($type === self::TYPE_NONE) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + // first check that the caller is not from a tests folder, in which case we always let deprecations pass + if (isset($backtrace[1]['file'], $backtrace[0]['file']) && strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) { + $path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $package) . DIRECTORY_SEPARATOR; + + if (strpos($backtrace[0]['file'], $path) === false) { + return; + } + + if (strpos($backtrace[1]['file'], $path) !== false) { + return; + } + } + + if (isset(self::$ignoredLinks[$link])) { + return; + } + + if (array_key_exists($link, self::$triggeredDeprecations)) { + self::$triggeredDeprecations[$link]++; + } else { + self::$triggeredDeprecations[$link] = 1; + } + + if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) { + return; + } + + if (isset(self::$ignoredPackages[$package])) { + return; + } + + $message = sprintf($message, ...$args); + + self::delegateTriggerToBackend($message, $backtrace, $link, $package); + } + + /** + * @param list<array{function: string, line?: int, file?: string, class?: class-string, type?: string, args?: mixed[], object?: object}> $backtrace + */ + private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void + { + $type = self::$type ?? self::getTypeFromEnv(); + + if (($type & self::TYPE_PSR_LOGGER) > 0) { + $context = [ + 'file' => $backtrace[0]['file'] ?? null, + 'line' => $backtrace[0]['line'] ?? null, + 'package' => $package, + 'link' => $link, + ]; + + assert(self::$logger !== null); + + self::$logger->notice($message, $context); + } + + if (! (($type & self::TYPE_TRIGGER_ERROR) > 0)) { + return; + } + + $message .= sprintf( + ' (%s:%d called by %s:%d, %s, package %s)', + self::basename($backtrace[0]['file'] ?? 'native code'), + $backtrace[0]['line'] ?? 0, + self::basename($backtrace[1]['file'] ?? 'native code'), + $backtrace[1]['line'] ?? 0, + $link, + $package + ); + + @trigger_error($message, E_USER_DEPRECATED); + } + + /** + * A non-local-aware version of PHPs basename function. + */ + private static function basename(string $filename): string + { + $pos = strrpos($filename, DIRECTORY_SEPARATOR); + + if ($pos === false) { + return $filename; + } + + return substr($filename, $pos + 1); + } + + public static function enableTrackingDeprecations(): void + { + self::$type = self::$type ?? 0; + self::$type |= self::TYPE_TRACK_DEPRECATIONS; + } + + public static function enableWithTriggerError(): void + { + self::$type = self::$type ?? 0; + self::$type |= self::TYPE_TRIGGER_ERROR; + } + + public static function enableWithPsrLogger(LoggerInterface $logger): void + { + self::$type = self::$type ?? 0; + self::$type |= self::TYPE_PSR_LOGGER; + self::$logger = $logger; + } + + public static function withoutDeduplication(): void + { + self::$deduplication = false; + } + + public static function disable(): void + { + self::$type = self::TYPE_NONE; + self::$logger = null; + self::$deduplication = true; + self::$ignoredLinks = []; + + foreach (self::$triggeredDeprecations as $link => $count) { + self::$triggeredDeprecations[$link] = 0; + } + } + + public static function ignorePackage(string $packageName): void + { + self::$ignoredPackages[$packageName] = true; + } + + public static function ignoreDeprecations(string ...$links): void + { + foreach ($links as $link) { + self::$ignoredLinks[$link] = true; + } + } + + public static function getUniqueTriggeredDeprecationsCount(): int + { + return array_reduce(self::$triggeredDeprecations, static function (int $carry, int $count) { + return $carry + $count; + }, 0); + } + + /** + * Returns each triggered deprecation link identifier and the amount of occurrences. + * + * @return array<string,int> + */ + public static function getTriggeredDeprecations(): array + { + return self::$triggeredDeprecations; + } + + /** + * @return int-mask-of<self::TYPE_*> + */ + private static function getTypeFromEnv(): int + { + switch ($_SERVER['DOCTRINE_DEPRECATIONS'] ?? $_ENV['DOCTRINE_DEPRECATIONS'] ?? null) { + case 'trigger': + self::$type = self::TYPE_TRIGGER_ERROR; + break; + + case 'track': + self::$type = self::TYPE_TRACK_DEPRECATIONS; + break; + + default: + self::$type = self::TYPE_NONE; + break; + } + + return self::$type; + } +} diff --git a/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php new file mode 100644 index 0000000..4c3366a --- /dev/null +++ b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php @@ -0,0 +1,66 @@ +<?php + +declare(strict_types=1); + +namespace Doctrine\Deprecations\PHPUnit; + +use Doctrine\Deprecations\Deprecation; + +use function sprintf; + +trait VerifyDeprecations +{ + /** @var array<string,int> */ + private $doctrineDeprecationsExpectations = []; + + /** @var array<string,int> */ + private $doctrineNoDeprecationsExpectations = []; + + public function expectDeprecationWithIdentifier(string $identifier): void + { + $this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + } + + public function expectNoDeprecationWithIdentifier(string $identifier): void + { + $this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + } + + /** + * @before + */ + public function enableDeprecationTracking(): void + { + Deprecation::enableTrackingDeprecations(); + } + + /** + * @after + */ + public function verifyDeprecationsAreTriggered(): void + { + foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) { + $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + + $this->assertTrue( + $actualCount > $expectation, + sprintf( + "Expected deprecation with identifier '%s' was not triggered by code executed in test.", + $identifier + ) + ); + } + + foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) { + $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + + $this->assertTrue( + $actualCount === $expectation, + sprintf( + "Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.", + $identifier + ) + ); + } + } +} diff --git a/vendor/dragonmantank/cron-expression/LICENSE b/vendor/dragonmantank/cron-expression/LICENSE new file mode 100644 index 0000000..3e38bbc --- /dev/null +++ b/vendor/dragonmantank/cron-expression/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Michael Dowling <mtdowling@gmail.com>, 2016 Chris Tankersley <chris@ctankersley.com>, and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/dragonmantank/cron-expression/composer.json b/vendor/dragonmantank/cron-expression/composer.json new file mode 100644 index 0000000..657a5b4 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/composer.json @@ -0,0 +1,47 @@ +{ + "name": "dragonmantank/cron-expression", + "type": "library", + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": ["cron", "schedule"], + "license": "MIT", + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "require": { + "php": "^7.2|^8.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "phpstan/phpstan-webmozart-assert": "^1.0", + "phpstan/extension-installer": "^1.0" + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "autoload-dev": { + "psr-4": { + "Cron\\Tests\\": "tests/Cron/" + } + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "scripts": { + "phpstan": "./vendor/bin/phpstan analyze", + "test": "phpunit" + }, + "config": { + "allow-plugins": { + "ocramius/package-versions": true, + "phpstan/extension-installer": true + } + } +} diff --git a/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php b/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php new file mode 100644 index 0000000..df2848d --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php @@ -0,0 +1,346 @@ +<?php + +declare(strict_types=1); + +namespace Cron; + +use DateTimeInterface; + +/** + * Abstract CRON expression field. + */ +abstract class AbstractField implements FieldInterface +{ + /** + * Full range of values that are allowed for this field type. + * + * @var array + */ + protected $fullRange = []; + + /** + * Literal values we need to convert to integers. + * + * @var array + */ + protected $literals = []; + + /** + * Start value of the full range. + * + * @var int + */ + protected $rangeStart; + + /** + * End value of the full range. + * + * @var int + */ + protected $rangeEnd; + + /** + * Constructor + */ + public function __construct() + { + $this->fullRange = range($this->rangeStart, $this->rangeEnd); + } + + /** + * Check to see if a field is satisfied by a value. + * + * @internal + * @param int $dateValue Date value to check + * @param string $value Value to test + * + * @return bool + */ + public function isSatisfied(int $dateValue, string $value): bool + { + if ($this->isIncrementsOfRanges($value)) { + return $this->isInIncrementsOfRanges($dateValue, $value); + } + + if ($this->isRange($value)) { + return $this->isInRange($dateValue, $value); + } + + return '*' === $value || $dateValue === (int) $value; + } + + /** + * Check if a value is a range. + * + * @internal + * @param string $value Value to test + * + * @return bool + */ + public function isRange(string $value): bool + { + return false !== strpos($value, '-'); + } + + /** + * Check if a value is an increments of ranges. + * + * @internal + * @param string $value Value to test + * + * @return bool + */ + public function isIncrementsOfRanges(string $value): bool + { + return false !== strpos($value, '/'); + } + + /** + * Test if a value is within a range. + * + * @internal + * @param int $dateValue Set date value + * @param string $value Value to test + * + * @return bool + */ + public function isInRange(int $dateValue, $value): bool + { + $parts = array_map( + function ($value) { + $value = trim($value); + + return $this->convertLiterals($value); + }, + explode('-', $value, 2) + ); + + return $dateValue >= $parts[0] && $dateValue <= $parts[1]; + } + + /** + * Test if a value is within an increments of ranges (offset[-to]/step size). + * + * @internal + * @param int $dateValue Set date value + * @param string $value Value to test + * + * @return bool + */ + public function isInIncrementsOfRanges(int $dateValue, string $value): bool + { + $chunks = array_map('trim', explode('/', $value, 2)); + $range = $chunks[0]; + $step = $chunks[1] ?? 0; + + // No step or 0 steps aren't cool + /** @phpstan-ignore-next-line */ + if (null === $step || '0' === $step || 0 === $step) { + return false; + } + + // Expand the * to a full range + if ('*' === $range) { + $range = $this->rangeStart . '-' . $this->rangeEnd; + } + + // Generate the requested small range + $rangeChunks = explode('-', $range, 2); + $rangeStart = (int) $rangeChunks[0]; + $rangeEnd = $rangeChunks[1] ?? $rangeStart; + $rangeEnd = (int) $rangeEnd; + + if ($rangeStart < $this->rangeStart || $rangeStart > $this->rangeEnd || $rangeStart > $rangeEnd) { + throw new \OutOfRangeException('Invalid range start requested'); + } + + if ($rangeEnd < $this->rangeStart || $rangeEnd > $this->rangeEnd || $rangeEnd < $rangeStart) { + throw new \OutOfRangeException('Invalid range end requested'); + } + + // Steps larger than the range need to wrap around and be handled + // slightly differently than smaller steps + + // UPDATE - This is actually false. The C implementation will allow a + // larger step as valid syntax, it never wraps around. It will stop + // once it hits the end. Unfortunately this means in future versions + // we will not wrap around. However, because the logic exists today + // per the above documentation, fixing the bug from #89 + if ($step > $this->rangeEnd) { + $thisRange = [$this->fullRange[$step % \count($this->fullRange)]]; + } else { + if ($step > ($rangeEnd - $rangeStart)) { + $thisRange[$rangeStart] = (int) $rangeStart; + } else { + $thisRange = range($rangeS |