composer.json000064400000001241150250332110007254 0ustar00{ "name": "phar-io/version", "description": "Library for handling version information and constraints", "license": "BSD-3-Clause", "authors": [ { "name": "Arne Blankerts", "email": "arne@blankerts.de", "role": "Developer" }, { "name": "Sebastian Heuer", "email": "sebastian@phpeople.de", "role": "Developer" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "Developer" } ], "support": { "issues": "https://github.com/phar-io/version/issues" }, "require": { "php": "^7.2 || ^8.0" }, "autoload": { "classmap": [ "src/" ] } } CHANGELOG.md000064400000007225150250332110006353 0ustar00# Changelog All notable changes to phar-io/version are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [3.2.1] - 2022-02-21 ### Fixed - Have ExactVersionConstraint honor build metadata (added in 3.2.0) ## [3.2.0] - 2022-02-21 ### Added - Build metadata is now supported and considered for equality checks only ## [3.1.1] - 2022-02-07 ### Fixed - [#28](https://github.com/phar-io/version/issues/28): `VersionConstraintParser` does not support logical OR represented by single pipe (|) (Thanks @llaville) ## [3.1.0] - 2021-02-23 ### Changed - Internal Refactoring - More scalar types ### Added - [#24](https://github.com/phar-io/version/issues/24): `Version::getOriginalString()` added (Thanks @addshore) - Version constraints using the caret operator (`^`) now honor pre-1.0 releases, e.g. `^0.3` translates to `0.3.*`) - Various integration tests for version constraint processing ### Fixed - [#23](https://github.com/phar-io/version/pull/23): Tilde operator without patch level ## [3.0.4] - 14.12.2020 ### Fixed - [#22](https://github.com/phar-io/version/pull/22): make dev suffix rank works for uppercase too ## [3.0.3] - 30.11.2020 ### Added - Comparator method `Version::equals()` added ## [3.0.2] - 27.06.2020 This release now supports PHP 7.2+ and PHP ^8.0. No other changes included. ## [3.0.1] - 09.05.2020 __Potential BC Break Notice:__ `Version::getVersionString()` no longer returns `v` prefixes in case the "input" string contained one. These are not part of the semver specs (see https://semver.org/#is-v123-a-semantic-version) and get stripped out. As of Version 3.1.0 `Version::getOriginalString()` can be used to still retrieve it as given. ### Changed - Internal Refactoring - More scalar types ### Fixed - Fixed Constraint processing Regression for ^1.2 and ~1.2 ## [3.0.0] - 05.05.2020 ### Changed - Require PHP 7.2+ - All code now uses strict mode - Scalar types have been added as needed ### Added - The technically invalid format using 'v' prefix ("v1.2.3") is now properly supported ## [2.0.1] - 08.07.2018 ### Fixed - Versions without a pre-release suffix are now always considered greater than versions with a pre-release suffix. Example: `3.0.0 > 3.0.0-alpha.1` ## [2.0.0] - 23.06.2018 Changes to public API: - `PreReleaseSuffix::construct()`: optional parameter `$number` removed - `PreReleaseSuffix::isGreaterThan()`: introduced - `Version::hasPreReleaseSuffix()`: introduced ### Added - [#11](https://github.com/phar-io/version/issues/11): Added support for pre-release version suffixes. Supported values are: - `dev` - `beta` (also abbreviated form `b`) - `rc` - `alpha` (also abbreviated form `a`) - `patch` (also abbreviated form `p`) All values can be followed by a number, e.g. `beta3`. When comparing versions, the pre-release suffix is taken into account. Example: `1.5.0 > 1.5.0-beta1 > 1.5.0-alpha3 > 1.5.0-alpha2 > 1.5.0-dev11` ### Changed - reorganized the source directories ### Fixed - [#10](https://github.com/phar-io/version/issues/10): Version numbers containing a numeric suffix as seen in Debian packages are now supported. [3.1.0]: https://github.com/phar-io/version/compare/3.0.4...3.1.0 [3.0.4]: https://github.com/phar-io/version/compare/3.0.3...3.0.4 [3.0.3]: https://github.com/phar-io/version/compare/3.0.2...3.0.3 [3.0.2]: https://github.com/phar-io/version/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/phar-io/version/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/phar-io/version/compare/2.0.1...3.0.0 [2.0.1]: https://github.com/phar-io/version/compare/2.0.0...2.0.1 [2.0.0]: https://github.com/phar-io/version/compare/1.0.1...2.0.0 src/VersionConstraintParser.php000064400000007377150250332110012721 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class VersionConstraintParser { /** * @throws UnsupportedVersionConstraintException */ public function parse(string $value): VersionConstraint { if (\strpos($value, '|') !== false) { return $this->handleOrGroup($value); } if (!\preg_match('/^[\^~*]?v?[\d.*]+(?:-.*)?$/i', $value)) { throw new UnsupportedVersionConstraintException( \sprintf('Version constraint %s is not supported.', $value) ); } switch ($value[0]) { case '~': return $this->handleTildeOperator($value); case '^': return $this->handleCaretOperator($value); } $constraint = new VersionConstraintValue($value); if ($constraint->getMajor()->isAny()) { return new AnyVersionConstraint(); } if ($constraint->getMinor()->isAny()) { return new SpecificMajorVersionConstraint( $constraint->getVersionString(), $constraint->getMajor()->getValue() ?? 0 ); } if ($constraint->getPatch()->isAny()) { return new SpecificMajorAndMinorVersionConstraint( $constraint->getVersionString(), $constraint->getMajor()->getValue() ?? 0, $constraint->getMinor()->getValue() ?? 0 ); } return new ExactVersionConstraint($constraint->getVersionString()); } private function handleOrGroup(string $value): OrVersionConstraintGroup { $constraints = []; foreach (\preg_split('{\s*\|\|?\s*}', \trim($value)) as $groupSegment) { $constraints[] = $this->parse(\trim($groupSegment)); } return new OrVersionConstraintGroup($value, $constraints); } private function handleTildeOperator(string $value): AndVersionConstraintGroup { $constraintValue = new VersionConstraintValue(\substr($value, 1)); if ($constraintValue->getPatch()->isAny()) { return $this->handleCaretOperator($value); } $constraints = [ new GreaterThanOrEqualToVersionConstraint( $value, new Version(\substr($value, 1)) ), new SpecificMajorAndMinorVersionConstraint( $value, $constraintValue->getMajor()->getValue() ?? 0, $constraintValue->getMinor()->getValue() ?? 0 ) ]; return new AndVersionConstraintGroup($value, $constraints); } private function handleCaretOperator(string $value): AndVersionConstraintGroup { $constraintValue = new VersionConstraintValue(\substr($value, 1)); $constraints = [ new GreaterThanOrEqualToVersionConstraint($value, new Version(\substr($value, 1))) ]; if ($constraintValue->getMajor()->getValue() === 0) { $constraints[] = new SpecificMajorAndMinorVersionConstraint( $value, $constraintValue->getMajor()->getValue() ?? 0, $constraintValue->getMinor()->getValue() ?? 0 ); } else { $constraints[] = new SpecificMajorVersionConstraint( $value, $constraintValue->getMajor()->getValue() ?? 0 ); } return new AndVersionConstraintGroup( $value, $constraints ); } } src/constraints/AndVersionConstraintGroup.php000064400000001727150250332110015544 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class AndVersionConstraintGroup extends AbstractVersionConstraint { /** @var VersionConstraint[] */ private $constraints = []; /** * @param VersionConstraint[] $constraints */ public function __construct(string $originalValue, array $constraints) { parent::__construct($originalValue); $this->constraints = $constraints; } public function complies(Version $version): bool { foreach ($this->constraints as $constraint) { if (!$constraint->complies($version)) { return false; } } return true; } } src/constraints/AbstractVersionConstraint.php000064400000001257150250332110015566 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; abstract class AbstractVersionConstraint implements VersionConstraint { /** @var string */ private $originalValue; public function __construct(string $originalValue) { $this->originalValue = $originalValue; } public function asString(): string { return $this->originalValue; } } src/constraints/AnyVersionConstraint.php000064400000001100150250332110014535 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class AnyVersionConstraint implements VersionConstraint { public function complies(Version $version): bool { return true; } public function asString(): string { return '*'; } } src/constraints/SpecificMajorVersionConstraint.php000064400000001372150250332110016537 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class SpecificMajorVersionConstraint extends AbstractVersionConstraint { /** @var int */ private $major; public function __construct(string $originalValue, int $major) { parent::__construct($originalValue); $this->major = $major; } public function complies(Version $version): bool { return $version->getMajor()->getValue() === $this->major; } } src/constraints/SpecificMajorAndMinorVersionConstraint.php000064400000001674150250332110020174 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class SpecificMajorAndMinorVersionConstraint extends AbstractVersionConstraint { /** @var int */ private $major; /** @var int */ private $minor; public function __construct(string $originalValue, int $major, int $minor) { parent::__construct($originalValue); $this->major = $major; $this->minor = $minor; } public function complies(Version $version): bool { if ($version->getMajor()->getValue() !== $this->major) { return false; } return $version->getMinor()->getValue() === $this->minor; } } src/constraints/VersionConstraint.php000064400000000755150250332110014104 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; interface VersionConstraint { public function complies(Version $version): bool; public function asString(): string; } src/constraints/ExactVersionConstraint.php000064400000001310150250332110015055 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class ExactVersionConstraint extends AbstractVersionConstraint { public function complies(Version $version): bool { $other = $version->getVersionString(); if ($version->hasBuildMetaData()) { $other .= '+' . $version->getBuildMetaData()->asString(); } return $this->asString() === $other; } } src/constraints/OrVersionConstraintGroup.php000064400000001777150250332110015427 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class OrVersionConstraintGroup extends AbstractVersionConstraint { /** @var VersionConstraint[] */ private $constraints = []; /** * @param string $originalValue * @param VersionConstraint[] $constraints */ public function __construct($originalValue, array $constraints) { parent::__construct($originalValue); $this->constraints = $constraints; } public function complies(Version $version): bool { foreach ($this->constraints as $constraint) { if ($constraint->complies($version)) { return true; } } return false; } } src/constraints/GreaterThanOrEqualToVersionConstraint.php000064400000001604150250332110020017 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class GreaterThanOrEqualToVersionConstraint extends AbstractVersionConstraint { /** @var Version */ private $minimalVersion; public function __construct(string $originalValue, Version $minimalVersion) { parent::__construct($originalValue); $this->minimalVersion = $minimalVersion; } public function complies(Version $version): bool { return $version->getVersionString() === $this->minimalVersion->getVersionString() || $version->isGreaterThan($this->minimalVersion); } } src/VersionConstraintValue.php000064400000005046150250332110012530 0ustar00versionString = $versionString; $this->parseVersion($versionString); } public function getLabel(): string { return $this->label; } public function getBuildMetaData(): string { return $this->buildMetaData; } public function getVersionString(): string { return $this->versionString; } public function getMajor(): VersionNumber { return $this->major; } public function getMinor(): VersionNumber { return $this->minor; } public function getPatch(): VersionNumber { return $this->patch; } private function parseVersion(string $versionString): void { $this->extractBuildMetaData($versionString); $this->extractLabel($versionString); $this->stripPotentialVPrefix($versionString); $versionSegments = \explode('.', $versionString); $this->major = new VersionNumber(\is_numeric($versionSegments[0]) ? (int)$versionSegments[0] : null); $minorValue = isset($versionSegments[1]) && \is_numeric($versionSegments[1]) ? (int)$versionSegments[1] : null; $patchValue = isset($versionSegments[2]) && \is_numeric($versionSegments[2]) ? (int)$versionSegments[2] : null; $this->minor = new VersionNumber($minorValue); $this->patch = new VersionNumber($patchValue); } private function extractBuildMetaData(string &$versionString): void { if (\preg_match('/\+(.*)/', $versionString, $matches) === 1) { $this->buildMetaData = $matches[1]; $versionString = \str_replace($matches[0], '', $versionString); } } private function extractLabel(string &$versionString): void { if (\preg_match('/-(.*)/', $versionString, $matches) === 1) { $this->label = $matches[1]; $versionString = \str_replace($matches[0], '', $versionString); } } private function stripPotentialVPrefix(string &$versionString): void { if ($versionString[0] !== 'v') { return; } $versionString = \substr($versionString, 1); } } src/exceptions/NoPreReleaseSuffixException.php000064400000000212150250332110015600 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; final class UnsupportedVersionConstraintException extends \RuntimeException implements Exception { } src/exceptions/NoBuildMetaDataException.php000064400000000207150250332110015030 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; use Throwable; interface Exception extends Throwable { } src/Version.php000064400000013453150250332110007467 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class Version { /** @var string */ private $originalVersionString; /** @var VersionNumber */ private $major; /** @var VersionNumber */ private $minor; /** @var VersionNumber */ private $patch; /** @var null|PreReleaseSuffix */ private $preReleaseSuffix; /** @var null|BuildMetaData */ private $buildMetadata; public function __construct(string $versionString) { $this->ensureVersionStringIsValid($versionString); $this->originalVersionString = $versionString; } /** * @throws NoPreReleaseSuffixException */ public function getPreReleaseSuffix(): PreReleaseSuffix { if ($this->preReleaseSuffix === null) { throw new NoPreReleaseSuffixException('No pre-release suffix set'); } return $this->preReleaseSuffix; } public function getOriginalString(): string { return $this->originalVersionString; } public function getVersionString(): string { $str = \sprintf( '%d.%d.%d', $this->getMajor()->getValue() ?? 0, $this->getMinor()->getValue() ?? 0, $this->getPatch()->getValue() ?? 0 ); if (!$this->hasPreReleaseSuffix()) { return $str; } return $str . '-' . $this->getPreReleaseSuffix()->asString(); } public function hasPreReleaseSuffix(): bool { return $this->preReleaseSuffix !== null; } public function equals(Version $other): bool { if ($this->getVersionString() !== $other->getVersionString()) { return false; } if ($this->hasBuildMetaData() !== $other->hasBuildMetaData()) { return false; } if ($this->hasBuildMetaData() && $other->hasBuildMetaData() && !$this->getBuildMetaData()->equals($other->getBuildMetaData())) { return false; } return true; } public function isGreaterThan(Version $version): bool { if ($version->getMajor()->getValue() > $this->getMajor()->getValue()) { return false; } if ($version->getMajor()->getValue() < $this->getMajor()->getValue()) { return true; } if ($version->getMinor()->getValue() > $this->getMinor()->getValue()) { return false; } if ($version->getMinor()->getValue() < $this->getMinor()->getValue()) { return true; } if ($version->getPatch()->getValue() > $this->getPatch()->getValue()) { return false; } if ($version->getPatch()->getValue() < $this->getPatch()->getValue()) { return true; } if (!$version->hasPreReleaseSuffix() && !$this->hasPreReleaseSuffix()) { return false; } if ($version->hasPreReleaseSuffix() && !$this->hasPreReleaseSuffix()) { return true; } if (!$version->hasPreReleaseSuffix() && $this->hasPreReleaseSuffix()) { return false; } return $this->getPreReleaseSuffix()->isGreaterThan($version->getPreReleaseSuffix()); } public function getMajor(): VersionNumber { return $this->major; } public function getMinor(): VersionNumber { return $this->minor; } public function getPatch(): VersionNumber { return $this->patch; } /** * @psalm-assert-if-true BuildMetaData $this->buildMetadata * @psalm-assert-if-true BuildMetaData $this->getBuildMetaData() */ public function hasBuildMetaData(): bool { return $this->buildMetadata !== null; } /** * @throws NoBuildMetaDataException */ public function getBuildMetaData(): BuildMetaData { if (!$this->hasBuildMetaData()) { throw new NoBuildMetaDataException('No build metadata set'); } return $this->buildMetadata; } /** * @param string[] $matches * * @throws InvalidPreReleaseSuffixException */ private function parseVersion(array $matches): void { $this->major = new VersionNumber((int)$matches['Major']); $this->minor = new VersionNumber((int)$matches['Minor']); $this->patch = isset($matches['Patch']) ? new VersionNumber((int)$matches['Patch']) : new VersionNumber(0); if (isset($matches['PreReleaseSuffix']) && $matches['PreReleaseSuffix'] !== '') { $this->preReleaseSuffix = new PreReleaseSuffix($matches['PreReleaseSuffix']); } if (isset($matches['BuildMetadata'])) { $this->buildMetadata = new BuildMetaData($matches['BuildMetadata']); } } /** * @param string $version * * @throws InvalidVersionException */ private function ensureVersionStringIsValid($version): void { $regex = '/^v? (?P0|[1-9]\d*) \\. (?P0|[1-9]\d*) (\\. (?P0|[1-9]\d*) )? (?: - (?(?:(dev|beta|b|rc|alpha|a|patch|p|pl)\.?\d*)) )? (?: \\+ (?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-@]+)*) )? $/xi'; if (\preg_match($regex, $version, $matches) !== 1) { throw new InvalidVersionException( \sprintf("Version string '%s' does not follow SemVer semantics", $version) ); } $this->parseVersion($matches); } } src/VersionNumber.php000064400000001241150250332110010630 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class VersionNumber { /** @var ?int */ private $value; public function __construct(?int $value) { $this->value = $value; } public function isAny(): bool { return $this->value === null; } public function getValue(): ?int { return $this->value; } } src/BuildMetaData.php000064400000001317150250332110010476 0ustar00, Sebastian Heuer , Sebastian Bergmann * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PharIo\Version; class BuildMetaData { /** @var string */ private $value; public function __construct(string $value) { $this->value = $value; } public function asString(): string { return $this->value; } public function equals(BuildMetaData $other): bool { return $this->asString() === $other->asString(); } } src/PreReleaseSuffix.php000064400000003536150250332110011257 0ustar00 0, 'a' => 1, 'alpha' => 1, 'b' => 2, 'beta' => 2, 'rc' => 3, 'p' => 4, 'pl' => 4, 'patch' => 4, ]; /** @var string */ private $value; /** @var int */ private $valueScore; /** @var int */ private $number = 0; /** @var string */ private $full; /** * @throws InvalidPreReleaseSuffixException */ public function __construct(string $value) { $this->parseValue($value); } public function asString(): string { return $this->full; } public function getValue(): string { return $this->value; } public function getNumber(): ?int { return $this->number; } public function isGreaterThan(PreReleaseSuffix $suffix): bool { if ($this->valueScore > $suffix->valueScore) { return true; } if ($this->valueScore < $suffix->valueScore) { return false; } return $this->getNumber() > $suffix->getNumber(); } private function mapValueToScore(string $value): int { $value = \strtolower($value); return self::valueScoreMap[$value]; } private function parseValue(string $value): void { $regex = '/-?((dev|beta|b|rc|alpha|a|patch|p|pl)\.?(\d*)).*$/i'; if (\preg_match($regex, $value, $matches) !== 1) { throw new InvalidPreReleaseSuffixException(\sprintf('Invalid label %s', $value)); } $this->full = $matches[1]; $this->value = $matches[2]; if ($matches[3] !== '') { $this->number = (int)$matches[3]; } $this->valueScore = $this->mapValueToScore($matches[2]); } } README.md000064400000004471150250332110006021 0ustar00# Version Library for handling version information and constraints [![Build Status](https://travis-ci.org/phar-io/version.svg?branch=master)](https://travis-ci.org/phar-io/version) ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): composer require phar-io/version If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: composer require --dev phar-io/version ## Version constraints A Version constraint describes a range of versions or a discrete version number. The format of version numbers follows the schema of [semantic versioning](http://semver.org): `..`. A constraint might contain an operator that describes the range. Beside the typical mathematical operators like `<=`, `>=`, there are two special operators: *Caret operator*: `^1.0` can be written as `>=1.0.0 <2.0.0` and read as »every Version within major version `1`«. *Tilde operator*: `~1.0.0` can be written as `>=1.0.0 <1.1.0` and read as »every version within minor version `1.1`. The behavior of tilde operator depends on whether a patch level version is provided or not. If no patch level is provided, tilde operator behaves like the caret operator: `~1.0` is identical to `^1.0`. ## Usage examples Parsing version constraints and check discrete versions for compliance: ```php use PharIo\Version\Version; use PharIo\Version\VersionConstraintParser; $parser = new VersionConstraintParser(); $caret_constraint = $parser->parse( '^7.0' ); $caret_constraint->complies( new Version( '7.0.17' ) ); // true $caret_constraint->complies( new Version( '7.1.0' ) ); // true $caret_constraint->complies( new Version( '6.4.34' ) ); // false $tilde_constraint = $parser->parse( '~1.1.0' ); $tilde_constraint->complies( new Version( '1.1.4' ) ); // true $tilde_constraint->complies( new Version( '1.2.0' ) ); // false ``` As of version 2.0.0, pre-release labels are supported and taken into account when comparing versions: ```php $leftVersion = new PharIo\Version\Version('3.0.0-alpha.1'); $rightVersion = new PharIo\Version\Version('3.0.0-alpha.2'); $leftVersion->isGreaterThan($rightVersion); // false $rightVersion->isGreaterThan($leftVersion); // true ``` LICENSE000064400000003046150250332110005544 0ustar00Copyright (c) 2016-2017 Arne Blankerts , Sebastian Heuer and contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.