Файловый менеджер - Редактировать - /var/www/html/semver.zip
Ðазад
PK ! }�H H README.mdnu �Iw�� composer/semver =============== Semver (Semantic Versioning) library that offers utilities, version constraint parsing and validation. Originally written as part of [composer/composer](https://github.com/composer/composer), now extracted and made available as a stand-alone library. [](https://github.com/composer/semver/actions/workflows/continuous-integration.yml) [](https://github.com/composer/semver/actions/workflows/lint.yml) [](https://github.com/composer/semver/actions/workflows/phpstan.yml) Installation ------------ Install the latest version with: ```bash composer require composer/semver ``` Requirements ------------ * PHP 5.3.2 is required but using the latest version of PHP is highly recommended. Version Comparison ------------------ For details on how versions are compared, refer to the [Versions](https://getcomposer.org/doc/articles/versions.md) article in the documentation section of the [getcomposer.org](https://getcomposer.org) website. Basic usage ----------- ### Comparator The [`Composer\Semver\Comparator`](https://github.com/composer/semver/blob/main/src/Comparator.php) class provides the following methods for comparing versions: * greaterThan($v1, $v2) * greaterThanOrEqualTo($v1, $v2) * lessThan($v1, $v2) * lessThanOrEqualTo($v1, $v2) * equalTo($v1, $v2) * notEqualTo($v1, $v2) Each function takes two version strings as arguments and returns a boolean. For example: ```php use Composer\Semver\Comparator; Comparator::greaterThan('1.25.0', '1.24.0'); // 1.25.0 > 1.24.0 ``` ### Semver The [`Composer\Semver\Semver`](https://github.com/composer/semver/blob/main/src/Semver.php) class provides the following methods: * satisfies($version, $constraints) * satisfiedBy(array $versions, $constraint) * sort($versions) * rsort($versions) ### Intervals The [`Composer\Semver\Intervals`](https://github.com/composer/semver/blob/main/src/Intervals.php) static class provides a few utilities to work with complex constraints or read version intervals from a constraint: ```php use Composer\Semver\Intervals; // Checks whether $candidate is a subset of $constraint Intervals::isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint); // Checks whether $a and $b have any intersection, equivalent to $a->matches($b) Intervals::haveIntersections(ConstraintInterface $a, ConstraintInterface $b); // Optimizes a complex multi constraint by merging all intervals down to the smallest // possible multi constraint. The drawbacks are this is not very fast, and the resulting // multi constraint will have no human readable prettyConstraint configured on it Intervals::compactConstraint(ConstraintInterface $constraint); // Creates an array of numeric intervals and branch constraints representing a given constraint Intervals::get(ConstraintInterface $constraint); // Clears the memoization cache when you are done processing constraints Intervals::clear() ``` See the class docblocks for more details. License ------- composer/semver is licensed under the MIT License, see the LICENSE file for details. PK ! E|�V~ ~ src/Interval.phpnu �Iw�� <?php /* * This file is part of composer/semver. * * (c) Composer <https://github.com/composer> * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace Composer\Semver; use Composer\Semver\Constraint\Constraint; class Interval { /** @var Constraint */ private $start; /** @var Constraint */ private $end; public function __construct(Constraint $start, Constraint $end) { $this->start = $start; $this->end = $end; } /** * @return Constraint */ public function getStart() { return $this->start; } /** * @return Constraint */ public function getEnd() { return $this->end; } /** * @return Constraint */ public static function fromZero() { static $zero; if (null === $zero) { $zero = new Constraint('>=', '0.0.0.0-dev'); } return $zero; } /** * @return Constraint */ public static function untilPositiveInfinity() { static $positiveInfinity; if (null === $positiveInfinity) { $positiveInfinity = new Constraint('<', PHP_INT_MAX.'.0.0.0'); } return $positiveInfinity; } /** * @return self */ public static function any() { return new self(self::fromZero(), self::untilPositiveInfinity()); } /** * @return array{'names': string[], 'exclude': bool} */ public static function anyDev() { // any == exclude nothing return array('names' => array(), 'exclude' => true); } /** * @return array{'names': string[], 'exclude': bool} */ public static function noDev() { // nothing == no names included return array('names' => array(), 'exclude' => false); } } PK ! Ș܁D D src/Comparator.phpnu �Iw�� <?php /* * This file is part of composer/semver. * * (c) Composer <https://github.com/composer> * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace Composer\Semver; use Composer\Semver\Constraint\Constraint; class Comparator { /** * Evaluates the expression: $version1 > $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function greaterThan($version1, $version2) { return self::compare($version1, '>', $version2); } /** * Evaluates the expression: $version1 >= $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function greaterThanOrEqualTo($version1, $version2) { return self::compare($version1, '>=', $version2); } /** * Evaluates the expression: $version1 < $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function lessThan($version1, $version2) { return self::compare($version1, '<', $version2); } /** * Evaluates the expression: $version1 <= $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function lessThanOrEqualTo($version1, $version2) { return self::compare($version1, '<=', $version2); } /** * Evaluates the expression: $version1 == $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function equalTo($version1, $version2) { return self::compare($version1, '==', $version2); } /** * Evaluates the expression: $version1 != $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function notEqualTo($version1, $version2) { return self::compare($version1, '!=', $version2); } /** * Evaluates the expression: $version1 $operator $version2. * * @param string $version1 * @param string $operator * @param string $version2 * * @return bool * * @phpstan-param Constraint::STR_OP_* $operator */ public static function compare($version1, $operator, $version2) { $constraint = new Constraint($operator, $version2); return $constraint->matchSpecific(new Constraint('==', $version1), true); } } PK ! =��? ? src/Semver.phpnu �Iw�� <?php /* * This file is part of composer/semver. * * (c) Composer <https://github.com/composer> * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace Composer\Semver; use Composer\Semver\Constraint\Constraint; class Semver { const SORT_ASC = 1; const SORT_DESC = -1; /** @var VersionParser */ private static $versionParser; /** * Determine if given version satisfies given constraints. * * @param string $version * @param string $constraints * * @return bool */ public static function satisfies($version, $constraints) { if (null === self::$versionParser) { self::$versionParser = new VersionParser(); } $versionParser = self::$versionParser; $provider = new Constraint('==', $versionParser->normalize($version)); $parsedConstraints = $versionParser->parseConstraints($constraints); return $parsedConstraints->matches($provider); } /** * Return all versions that satisfy given constraints. * * @param string[] $versions * @param string $constraints * * @return string[] */ public static function satisfiedBy(array $versions, $constraints) { $versions = array_filter($versions, function ($version) use ($constraints) { return Semver::satisfies($version, $constraints); }); return array_values($versions); } /** * Sort given array of versions. * * @param string[] $versions * * @return string[] */ public static function sort(array $versions) { return self::usort($versions, self::SORT_ASC); } /** * Sort given array of versions in reverse. * * @param string[] $versions * * @return string[] */ public static function rsort(array $versions) { return self::usort($versions, self::SORT_DESC); } /** * @param string[] $versions * @param int $direction * * @return string[] */ private static function usort(array $versions, $direction) { if (null === self::$versionParser) { self::$versionParser = new VersionParser(); } $versionParser = self::$versionParser; $normalized = array(); // Normalize outside of usort() scope for minor performance increase. // Creates an array of arrays: [[normalized, key], ...] foreach ($versions as $key => $version) { $normalizedVersion = $versionParser->normalize($version); $normalizedVersion = $versionParser->normalizeDefaultBranch($normalizedVersion); $normalized[] = array($normalizedVersion, $key); } usort($normalized, function (array $left, array $right) use ($direction) { if ($left[0] === $right[0]) { return 0; } if (Comparator::lessThan($left[0], $right[0])) { return -$direction; } return $direction; }); // Recreate input array, using the original indexes which are now in sorted order. $sorted = array(); foreach ($normalized as $item) { $sorted[] = $versions[$item[1]]; } return $sorted; } } PK ! }~�@ src/CompilingMatcher.phpnu �Iw�� <?php /* * This file is part of composer/semver. * * (c) Composer <https://github.com/composer> * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace Composer\Semver; use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\ConstraintInterface; /** * Helper class to evaluate constraint by compiling and reusing the code to evaluate */ class CompilingMatcher { /** * @var array * @phpstan-var array<string, callable> */ private static $compiledCheckerCache = array(); /** * @var array * @phpstan-var array<string, bool> */ private static $resultCache = array(); /** @var bool */ private static $enabled; /** * @phpstan-var array<Constraint::OP_*, Constraint::STR_OP_*> */ private static $transOpInt = array( Constraint::OP_EQ => Constraint::STR_OP_EQ, Constraint::OP_LT => Constraint::STR_OP_LT, Constraint::OP_LE => Constraint::STR_OP_LE, Constraint::OP_GT => Constraint::STR_OP_GT, Constraint::OP_GE => Constraint::STR_OP_GE, Constraint::OP_NE => Constraint::STR_OP_NE, ); /** * Clears the memoization cache once you are done * * @return void */ public static function clear() { self::$resultCache = array(); self::$compiledCheckerCache = array(); } /** * Evaluates the expression: $constraint match $operator $version * * @param ConstraintInterface $constraint * @param int $operator * @phpstan-param Constraint::OP_* $operator * @param string $version * * @return bool */ public static function match(ConstraintInterface $constraint, $operator, $version) { $resultCacheKey = $operator.$constraint.';'.$version; if (isset(self::$resultCache[$resultCacheKey])) { return self::$resultCache[$resultCacheKey]; } if (self::$enabled === null) { self::$enabled = !\in_array('eval', explode(',', (string) ini_get('disable_functions')), true); } if (!self::$enabled) { return self::$resultCache[$resultCacheKey] = $constraint->matches(new Constraint(self::$transOpInt[$operator], $version)); } $cacheKey = $operator.$constraint; if (!isset(self::$compiledCheckerCache[$cacheKey])) { $code = $constraint->compile($operator); self::$compiledCheckerCache[$cacheKey] = $function = eval('return function($v, $b){return '.$code.';};'); } else { $function = self::$compiledCheckerCache[$cacheKey]; } return self::$resultCache[$resultCacheKey] = $function($version, strpos($version, 'dev-') === 0); } } PK ! 3���O �O src/Intervals.phpnu �Iw�� <?php /* * This file is part of composer/semver. * * (c) Composer <https://github.com/composer> * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace Composer\Semver; use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\ConstraintInterface; use Composer\Semver\Constraint\MatchAllConstraint; use Composer\Semver\Constraint\MatchNoneConstraint; use Composer\Semver\Constraint\MultiConstraint; /** * Helper class generating intervals from constraints * * This contains utilities for: * * - compacting an existing constraint which can be used to combine several into one * by creating a MultiConstraint out of the many constraints you have. * * - checking whether one subset is a subset of another. * * Note: You should call clear to free memoization memory usage when you are done using this class */ class Intervals { /** * @phpstan-var array<string, array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}}> */ private static $intervalsCache = array(); /** * @phpstan-var array<string, int> */ private static $opSortOrder = array( '>=' => -3, '<' => -2, '>' => 2, '<=' => 3, ); /** * Clears the memoization cache once you are done * * @return void */ public static function clear() { self::$intervalsCache = array(); } /** * Checks whether $candidate is a subset of $constraint * * @return bool */ public static function isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint) { if ($constraint instanceof MatchAllConstraint) { return true; } if ($candidate instanceof MatchNoneConstraint || $constraint instanceof MatchNoneConstraint) { return false; } $intersectionIntervals = self::get(new MultiConstraint(array($candidate, $constraint), true)); $candidateIntervals = self::get($candidate); if (\count($intersectionIntervals['numeric']) !== \count($candidateIntervals['numeric'])) { return false; } foreach ($intersectionIntervals['numeric'] as $index => $interval) { if (!isset($candidateIntervals['numeric'][$index])) { return false; } if ((string) $candidateIntervals['numeric'][$index]->getStart() !== (string) $interval->getStart()) { return false; } if ((string) $candidateIntervals['numeric'][$index]->getEnd() !== (string) $interval->getEnd()) { return false; } } if ($intersectionIntervals['branches']['exclude'] !== $candidateIntervals['branches']['exclude']) { return false; } if (\count($intersectionIntervals['branches']['names']) !== \count($candidateIntervals['branches']['names'])) { return false; } foreach ($intersectionIntervals['branches']['names'] as $index => $name) { if ($name !== $candidateIntervals['branches']['names'][$index]) { return false; } } return true; } /** * Checks whether $a and $b have any intersection, equivalent to $a->matches($b) * * @return bool */ public static function haveIntersections(ConstraintInterface $a, ConstraintInterface $b) { if ($a instanceof MatchAllConstraint || $b instanceof MatchAllConstraint) { return true; } if ($a instanceof MatchNoneConstraint || $b instanceof MatchNoneConstraint) { return false; } $intersectionIntervals = self::generateIntervals(new MultiConstraint(array($a, $b), true), true); return \count($intersectionIntervals['numeric']) > 0 || $intersectionIntervals['branches']['exclude'] || \count($intersectionIntervals['branches']['names']) > 0; } /** * Attempts to optimize a MultiConstraint * * When merging MultiConstraints together they can get very large, this will * compact it by looking at the real intervals covered by all the constraints * and then creates a new constraint containing only the smallest amount of rules * to match the same intervals. * * @return ConstraintInterface */ public static function compactConstraint(ConstraintInterface $constraint) { if (!$constraint instanceof MultiConstraint) { return $constraint; } $intervals = self::generateIntervals($constraint); $constraints = array(); $hasNumericMatchAll = false; if (\count($intervals['numeric']) === 1 && (string) $intervals['numeric'][0]->getStart() === (string) Interval::fromZero() && (string) $intervals['numeric'][0]->getEnd() === (string) Interval::untilPositiveInfinity()) { $constraints[] = $intervals['numeric'][0]->getStart(); $hasNumericMatchAll = true; } else { $unEqualConstraints = array(); for ($i = 0, $count = \count($intervals['numeric']); $i < $count; $i++) { $interval = $intervals['numeric'][$i]; // if current interval ends with < N and next interval begins with > N we can swap this out for != N // but this needs to happen as a conjunctive expression together with the start of the current interval // and end of next interval, so [>=M, <N] || [>N, <P] => [>=M, !=N, <P] but M/P can be skipped if // they are zero/+inf if ($interval->getEnd()->getOperator() === '<' && $i+1 < $count) { $nextInterval = $intervals['numeric'][$i+1]; if ($interval->getEnd()->getVersion() === $nextInterval->getStart()->getVersion() && $nextInterval->getStart()->getOperator() === '>') { // only add a start if we didn't already do so, can be skipped if we're looking at second // interval in [>=M, <N] || [>N, <P] || [>P, <Q] where unEqualConstraints currently contains // [>=M, !=N] already and we only want to add !=P right now if (\count($unEqualConstraints) === 0 && (string) $interval->getStart() !== (string) Interval::fromZero()) { $unEqualConstraints[] = $interval->getStart(); } $unEqualConstraints[] = new Constraint('!=', $interval->getEnd()->getVersion()); continue; } } if (\count($unEqualConstraints) > 0) { // this is where the end of the following interval of a != constraint is added as explained above if ((string) $interval->getEnd() !== (string) Interval::untilPositiveInfinity()) { $unEqualConstraints[] = $interval->getEnd(); } // count is 1 if entire constraint is just one != expression if (\count($unEqualConstraints) > 1) { $constraints[] = new MultiConstraint($unEqualConstraints, true); } else { $constraints[] = $unEqualConstraints[0]; } $unEqualConstraints = array(); continue; } // convert back >= x - <= x intervals to == x if ($interval->getStart()->getVersion() === $interval->getEnd()->getVersion() && $interval->getStart()->getOperator() === '>=' && $interval->getEnd()->getOperator() === '<=') { $constraints[] = new Constraint('==', $interval->getStart()->getVersion()); continue; } if ((string) $interval->getStart() === (string) Interval::fromZero()) { $constraints[] = $interval->getEnd(); } elseif ((string) $interval->getEnd() === (string) Interval::untilPositiveInfinity()) { $constraints[] = $interval->getStart(); } else { $constraints[] = new MultiConstraint(array($interval->getStart(), $interval->getEnd()), true); } } } $devConstraints = array(); if (0 === \count($intervals['branches']['names'])) { if ($intervals['branches']['exclude']) { if ($hasNumericMatchAll) { return new MatchAllConstraint; } // otherwise constraint should contain a != operator and already cover this } } else { foreach ($intervals['branches']['names'] as $branchName) { if ($intervals['branches']['exclude']) { $devConstraints[] = new Constraint('!=', $branchName); } else { $devConstraints[] = new Constraint('==', $branchName); } } // excluded branches, e.g. != dev-foo are conjunctive with the interval, so // > 2.0 != dev-foo must return a conjunctive constraint if ($intervals['branches']['exclude']) { if (\count($constraints) > 1) { return new MultiConstraint(array_merge( array(new MultiConstraint($constraints, false)), $devConstraints ), true); } if (\count($constraints) === 1 && (string)$constraints[0] === (string)Interval::fromZero()) { if (\count($devConstraints) > 1) { return new MultiConstraint($devConstraints, true); } return $devConstraints[0]; } return new MultiConstraint(array_merge($constraints, $devConstraints), true); } // otherwise devConstraints contains a list of == operators for branches which are disjunctive with the // rest of the constraint $constraints = array_merge($constraints, $devConstraints); } if (\count($constraints) > 1) { return new MultiConstraint($constraints, false); } if (\count($constraints) === 1) { return $constraints[0]; } return new MatchNoneConstraint; } /** * Creates an array of numeric intervals and branch constraints representing a given constraint * * if the returned numeric array is empty it means the constraint matches nothing in the numeric range (0 - +inf) * if the returned branches array is empty it means no dev-* versions are matched * if a constraint matches all possible dev-* versions, branches will contain Interval::anyDev() * * @return array * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}} */ public static function get(ConstraintInterface $constraint) { $key = (string) $constraint; if (!isset(self::$intervalsCache[$key])) { self::$intervalsCache[$key] = self::generateIntervals($constraint); } return self::$intervalsCache[$key]; } /** * @param bool $stopOnFirstValidInterval * * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}} */ private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = false) { if ($constraint instanceof MatchAllConstraint) { return array('numeric' => array(new Interval(Interval::fromZero(), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev()); } if ($constraint instanceof MatchNoneConstraint) { return array('numeric' => array(), 'branches' => array('names' => array(), 'exclude' => false)); } if ($constraint instanceof Constraint) { return self::generateSingleConstraintIntervals($constraint); } if (!$constraint instanceof MultiConstraint) { throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got '.\get_class($constraint).'.'); } $constraints = $constraint->getConstraints(); $numericGroups = array(); $constraintBranches = array(); foreach ($constraints as $c) { $res = self::get($c); $numericGroups[] = $res['numeric']; $constraintBranches[] = $res['branches']; } if ($constraint->isDisjunctive()) { $branches = Interval::noDev(); foreach ($constraintBranches as $b) { if ($b['exclude']) { if ($branches['exclude']) { // disjunctive constraint, so only exclude what's excluded in all constraints // !=a,!=b || !=b,!=c => !=b $branches['names'] = array_intersect($branches['names'], $b['names']); } else { // disjunctive constraint so exclude all names which are not explicitly included in the alternative // (==b || ==c) || !=a,!=b => !=a $branches['exclude'] = true; $branches['names'] = array_diff($b['names'], $branches['names']); } } else { if ($branches['exclude']) { // disjunctive constraint so exclude all names which are not explicitly included in the alternative // !=a,!=b || (==b || ==c) => !=a $branches['names'] = array_diff($branches['names'], $b['names']); } else { // disjunctive constraint, so just add all the other branches // (==a || ==b) || ==c => ==a || ==b || ==c $branches['names'] = array_merge($branches['names'], $b['names']); } } } } else { $branches = Interval::anyDev(); foreach ($constraintBranches as $b) { if ($b['exclude']) { if ($branches['exclude']) { // conjunctive, so just add all branch names to be excluded // !=a && !=b => !=a,!=b $branches['names'] = array_merge($branches['names'], $b['names']); } else { // conjunctive, so only keep included names which are not excluded // (==a||==c) && !=a,!=b => ==c $branches['names'] = array_diff($branches['names'], $b['names']); } } else { if ($branches['exclude']) { // conjunctive, so only keep included names which are not excluded // !=a,!=b && (==a||==c) => ==c $branches['names'] = array_diff($b['names'], $branches['names']); $branches['exclude'] = false; } else { // conjunctive, so only keep names that are included in both // (==a||==b) && (==a||==c) => ==a $branches['names'] = array_intersect($branches['names'], $b['names']); } } } } $branches['names'] = array_unique($branches['names']); if (\count($numericGroups) === 1) { return array('numeric' => $numericGroups[0], 'branches' => $branches); } $borders = array(); foreach ($numericGroups as $group) { foreach ($group as $interval) { $borders[] = array('version' => $interval->getStart()->getVersion(), 'operator' => $interval->getStart()->getOperator(), 'side' => 'start'); $borders[] = array('version' => $interval->getEnd()->getVersion(), 'operator' => $interval->getEnd()->getOperator(), 'side' => 'end'); } } $opSortOrder = self::$opSortOrder; usort($borders, function ($a, $b) use ($opSortOrder) { $order = version_compare($a['version'], $b['version']); if ($order === 0) { return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']]; } return $order; }); $activeIntervals = 0; $intervals = array(); $index = 0; $activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1; $start = null; foreach ($borders as $border) { if ($border['side'] === 'start') { $activeIntervals++; } else { $activeIntervals--; } if (!$start && $activeIntervals >= $activationThreshold) { $start = new Constraint($border['operator'], $border['version']); } elseif ($start && $activeIntervals < $activationThreshold) { // filter out invalid intervals like > x - <= x, or >= x - < x if ( version_compare($start->getVersion(), $border['version'], '=') && ( ($start->getOperator() === '>' && $border['operator'] === '<=') || ($start->getOperator() === '>=' && $border['operator'] === '<') ) ) { unset($intervals[$index]); } else { $intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version'])); $index++; if ($stopOnFirstValidInterval) { break; } } $start = null; } } return array('numeric' => $intervals, 'branches' => $branches); } /** * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}} */ private static function generateSingleConstraintIntervals(Constraint $constraint) { $op = $constraint->getOperator(); // handle branch constraints first if (strpos($constraint->getVersion(), 'dev-') === 0) { $intervals = array(); $branches = array('names' => array(), 'exclude' => false); // != dev-foo means any numeric version may match, we treat >/< like != they are not really defined for branches if ($op === '!=') { $intervals[] = new Interval(Interval::fromZero(), Interval::untilPositiveInfinity()); $branches = array('names' => array($constraint->getVersion()), 'exclude' => true); } elseif ($op === '==') { $branches['names'][] = $constraint->getVersion(); } return array( 'numeric' => $intervals, 'branches' => $branches, ); } if ($op[0] === '>') { // > & >= return array('numeric' => array(new Interval($constraint, Interval::untilPositiveInfinity())), 'branches' => Interval::noDev()); } if ($op[0] === '<') { // < & <= return array('numeric' => array(new Interval(Interval::fromZero(), $constraint)), 'branches' => Interval::noDev()); } if ($op === '!=') { // convert !=x to intervals of 0 - <x && >x - +inf + dev* return array('numeric' => array( new Interval(Interval::fromZero(), new Constraint('<', $constraint->getVersion())), new Interval(new Constraint('>', $constraint->getVersion()), Interval::untilPositiveInfinity()), ), 'branches' => Interval::anyDev()); } // convert ==x to an interval of >=x - <=x return array('numeric' => array( new Interval(new Constraint('>=', $constraint->getVersion()), new Constraint('<=', $constraint->getVersion())), ), 'branches' => Interval::noDev()); } } PK ! ��vx� � &