mirror of
https://github.com/composer/composer
synced 2025-05-10 17:12:51 +00:00
php-cs-fixer magic
This commit is contained in:
parent
4ea9b33a6c
commit
1bd4ccbd54
90 changed files with 396 additions and 400 deletions
|
@ -12,7 +12,6 @@
|
|||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||
|
@ -179,7 +178,7 @@ class DefaultPolicy implements PolicyInterface
|
|||
if ($this->versionCompare($package, $bestPackage, '>')) {
|
||||
$bestPackage = $package;
|
||||
$bestLiterals = array($literal);
|
||||
} else if ($this->versionCompare($package, $bestPackage, '==')) {
|
||||
} elseif ($this->versionCompare($package, $bestPackage, '==')) {
|
||||
$bestLiterals[] = $literal;
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +198,7 @@ class DefaultPolicy implements PolicyInterface
|
|||
if ($this->versionCompare($literal->getPackage(), $maxPackage, '>')) {
|
||||
$maxPackage = $literal->getPackage();
|
||||
$maxLiterals = array($literal);
|
||||
} else if ($this->versionCompare($literal->getPackage(), $maxPackage, '==')) {
|
||||
} elseif ($this->versionCompare($literal->getPackage(), $maxPackage, '==')) {
|
||||
$maxLiterals[] = $literal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ class InstallOperation extends SolverOperation
|
|||
/**
|
||||
* Initializes operation.
|
||||
*
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $reason operation reason
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $reason operation reason
|
||||
*/
|
||||
public function __construct(PackageInterface $package, $reason = null)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ class InstallOperation extends SolverOperation
|
|||
/**
|
||||
* Returns package instance.
|
||||
*
|
||||
* @return PackageInterface
|
||||
* @return PackageInterface
|
||||
*/
|
||||
public function getPackage()
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ class InstallOperation extends SolverOperation
|
|||
/**
|
||||
* Returns job type.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getJobType()
|
||||
{
|
||||
|
|
|
@ -26,8 +26,8 @@ class MarkAliasInstalledOperation extends SolverOperation
|
|||
/**
|
||||
* Initializes operation.
|
||||
*
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $reason operation reason
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $reason operation reason
|
||||
*/
|
||||
public function __construct(AliasPackage $package, $reason = null)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ class MarkAliasInstalledOperation extends SolverOperation
|
|||
/**
|
||||
* Returns package instance.
|
||||
*
|
||||
* @return PackageInterface
|
||||
* @return PackageInterface
|
||||
*/
|
||||
public function getPackage()
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ class MarkAliasInstalledOperation extends SolverOperation
|
|||
/**
|
||||
* Returns job type.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getJobType()
|
||||
{
|
||||
|
|
|
@ -26,8 +26,8 @@ class MarkAliasUninstalledOperation extends SolverOperation
|
|||
/**
|
||||
* Initializes operation.
|
||||
*
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $reason operation reason
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $reason operation reason
|
||||
*/
|
||||
public function __construct(AliasPackage $package, $reason = null)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ class MarkAliasUninstalledOperation extends SolverOperation
|
|||
/**
|
||||
* Returns package instance.
|
||||
*
|
||||
* @return PackageInterface
|
||||
* @return PackageInterface
|
||||
*/
|
||||
public function getPackage()
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ class MarkAliasUninstalledOperation extends SolverOperation
|
|||
/**
|
||||
* Returns job type.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getJobType()
|
||||
{
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
namespace Composer\DependencyResolver\Operation;
|
||||
|
||||
use Composer\Package\PackageInterface;
|
||||
|
||||
/**
|
||||
* Solver operation interface.
|
||||
|
@ -24,14 +23,14 @@ interface OperationInterface
|
|||
/**
|
||||
* Returns job type.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
function getJobType();
|
||||
|
||||
/**
|
||||
* Returns operation reason.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
function getReason();
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ abstract class SolverOperation implements OperationInterface
|
|||
/**
|
||||
* Initializes operation.
|
||||
*
|
||||
* @param string $reason operation reason
|
||||
* @param string $reason operation reason
|
||||
*/
|
||||
public function __construct($reason = null)
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ abstract class SolverOperation implements OperationInterface
|
|||
/**
|
||||
* Returns operation reason.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getReason()
|
||||
{
|
||||
|
|
|
@ -26,8 +26,8 @@ class UninstallOperation extends SolverOperation
|
|||
/**
|
||||
* Initializes operation.
|
||||
*
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $reason operation reason
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $reason operation reason
|
||||
*/
|
||||
public function __construct(PackageInterface $package, $reason = null)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ class UninstallOperation extends SolverOperation
|
|||
/**
|
||||
* Returns package instance.
|
||||
*
|
||||
* @return PackageInterface
|
||||
* @return PackageInterface
|
||||
*/
|
||||
public function getPackage()
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ class UninstallOperation extends SolverOperation
|
|||
/**
|
||||
* Returns job type.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getJobType()
|
||||
{
|
||||
|
|
|
@ -27,9 +27,9 @@ class UpdateOperation extends SolverOperation
|
|||
/**
|
||||
* Initializes update operation.
|
||||
*
|
||||
* @param PackageInterface $initial initial package
|
||||
* @param PackageInterface $target target package (updated)
|
||||
* @param string $reason update reason
|
||||
* @param PackageInterface $initial initial package
|
||||
* @param PackageInterface $target target package (updated)
|
||||
* @param string $reason update reason
|
||||
*/
|
||||
public function __construct(PackageInterface $initial, PackageInterface $target, $reason = null)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ class UpdateOperation extends SolverOperation
|
|||
/**
|
||||
* Returns initial package.
|
||||
*
|
||||
* @return PackageInterface
|
||||
* @return PackageInterface
|
||||
*/
|
||||
public function getInitialPackage()
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ class UpdateOperation extends SolverOperation
|
|||
/**
|
||||
* Returns target package.
|
||||
*
|
||||
* @return PackageInterface
|
||||
* @return PackageInterface
|
||||
*/
|
||||
public function getTargetPackage()
|
||||
{
|
||||
|
@ -62,7 +62,7 @@ class UpdateOperation extends SolverOperation
|
|||
/**
|
||||
* Returns job type.
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getJobType()
|
||||
{
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
|
||||
/**
|
||||
|
|
|
@ -127,7 +127,7 @@ class Pool
|
|||
* @param string $name The package name to be searched for
|
||||
* @param LinkConstraintInterface $constraint A constraint that all returned
|
||||
* packages must match or null to return all
|
||||
* @return array A set of packages
|
||||
* @return array A set of packages
|
||||
*/
|
||||
public function whatProvides($name, LinkConstraintInterface $constraint = null)
|
||||
{
|
||||
|
@ -155,6 +155,7 @@ class Pool
|
|||
public function literalToPackage($literal)
|
||||
{
|
||||
$packageId = abs($literal);
|
||||
|
||||
return $this->packageById($packageId);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class Problem
|
|||
/**
|
||||
* Add a rule as a reason
|
||||
*
|
||||
* @param Rule $rule A rule which is a reason for this problem
|
||||
* @param Rule $rule A rule which is a reason for this problem
|
||||
*/
|
||||
public function addRule(Rule $rule)
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ class Problem
|
|||
/**
|
||||
* Retrieve all reasons for this problem
|
||||
*
|
||||
* @return array The problem's reasons
|
||||
* @return array The problem's reasons
|
||||
*/
|
||||
public function getReasons()
|
||||
{
|
||||
|
@ -65,8 +65,10 @@ class Problem
|
|||
if (0 === stripos($job['packageName'], 'ext-')) {
|
||||
$ext = substr($job['packageName'], 4);
|
||||
$error = extension_loaded($ext) ? 'has the wrong version ('.phpversion($ext).') installed' : 'is missing from your system';
|
||||
|
||||
return 'The requested PHP extension "'.$job['packageName'].'" '.$this->constraintToText($job['constraint']).$error.'.';
|
||||
}
|
||||
|
||||
return 'The requested package "'.$job['packageName'].'" '.$this->constraintToText($job['constraint']).'could not be found.';
|
||||
}
|
||||
}
|
||||
|
@ -93,8 +95,8 @@ class Problem
|
|||
/**
|
||||
* Store a reason descriptor but ignore duplicates
|
||||
*
|
||||
* @param string $id A canonical identifier for the reason
|
||||
* @param string $reason The reason descriptor
|
||||
* @param string $id A canonical identifier for the reason
|
||||
* @param string $reason The reason descriptor
|
||||
*/
|
||||
protected function addReason($id, $reason)
|
||||
{
|
||||
|
@ -106,8 +108,8 @@ class Problem
|
|||
/**
|
||||
* Turns a job into a human readable description
|
||||
*
|
||||
* @param array $job
|
||||
* @return string
|
||||
* @param array $job
|
||||
* @return string
|
||||
*/
|
||||
protected function jobToText($job)
|
||||
{
|
||||
|
@ -126,8 +128,8 @@ class Problem
|
|||
/**
|
||||
* Turns a constraint into text usable in a sentence describing a job
|
||||
*
|
||||
* @param LinkConstraint $constraint
|
||||
* @return string
|
||||
* @param LinkConstraint $constraint
|
||||
* @return string
|
||||
*/
|
||||
protected function constraintToText($constraint)
|
||||
{
|
||||
|
|
|
@ -86,7 +86,7 @@ class Rule
|
|||
* Ignores whether either of the rules is disabled.
|
||||
*
|
||||
* @param Rule $rule The rule to check against
|
||||
* @return bool Whether the rules are equal
|
||||
* @return bool Whether the rules are equal
|
||||
*/
|
||||
public function equals(Rule $rule)
|
||||
{
|
||||
|
@ -170,6 +170,7 @@ class Rule
|
|||
case self::RULE_PACKAGE_CONFLICT:
|
||||
$package1 = $this->pool->literalToPackage($this->literals[0]);
|
||||
$package2 = $this->pool->literalToPackage($this->literals[1]);
|
||||
|
||||
return 'Package "'.$package1.'" conflicts with "'.$package2.'"';
|
||||
|
||||
case self::RULE_PACKAGE_REQUIRES:
|
||||
|
@ -188,6 +189,7 @@ class Rule
|
|||
} else {
|
||||
$text .= 'No package satisfies this dependency.';
|
||||
}
|
||||
|
||||
return $text;
|
||||
|
||||
case self::RULE_PACKAGE_OBSOLETES:
|
||||
|
|
|
@ -93,16 +93,14 @@ class RuleSet implements \IteratorAggregate, \Countable
|
|||
|
||||
public function getIteratorFor($types)
|
||||
{
|
||||
if (!is_array($types))
|
||||
{
|
||||
if (!is_array($types)) {
|
||||
$types = array($types);
|
||||
}
|
||||
|
||||
$allRules = $this->getRules();
|
||||
$rules = array();
|
||||
|
||||
foreach ($types as $type)
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
$rules[$type] = $allRules[$type];
|
||||
}
|
||||
|
||||
|
@ -112,15 +110,13 @@ class RuleSet implements \IteratorAggregate, \Countable
|
|||
|
||||
public function getIteratorWithout($types)
|
||||
{
|
||||
if (!is_array($types))
|
||||
{
|
||||
if (!is_array($types)) {
|
||||
$types = array($types);
|
||||
}
|
||||
|
||||
$rules = $this->getRules();
|
||||
|
||||
foreach ($types as $type)
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
unset($rules[$type]);
|
||||
}
|
||||
|
||||
|
@ -131,6 +127,7 @@ class RuleSet implements \IteratorAggregate, \Countable
|
|||
{
|
||||
$types = self::$types;
|
||||
unset($types[-1]);
|
||||
|
||||
return array_keys($types);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,8 @@
|
|||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\DependencyResolver\Operation;
|
||||
|
||||
/**
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
|
@ -40,13 +38,13 @@ class RuleSetGenerator
|
|||
* This rule is of the form (-A|B|C), where B and C are the providers of
|
||||
* one requirement of the package A.
|
||||
*
|
||||
* @param PackageInterface $package The package with a requirement
|
||||
* @param array $providers The providers of the requirement
|
||||
* @param int $reason A RULE_* constant describing the
|
||||
* @param PackageInterface $package The package with a requirement
|
||||
* @param array $providers The providers of the requirement
|
||||
* @param int $reason A RULE_* constant describing the
|
||||
* reason for generating this rule
|
||||
* @param mixed $reasonData Any data, e.g. the requirement name,
|
||||
* @param mixed $reasonData Any data, e.g. the requirement name,
|
||||
* that goes with the reason
|
||||
* @return Rule The generated rule or null if tautological
|
||||
* @return Rule The generated rule or null if tautological
|
||||
*/
|
||||
protected function createRequireRule(PackageInterface $package, array $providers, $reason, $reasonData = null)
|
||||
{
|
||||
|
@ -69,11 +67,11 @@ class RuleSetGenerator
|
|||
* The rule is (A|B|C) with A, B and C different packages. If the given
|
||||
* set of packages is empty an impossible rule is generated.
|
||||
*
|
||||
* @param array $packages The set of packages to choose from
|
||||
* @param int $reason A RULE_* constant describing the reason for
|
||||
* @param array $packages The set of packages to choose from
|
||||
* @param int $reason A RULE_* constant describing the reason for
|
||||
* generating this rule
|
||||
* @param array $job The job this rule was created from
|
||||
* @return Rule The generated rule
|
||||
* @param array $job The job this rule was created from
|
||||
* @return Rule The generated rule
|
||||
*/
|
||||
protected function createInstallOneOfRule(array $packages, $reason, $job)
|
||||
{
|
||||
|
@ -90,11 +88,11 @@ class RuleSetGenerator
|
|||
*
|
||||
* The rule for a package A is (-A).
|
||||
*
|
||||
* @param PackageInterface $package The package to be removed
|
||||
* @param int $reason A RULE_* constant describing the
|
||||
* @param PackageInterface $package The package to be removed
|
||||
* @param int $reason A RULE_* constant describing the
|
||||
* reason for generating this rule
|
||||
* @param array $job The job this rule was created from
|
||||
* @return Rule The generated rule
|
||||
* @param array $job The job this rule was created from
|
||||
* @return Rule The generated rule
|
||||
*/
|
||||
protected function createRemoveRule(PackageInterface $package, $reason, $job)
|
||||
{
|
||||
|
@ -107,13 +105,13 @@ class RuleSetGenerator
|
|||
* The rule for conflicting packages A and B is (-A|-B). A is called the issuer
|
||||
* and B the provider.
|
||||
*
|
||||
* @param PackageInterface $issuer The package declaring the conflict
|
||||
* @param Package $provider The package causing the conflict
|
||||
* @param int $reason A RULE_* constant describing the
|
||||
* @param PackageInterface $issuer The package declaring the conflict
|
||||
* @param Package $provider The package causing the conflict
|
||||
* @param int $reason A RULE_* constant describing the
|
||||
* reason for generating this rule
|
||||
* @param mixed $reasonData Any data, e.g. the package name, that
|
||||
* @param mixed $reasonData Any data, e.g. the package name, that
|
||||
* goes with the reason
|
||||
* @return Rule The generated rule
|
||||
* @return Rule The generated rule
|
||||
*/
|
||||
protected function createConflictRule(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null)
|
||||
{
|
||||
|
@ -134,7 +132,8 @@ class RuleSetGenerator
|
|||
* @param int $type A TYPE_* constant defining the rule type
|
||||
* @param Rule $newRule The rule about to be added
|
||||
*/
|
||||
private function addRule($type, Rule $newRule = null) {
|
||||
private function addRule($type, Rule $newRule = null)
|
||||
{
|
||||
if ($this->rules->containsEqual($newRule)) {
|
||||
return;
|
||||
}
|
||||
|
@ -230,9 +229,9 @@ class RuleSetGenerator
|
|||
/**
|
||||
* Adds all rules for all update packages of a given package
|
||||
*
|
||||
* @param PackageInterface $package Rules for this package's updates are to
|
||||
* @param PackageInterface $package Rules for this package's updates are to
|
||||
* be added
|
||||
* @param bool $allowAll Whether downgrades are allowed
|
||||
* @param bool $allowAll Whether downgrades are allowed
|
||||
*/
|
||||
private function addRulesForUpdatePackages(PackageInterface $package)
|
||||
{
|
||||
|
|
|
@ -70,7 +70,7 @@ class RuleWatchGraph
|
|||
* B must now be decided true as well.
|
||||
*
|
||||
* @param int $decidedLiteral The literal which was decided (A in our example)
|
||||
* @param int $level The level at which the decision took place and at which
|
||||
* @param int $level The level at which the decision took place and at which
|
||||
* all resulting decisions should be made.
|
||||
* @param Callable $decisionsSatisfyCallback A callback which checks if a
|
||||
* literal has already been positively decided and the rule is thus
|
||||
|
|
|
@ -99,7 +99,7 @@ class RuleWatchNode
|
|||
* Moves a watch from one literal to another
|
||||
*
|
||||
* @param int $from The previously watched literal
|
||||
* @param int $to The literal to be watched now
|
||||
* @param int $to The literal to be watched now
|
||||
*/
|
||||
public function moveWatch($from, $to)
|
||||
{
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\DependencyResolver\Operation;
|
||||
|
||||
/**
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
|
@ -119,7 +117,7 @@ class Solver
|
|||
$assertRuleLiterals = $assertRule->getLiterals();
|
||||
$assertRuleLiteral = $assertRuleLiterals[0];
|
||||
|
||||
if (abs($literal) !== abs($assertRuleLiteral)) {
|
||||
if (abs($literal) !== abs($assertRuleLiteral)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -202,12 +200,14 @@ class Solver
|
|||
}
|
||||
|
||||
$transaction = new Transaction($this->policy, $this->pool, $this->installedMap, $this->decisionMap, $this->decisionQueue, $this->decisionQueueWhy);
|
||||
|
||||
return $transaction->getOperations();
|
||||
}
|
||||
|
||||
protected function literalFromId($id)
|
||||
{
|
||||
$package = $this->pool->packageById(abs($id));
|
||||
|
||||
return new Literal($package, $id > 0);
|
||||
}
|
||||
|
||||
|
@ -241,6 +241,7 @@ class Solver
|
|||
public function decisionsContain($literal)
|
||||
{
|
||||
$packageId = abs($literal);
|
||||
|
||||
return (
|
||||
$this->decisionMap[$packageId] > 0 && $literal > 0 ||
|
||||
$this->decisionMap[$packageId] < 0 && $literal < 0
|
||||
|
@ -250,6 +251,7 @@ class Solver
|
|||
protected function decisionsSatisfy($literal)
|
||||
{
|
||||
$packageId = abs($literal);
|
||||
|
||||
return (
|
||||
$literal > 0 && $this->decisionMap[$packageId] > 0 ||
|
||||
$literal < 0 && $this->decisionMap[$packageId] < 0
|
||||
|
@ -259,6 +261,7 @@ class Solver
|
|||
public function decisionsConflict($literal)
|
||||
{
|
||||
$packageId = abs($literal);
|
||||
|
||||
return (
|
||||
($this->decisionMap[$packageId] > 0 && $literal < 0) ||
|
||||
($this->decisionMap[$packageId] < 0 && $literal > 0)
|
||||
|
@ -274,7 +277,8 @@ class Solver
|
|||
return $this->decisionMap[$packageId] == 0;
|
||||
}
|
||||
|
||||
protected function decidedInstall($packageId) {
|
||||
protected function decidedInstall($packageId)
|
||||
{
|
||||
return $this->decisionMap[$packageId] > 0;
|
||||
}
|
||||
|
||||
|
@ -433,7 +437,7 @@ class Solver
|
|||
|
||||
$this->learnedPool[] = array();
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
$this->learnedPool[count($this->learnedPool) - 1][] = $rule;
|
||||
|
||||
foreach ($rule->getLiterals() as $literal) {
|
||||
|
@ -535,6 +539,7 @@ class Solver
|
|||
foreach ($problemRules as $problemRule) {
|
||||
$this->analyzeUnsolvableRule($problem, $problemRule);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -600,6 +605,7 @@ class Solver
|
|||
}
|
||||
|
||||
$this->resetSolver();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ class Transaction
|
|||
$package, $this->decisionQueueWhy[$i]
|
||||
);
|
||||
}
|
||||
} else if (!isset($ignoreRemove[$package->getId()])) {
|
||||
} elseif (!isset($ignoreRemove[$package->getId()])) {
|
||||
if ($package instanceof AliasPackage) {
|
||||
$transaction[] = new Operation\MarkAliasInstalledOperation(
|
||||
$package, $this->decisionQueueWhy[$i]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue