N, [>=M, !=N,
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, P, =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 - +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());
+ }
+}
diff --git a/vendor/composer/semver/src/Semver.php b/vendor/composer/semver/src/Semver.php
new file mode 100644
index 0000000000..7df640027e
--- /dev/null
+++ b/vendor/composer/semver/src/Semver.php
@@ -0,0 +1,111 @@
+
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+namespace EasyCI202401\Composer\Semver;
+
+use EasyCI202401\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;
+ }
+}
diff --git a/vendor/composer/semver/src/VersionParser.php b/vendor/composer/semver/src/VersionParser.php
new file mode 100644
index 0000000000..b2d6be0315
--- /dev/null
+++ b/vendor/composer/semver/src/VersionParser.php
@@ -0,0 +1,488 @@
+
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+namespace EasyCI202401\Composer\Semver;
+
+use EasyCI202401\Composer\Semver\Constraint\ConstraintInterface;
+use EasyCI202401\Composer\Semver\Constraint\MatchAllConstraint;
+use EasyCI202401\Composer\Semver\Constraint\MultiConstraint;
+use EasyCI202401\Composer\Semver\Constraint\Constraint;
+/**
+ * Version parser.
+ *
+ * @author Jordi Boggiano
+ */
+class VersionParser
+{
+ /**
+ * Regex to match pre-release data (sort of).
+ *
+ * Due to backwards compatibility:
+ * - Instead of enforcing hyphen, an underscore, dot or nothing at all are also accepted.
+ * - Only stabilities as recognized by Composer are allowed to precede a numerical identifier.
+ * - Numerical-only pre-release identifiers are not supported, see tests.
+ *
+ * |--------------|
+ * [major].[minor].[patch] -[pre-release] +[build-metadata]
+ *
+ * @var string
+ */
+ private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\\d+)*+)?)?([.-]?dev)?';
+ /** @var string */
+ private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev';
+ /**
+ * Returns the stability of a version.
+ *
+ * @param string $version
+ *
+ * @return string
+ * @phpstan-return 'stable'|'RC'|'beta'|'alpha'|'dev'
+ */
+ public static function parseStability($version)
+ {
+ $version = (string) \preg_replace('{#.+$}', '', (string) $version);
+ if (\strpos($version, 'dev-') === 0 || '-dev' === \substr($version, -4)) {
+ return 'dev';
+ }
+ \preg_match('{' . self::$modifierRegex . '(?:\\+.*)?$}i', \strtolower($version), $match);
+ if (!empty($match[3])) {
+ return 'dev';
+ }
+ if (!empty($match[1])) {
+ if ('beta' === $match[1] || 'b' === $match[1]) {
+ return 'beta';
+ }
+ if ('alpha' === $match[1] || 'a' === $match[1]) {
+ return 'alpha';
+ }
+ if ('rc' === $match[1]) {
+ return 'RC';
+ }
+ }
+ return 'stable';
+ }
+ /**
+ * @param string $stability
+ *
+ * @return string
+ */
+ public static function normalizeStability($stability)
+ {
+ $stability = \strtolower((string) $stability);
+ return $stability === 'rc' ? 'RC' : $stability;
+ }
+ /**
+ * Normalizes a version string to be able to perform comparisons on it.
+ *
+ * @param string $version
+ * @param ?string $fullVersion optional complete version string to give more context
+ *
+ * @throws \UnexpectedValueException
+ *
+ * @return string
+ */
+ public function normalize($version, $fullVersion = null)
+ {
+ $version = \trim((string) $version);
+ $origVersion = $version;
+ if (null === $fullVersion) {
+ $fullVersion = $version;
+ }
+ // strip off aliasing
+ if (\preg_match('{^([^,\\s]++) ++as ++([^,\\s]++)$}', $version, $match)) {
+ $version = $match[1];
+ }
+ // strip off stability flag
+ if (\preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) {
+ $version = \substr($version, 0, \strlen($version) - \strlen($match[0]));
+ }
+ // normalize master/trunk/default branches to dev-name for BC with 1.x as these used to be valid constraints
+ if (\in_array($version, array('master', 'trunk', 'default'), \true)) {
+ $version = 'dev-' . $version;
+ }
+ // if requirement is branch-like, use full name
+ if (\stripos($version, 'dev-') === 0) {
+ return 'dev-' . \substr($version, 4);
+ }
+ // strip off build metadata
+ if (\preg_match('{^([^,\\s+]++)\\+[^\\s]++$}', $version, $match)) {
+ $version = $match[1];
+ }
+ // match classical versioning
+ if (\preg_match('{^v?(\\d{1,5}+)(\\.\\d++)?(\\.\\d++)?(\\.\\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
+ $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0');
+ $index = 5;
+ // match date(time) based versioning
+ } elseif (\preg_match('{^v?(\\d{4}(?:[.:-]?\\d{2}){1,6}(?:[.:-]?\\d{1,3}){0,2})' . self::$modifierRegex . '$}i', $version, $matches)) {
+ $version = (string) \preg_replace('{\\D}', '.', $matches[1]);
+ $index = 2;
+ }
+ // add version modifiers if a version was matched
+ if (isset($index)) {
+ if (!empty($matches[$index])) {
+ if ('stable' === $matches[$index]) {
+ return $version;
+ }
+ $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? \ltrim($matches[$index + 1], '.-') : '');
+ }
+ if (!empty($matches[$index + 2])) {
+ $version .= '-dev';
+ }
+ return $version;
+ }
+ // match dev branches
+ if (\preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
+ try {
+ $normalized = $this->normalizeBranch($match[1]);
+ // a branch ending with -dev is only valid if it is numeric
+ // if it gets prefixed with dev- it means the branch name should
+ // have had a dev- prefix already when passed to normalize
+ if (\strpos($normalized, 'dev-') === \false) {
+ return $normalized;
+ }
+ } catch (\Exception $e) {
+ }
+ }
+ $extraMessage = '';
+ if (\preg_match('{ +as +' . \preg_quote($version) . '(?:@(?:' . self::$stabilitiesRegex . '))?$}', $fullVersion)) {
+ $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
+ } elseif (\preg_match('{^' . \preg_quote($version) . '(?:@(?:' . self::$stabilitiesRegex . '))? +as +}', $fullVersion)) {
+ $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
+ }
+ throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage);
+ }
+ /**
+ * Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison.
+ *
+ * @param string $branch Branch name (e.g. 2.1.x-dev)
+ *
+ * @return string|false Numeric prefix if present (e.g. 2.1.) or false
+ */
+ public function parseNumericAliasPrefix($branch)
+ {
+ if (\preg_match('{^(?P(\\d++\\.)*\\d++)(?:\\.x)?-dev$}i', (string) $branch, $matches)) {
+ return $matches['version'] . '.';
+ }
+ return \false;
+ }
+ /**
+ * Normalizes a branch name to be able to perform comparisons on it.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function normalizeBranch($name)
+ {
+ $name = \trim((string) $name);
+ if (\preg_match('{^v?(\\d++)(\\.(?:\\d++|[xX*]))?(\\.(?:\\d++|[xX*]))?(\\.(?:\\d++|[xX*]))?$}i', $name, $matches)) {
+ $version = '';
+ for ($i = 1; $i < 5; ++$i) {
+ $version .= isset($matches[$i]) ? \str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
+ }
+ return \str_replace('x', '9999999', $version) . '-dev';
+ }
+ return 'dev-' . $name;
+ }
+ /**
+ * Normalizes a default branch name (i.e. master on git) to 9999999-dev.
+ *
+ * @param string $name
+ *
+ * @return string
+ *
+ * @deprecated No need to use this anymore in theory, Composer 2 does not normalize any branch names to 9999999-dev anymore
+ */
+ public function normalizeDefaultBranch($name)
+ {
+ if ($name === 'dev-master' || $name === 'dev-default' || $name === 'dev-trunk') {
+ return '9999999-dev';
+ }
+ return (string) $name;
+ }
+ /**
+ * Parses a constraint string into MultiConstraint and/or Constraint objects.
+ *
+ * @param string $constraints
+ *
+ * @return ConstraintInterface
+ */
+ public function parseConstraints($constraints)
+ {
+ $prettyConstraint = (string) $constraints;
+ $orConstraints = \preg_split('{\\s*\\|\\|?\\s*}', \trim((string) $constraints));
+ if (\false === $orConstraints) {
+ throw new \RuntimeException('Failed to preg_split string: ' . $constraints);
+ }
+ $orGroups = array();
+ foreach ($orConstraints as $orConstraint) {
+ $andConstraints = \preg_split('{(?< ,]) *(? 1) {
+ $constraintObjects = array();
+ foreach ($andConstraints as $andConstraint) {
+ foreach ($this->parseConstraint($andConstraint) as $parsedAndConstraint) {
+ $constraintObjects[] = $parsedAndConstraint;
+ }
+ }
+ } else {
+ $constraintObjects = $this->parseConstraint($andConstraints[0]);
+ }
+ if (1 === \count($constraintObjects)) {
+ $constraint = $constraintObjects[0];
+ } else {
+ $constraint = new MultiConstraint($constraintObjects);
+ }
+ $orGroups[] = $constraint;
+ }
+ $parsedConstraint = MultiConstraint::create($orGroups, \false);
+ $parsedConstraint->setPrettyString($prettyConstraint);
+ return $parsedConstraint;
+ }
+ /**
+ * @param string $constraint
+ *
+ * @throws \UnexpectedValueException
+ *
+ * @return array
+ *
+ * @phpstan-return non-empty-array
+ */
+ private function parseConstraint($constraint)
+ {
+ // strip off aliasing
+ if (\preg_match('{^([^,\\s]++) ++as ++([^,\\s]++)$}', $constraint, $match)) {
+ $constraint = $match[1];
+ }
+ // strip @stability flags, and keep it for later use
+ if (\preg_match('{^([^,\\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) {
+ $constraint = '' !== $match[1] ? $match[1] : '*';
+ if ($match[2] !== 'stable') {
+ $stabilityModifier = $match[2];
+ }
+ }
+ // get rid of #refs as those are used by composer only
+ if (\preg_match('{^(dev-[^,\\s@]+?|[^,\\s@]+?\\.x-dev)#.+$}i', $constraint, $match)) {
+ $constraint = $match[1];
+ }
+ if (\preg_match('{^(v)?[xX*](\\.[xX*])*$}i', $constraint, $match)) {
+ if (!empty($match[1]) || !empty($match[2])) {
+ return array(new Constraint('>=', '0.0.0.0-dev'));
+ }
+ return array(new MatchAllConstraint());
+ }
+ $versionRegex = 'v?(\\d++)(?:\\.(\\d++))?(?:\\.(\\d++))?(?:\\.(\\d++))?(?:' . self::$modifierRegex . '|\\.([xX*][.-]?dev))(?:\\+[^\\s]+)?';
+ // Tilde Range
+ //
+ // Like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous
+ // version, to ensure that unstable instances of the current version are allowed. However, if a stability
+ // suffix is added to the constraint, then a >= match on the current version is used instead.
+ if (\preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
+ if (\strpos($constraint, '~>') === 0) {
+ throw new \UnexpectedValueException('Could not parse version constraint ' . $constraint . ': ' . 'Invalid operator "~>", you probably meant to use the "~" operator');
+ }
+ // Work out which position in the version we are operating at
+ if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
+ $position = 4;
+ } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
+ $position = 3;
+ } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
+ $position = 2;
+ } else {
+ $position = 1;
+ }
+ // when matching 2.x-dev or 3.0.x-dev we have to shift the second or third number, despite no second/third number matching above
+ if (!empty($matches[8])) {
+ $position++;
+ }
+ // Calculate the stability suffix
+ $stabilitySuffix = '';
+ if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
+ $stabilitySuffix .= '-dev';
+ }
+ $lowVersion = $this->normalize(\substr($constraint . $stabilitySuffix, 1));
+ $lowerBound = new Constraint('>=', $lowVersion);
+ // For upper bound, we increment the position of one more significance,
+ // but highPosition = 0 would be illegal
+ $highPosition = \max(1, $position - 1);
+ $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
+ $upperBound = new Constraint('<', $highVersion);
+ return array($lowerBound, $upperBound);
+ }
+ // Caret Range
+ //
+ // Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple.
+ // In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for
+ // versions 0.X >=0.1.0, and no updates for versions 0.0.X
+ if (\preg_match('{^\\^' . $versionRegex . '($)}i', $constraint, $matches)) {
+ // Work out which position in the version we are operating at
+ if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
+ $position = 1;
+ } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
+ $position = 2;
+ } else {
+ $position = 3;
+ }
+ // Calculate the stability suffix
+ $stabilitySuffix = '';
+ if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
+ $stabilitySuffix .= '-dev';
+ }
+ $lowVersion = $this->normalize(\substr($constraint . $stabilitySuffix, 1));
+ $lowerBound = new Constraint('>=', $lowVersion);
+ // For upper bound, we increment the position of one more significance,
+ // but highPosition = 0 would be illegal
+ $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
+ $upperBound = new Constraint('<', $highVersion);
+ return array($lowerBound, $upperBound);
+ }
+ // X Range
+ //
+ // Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple.
+ // A partial version range is treated as an X-Range, so the special character is in fact optional.
+ if (\preg_match('{^v?(\\d++)(?:\\.(\\d++))?(?:\\.(\\d++))?(?:\\.[xX*])++$}', $constraint, $matches)) {
+ if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
+ $position = 3;
+ } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
+ $position = 2;
+ } else {
+ $position = 1;
+ }
+ $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
+ $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
+ if ($lowVersion === '0.0.0.0-dev') {
+ return array(new Constraint('<', $highVersion));
+ }
+ return array(new Constraint('>=', $lowVersion), new Constraint('<', $highVersion));
+ }
+ // Hyphen Range
+ //
+ // Specifies an inclusive set. If a partial version is provided as the first version in the inclusive range,
+ // then the missing pieces are replaced with zeroes. If a partial version is provided as the second version in
+ // the inclusive range, then all versions that start with the supplied parts of the tuple are accepted, but
+ // nothing that would be greater than the provided tuple parts.
+ if (\preg_match('{^(?P' . $versionRegex . ') +- +(?P' . $versionRegex . ')($)}i', $constraint, $matches)) {
+ // Calculate the stability suffix
+ $lowStabilitySuffix = '';
+ if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) {
+ $lowStabilitySuffix = '-dev';
+ }
+ $lowVersion = $this->normalize($matches['from']);
+ $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
+ $empty = function ($x) {
+ return $x === 0 || $x === '0' ? \false : empty($x);
+ };
+ if (!$empty($matches[12]) && !$empty($matches[13]) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) {
+ $highVersion = $this->normalize($matches['to']);
+ $upperBound = new Constraint('<=', $highVersion);
+ } else {
+ $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]);
+ // validate to version
+ $this->normalize($matches['to']);
+ $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev';
+ $upperBound = new Constraint('<', $highVersion);
+ }
+ return array($lowerBound, $upperBound);
+ }
+ // Basic Comparators
+ if (\preg_match('{^(<>|!=|>=?|<=?|==?)?\\s*(.*)}', $constraint, $matches)) {
+ try {
+ try {
+ $version = $this->normalize($matches[2]);
+ } catch (\UnexpectedValueException $e) {
+ // recover from an invalid constraint like foobar-dev which should be dev-foobar
+ // except if the constraint uses a known operator, in which case it must be a parse error
+ if (\substr($matches[2], -4) === '-dev' && \preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) {
+ $version = $this->normalize('dev-' . \substr($matches[2], 0, -4));
+ } else {
+ throw $e;
+ }
+ }
+ $op = $matches[1] ?: '=';
+ if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') {
+ $version .= '-' . $stabilityModifier;
+ } elseif ('<' === $op || '>=' === $op) {
+ if (!\preg_match('/-' . self::$modifierRegex . '$/', \strtolower($matches[2]))) {
+ if (\strpos($matches[2], 'dev-') !== 0) {
+ $version .= '-dev';
+ }
+ }
+ }
+ return array(new Constraint($matches[1] ?: '=', $version));
+ } catch (\Exception $e) {
+ }
+ }
+ $message = 'Could not parse version constraint ' . $constraint;
+ if (isset($e)) {
+ $message .= ': ' . $e->getMessage();
+ }
+ throw new \UnexpectedValueException($message);
+ }
+ /**
+ * Increment, decrement, or simply pad a version number.
+ *
+ * Support function for {@link parseConstraint()}
+ *
+ * @param array $matches Array with version parts in array indexes 1,2,3,4
+ * @param int $position 1,2,3,4 - which segment of the version to increment/decrement
+ * @param int $increment
+ * @param string $pad The string to pad version parts after $position
+ *
+ * @return string|null The new version
+ *
+ * @phpstan-param string[] $matches
+ */
+ private function manipulateVersionString(array $matches, $position, $increment = 0, $pad = '0')
+ {
+ for ($i = 4; $i > 0; --$i) {
+ if ($i > $position) {
+ $matches[$i] = $pad;
+ } elseif ($i === $position && $increment) {
+ $matches[$i] += $increment;
+ // If $matches[$i] was 0, carry the decrement
+ if ($matches[$i] < 0) {
+ $matches[$i] = $pad;
+ --$position;
+ // Return null on a carry overflow
+ if ($i === 1) {
+ return null;
+ }
+ }
+ }
+ }
+ return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
+ }
+ /**
+ * Expand shorthand stability string to long version.
+ *
+ * @param string $stability
+ *
+ * @return string
+ */
+ private function expandStability($stability)
+ {
+ $stability = \strtolower($stability);
+ switch ($stability) {
+ case 'a':
+ return 'alpha';
+ case 'b':
+ return 'beta';
+ case 'p':
+ case 'pl':
+ return 'patch';
+ case 'rc':
+ return 'RC';
+ default:
+ return $stability;
+ }
+ }
+}
diff --git a/vendor/illuminate/container/BoundMethod.php b/vendor/illuminate/container/BoundMethod.php
new file mode 100644
index 0000000000..34c7fc157e
--- /dev/null
+++ b/vendor/illuminate/container/BoundMethod.php
@@ -0,0 +1,170 @@
+make($segments[0]), $method], $parameters);
+ }
+ /**
+ * Call a method that has been bound to the container.
+ *
+ * @param \Illuminate\Container\Container $container
+ * @param callable $callback
+ * @param mixed $default
+ * @return mixed
+ */
+ protected static function callBoundMethod($container, $callback, $default)
+ {
+ if (!\is_array($callback)) {
+ return Util::unwrapIfClosure($default);
+ }
+ // Here we need to turn the array callable into a Class@method string we can use to
+ // examine the container and see if there are any method bindings for this given
+ // method. If there are, we can call this method binding callback immediately.
+ $method = static::normalizeMethod($callback);
+ if ($container->hasMethodBinding($method)) {
+ return $container->callMethodBinding($method, $callback[0]);
+ }
+ return Util::unwrapIfClosure($default);
+ }
+ /**
+ * Normalize the given callback into a Class@method string.
+ *
+ * @param callable $callback
+ * @return string
+ */
+ protected static function normalizeMethod($callback)
+ {
+ $class = \is_string($callback[0]) ? $callback[0] : \get_class($callback[0]);
+ return "{$class}@{$callback[1]}";
+ }
+ /**
+ * Get all dependencies for a given method.
+ *
+ * @param \Illuminate\Container\Container $container
+ * @param callable|string $callback
+ * @param array $parameters
+ * @return array
+ *
+ * @throws \ReflectionException
+ */
+ protected static function getMethodDependencies($container, $callback, array $parameters = [])
+ {
+ $dependencies = [];
+ foreach (static::getCallReflector($callback)->getParameters() as $parameter) {
+ static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies);
+ }
+ return \array_merge($dependencies, \array_values($parameters));
+ }
+ /**
+ * Get the proper reflection instance for the given callback.
+ *
+ * @param callable|string $callback
+ * @return \ReflectionFunctionAbstract
+ *
+ * @throws \ReflectionException
+ */
+ protected static function getCallReflector($callback)
+ {
+ if (\is_string($callback) && \strpos($callback, '::') !== \false) {
+ $callback = \explode('::', $callback);
+ } elseif (\is_object($callback) && !$callback instanceof Closure) {
+ $callback = [$callback, '__invoke'];
+ }
+ return \is_array($callback) ? new ReflectionMethod($callback[0], $callback[1]) : new ReflectionFunction($callback);
+ }
+ /**
+ * Get the dependency for the given call parameter.
+ *
+ * @param \Illuminate\Container\Container $container
+ * @param \ReflectionParameter $parameter
+ * @param array $parameters
+ * @param array $dependencies
+ * @return void
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ protected static function addDependencyForCallParameter($container, $parameter, array &$parameters, &$dependencies)
+ {
+ if (\array_key_exists($paramName = $parameter->getName(), $parameters)) {
+ $dependencies[] = $parameters[$paramName];
+ unset($parameters[$paramName]);
+ } elseif (!\is_null($className = Util::getParameterClassName($parameter))) {
+ if (\array_key_exists($className, $parameters)) {
+ $dependencies[] = $parameters[$className];
+ unset($parameters[$className]);
+ } elseif ($parameter->isVariadic()) {
+ $variadicDependencies = $container->make($className);
+ $dependencies = \array_merge($dependencies, \is_array($variadicDependencies) ? $variadicDependencies : [$variadicDependencies]);
+ } else {
+ $dependencies[] = $container->make($className);
+ }
+ } elseif ($parameter->isDefaultValueAvailable()) {
+ $dependencies[] = $parameter->getDefaultValue();
+ } elseif (!$parameter->isOptional() && !\array_key_exists($paramName, $parameters)) {
+ $message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}";
+ throw new BindingResolutionException($message);
+ }
+ }
+ /**
+ * Determine if the given string is in Class@method syntax.
+ *
+ * @param mixed $callback
+ * @return bool
+ */
+ protected static function isCallableWithAtSign($callback)
+ {
+ return \is_string($callback) && \strpos($callback, '@') !== \false;
+ }
+}
diff --git a/vendor/illuminate/container/Container.php b/vendor/illuminate/container/Container.php
new file mode 100755
index 0000000000..2dd76c66dc
--- /dev/null
+++ b/vendor/illuminate/container/Container.php
@@ -0,0 +1,1293 @@
+getAlias($c);
+ }
+ return new ContextualBindingBuilder($this, $aliases);
+ }
+ /**
+ * Determine if the given abstract type has been bound.
+ *
+ * @param string $abstract
+ * @return bool
+ */
+ public function bound($abstract)
+ {
+ return isset($this->bindings[$abstract]) || isset($this->instances[$abstract]) || $this->isAlias($abstract);
+ }
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function has(string $id) : bool
+ {
+ return $this->bound($id);
+ }
+ /**
+ * Determine if the given abstract type has been resolved.
+ *
+ * @param string $abstract
+ * @return bool
+ */
+ public function resolved($abstract)
+ {
+ if ($this->isAlias($abstract)) {
+ $abstract = $this->getAlias($abstract);
+ }
+ return isset($this->resolved[$abstract]) || isset($this->instances[$abstract]);
+ }
+ /**
+ * Determine if a given type is shared.
+ *
+ * @param string $abstract
+ * @return bool
+ */
+ public function isShared($abstract)
+ {
+ return isset($this->instances[$abstract]) || isset($this->bindings[$abstract]['shared']) && $this->bindings[$abstract]['shared'] === \true;
+ }
+ /**
+ * Determine if a given string is an alias.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function isAlias($name)
+ {
+ return isset($this->aliases[$name]);
+ }
+ /**
+ * Register a binding with the container.
+ *
+ * @param string $abstract
+ * @param \Closure|string|null $concrete
+ * @param bool $shared
+ * @return void
+ *
+ * @throws \TypeError
+ */
+ public function bind($abstract, $concrete = null, $shared = \false)
+ {
+ $this->dropStaleInstances($abstract);
+ // If no concrete type was given, we will simply set the concrete type to the
+ // abstract type. After that, the concrete type to be registered as shared
+ // without being forced to state their classes in both of the parameters.
+ if (\is_null($concrete)) {
+ $concrete = $abstract;
+ }
+ // If the factory is not a Closure, it means it is just a class name which is
+ // bound into this container to the abstract type and we will just wrap it
+ // up inside its own Closure to give us more convenience when extending.
+ if (!$concrete instanceof Closure) {
+ if (!\is_string($concrete)) {
+ throw new TypeError(self::class . '::bind(): Argument #2 ($concrete) must be of type Closure|string|null');
+ }
+ $concrete = $this->getClosure($abstract, $concrete);
+ }
+ $this->bindings[$abstract] = \compact('concrete', 'shared');
+ // If the abstract type was already resolved in this container we'll fire the
+ // rebound listener so that any objects which have already gotten resolved
+ // can have their copy of the object updated via the listener callbacks.
+ if ($this->resolved($abstract)) {
+ $this->rebound($abstract);
+ }
+ }
+ /**
+ * Get the Closure to be used when building a type.
+ *
+ * @param string $abstract
+ * @param string $concrete
+ * @return \Closure
+ */
+ protected function getClosure($abstract, $concrete)
+ {
+ return function ($container, $parameters = []) use($abstract, $concrete) {
+ if ($abstract == $concrete) {
+ return $container->build($concrete);
+ }
+ return $container->resolve($concrete, $parameters, $raiseEvents = \false);
+ };
+ }
+ /**
+ * Determine if the container has a method binding.
+ *
+ * @param string $method
+ * @return bool
+ */
+ public function hasMethodBinding($method)
+ {
+ return isset($this->methodBindings[$method]);
+ }
+ /**
+ * Bind a callback to resolve with Container::call.
+ *
+ * @param array|string $method
+ * @param \Closure $callback
+ * @return void
+ */
+ public function bindMethod($method, $callback)
+ {
+ $this->methodBindings[$this->parseBindMethod($method)] = $callback;
+ }
+ /**
+ * Get the method to be bound in class@method format.
+ *
+ * @param array|string $method
+ * @return string
+ */
+ protected function parseBindMethod($method)
+ {
+ if (\is_array($method)) {
+ return $method[0] . '@' . $method[1];
+ }
+ return $method;
+ }
+ /**
+ * Get the method binding for the given method.
+ *
+ * @param string $method
+ * @param mixed $instance
+ * @return mixed
+ */
+ public function callMethodBinding($method, $instance)
+ {
+ return \call_user_func($this->methodBindings[$method], $instance, $this);
+ }
+ /**
+ * Add a contextual binding to the container.
+ *
+ * @param string $concrete
+ * @param string $abstract
+ * @param \Closure|string $implementation
+ * @return void
+ */
+ public function addContextualBinding($concrete, $abstract, $implementation)
+ {
+ $this->contextual[$concrete][$this->getAlias($abstract)] = $implementation;
+ }
+ /**
+ * Register a binding if it hasn't already been registered.
+ *
+ * @param string $abstract
+ * @param \Closure|string|null $concrete
+ * @param bool $shared
+ * @return void
+ */
+ public function bindIf($abstract, $concrete = null, $shared = \false)
+ {
+ if (!$this->bound($abstract)) {
+ $this->bind($abstract, $concrete, $shared);
+ }
+ }
+ /**
+ * Register a shared binding in the container.
+ *
+ * @param string $abstract
+ * @param \Closure|string|null $concrete
+ * @return void
+ */
+ public function singleton($abstract, $concrete = null)
+ {
+ $this->bind($abstract, $concrete, \true);
+ }
+ /**
+ * Register a shared binding if it hasn't already been registered.
+ *
+ * @param string $abstract
+ * @param \Closure|string|null $concrete
+ * @return void
+ */
+ public function singletonIf($abstract, $concrete = null)
+ {
+ if (!$this->bound($abstract)) {
+ $this->singleton($abstract, $concrete);
+ }
+ }
+ /**
+ * Register a scoped binding in the container.
+ *
+ * @param string $abstract
+ * @param \Closure|string|null $concrete
+ * @return void
+ */
+ public function scoped($abstract, $concrete = null)
+ {
+ $this->scopedInstances[] = $abstract;
+ $this->singleton($abstract, $concrete);
+ }
+ /**
+ * Register a scoped binding if it hasn't already been registered.
+ *
+ * @param string $abstract
+ * @param \Closure|string|null $concrete
+ * @return void
+ */
+ public function scopedIf($abstract, $concrete = null)
+ {
+ if (!$this->bound($abstract)) {
+ $this->scoped($abstract, $concrete);
+ }
+ }
+ /**
+ * "Extend" an abstract type in the container.
+ *
+ * @param string $abstract
+ * @param \Closure $closure
+ * @return void
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function extend($abstract, Closure $closure)
+ {
+ $abstract = $this->getAlias($abstract);
+ if (isset($this->instances[$abstract])) {
+ $this->instances[$abstract] = $closure($this->instances[$abstract], $this);
+ $this->rebound($abstract);
+ } else {
+ $this->extenders[$abstract][] = $closure;
+ if ($this->resolved($abstract)) {
+ $this->rebound($abstract);
+ }
+ }
+ }
+ /**
+ * Register an existing instance as shared in the container.
+ *
+ * @param string $abstract
+ * @param mixed $instance
+ * @return mixed
+ */
+ public function instance($abstract, $instance)
+ {
+ $this->removeAbstractAlias($abstract);
+ $isBound = $this->bound($abstract);
+ unset($this->aliases[$abstract]);
+ // We'll check to determine if this type has been bound before, and if it has
+ // we will fire the rebound callbacks registered with the container and it
+ // can be updated with consuming classes that have gotten resolved here.
+ $this->instances[$abstract] = $instance;
+ if ($isBound) {
+ $this->rebound($abstract);
+ }
+ return $instance;
+ }
+ /**
+ * Remove an alias from the contextual binding alias cache.
+ *
+ * @param string $searched
+ * @return void
+ */
+ protected function removeAbstractAlias($searched)
+ {
+ if (!isset($this->aliases[$searched])) {
+ return;
+ }
+ foreach ($this->abstractAliases as $abstract => $aliases) {
+ foreach ($aliases as $index => $alias) {
+ if ($alias == $searched) {
+ unset($this->abstractAliases[$abstract][$index]);
+ }
+ }
+ }
+ }
+ /**
+ * Assign a set of tags to a given binding.
+ *
+ * @param array|string $abstracts
+ * @param array|mixed ...$tags
+ * @return void
+ */
+ public function tag($abstracts, $tags)
+ {
+ $tags = \is_array($tags) ? $tags : \array_slice(\func_get_args(), 1);
+ foreach ($tags as $tag) {
+ if (!isset($this->tags[$tag])) {
+ $this->tags[$tag] = [];
+ }
+ foreach ((array) $abstracts as $abstract) {
+ $this->tags[$tag][] = $abstract;
+ }
+ }
+ }
+ /**
+ * Resolve all of the bindings for a given tag.
+ *
+ * @param string $tag
+ * @return iterable
+ */
+ public function tagged($tag)
+ {
+ if (!isset($this->tags[$tag])) {
+ return [];
+ }
+ return new RewindableGenerator(function () use($tag) {
+ foreach ($this->tags[$tag] as $abstract) {
+ (yield $this->make($abstract));
+ }
+ }, \count($this->tags[$tag]));
+ }
+ /**
+ * Alias a type to a different name.
+ *
+ * @param string $abstract
+ * @param string $alias
+ * @return void
+ *
+ * @throws \LogicException
+ */
+ public function alias($abstract, $alias)
+ {
+ if ($alias === $abstract) {
+ throw new LogicException("[{$abstract}] is aliased to itself.");
+ }
+ $this->aliases[$alias] = $abstract;
+ $this->abstractAliases[$abstract][] = $alias;
+ }
+ /**
+ * Bind a new callback to an abstract's rebind event.
+ *
+ * @param string $abstract
+ * @param \Closure $callback
+ * @return mixed
+ */
+ public function rebinding($abstract, Closure $callback)
+ {
+ $this->reboundCallbacks[$abstract = $this->getAlias($abstract)][] = $callback;
+ if ($this->bound($abstract)) {
+ return $this->make($abstract);
+ }
+ }
+ /**
+ * Refresh an instance on the given target and method.
+ *
+ * @param string $abstract
+ * @param mixed $target
+ * @param string $method
+ * @return mixed
+ */
+ public function refresh($abstract, $target, $method)
+ {
+ return $this->rebinding($abstract, function ($app, $instance) use($target, $method) {
+ $target->{$method}($instance);
+ });
+ }
+ /**
+ * Fire the "rebound" callbacks for the given abstract type.
+ *
+ * @param string $abstract
+ * @return void
+ */
+ protected function rebound($abstract)
+ {
+ $instance = $this->make($abstract);
+ foreach ($this->getReboundCallbacks($abstract) as $callback) {
+ $callback($this, $instance);
+ }
+ }
+ /**
+ * Get the rebound callbacks for a given type.
+ *
+ * @param string $abstract
+ * @return array
+ */
+ protected function getReboundCallbacks($abstract)
+ {
+ return $this->reboundCallbacks[$abstract] ?? [];
+ }
+ /**
+ * Wrap the given closure such that its dependencies will be injected when executed.
+ *
+ * @param \Closure $callback
+ * @param array $parameters
+ * @return \Closure
+ */
+ public function wrap(Closure $callback, array $parameters = [])
+ {
+ return function () use($callback, $parameters) {
+ return $this->call($callback, $parameters);
+ };
+ }
+ /**
+ * Call the given Closure / class@method and inject its dependencies.
+ *
+ * @param callable|string $callback
+ * @param array $parameters
+ * @param string|null $defaultMethod
+ * @return mixed
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function call($callback, array $parameters = [], $defaultMethod = null)
+ {
+ $pushedToBuildStack = \false;
+ if (($className = $this->getClassForCallable($callback)) && !\in_array($className, $this->buildStack, \true)) {
+ $this->buildStack[] = $className;
+ $pushedToBuildStack = \true;
+ }
+ $result = BoundMethod::call($this, $callback, $parameters, $defaultMethod);
+ if ($pushedToBuildStack) {
+ \array_pop($this->buildStack);
+ }
+ return $result;
+ }
+ /**
+ * Get the class name for the given callback, if one can be determined.
+ *
+ * @param callable|string $callback
+ * @return string|false
+ */
+ protected function getClassForCallable($callback)
+ {
+ if (\PHP_VERSION_ID >= 80200) {
+ if (\is_callable($callback) && !($reflector = new ReflectionFunction(\Closure::fromCallable($callback)))->isAnonymous()) {
+ return $reflector->getClosureScopeClass()->name ?? \false;
+ }
+ return \false;
+ }
+ if (!\is_array($callback)) {
+ return \false;
+ }
+ return \is_string($callback[0]) ? $callback[0] : \get_class($callback[0]);
+ }
+ /**
+ * Get a closure to resolve the given type from the container.
+ *
+ * @param string $abstract
+ * @return \Closure
+ */
+ public function factory($abstract)
+ {
+ return function () use($abstract) {
+ return $this->make($abstract);
+ };
+ }
+ /**
+ * An alias function name for make().
+ *
+ * @param string|callable $abstract
+ * @param array $parameters
+ * @return mixed
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ public function makeWith($abstract, array $parameters = [])
+ {
+ return $this->make($abstract, $parameters);
+ }
+ /**
+ * Resolve the given type from the container.
+ *
+ * @param string|callable $abstract
+ * @param array $parameters
+ * @return mixed
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ public function make($abstract, array $parameters = [])
+ {
+ return $this->resolve($abstract, $parameters);
+ }
+ /**
+ * {@inheritdoc}
+ *
+ * @return mixed
+ */
+ public function get(string $id)
+ {
+ try {
+ return $this->resolve($id);
+ } catch (Exception $e) {
+ if ($this->has($id) || $e instanceof CircularDependencyException) {
+ throw $e;
+ }
+ throw new EntryNotFoundException($id, \is_int($e->getCode()) ? $e->getCode() : 0, $e);
+ }
+ }
+ /**
+ * Resolve the given type from the container.
+ *
+ * @param string|callable $abstract
+ * @param array $parameters
+ * @param bool $raiseEvents
+ * @return mixed
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ * @throws \Illuminate\Contracts\Container\CircularDependencyException
+ */
+ protected function resolve($abstract, $parameters = [], $raiseEvents = \true)
+ {
+ $abstract = $this->getAlias($abstract);
+ // First we'll fire any event handlers which handle the "before" resolving of
+ // specific types. This gives some hooks the chance to add various extends
+ // calls to change the resolution of objects that they're interested in.
+ if ($raiseEvents) {
+ $this->fireBeforeResolvingCallbacks($abstract, $parameters);
+ }
+ $concrete = $this->getContextualConcrete($abstract);
+ $needsContextualBuild = !empty($parameters) || !\is_null($concrete);
+ // If an instance of the type is currently being managed as a singleton we'll
+ // just return an existing instance instead of instantiating new instances
+ // so the developer can keep using the same objects instance every time.
+ if (isset($this->instances[$abstract]) && !$needsContextualBuild) {
+ return $this->instances[$abstract];
+ }
+ $this->with[] = $parameters;
+ if (\is_null($concrete)) {
+ $concrete = $this->getConcrete($abstract);
+ }
+ // We're ready to instantiate an instance of the concrete type registered for
+ // the binding. This will instantiate the types, as well as resolve any of
+ // its "nested" dependencies recursively until all have gotten resolved.
+ $object = $this->isBuildable($concrete, $abstract) ? $this->build($concrete) : $this->make($concrete);
+ // If we defined any extenders for this type, we'll need to spin through them
+ // and apply them to the object being built. This allows for the extension
+ // of services, such as changing configuration or decorating the object.
+ foreach ($this->getExtenders($abstract) as $extender) {
+ $object = $extender($object, $this);
+ }
+ // If the requested type is registered as a singleton we'll want to cache off
+ // the instances in "memory" so we can return it later without creating an
+ // entirely new instance of an object on each subsequent request for it.
+ if ($this->isShared($abstract) && !$needsContextualBuild) {
+ $this->instances[$abstract] = $object;
+ }
+ if ($raiseEvents) {
+ $this->fireResolvingCallbacks($abstract, $object);
+ }
+ // Before returning, we will also set the resolved flag to "true" and pop off
+ // the parameter overrides for this build. After those two things are done
+ // we will be ready to return back the fully constructed class instance.
+ $this->resolved[$abstract] = \true;
+ \array_pop($this->with);
+ return $object;
+ }
+ /**
+ * Get the concrete type for a given abstract.
+ *
+ * @param string|callable $abstract
+ * @return mixed
+ */
+ protected function getConcrete($abstract)
+ {
+ // If we don't have a registered resolver or concrete for the type, we'll just
+ // assume each type is a concrete name and will attempt to resolve it as is
+ // since the container should be able to resolve concretes automatically.
+ if (isset($this->bindings[$abstract])) {
+ return $this->bindings[$abstract]['concrete'];
+ }
+ return $abstract;
+ }
+ /**
+ * Get the contextual concrete binding for the given abstract.
+ *
+ * @param string|callable $abstract
+ * @return \Closure|string|array|null
+ */
+ protected function getContextualConcrete($abstract)
+ {
+ if (!\is_null($binding = $this->findInContextualBindings($abstract))) {
+ return $binding;
+ }
+ // Next we need to see if a contextual binding might be bound under an alias of the
+ // given abstract type. So, we will need to check if any aliases exist with this
+ // type and then spin through them and check for contextual bindings on these.
+ if (empty($this->abstractAliases[$abstract])) {
+ return;
+ }
+ foreach ($this->abstractAliases[$abstract] as $alias) {
+ if (!\is_null($binding = $this->findInContextualBindings($alias))) {
+ return $binding;
+ }
+ }
+ }
+ /**
+ * Find the concrete binding for the given abstract in the contextual binding array.
+ *
+ * @param string|callable $abstract
+ * @return \Closure|string|null
+ */
+ protected function findInContextualBindings($abstract)
+ {
+ return $this->contextual[\end($this->buildStack)][$abstract] ?? null;
+ }
+ /**
+ * Determine if the given concrete is buildable.
+ *
+ * @param mixed $concrete
+ * @param string $abstract
+ * @return bool
+ */
+ protected function isBuildable($concrete, $abstract)
+ {
+ return $concrete === $abstract || $concrete instanceof Closure;
+ }
+ /**
+ * Instantiate a concrete instance of the given type.
+ *
+ * @param \Closure|string $concrete
+ * @return mixed
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ * @throws \Illuminate\Contracts\Container\CircularDependencyException
+ */
+ public function build($concrete)
+ {
+ // If the concrete type is actually a Closure, we will just execute it and
+ // hand back the results of the functions, which allows functions to be
+ // used as resolvers for more fine-tuned resolution of these objects.
+ if ($concrete instanceof Closure) {
+ return $concrete($this, $this->getLastParameterOverride());
+ }
+ try {
+ $reflector = new ReflectionClass($concrete);
+ } catch (ReflectionException $e) {
+ throw new BindingResolutionException("Target class [{$concrete}] does not exist.", 0, $e);
+ }
+ // If the type is not instantiable, the developer is attempting to resolve
+ // an abstract type such as an Interface or Abstract Class and there is
+ // no binding registered for the abstractions so we need to bail out.
+ if (!$reflector->isInstantiable()) {
+ return $this->notInstantiable($concrete);
+ }
+ $this->buildStack[] = $concrete;
+ $constructor = $reflector->getConstructor();
+ // If there are no constructors, that means there are no dependencies then
+ // we can just resolve the instances of the objects right away, without
+ // resolving any other types or dependencies out of these containers.
+ if (\is_null($constructor)) {
+ \array_pop($this->buildStack);
+ return new $concrete();
+ }
+ $dependencies = $constructor->getParameters();
+ // Once we have all the constructor's parameters we can create each of the
+ // dependency instances and then use the reflection instances to make a
+ // new instance of this class, injecting the created dependencies in.
+ try {
+ $instances = $this->resolveDependencies($dependencies);
+ } catch (BindingResolutionException $e) {
+ \array_pop($this->buildStack);
+ throw $e;
+ }
+ \array_pop($this->buildStack);
+ return $reflector->newInstanceArgs($instances);
+ }
+ /**
+ * Resolve all of the dependencies from the ReflectionParameters.
+ *
+ * @param \ReflectionParameter[] $dependencies
+ * @return array
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ protected function resolveDependencies(array $dependencies)
+ {
+ $results = [];
+ foreach ($dependencies as $dependency) {
+ // If the dependency has an override for this particular build we will use
+ // that instead as the value. Otherwise, we will continue with this run
+ // of resolutions and let reflection attempt to determine the result.
+ if ($this->hasParameterOverride($dependency)) {
+ $results[] = $this->getParameterOverride($dependency);
+ continue;
+ }
+ // If the class is null, it means the dependency is a string or some other
+ // primitive type which we can not resolve since it is not a class and
+ // we will just bomb out with an error since we have no-where to go.
+ $result = \is_null(Util::getParameterClassName($dependency)) ? $this->resolvePrimitive($dependency) : $this->resolveClass($dependency);
+ if ($dependency->isVariadic()) {
+ $results = \array_merge($results, $result);
+ } else {
+ $results[] = $result;
+ }
+ }
+ return $results;
+ }
+ /**
+ * Determine if the given dependency has a parameter override.
+ *
+ * @param \ReflectionParameter $dependency
+ * @return bool
+ */
+ protected function hasParameterOverride($dependency)
+ {
+ return \array_key_exists($dependency->name, $this->getLastParameterOverride());
+ }
+ /**
+ * Get a parameter override for a dependency.
+ *
+ * @param \ReflectionParameter $dependency
+ * @return mixed
+ */
+ protected function getParameterOverride($dependency)
+ {
+ return $this->getLastParameterOverride()[$dependency->name];
+ }
+ /**
+ * Get the last parameter override.
+ *
+ * @return array
+ */
+ protected function getLastParameterOverride()
+ {
+ return \count($this->with) ? \end($this->with) : [];
+ }
+ /**
+ * Resolve a non-class hinted primitive dependency.
+ *
+ * @param \ReflectionParameter $parameter
+ * @return mixed
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ protected function resolvePrimitive(ReflectionParameter $parameter)
+ {
+ if (!\is_null($concrete = $this->getContextualConcrete('$' . $parameter->getName()))) {
+ return Util::unwrapIfClosure($concrete, $this);
+ }
+ if ($parameter->isDefaultValueAvailable()) {
+ return $parameter->getDefaultValue();
+ }
+ if ($parameter->isVariadic()) {
+ return [];
+ }
+ $this->unresolvablePrimitive($parameter);
+ }
+ /**
+ * Resolve a class based dependency from the container.
+ *
+ * @param \ReflectionParameter $parameter
+ * @return mixed
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ protected function resolveClass(ReflectionParameter $parameter)
+ {
+ try {
+ return $parameter->isVariadic() ? $this->resolveVariadicClass($parameter) : $this->make(Util::getParameterClassName($parameter));
+ } catch (BindingResolutionException $e) {
+ if ($parameter->isDefaultValueAvailable()) {
+ \array_pop($this->with);
+ return $parameter->getDefaultValue();
+ }
+ if ($parameter->isVariadic()) {
+ \array_pop($this->with);
+ return [];
+ }
+ throw $e;
+ }
+ }
+ /**
+ * Resolve a class based variadic dependency from the container.
+ *
+ * @param \ReflectionParameter $parameter
+ * @return mixed
+ */
+ protected function resolveVariadicClass(ReflectionParameter $parameter)
+ {
+ $className = Util::getParameterClassName($parameter);
+ $abstract = $this->getAlias($className);
+ if (!\is_array($concrete = $this->getContextualConcrete($abstract))) {
+ return $this->make($className);
+ }
+ return \array_map(function ($abstract) {
+ return $this->resolve($abstract);
+ }, $concrete);
+ }
+ /**
+ * Throw an exception that the concrete is not instantiable.
+ *
+ * @param string $concrete
+ * @return void
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ protected function notInstantiable($concrete)
+ {
+ if (!empty($this->buildStack)) {
+ $previous = \implode(', ', $this->buildStack);
+ $message = "Target [{$concrete}] is not instantiable while building [{$previous}].";
+ } else {
+ $message = "Target [{$concrete}] is not instantiable.";
+ }
+ throw new BindingResolutionException($message);
+ }
+ /**
+ * Throw an exception for an unresolvable primitive.
+ *
+ * @param \ReflectionParameter $parameter
+ * @return void
+ *
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ protected function unresolvablePrimitive(ReflectionParameter $parameter)
+ {
+ $message = "Unresolvable dependency resolving [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}";
+ throw new BindingResolutionException($message);
+ }
+ /**
+ * Register a new before resolving callback for all types.
+ *
+ * @param \Closure|string $abstract
+ * @param \Closure|null $callback
+ * @return void
+ */
+ public function beforeResolving($abstract, Closure $callback = null)
+ {
+ if (\is_string($abstract)) {
+ $abstract = $this->getAlias($abstract);
+ }
+ if ($abstract instanceof Closure && \is_null($callback)) {
+ $this->globalBeforeResolvingCallbacks[] = $abstract;
+ } else {
+ $this->beforeResolvingCallbacks[$abstract][] = $callback;
+ }
+ }
+ /**
+ * Register a new resolving callback.
+ *
+ * @param \Closure|string $abstract
+ * @param \Closure|null $callback
+ * @return void
+ */
+ public function resolving($abstract, Closure $callback = null)
+ {
+ if (\is_string($abstract)) {
+ $abstract = $this->getAlias($abstract);
+ }
+ if (\is_null($callback) && $abstract instanceof Closure) {
+ $this->globalResolvingCallbacks[] = $abstract;
+ } else {
+ $this->resolvingCallbacks[$abstract][] = $callback;
+ }
+ }
+ /**
+ * Register a new after resolving callback for all types.
+ *
+ * @param \Closure|string $abstract
+ * @param \Closure|null $callback
+ * @return void
+ */
+ public function afterResolving($abstract, Closure $callback = null)
+ {
+ if (\is_string($abstract)) {
+ $abstract = $this->getAlias($abstract);
+ }
+ if ($abstract instanceof Closure && \is_null($callback)) {
+ $this->globalAfterResolvingCallbacks[] = $abstract;
+ } else {
+ $this->afterResolvingCallbacks[$abstract][] = $callback;
+ }
+ }
+ /**
+ * Fire all of the before resolving callbacks.
+ *
+ * @param string $abstract
+ * @param array $parameters
+ * @return void
+ */
+ protected function fireBeforeResolvingCallbacks($abstract, $parameters = [])
+ {
+ $this->fireBeforeCallbackArray($abstract, $parameters, $this->globalBeforeResolvingCallbacks);
+ foreach ($this->beforeResolvingCallbacks as $type => $callbacks) {
+ if ($type === $abstract || \is_subclass_of($abstract, $type)) {
+ $this->fireBeforeCallbackArray($abstract, $parameters, $callbacks);
+ }
+ }
+ }
+ /**
+ * Fire an array of callbacks with an object.
+ *
+ * @param string $abstract
+ * @param array $parameters
+ * @param array $callbacks
+ * @return void
+ */
+ protected function fireBeforeCallbackArray($abstract, $parameters, array $callbacks)
+ {
+ foreach ($callbacks as $callback) {
+ $callback($abstract, $parameters, $this);
+ }
+ }
+ /**
+ * Fire all of the resolving callbacks.
+ *
+ * @param string $abstract
+ * @param mixed $object
+ * @return void
+ */
+ protected function fireResolvingCallbacks($abstract, $object)
+ {
+ $this->fireCallbackArray($object, $this->globalResolvingCallbacks);
+ $this->fireCallbackArray($object, $this->getCallbacksForType($abstract, $object, $this->resolvingCallbacks));
+ $this->fireAfterResolvingCallbacks($abstract, $object);
+ }
+ /**
+ * Fire all of the after resolving callbacks.
+ *
+ * @param string $abstract
+ * @param mixed $object
+ * @return void
+ */
+ protected function fireAfterResolvingCallbacks($abstract, $object)
+ {
+ $this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks);
+ $this->fireCallbackArray($object, $this->getCallbacksForType($abstract, $object, $this->afterResolvingCallbacks));
+ }
+ /**
+ * Get all callbacks for a given type.
+ *
+ * @param string $abstract
+ * @param object $object
+ * @param array $callbacksPerType
+ * @return array
+ */
+ protected function getCallbacksForType($abstract, $object, array $callbacksPerType)
+ {
+ $results = [];
+ foreach ($callbacksPerType as $type => $callbacks) {
+ if ($type === $abstract || $object instanceof $type) {
+ $results = \array_merge($results, $callbacks);
+ }
+ }
+ return $results;
+ }
+ /**
+ * Fire an array of callbacks with an object.
+ *
+ * @param mixed $object
+ * @param array $callbacks
+ * @return void
+ */
+ protected function fireCallbackArray($object, array $callbacks)
+ {
+ foreach ($callbacks as $callback) {
+ $callback($object, $this);
+ }
+ }
+ /**
+ * Get the container's bindings.
+ *
+ * @return array
+ */
+ public function getBindings()
+ {
+ return $this->bindings;
+ }
+ /**
+ * Get the alias for an abstract if available.
+ *
+ * @param string $abstract
+ * @return string
+ */
+ public function getAlias($abstract)
+ {
+ return isset($this->aliases[$abstract]) ? $this->getAlias($this->aliases[$abstract]) : $abstract;
+ }
+ /**
+ * Get the extender callbacks for a given type.
+ *
+ * @param string $abstract
+ * @return array
+ */
+ protected function getExtenders($abstract)
+ {
+ return $this->extenders[$this->getAlias($abstract)] ?? [];
+ }
+ /**
+ * Remove all of the extender callbacks for a given type.
+ *
+ * @param string $abstract
+ * @return void
+ */
+ public function forgetExtenders($abstract)
+ {
+ unset($this->extenders[$this->getAlias($abstract)]);
+ }
+ /**
+ * Drop all of the stale instances and aliases.
+ *
+ * @param string $abstract
+ * @return void
+ */
+ protected function dropStaleInstances($abstract)
+ {
+ unset($this->instances[$abstract], $this->aliases[$abstract]);
+ }
+ /**
+ * Remove a resolved instance from the instance cache.
+ *
+ * @param string $abstract
+ * @return void
+ */
+ public function forgetInstance($abstract)
+ {
+ unset($this->instances[$abstract]);
+ }
+ /**
+ * Clear all of the instances from the container.
+ *
+ * @return void
+ */
+ public function forgetInstances()
+ {
+ $this->instances = [];
+ }
+ /**
+ * Clear all of the scoped instances from the container.
+ *
+ * @return void
+ */
+ public function forgetScopedInstances()
+ {
+ foreach ($this->scopedInstances as $scoped) {
+ unset($this->instances[$scoped]);
+ }
+ }
+ /**
+ * Flush the container of all bindings and resolved instances.
+ *
+ * @return void
+ */
+ public function flush()
+ {
+ $this->aliases = [];
+ $this->resolved = [];
+ $this->bindings = [];
+ $this->instances = [];
+ $this->abstractAliases = [];
+ $this->scopedInstances = [];
+ }
+ /**
+ * Get the globally available instance of the container.
+ *
+ * @return static
+ */
+ public static function getInstance()
+ {
+ if (\is_null(static::$instance)) {
+ static::$instance = new static();
+ }
+ return static::$instance;
+ }
+ /**
+ * Set the shared instance of the container.
+ *
+ * @param \Illuminate\Contracts\Container\Container|null $container
+ * @return \Illuminate\Contracts\Container\Container|static
+ */
+ public static function setInstance(ContainerContract $container = null)
+ {
+ return static::$instance = $container;
+ }
+ /**
+ * Determine if a given offset exists.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function offsetExists($key) : bool
+ {
+ return $this->bound($key);
+ }
+ /**
+ * Get the value at a given offset.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetGet($key)
+ {
+ return $this->make($key);
+ }
+ /**
+ * Set the value at a given offset.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function offsetSet($key, $value) : void
+ {
+ $this->bind($key, $value instanceof Closure ? $value : function () use($value) {
+ return $value;
+ });
+ }
+ /**
+ * Unset the value at a given offset.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function offsetUnset($key) : void
+ {
+ unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]);
+ }
+ /**
+ * Dynamically access container services.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ return $this[$key];
+ }
+ /**
+ * Dynamically set container services.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ $this[$key] = $value;
+ }
+}
diff --git a/vendor/illuminate/container/ContextualBindingBuilder.php b/vendor/illuminate/container/ContextualBindingBuilder.php
new file mode 100644
index 0000000000..307fe7f78c
--- /dev/null
+++ b/vendor/illuminate/container/ContextualBindingBuilder.php
@@ -0,0 +1,88 @@
+concrete = $concrete;
+ $this->container = $container;
+ }
+ /**
+ * Define the abstract target that depends on the context.
+ *
+ * @param string $abstract
+ * @return $this
+ */
+ public function needs($abstract)
+ {
+ $this->needs = $abstract;
+ return $this;
+ }
+ /**
+ * Define the implementation for the contextual binding.
+ *
+ * @param \Closure|string|array $implementation
+ * @return void
+ */
+ public function give($implementation)
+ {
+ foreach (Util::arrayWrap($this->concrete) as $concrete) {
+ $this->container->addContextualBinding($concrete, $this->needs, $implementation);
+ }
+ }
+ /**
+ * Define tagged services to be used as the implementation for the contextual binding.
+ *
+ * @param string $tag
+ * @return void
+ */
+ public function giveTagged($tag)
+ {
+ $this->give(function ($container) use($tag) {
+ $taggedServices = $container->tagged($tag);
+ return \is_array($taggedServices) ? $taggedServices : \iterator_to_array($taggedServices);
+ });
+ }
+ /**
+ * Specify the configuration item to bind as a primitive.
+ *
+ * @param string $key
+ * @param mixed $default
+ * @return void
+ */
+ public function giveConfig($key, $default = null)
+ {
+ $this->give(function ($container) use($key, $default) {
+ return $container->get('config')->get($key, $default);
+ });
+ }
+}
diff --git a/vendor/illuminate/container/EntryNotFoundException.php b/vendor/illuminate/container/EntryNotFoundException.php
new file mode 100644
index 0000000000..4c54a1bdb1
--- /dev/null
+++ b/vendor/illuminate/container/EntryNotFoundException.php
@@ -0,0 +1,10 @@
+count = $count;
+ $this->generator = $generator;
+ }
+ /**
+ * Get an iterator from the generator.
+ *
+ * @return \Traversable
+ */
+ public function getIterator() : Traversable
+ {
+ return ($this->generator)();
+ }
+ /**
+ * Get the total number of tagged services.
+ *
+ * @return int
+ */
+ public function count() : int
+ {
+ if (\is_callable($count = $this->count)) {
+ $this->count = $count();
+ }
+ return $this->count;
+ }
+}
diff --git a/vendor/illuminate/container/Util.php b/vendor/illuminate/container/Util.php
new file mode 100644
index 0000000000..4910fc65f1
--- /dev/null
+++ b/vendor/illuminate/container/Util.php
@@ -0,0 +1,65 @@
+getType();
+ if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) {
+ return null;
+ }
+ $name = $type->getName();
+ if (!\is_null($class = $parameter->getDeclaringClass())) {
+ if ($name === 'self') {
+ return $class->getName();
+ }
+ if ($name === 'parent' && ($parent = $class->getParentClass())) {
+ return $parent->getName();
+ }
+ }
+ return $name;
+ }
+}
diff --git a/vendor/illuminate/container/composer.json b/vendor/illuminate/container/composer.json
new file mode 100755
index 0000000000..aafc43f7e4
--- /dev/null
+++ b/vendor/illuminate/container/composer.json
@@ -0,0 +1,38 @@
+{
+ "name": "illuminate\/container",
+ "description": "The Illuminate Container package.",
+ "license": "MIT",
+ "homepage": "https:\/\/laravel.com",
+ "support": {
+ "issues": "https:\/\/github.com\/laravel\/framework\/issues",
+ "source": "https:\/\/github.com\/laravel\/framework"
+ },
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "require": {
+ "php": "^8.1",
+ "illuminate\/contracts": "^10.0",
+ "psr\/container": "^1.1.1|^2.0.1"
+ },
+ "provide": {
+ "psr\/container-implementation": "1.1|2.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "EasyCI202401\\Illuminate\\Container\\": ""
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "10.x-dev"
+ }
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "minimum-stability": "dev"
+}
\ No newline at end of file
diff --git a/vendor/illuminate/contracts/Auth/Access/Authorizable.php b/vendor/illuminate/contracts/Auth/Access/Authorizable.php
new file mode 100644
index 0000000000..db9566fd06
--- /dev/null
+++ b/vendor/illuminate/contracts/Auth/Access/Authorizable.php
@@ -0,0 +1,15 @@
+|CastsAttributes|CastsInboundAttributes
+ */
+ public static function castUsing(array $arguments);
+}
diff --git a/vendor/illuminate/contracts/Database/Eloquent/CastsAttributes.php b/vendor/illuminate/contracts/Database/Eloquent/CastsAttributes.php
new file mode 100644
index 0000000000..28bb2319aa
--- /dev/null
+++ b/vendor/illuminate/contracts/Database/Eloquent/CastsAttributes.php
@@ -0,0 +1,32 @@
+ $attributes
+ * @return TGet|null
+ */
+ public function get(Model $model, string $key, $value, array $attributes);
+ /**
+ * Transform the attribute to its underlying model values.
+ *
+ * @param \Illuminate\Database\Eloquent\Model $model
+ * @param string $key
+ * @param mixed $value
+ * @param array $attributes
+ * @return mixed
+ */
+ public function set(Model $model, string $key, $value, array $attributes);
+}
diff --git a/vendor/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php b/vendor/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php
new file mode 100644
index 0000000000..73087731b3
--- /dev/null
+++ b/vendor/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php
@@ -0,0 +1,18 @@
+id = $id;
+ $this->class = $class;
+ $this->relations = $relations;
+ $this->connection = $connection;
+ }
+ /**
+ * Specify the collection class that should be used when serializing / restoring collections.
+ *
+ * @param string|null $collectionClass
+ * @return $this
+ */
+ public function useCollectionClass(?string $collectionClass)
+ {
+ $this->collectionClass = $collectionClass;
+ return $this;
+ }
+}
diff --git a/vendor/illuminate/contracts/Database/Query/Builder.php b/vendor/illuminate/contracts/Database/Query/Builder.php
new file mode 100644
index 0000000000..412cee3f09
--- /dev/null
+++ b/vendor/illuminate/contracts/Database/Query/Builder.php
@@ -0,0 +1,12 @@
+
+ */
+ public function getQueueableIds();
+ /**
+ * Get the relationships of the entities being queued.
+ *
+ * @return array
+ */
+ public function getQueueableRelations();
+ /**
+ * Get the connection of the entities being queued.
+ *
+ * @return string|null
+ */
+ public function getQueueableConnection();
+}
diff --git a/vendor/illuminate/contracts/Queue/QueueableEntity.php b/vendor/illuminate/contracts/Queue/QueueableEntity.php
new file mode 100644
index 0000000000..7f37f51fe1
--- /dev/null
+++ b/vendor/illuminate/contracts/Queue/QueueableEntity.php
@@ -0,0 +1,25 @@
+
+ */
+ public function toArray();
+}
diff --git a/vendor/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php b/vendor/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php
new file mode 100644
index 0000000000..225c64d71c
--- /dev/null
+++ b/vendor/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php
@@ -0,0 +1,14 @@
+=7.1",
+ "nette\/utils": "^2.4 || ^3.0"
+ },
+ "require-dev": {
+ "nette\/tester": "^2.0",
+ "tracy\/tracy": "^2.3",
+ "phpstan\/phpstan": "^0.12"
+ },
+ "conflict": {
+ "nette\/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": [
+ "src\/"
+ ]
+ },
+ "minimum-stability": "dev",
+ "scripts": {
+ "phpstan": "phpstan analyse",
+ "tester": "tester tests -s"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.6-dev"
+ }
+ }
+}
\ No newline at end of file
diff --git a/vendor/nette/finder/license.md b/vendor/nette/finder/license.md
new file mode 100644
index 0000000000..cf741bd05f
--- /dev/null
+++ b/vendor/nette/finder/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
+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 "Nette Framework" nor the names of its 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 owner 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.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/finder/readme.md b/vendor/nette/finder/readme.md
new file mode 100644
index 0000000000..6feeafb490
--- /dev/null
+++ b/vendor/nette/finder/readme.md
@@ -0,0 +1,159 @@
+Nette Finder: Files Searching
+=============================
+
+[![Downloads this Month](https://img.shields.io/packagist/dm/nette/finder.svg)](https://packagist.org/packages/nette/finder)
+[![Tests](https://github.com/nette/finder/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/finder/actions)
+[![Coverage Status](https://coveralls.io/repos/github/nette/finder/badge.svg?branch=master)](https://coveralls.io/github/nette/finder?branch=master)
+[![Latest Stable Version](https://poser.pugx.org/nette/finder/v/stable)](https://github.com/nette/finder/releases)
+[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/finder/blob/master/license.md)
+
+
+Introduction
+------------
+
+Nette Finder makes browsing the directory structure really easy.
+
+Documentation can be found on the [website](https://doc.nette.org/finder).
+
+
+[Support Me](https://github.com/sponsors/dg)
+--------------------------------------------
+
+Do you like Nette Finder? Are you looking forward to the new features?
+
+[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
+
+Thank you!
+
+
+Installation
+------------
+
+```shell
+composer require nette/finder
+```
+
+All examples assume the following class alias is defined:
+
+```php
+use Nette\Utils\Finder;
+```
+
+
+Searching for Files
+-------------------
+
+How to find all `*.txt` files in `$dir` directory and all its subdirectories?
+
+```php
+foreach (Finder::findFiles('*.txt')->from($dir) as $key => $file) {
+ // $key is a string containing absolute filename with path
+ // $file is an instance of SplFileInfo
+}
+```
+
+The files in the `$file` variable are instances of the `SplFileInfo` class.
+
+If the directory does not exist, an `Nette\UnexpectedValueException` is thrown.
+
+And what about searching for files in a directory without subdirectories? Instead of `from()` use `in()`:
+
+```php
+Finder::findFiles('*.txt')->in($dir)
+```
+
+Search by multiple masks and even multiple directories at once:
+
+```php
+Finder::findFiles('*.txt', '*.php')
+ ->in($dir1, $dir2) // or from($dir1, $dir2)
+```
+
+Depth of search can be limited using the `limitDepth()` method.
+
+
+Searching for Directories
+-------------------------
+
+In addition to files, it is possible to search for directories using `Finder::findDirectories('subdir*')`.
+
+Or to search for files and directories together using `Finder::find('*.txt')`, the mask in this case only applies to files. When searching recursively with `from()`, the subdirectory is returned first, followed by the files in it, which can be reversed with `childFirst()`.
+
+
+Mask
+----
+
+The mask does not have to describe only the file name, but also the path. Example: searching for `*.jpg` files located in a subdirectory starting with `imag`:
+
+```php
+Finder::findFiles('imag*/*.jpg')
+```
+
+Thus, the known wildcards `*` and `?` represent any characters except the directory separator `/`. The double `**` represents any characters, including the directory separator:
+
+```php
+Finder::findFiles('imag**/*.jpg')
+// finds also image/subdir/file.jpg
+```
+
+In addition you can use in the mask ranges `[...]` or negative ranges `[!...]` known from regular expressions. Searching for `*.txt` files containing a digit in the name:
+
+```php
+Finder::findFiles('*[0-9]*.txt')
+```
+
+
+Excluding
+---------
+
+Use `exclude()` to pass masks that the file must not match. Searching for `*.txt` files, except those containing '`X`' in the name:
+
+```php
+Finder::findFiles('*.txt')
+ ->exclude('*X*')
+```
+
+If `exclude()` is specified **after** `from()`, it applies to crawled subdirectories:
+
+```php
+Finder::findFiles('*.php')
+ ->from($dir)
+ ->exclude('temp', '.git')
+```
+
+
+
+Filtering
+---------
+
+You can also filter the results, for example by file size. Here's how to find files of size between 100 and 200 bytes:
+
+```php
+Finder::findFiles('*.php')
+ ->size('>=', 100)
+ ->size('<=', 200)
+ ->from($dir)
+```
+
+Filtering by date of last change. Example: searching for files changed in the last two weeks:
+
+```php
+Finder::findFiles('*.php')
+ ->date('>', '- 2 weeks')
+ ->from($dir)
+```
+
+Both functions understand the operators `>`, `>=`, `<`, `<=`, `=`, `!=`.
+
+Here we traverse PHP files with number of lines greater than 1000. As a filter we use a custom callback:
+
+```php
+$hasMoreThan100Lines = function (SplFileInfo $file): bool {
+ return count(file($file->getPathname())) > 1000;
+};
+
+Finder::findFiles('*.php')
+ ->filter($hasMoreThan100Lines)
+```
+
+Handy, right? You will certainly find a use for Finder in your applications.
diff --git a/vendor/nette/finder/src/Utils/Finder.php b/vendor/nette/finder/src/Utils/Finder.php
new file mode 100644
index 0000000000..e019435c5d
--- /dev/null
+++ b/vendor/nette/finder/src/Utils/Finder.php
@@ -0,0 +1,317 @@
+
+ * Finder::findFiles('*.php')
+ * ->size('> 10kB')
+ * ->from('.')
+ * ->exclude('temp');
+ *
+ *
+ * @implements \IteratorAggregate
+ */
+class Finder implements \IteratorAggregate, \Countable
+{
+ use Nette\SmartObject;
+ /** @var callable[] extension methods */
+ private static $extMethods = [];
+ /** @var array */
+ private $paths = [];
+ /** @var array of filters */
+ private $groups = [];
+ /** @var array filter for recursive traversing */
+ private $exclude = [];
+ /** @var int */
+ private $order = RecursiveIteratorIterator::SELF_FIRST;
+ /** @var int */
+ private $maxDepth = -1;
+ /** @var array */
+ private $cursor;
+ /**
+ * Begins search for files and directories matching mask.
+ * @param string ...$masks
+ * @return static
+ */
+ public static function find(...$masks) : self
+ {
+ $masks = \is_array($tmp = \reset($masks)) ? $tmp : $masks;
+ return (new static())->select($masks, 'isDir')->select($masks, 'isFile');
+ }
+ /**
+ * Begins search for files matching mask.
+ * @param string ...$masks
+ * @return static
+ */
+ public static function findFiles(...$masks) : self
+ {
+ $masks = \is_array($tmp = \reset($masks)) ? $tmp : $masks;
+ return (new static())->select($masks, 'isFile');
+ }
+ /**
+ * Begins search for directories matching mask.
+ * @param string ...$masks
+ * @return static
+ */
+ public static function findDirectories(...$masks) : self
+ {
+ $masks = \is_array($tmp = \reset($masks)) ? $tmp : $masks;
+ return (new static())->select($masks, 'isDir');
+ }
+ /**
+ * Creates filtering group by mask & type selector.
+ * @return static
+ */
+ private function select(array $masks, string $type) : self
+ {
+ $this->cursor =& $this->groups[];
+ $pattern = self::buildPattern($masks);
+ $this->filter(function (RecursiveDirectoryIterator $file) use($type, $pattern) : bool {
+ return !$file->isDot() && $file->{$type}() && (!$pattern || \preg_match($pattern, '/' . \strtr($file->getSubPathName(), '\\', '/')));
+ });
+ return $this;
+ }
+ /**
+ * Searches in the given folder(s).
+ * @param string ...$paths
+ * @return static
+ */
+ public function in(...$paths) : self
+ {
+ $this->maxDepth = 0;
+ return $this->from(...$paths);
+ }
+ /**
+ * Searches recursively from the given folder(s).
+ * @param string ...$paths
+ * @return static
+ */
+ public function from(...$paths) : self
+ {
+ if ($this->paths) {
+ throw new Nette\InvalidStateException('Directory to search has already been specified.');
+ }
+ $this->paths = \is_array($tmp = \reset($paths)) ? $tmp : $paths;
+ $this->cursor =& $this->exclude;
+ return $this;
+ }
+ /**
+ * Shows folder content prior to the folder.
+ * @return static
+ */
+ public function childFirst() : self
+ {
+ $this->order = RecursiveIteratorIterator::CHILD_FIRST;
+ return $this;
+ }
+ /**
+ * Converts Finder pattern to regular expression.
+ */
+ private static function buildPattern(array $masks) : ?string
+ {
+ $pattern = [];
+ foreach ($masks as $mask) {
+ $mask = \rtrim(\strtr($mask, '\\', '/'), '/');
+ $prefix = '';
+ if ($mask === '') {
+ continue;
+ } elseif ($mask === '*') {
+ return null;
+ } elseif ($mask[0] === '/') {
+ // absolute fixing
+ $mask = \ltrim($mask, '/');
+ $prefix = '(?<=^/)';
+ }
+ $pattern[] = $prefix . \strtr(\preg_quote($mask, '#'), ['\\*\\*' => '.*', '\\*' => '[^/]*', '\\?' => '[^/]', '\\[\\!' => '[^', '\\[' => '[', '\\]' => ']', '\\-' => '-']);
+ }
+ return $pattern ? '#/(' . \implode('|', $pattern) . ')$#Di' : null;
+ }
+ /********************* iterator generator ****************d*g**/
+ /** @deprecated */
+ public function count() : int
+ {
+ \trigger_error('Nette\\Utils\\Finder::count is deprecated.', \E_USER_DEPRECATED);
+ return \iterator_count($this->getIterator());
+ }
+ /**
+ * Returns iterator.
+ */
+ public function getIterator() : \Iterator
+ {
+ if (!$this->paths) {
+ throw new Nette\InvalidStateException('Call in() or from() to specify directory to search.');
+ } elseif (\count($this->paths) === 1) {
+ return $this->buildIterator((string) $this->paths[0]);
+ }
+ $iterator = new \AppendIterator();
+ foreach ($this->paths as $path) {
+ $iterator->append($this->buildIterator((string) $path));
+ }
+ return $iterator;
+ }
+ /**
+ * Returns per-path iterator.
+ */
+ private function buildIterator(string $path) : \Iterator
+ {
+ $iterator = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::FOLLOW_SYMLINKS);
+ if ($this->exclude) {
+ $iterator = new \RecursiveCallbackFilterIterator($iterator, function ($foo, $bar, RecursiveDirectoryIterator $file) : bool {
+ if (!$file->isDot() && !$file->isFile()) {
+ foreach ($this->exclude as $filter) {
+ if (!$filter($file)) {
+ return \false;
+ }
+ }
+ }
+ return \true;
+ });
+ }
+ if ($this->maxDepth !== 0) {
+ $iterator = new RecursiveIteratorIterator($iterator, $this->order);
+ $iterator->setMaxDepth($this->maxDepth);
+ }
+ $iterator = new \CallbackFilterIterator($iterator, function ($foo, $bar, \Iterator $file) : bool {
+ while ($file instanceof \OuterIterator) {
+ $file = $file->getInnerIterator();
+ }
+ foreach ($this->groups as $filters) {
+ foreach ($filters as $filter) {
+ if (!$filter($file)) {
+ continue 2;
+ }
+ }
+ return \true;
+ }
+ return \false;
+ });
+ return $iterator;
+ }
+ /********************* filtering ****************d*g**/
+ /**
+ * Restricts the search using mask.
+ * Excludes directories from recursive traversing.
+ * @param string ...$masks
+ * @return static
+ */
+ public function exclude(...$masks) : self
+ {
+ $masks = \is_array($tmp = \reset($masks)) ? $tmp : $masks;
+ $pattern = self::buildPattern($masks);
+ if ($pattern) {
+ $this->filter(function (RecursiveDirectoryIterator $file) use($pattern) : bool {
+ return !\preg_match($pattern, '/' . \strtr($file->getSubPathName(), '\\', '/'));
+ });
+ }
+ return $this;
+ }
+ /**
+ * Restricts the search using callback.
+ * @param callable(RecursiveDirectoryIterator): bool $callback
+ * @return static
+ */
+ public function filter(callable $callback) : self
+ {
+ $this->cursor[] = $callback;
+ return $this;
+ }
+ /**
+ * Limits recursion level.
+ * @return static
+ */
+ public function limitDepth(int $depth) : self
+ {
+ $this->maxDepth = $depth;
+ return $this;
+ }
+ /**
+ * Restricts the search by size.
+ * @param string $operator "[operator] [size] [unit]" example: >=10kB
+ * @return static
+ */
+ public function size(string $operator, ?int $size = null) : self
+ {
+ if (\func_num_args() === 1) {
+ // in $operator is predicate
+ if (!\preg_match('#^(?:([=<>!]=?|<>)\\s*)?((?:\\d*\\.)?\\d+)\\s*(K|M|G|)B?$#Di', $operator, $matches)) {
+ throw new Nette\InvalidArgumentException('Invalid size predicate format.');
+ }
+ [, $operator, $size, $unit] = $matches;
+ static $units = ['' => 1, 'k' => 1000.0, 'm' => 1000000.0, 'g' => 1000000000.0];
+ $size *= $units[\strtolower($unit)];
+ $operator = $operator ?: '=';
+ }
+ return $this->filter(function (RecursiveDirectoryIterator $file) use($operator, $size) : bool {
+ return self::compare($file->getSize(), $operator, $size);
+ });
+ }
+ /**
+ * Restricts the search by modified time.
+ * @param string $operator "[operator] [date]" example: >1978-01-23
+ * @param string|int|\DateTimeInterface $date
+ * @return static
+ */
+ public function date(string $operator, $date = null) : self
+ {
+ if (\func_num_args() === 1) {
+ // in $operator is predicate
+ if (!\preg_match('#^(?:([=<>!]=?|<>)\\s*)?(.+)$#Di', $operator, $matches)) {
+ throw new Nette\InvalidArgumentException('Invalid date predicate format.');
+ }
+ [, $operator, $date] = $matches;
+ $operator = $operator ?: '=';
+ }
+ $date = DateTime::from($date)->format('U');
+ return $this->filter(function (RecursiveDirectoryIterator $file) use($operator, $date) : bool {
+ return self::compare($file->getMTime(), $operator, $date);
+ });
+ }
+ /**
+ * Compares two values.
+ */
+ public static function compare($l, string $operator, $r) : bool
+ {
+ switch ($operator) {
+ case '>':
+ return $l > $r;
+ case '>=':
+ return $l >= $r;
+ case '<':
+ return $l < $r;
+ case '<=':
+ return $l <= $r;
+ case '=':
+ case '==':
+ return $l == $r;
+ case '!':
+ case '!=':
+ case '<>':
+ return $l != $r;
+ default:
+ throw new Nette\InvalidArgumentException("Unknown operator {$operator}.");
+ }
+ }
+ /********************* extension methods ****************d*g**/
+ /** @deprecated */
+ public function __call(string $name, array $args)
+ {
+ return isset(self::$extMethods[$name]) ? self::$extMethods[$name]($this, ...$args) : Nette\Utils\ObjectHelpers::strictCall(static::class, $name, \array_keys(self::$extMethods));
+ }
+ /** @deprecated */
+ public static function extensionMethod(string $name, callable $callback) : void
+ {
+ \trigger_error(__METHOD__ . '() is deprecated.', \E_USER_DEPRECATED);
+ self::$extMethods[$name] = $callback;
+ }
+}
diff --git a/vendor/nette/robot-loader/composer.json b/vendor/nette/robot-loader/composer.json
new file mode 100644
index 0000000000..cad004ebef
--- /dev/null
+++ b/vendor/nette/robot-loader/composer.json
@@ -0,0 +1,53 @@
+{
+ "name": "nette\/robot-loader",
+ "description": "\ud83c\udf40 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.",
+ "keywords": [
+ "nette",
+ "autoload",
+ "class",
+ "trait",
+ "interface"
+ ],
+ "homepage": "https:\/\/nette.org",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0-only",
+ "GPL-3.0-only"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https:\/\/davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https:\/\/nette.org\/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1",
+ "ext-tokenizer": "*",
+ "nette\/finder": "^2.5 || ^3.0",
+ "nette\/utils": "^3.0"
+ },
+ "require-dev": {
+ "nette\/tester": "^2.0",
+ "tracy\/tracy": "^2.3",
+ "phpstan\/phpstan": "^0.12"
+ },
+ "autoload": {
+ "classmap": [
+ "src\/"
+ ]
+ },
+ "minimum-stability": "dev",
+ "scripts": {
+ "phpstan": "phpstan analyse",
+ "tester": "tester tests -s"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.4-dev"
+ }
+ }
+}
\ No newline at end of file
diff --git a/vendor/nette/robot-loader/license.md b/vendor/nette/robot-loader/license.md
new file mode 100644
index 0000000000..cf741bd05f
--- /dev/null
+++ b/vendor/nette/robot-loader/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
+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 "Nette Framework" nor the names of its 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 owner 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.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/robot-loader/ncs.php b/vendor/nette/robot-loader/ncs.php
new file mode 100644
index 0000000000..2987ca75b4
--- /dev/null
+++ b/vendor/nette/robot-loader/ncs.php
@@ -0,0 +1,13 @@
+ \false,
+];
diff --git a/vendor/nette/robot-loader/readme.md b/vendor/nette/robot-loader/readme.md
new file mode 100644
index 0000000000..51036982b0
--- /dev/null
+++ b/vendor/nette/robot-loader/readme.md
@@ -0,0 +1,131 @@
+RobotLoader: comfortable autoloading
+====================================
+
+[![Downloads this Month](https://img.shields.io/packagist/dm/nette/robot-loader.svg)](https://packagist.org/packages/nette/robot-loader)
+[![Tests](https://github.com/nette/robot-loader/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/robot-loader/actions)
+[![Coverage Status](https://coveralls.io/repos/github/nette/robot-loader/badge.svg?branch=master)](https://coveralls.io/github/nette/robot-loader?branch=master)
+[![Latest Stable Version](https://poser.pugx.org/nette/robot-loader/v/stable)](https://github.com/nette/robot-loader/releases)
+[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/robot-loader/blob/master/license.md)
+
+
+Introduction
+------------
+
+RobotLoader is a tool that gives you comfort of automated class loading for your entire application including third-party libraries.
+
+- get rid of all `require`
+- does not require strict directory or file naming conventions
+- extremely fast
+- no manual cache updates, everything runs automatically
+- highly mature, stable and widely used library
+
+So we can forget about those famous code blocks:
+
+```php
+require_once 'Utils/Page.php';
+require_once 'Utils/Style.php';
+require_once 'Utils/Paginator.php';
+...
+```
+
+[Support Me](https://github.com/sponsors/dg)
+--------------------------------------------
+
+Do you like RobotLoader? Are you looking forward to the new features?
+
+[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
+
+Thank you!
+
+
+Installation
+------------
+
+The recommended way to install is via Composer:
+
+```shell
+composer require nette/robot-loader
+```
+
+It requires PHP version 7.1 and supports PHP up to 8.2.
+
+
+Usage
+-----
+
+Like the Google robot crawls and indexes websites, [RobotLoader](https://api.nette.org/3.0/Nette/Loaders/RobotLoader.html) crawls all PHP scripts and records what classes and interfaces were found in them. These records are then saved in cache and used during all subsequent requests. You just need to specify what directories to index and where to save the cache:
+
+```php
+$loader = new Nette\Loaders\RobotLoader;
+
+// directories to be indexed by RobotLoader (including subdirectories)
+$loader->addDirectory(__DIR__ . '/app');
+$loader->addDirectory(__DIR__ . '/libs');
+
+// use 'temp' directory for cache
+$loader->setTempDirectory(__DIR__ . '/temp');
+$loader->register(); // Run the RobotLoader
+```
+
+And that's all. From now on, you don't need to use `require`. Great, isn't it?
+
+When RobotLoader encounters duplicate class name during indexing, it throws an exception and informs you about it. RobotLoader also automatically updates the cache when it has to load a class it doesn't know. We recommend disabling this on production servers, see [Caching](#Caching).
+
+If you want RobotLoader to skip some directories, use `$loader->excludeDirectory('temp')` (it can be called multiple times or you can pass multiple directories).
+
+By default, RobotLoader reports errors in PHP files by throwing exception `ParseError`. It can be disabled via `$loader->reportParseErrors(false)`.
+
+
+PHP Files Analyzer
+------------------
+
+RobotLoader can also be used purely to find classes, interfaces, and trait in PHP files **without** using the autoloading feature:
+
+```php
+$loader = new Nette\Loaders\RobotLoader;
+$loader->addDirectory(__DIR__ . '/app');
+
+// Scans directories for classes / intefaces / traits
+$loader->rebuild();
+
+// Returns array of class => filename pairs
+$res = $loader->getIndexedClasses();
+```
+
+Even with such use, you can use the cache. As a result, unmodified files will not be repeatedly analyzed when rescanning:
+
+```php
+$loader = new Nette\Loaders\RobotLoader;
+$loader->addDirectory(__DIR__ . '/app');
+$loader->setTempDirectory(__DIR__ . '/temp');
+
+// Scans directories using a cache
+$loader->refresh();
+
+// Returns array of class => filename pairs
+$res = $loader->getIndexedClasses();
+```
+
+Caching
+-------
+
+RobotLoader is very fast because it cleverly uses the cache.
+
+When developing with it, you have practically no idea that it runs on the background. It continuously updates the cache because it knows that classes and files can be created, deleted, renamed, etc. And it doesn't repeatedly scan unmodified files.
+
+When used on a production server, on the other hand, we recommend disabling the cache update using `$loader->setAutoRefresh(false)`, because the files are not changing. At the same time, it is necessary to **clear the cache** when uploading a new version on the hosting.
+
+Of course, the initial scanning of files, when the cache does not already exist, may take a few seconds for larger applications. RobotLoader has built-in prevention against [cache stampede](https://en.wikipedia.org/wiki/Cache_stampede).
+This is a situation where production server receives a large number of concurrent requests and because RobotLoader's cache does not yet exist, they would all start scanning the files. Which spikes CPU and filesystem usage.
+Fortunately, RobotLoader works in such a way that for multiple concurrent requests, only the first thread indexes the files, creates a cache, the others wait, and then use the cache.
+
+
+PSR-4
+-----
+
+Today, Composer can be used for autoloading in compliance with PSR-4. Simply saying, it is a system where the namespaces and class names correspond to the directory structure and file names, ie `App\Router\RouterFactory` is located in the file `/path/to/App/Router/RouterFactory.php`.
+
+RobotLoader is not tied to any fixed structure, therefore, it is useful in situations where it does not suit you to have the directory structure designed as namespaces in PHP, or when you are developing an application that has historically not used such conventions. It is also possible to use both loaders together.
+
+
+If you like RobotLoader, **[please make a donation now](https://nette.org/donate)**. Thank you!
diff --git a/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php b/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php
new file mode 100644
index 0000000000..1ab63695f6
--- /dev/null
+++ b/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php
@@ -0,0 +1,444 @@
+
+ * $loader = new Nette\Loaders\RobotLoader;
+ * $loader->addDirectory('app');
+ * $loader->excludeDirectory('app/exclude');
+ * $loader->setTempDirectory('temp');
+ * $loader->register();
+ *
+ */
+class RobotLoader
+{
+ use Nette\SmartObject;
+ private const RetryLimit = 3;
+ /** @var string[] */
+ public $ignoreDirs = ['.*', '*.old', '*.bak', '*.tmp', 'temp'];
+ /** @var string[] */
+ public $acceptFiles = ['*.php'];
+ /** @var bool */
+ private $autoRebuild = \true;
+ /** @var bool */
+ private $reportParseErrors = \true;
+ /** @var string[] */
+ private $scanPaths = [];
+ /** @var string[] */
+ private $excludeDirs = [];
+ /** @var array class => [file, time] */
+ private $classes = [];
+ /** @var bool */
+ private $cacheLoaded = \false;
+ /** @var bool */
+ private $refreshed = \false;
+ /** @var array class => counter */
+ private $missingClasses = [];
+ /** @var array file => mtime */
+ private $emptyFiles = [];
+ /** @var string|null */
+ private $tempDirectory;
+ /** @var bool */
+ private $needSave = \false;
+ public function __construct()
+ {
+ if (!\extension_loaded('tokenizer')) {
+ throw new Nette\NotSupportedException('PHP extension Tokenizer is not loaded.');
+ }
+ }
+ public function __destruct()
+ {
+ if ($this->needSave) {
+ $this->saveCache();
+ }
+ }
+ /**
+ * Register autoloader.
+ */
+ public function register(bool $prepend = \false) : self
+ {
+ \spl_autoload_register([$this, 'tryLoad'], \true, $prepend);
+ return $this;
+ }
+ /**
+ * Handles autoloading of classes, interfaces or traits.
+ */
+ public function tryLoad(string $type) : void
+ {
+ $this->loadCache();
+ $missing = $this->missingClasses[$type] ?? null;
+ if ($missing >= self::RetryLimit) {
+ return;
+ }
+ [$file, $mtime] = $this->classes[$type] ?? null;
+ if ($this->autoRebuild) {
+ if (!$this->refreshed) {
+ if (!$file || !\is_file($file)) {
+ $this->refreshClasses();
+ [$file] = $this->classes[$type] ?? null;
+ $this->needSave = \true;
+ } elseif (\filemtime($file) !== $mtime) {
+ $this->updateFile($file);
+ [$file] = $this->classes[$type] ?? null;
+ $this->needSave = \true;
+ }
+ }
+ if (!$file || !\is_file($file)) {
+ $this->missingClasses[$type] = ++$missing;
+ $this->needSave = $this->needSave || $file || $missing <= self::RetryLimit;
+ unset($this->classes[$type]);
+ $file = null;
+ }
+ }
+ if ($file) {
+ (static function ($file) {
+ require $file;
+ })($file);
+ }
+ }
+ /**
+ * Add path or paths to list.
+ * @param string ...$paths absolute path
+ */
+ public function addDirectory(...$paths) : self
+ {
+ if (\is_array($paths[0] ?? null)) {
+ \trigger_error(__METHOD__ . '() use variadics ...$paths to add an array of paths.', \E_USER_WARNING);
+ $paths = $paths[0];
+ }
+ $this->scanPaths = \array_merge($this->scanPaths, $paths);
+ return $this;
+ }
+ public function reportParseErrors(bool $on = \true) : self
+ {
+ $this->reportParseErrors = $on;
+ return $this;
+ }
+ /**
+ * Excludes path or paths from list.
+ * @param string ...$paths absolute path
+ */
+ public function excludeDirectory(...$paths) : self
+ {
+ if (\is_array($paths[0] ?? null)) {
+ \trigger_error(__METHOD__ . '() use variadics ...$paths to add an array of paths.', \E_USER_WARNING);
+ $paths = $paths[0];
+ }
+ $this->excludeDirs = \array_merge($this->excludeDirs, $paths);
+ return $this;
+ }
+ /**
+ * @return array class => filename
+ */
+ public function getIndexedClasses() : array
+ {
+ $this->loadCache();
+ $res = [];
+ foreach ($this->classes as $class => [$file]) {
+ $res[$class] = $file;
+ }
+ return $res;
+ }
+ /**
+ * Rebuilds class list cache.
+ */
+ public function rebuild() : void
+ {
+ $this->cacheLoaded = \true;
+ $this->classes = $this->missingClasses = $this->emptyFiles = [];
+ $this->refreshClasses();
+ if ($this->tempDirectory) {
+ $this->saveCache();
+ }
+ }
+ /**
+ * Refreshes class list cache.
+ */
+ public function refresh() : void
+ {
+ $this->loadCache();
+ if (!$this->refreshed) {
+ $this->refreshClasses();
+ $this->saveCache();
+ }
+ }
+ /**
+ * Refreshes $this->classes & $this->emptyFiles.
+ */
+ private function refreshClasses() : void
+ {
+ $this->refreshed = \true;
+ // prevents calling refreshClasses() or updateFile() in tryLoad()
+ $files = $this->emptyFiles;
+ $classes = [];
+ foreach ($this->classes as $class => [$file, $mtime]) {
+ $files[$file] = $mtime;
+ $classes[$file][] = $class;
+ }
+ $this->classes = $this->emptyFiles = [];
+ foreach ($this->scanPaths as $path) {
+ $iterator = \is_file($path) ? [new SplFileInfo($path)] : $this->createFileIterator($path);
+ foreach ($iterator as $fileInfo) {
+ $mtime = $fileInfo->getMTime();
+ $file = $fileInfo->getPathname();
+ $foundClasses = isset($files[$file]) && $files[$file] === $mtime ? $classes[$file] ?? [] : $this->scanPhp($file);
+ if (!$foundClasses) {
+ $this->emptyFiles[$file] = $mtime;
+ }
+ $files[$file] = $mtime;
+ $classes[$file] = [];
+ // prevents the error when adding the same file twice
+ foreach ($foundClasses as $class) {
+ if (isset($this->classes[$class])) {
+ throw new Nette\InvalidStateException(\sprintf('Ambiguous class %s resolution; defined in %s and in %s.', $class, $this->classes[$class][0], $file));
+ }
+ $this->classes[$class] = [$file, $mtime];
+ unset($this->missingClasses[$class]);
+ }
+ }
+ }
+ }
+ /**
+ * Creates an iterator scaning directory for PHP files, subdirectories and 'netterobots.txt' files.
+ * @throws Nette\IOException if path is not found
+ */
+ private function createFileIterator(string $dir) : Nette\Utils\Finder
+ {
+ if (!\is_dir($dir)) {
+ throw new Nette\IOException(\sprintf("File or directory '%s' not found.", $dir));
+ }
+ $dir = \realpath($dir) ?: $dir;
+ // realpath does not work in phar
+ if (\is_string($ignoreDirs = $this->ignoreDirs)) {
+ \trigger_error(self::class . ': $ignoreDirs must be an array.', \E_USER_WARNING);
+ $ignoreDirs = \preg_split('#[,\\s]+#', $ignoreDirs);
+ }
+ $disallow = [];
+ foreach (\array_merge($ignoreDirs, $this->excludeDirs) as $item) {
+ if ($item = \realpath($item)) {
+ $disallow[\str_replace('\\', '/', $item)] = \true;
+ }
+ }
+ if (\is_string($acceptFiles = $this->acceptFiles)) {
+ \trigger_error(self::class . ': $acceptFiles must be an array.', \E_USER_WARNING);
+ $acceptFiles = \preg_split('#[,\\s]+#', $acceptFiles);
+ }
+ $iterator = Nette\Utils\Finder::findFiles(...$acceptFiles)->filter(function (SplFileInfo $file) use(&$disallow) {
+ return $file->getRealPath() === \false ? \true : !isset($disallow[\str_replace('\\', '/', $file->getRealPath())]);
+ })->from($dir)->exclude(...$ignoreDirs)->filter($filter = function (SplFileInfo $dir) use(&$disallow) {
+ if ($dir->getRealPath() === \false) {
+ return \true;
+ }
+ $path = \str_replace('\\', '/', $dir->getRealPath());
+ if (\is_file("{$path}/netterobots.txt")) {
+ foreach (\file("{$path}/netterobots.txt") as $s) {
+ if (\preg_match('#^(?:disallow\\s*:)?\\s*(\\S+)#i', $s, $matches)) {
+ $disallow[$path . \rtrim('/' . \ltrim($matches[1], '/'), '/')] = \true;
+ }
+ }
+ }
+ return !isset($disallow[$path]);
+ });
+ $filter(new SplFileInfo($dir));
+ return $iterator;
+ }
+ private function updateFile(string $file) : void
+ {
+ foreach ($this->classes as $class => [$prevFile]) {
+ if ($file === $prevFile) {
+ unset($this->classes[$class]);
+ }
+ }
+ $foundClasses = \is_file($file) ? $this->scanPhp($file) : [];
+ foreach ($foundClasses as $class) {
+ [$prevFile, $prevMtime] = $this->classes[$class] ?? null;
+ if (isset($prevFile) && @\filemtime($prevFile) !== $prevMtime) {
+ // @ file may not exists
+ $this->updateFile($prevFile);
+ [$prevFile] = $this->classes[$class] ?? null;
+ }
+ if (isset($prevFile)) {
+ throw new Nette\InvalidStateException(\sprintf('Ambiguous class %s resolution; defined in %s and in %s.', $class, $prevFile, $file));
+ }
+ $this->classes[$class] = [$file, \filemtime($file)];
+ }
+ }
+ /**
+ * Searches classes, interfaces and traits in PHP file.
+ * @return string[]
+ */
+ private function scanPhp(string $file) : array
+ {
+ $code = \file_get_contents($file);
+ $expected = \false;
+ $namespace = $name = '';
+ $level = $minLevel = 0;
+ $classes = [];
+ try {
+ $tokens = \token_get_all($code, \TOKEN_PARSE);
+ } catch (\ParseError $e) {
+ if ($this->reportParseErrors) {
+ $rp = new \ReflectionProperty($e, 'file');
+ $rp->setAccessible(\true);
+ $rp->setValue($e, $file);
+ throw $e;
+ }
+ $tokens = [];
+ }
+ foreach ($tokens as $token) {
+ if (\is_array($token)) {
+ switch ($token[0]) {
+ case \T_COMMENT:
+ case \T_DOC_COMMENT:
+ case \T_WHITESPACE:
+ continue 2;
+ case \T_STRING:
+ case \PHP_VERSION_ID < 80000 ? \T_NS_SEPARATOR : \T_NAME_QUALIFIED:
+ if ($expected) {
+ $name .= $token[1];
+ }
+ continue 2;
+ case \T_NAMESPACE:
+ case \T_CLASS:
+ case \T_INTERFACE:
+ case \T_TRAIT:
+ case \PHP_VERSION_ID < 80100 ? \T_CLASS : \T_ENUM:
+ $expected = $token[0];
+ $name = '';
+ continue 2;
+ case \T_CURLY_OPEN:
+ case \T_DOLLAR_OPEN_CURLY_BRACES:
+ $level++;
+ }
+ }
+ if ($expected) {
+ if ($expected === \T_NAMESPACE) {
+ $namespace = $name ? $name . '\\' : '';
+ $minLevel = $token === '{' ? 1 : 0;
+ } elseif ($name && $level === $minLevel) {
+ $classes[] = $namespace . $name;
+ }
+ $expected = null;
+ }
+ if ($token === '{') {
+ $level++;
+ } elseif ($token === '}') {
+ $level--;
+ }
+ }
+ return $classes;
+ }
+ /********************* caching ****************d*g**/
+ /**
+ * Sets auto-refresh mode.
+ */
+ public function setAutoRefresh(bool $on = \true) : self
+ {
+ $this->autoRebuild = $on;
+ return $this;
+ }
+ /**
+ * Sets path to temporary directory.
+ */
+ public function setTempDirectory(string $dir) : self
+ {
+ Nette\Utils\FileSystem::createDir($dir);
+ $this->tempDirectory = $dir;
+ return $this;
+ }
+ /**
+ * Loads class list from cache.
+ */
+ private function loadCache() : void
+ {
+ if ($this->cacheLoaded) {
+ return;
+ }
+ $this->cacheLoaded = \true;
+ $file = $this->generateCacheFileName();
+ // Solving atomicity to work everywhere is really pain in the ass.
+ // 1) We want to do as little as possible IO calls on production and also directory and file can be not writable (#19)
+ // so on Linux we include the file directly without shared lock, therefore, the file must be created atomically by renaming.
+ // 2) On Windows file cannot be renamed-to while is open (ie by include() #11), so we have to acquire a lock.
+ $lock = \defined('PHP_WINDOWS_VERSION_BUILD') ? $this->acquireLock("{$file}.lock", \LOCK_SH) : null;
+ $data = @(include $file);
+ // @ file may not exist
+ if (\is_array($data)) {
+ [$this->classes, $this->missingClasses, $this->emptyFiles] = $data;
+ return;
+ }
+ if ($lock) {
+ \flock($lock, \LOCK_UN);
+ // release shared lock so we can get exclusive
+ }
+ $lock = $this->acquireLock("{$file}.lock", \LOCK_EX);
+ // while waiting for exclusive lock, someone might have already created the cache
+ $data = @(include $file);
+ // @ file may not exist
+ if (\is_array($data)) {
+ [$this->classes, $this->missingClasses, $this->emptyFiles] = $data;
+ return;
+ }
+ $this->classes = $this->missingClasses = $this->emptyFiles = [];
+ $this->refreshClasses();
+ $this->saveCache($lock);
+ // On Windows concurrent creation and deletion of a file can cause a 'permission denied' error,
+ // therefore, we will not delete the lock file. Windows is really annoying.
+ }
+ /**
+ * Writes class list to cache.
+ * @param resource $lock
+ */
+ private function saveCache($lock = null) : void
+ {
+ // we have to acquire a lock to be able safely rename file
+ // on Linux: that another thread does not rename the same named file earlier
+ // on Windows: that the file is not read by another thread
+ $file = $this->generateCacheFileName();
+ $lock = $lock ?: $this->acquireLock("{$file}.lock", \LOCK_EX);
+ $code = "classes, $this->missingClasses, $this->emptyFiles], \true) . ";\n";
+ if (\file_put_contents("{$file}.tmp", $code) !== \strlen($code) || !\rename("{$file}.tmp", $file)) {
+ @\unlink("{$file}.tmp");
+ // @ file may not exist
+ throw new \RuntimeException(\sprintf("Unable to create '%s'.", $file));
+ }
+ if (\function_exists('opcache_invalidate')) {
+ @\opcache_invalidate($file, \true);
+ // @ can be restricted
+ }
+ }
+ /** @return resource */
+ private function acquireLock(string $file, int $mode)
+ {
+ $handle = @\fopen($file, 'w');
+ // @ is escalated to exception
+ if (!$handle) {
+ throw new \RuntimeException(\sprintf("Unable to create file '%s'. %s", $file, \error_get_last()['message']));
+ } elseif (!@\flock($handle, $mode)) {
+ // @ is escalated to exception
+ throw new \RuntimeException(\sprintf("Unable to acquire %s lock on file '%s'. %s", $mode & \LOCK_EX ? 'exclusive' : 'shared', $file, \error_get_last()['message']));
+ }
+ return $handle;
+ }
+ private function generateCacheFileName() : string
+ {
+ if (!$this->tempDirectory) {
+ throw new \LogicException('Set path to temporary directory using setTempDirectory().');
+ }
+ return $this->tempDirectory . '/' . \md5(\serialize($this->getCacheKey())) . '.php';
+ }
+ protected function getCacheKey() : array
+ {
+ return [$this->ignoreDirs, $this->acceptFiles, $this->scanPaths, $this->excludeDirs, 'v2'];
+ }
+}
diff --git a/vendor/nette/utils/composer.json b/vendor/nette/utils/composer.json
new file mode 100644
index 0000000000..c107f1f0c5
--- /dev/null
+++ b/vendor/nette/utils/composer.json
@@ -0,0 +1,72 @@
+{
+ "name": "nette\/utils",
+ "description": "\ud83d\udee0 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding\/decoding, validation, slug or strong password generating etc.",
+ "keywords": [
+ "nette",
+ "images",
+ "json",
+ "password",
+ "validation",
+ "utility",
+ "string",
+ "array",
+ "core",
+ "slugify",
+ "utf-8",
+ "unicode",
+ "paginator",
+ "datetime"
+ ],
+ "homepage": "https:\/\/nette.org",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0-only",
+ "GPL-3.0-only"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https:\/\/davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https:\/\/nette.org\/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.2 <8.4"
+ },
+ "require-dev": {
+ "nette\/tester": "~2.0",
+ "tracy\/tracy": "^2.3",
+ "phpstan\/phpstan": "^1.0",
+ "jetbrains\/phpstorm-attributes": "dev-master"
+ },
+ "conflict": {
+ "nette\/di": "<3.0.6"
+ },
+ "suggest": {
+ "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
+ "ext-json": "to use Nette\\Utils\\Json",
+ "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
+ "ext-mbstring": "to use Strings::lower() etc...",
+ "ext-xml": "to use Strings::length() etc. when mbstring is not available",
+ "ext-gd": "to use Image",
+ "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
+ },
+ "autoload": {
+ "classmap": [
+ "src\/"
+ ]
+ },
+ "minimum-stability": "dev",
+ "scripts": {
+ "phpstan": "phpstan analyse",
+ "tester": "tester tests -s"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.2-dev"
+ }
+ }
+}
\ No newline at end of file
diff --git a/vendor/nette/utils/license.md b/vendor/nette/utils/license.md
new file mode 100644
index 0000000000..cf741bd05f
--- /dev/null
+++ b/vendor/nette/utils/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
+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 "Nette Framework" nor the names of its 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 owner 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.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/utils/readme.md b/vendor/nette/utils/readme.md
new file mode 100644
index 0000000000..5317b8e654
--- /dev/null
+++ b/vendor/nette/utils/readme.md
@@ -0,0 +1,54 @@
+Nette Utility Classes
+=====================
+
+[![Downloads this Month](https://img.shields.io/packagist/dm/nette/utils.svg)](https://packagist.org/packages/nette/utils)
+[![Tests](https://github.com/nette/utils/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/utils/actions)
+[![Coverage Status](https://coveralls.io/repos/github/nette/utils/badge.svg?branch=master)](https://coveralls.io/github/nette/utils?branch=master)
+[![Latest Stable Version](https://poser.pugx.org/nette/utils/v/stable)](https://github.com/nette/utils/releases)
+[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/utils/blob/master/license.md)
+
+
+Introduction
+------------
+
+In package nette/utils you will find a set of [useful classes](https://doc.nette.org/utils) for everyday use:
+
+- [Arrays](https://doc.nette.org/utils/arrays) - manipulate arrays
+- [Callback](https://doc.nette.org/utils/callback) - PHP callbacks
+- [Date and Time](https://doc.nette.org/utils/datetime) - modify times and dates
+- [Filesystem](https://doc.nette.org/utils/filesystem) - copying, renaming, …
+- [Helper Functions](https://doc.nette.org/utils/helpers)
+- [HTML elements](https://doc.nette.org/utils/html-elements) - generate HTML
+- [Images](https://doc.nette.org/utils/images) - crop, resize, rotate images
+- [JSON](https://doc.nette.org/utils/json) - encoding and decoding
+- [Generating Random Strings](https://doc.nette.org/utils/random)
+- [Paginator](https://doc.nette.org/utils/paginator) - pagination math
+- [PHP Reflection](https://doc.nette.org/utils/reflection)
+- [Strings](https://doc.nette.org/utils/strings) - useful text functions
+- [SmartObject](https://doc.nette.org/utils/smartobject) - PHP object enhancements
+- [Validation](https://doc.nette.org/utils/validators) - validate inputs
+- [Type](https://doc.nette.org/utils/type) - PHP data type
+
+
+Installation
+------------
+
+The recommended way to install is via Composer:
+
+```
+composer require nette/utils
+```
+
+- Nette Utils 3.2 is compatible with PHP 7.2 to 8.3
+- Nette Utils 3.1 is compatible with PHP 7.1 to 8.0
+- Nette Utils 3.0 is compatible with PHP 7.1 to 8.0
+- Nette Utils 2.5 is compatible with PHP 5.6 to 8.0
+
+[Support Me](https://github.com/sponsors/dg)
+--------------------------------------------
+
+Do you like Nette Utils? Are you looking forward to the new features?
+
+[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
+
+Thank you!
diff --git a/vendor/nette/utils/src/HtmlStringable.php b/vendor/nette/utils/src/HtmlStringable.php
new file mode 100644
index 0000000000..024d015258
--- /dev/null
+++ b/vendor/nette/utils/src/HtmlStringable.php
@@ -0,0 +1,17 @@
+getIterator();
+ } while ($iterator instanceof \IteratorAggregate);
+ \assert($iterator instanceof \Iterator);
+ } elseif ($iterator instanceof \Iterator) {
+ } elseif ($iterator instanceof \Traversable) {
+ $iterator = new \IteratorIterator($iterator);
+ } else {
+ throw new Nette\InvalidArgumentException(\sprintf('Invalid argument passed to %s; array or Traversable expected, %s given.', self::class, \is_object($iterator) ? \get_class($iterator) : \gettype($iterator)));
+ }
+ parent::__construct($iterator, 0);
+ }
+ /**
+ * Is the current element the first one?
+ */
+ public function isFirst(?int $gridWidth = null) : bool
+ {
+ return $this->counter === 1 || $gridWidth && $this->counter !== 0 && ($this->counter - 1) % $gridWidth === 0;
+ }
+ /**
+ * Is the current element the last one?
+ */
+ public function isLast(?int $gridWidth = null) : bool
+ {
+ return !$this->hasNext() || $gridWidth && $this->counter % $gridWidth === 0;
+ }
+ /**
+ * Is the iterator empty?
+ */
+ public function isEmpty() : bool
+ {
+ return $this->counter === 0;
+ }
+ /**
+ * Is the counter odd?
+ */
+ public function isOdd() : bool
+ {
+ return $this->counter % 2 === 1;
+ }
+ /**
+ * Is the counter even?
+ */
+ public function isEven() : bool
+ {
+ return $this->counter % 2 === 0;
+ }
+ /**
+ * Returns the counter.
+ */
+ public function getCounter() : int
+ {
+ return $this->counter;
+ }
+ /**
+ * Returns the count of elements.
+ */
+ public function count() : int
+ {
+ $inner = $this->getInnerIterator();
+ if ($inner instanceof \Countable) {
+ return $inner->count();
+ } else {
+ throw new Nette\NotSupportedException('Iterator is not countable.');
+ }
+ }
+ /**
+ * Forwards to the next element.
+ */
+ public function next() : void
+ {
+ parent::next();
+ if (parent::valid()) {
+ $this->counter++;
+ }
+ }
+ /**
+ * Rewinds the Iterator.
+ */
+ public function rewind() : void
+ {
+ parent::rewind();
+ $this->counter = parent::valid() ? 1 : 0;
+ }
+ /**
+ * Returns the next key.
+ * @return mixed
+ */
+ public function getNextKey()
+ {
+ return $this->getInnerIterator()->key();
+ }
+ /**
+ * Returns the next element.
+ * @return mixed
+ */
+ public function getNextValue()
+ {
+ return $this->getInnerIterator()->current();
+ }
+}
diff --git a/vendor/nette/utils/src/Iterators/Mapper.php b/vendor/nette/utils/src/Iterators/Mapper.php
new file mode 100644
index 0000000000..02622001ef
--- /dev/null
+++ b/vendor/nette/utils/src/Iterators/Mapper.php
@@ -0,0 +1,27 @@
+callback = $callback;
+ }
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ return ($this->callback)(parent::current(), parent::key());
+ }
+}
diff --git a/vendor/nette/utils/src/SmartObject.php b/vendor/nette/utils/src/SmartObject.php
new file mode 100644
index 0000000000..dfeaa29ee5
--- /dev/null
+++ b/vendor/nette/utils/src/SmartObject.php
@@ -0,0 +1,120 @@
+{$name} ?? null;
+ if (\is_iterable($handlers)) {
+ foreach ($handlers as $handler) {
+ $handler(...$args);
+ }
+ } elseif ($handlers !== null) {
+ throw new UnexpectedValueException("Property {$class}::\${$name} must be iterable or null, " . \gettype($handlers) . ' given.');
+ }
+ } else {
+ ObjectHelpers::strictCall($class, $name);
+ }
+ }
+ /**
+ * @throws MemberAccessException
+ */
+ public static function __callStatic(string $name, array $args)
+ {
+ ObjectHelpers::strictStaticCall(static::class, $name);
+ }
+ /**
+ * @return mixed
+ * @throws MemberAccessException if the property is not defined.
+ */
+ public function &__get(string $name)
+ {
+ $class = static::class;
+ if ($prop = ObjectHelpers::getMagicProperties($class)[$name] ?? null) {
+ // property getter
+ if (!($prop & 0b1)) {
+ throw new MemberAccessException("Cannot read a write-only property {$class}::\${$name}.");
+ }
+ $m = ($prop & 0b10 ? 'get' : 'is') . \ucfirst($name);
+ if ($prop & 0b10000) {
+ $trace = \debug_backtrace(0, 1)[0];
+ // suppose this method is called from __call()
+ $loc = isset($trace['file'], $trace['line']) ? " in {$trace['file']} on line {$trace['line']}" : '';
+ \trigger_error("Property {$class}::\${$name} is deprecated, use {$class}::{$m}() method{$loc}.", \E_USER_DEPRECATED);
+ }
+ if ($prop & 0b100) {
+ // return by reference
+ return $this->{$m}();
+ } else {
+ $val = $this->{$m}();
+ return $val;
+ }
+ } else {
+ ObjectHelpers::strictGet($class, $name);
+ }
+ }
+ /**
+ * @param mixed $value
+ * @return void
+ * @throws MemberAccessException if the property is not defined or is read-only
+ */
+ public function __set(string $name, $value)
+ {
+ $class = static::class;
+ if (ObjectHelpers::hasProperty($class, $name)) {
+ // unsetted property
+ $this->{$name} = $value;
+ } elseif ($prop = ObjectHelpers::getMagicProperties($class)[$name] ?? null) {
+ // property setter
+ if (!($prop & 0b1000)) {
+ throw new MemberAccessException("Cannot write to a read-only property {$class}::\${$name}.");
+ }
+ $m = 'set' . \ucfirst($name);
+ if ($prop & 0b10000) {
+ $trace = \debug_backtrace(0, 1)[0];
+ // suppose this method is called from __call()
+ $loc = isset($trace['file'], $trace['line']) ? " in {$trace['file']} on line {$trace['line']}" : '';
+ \trigger_error("Property {$class}::\${$name} is deprecated, use {$class}::{$m}() method{$loc}.", \E_USER_DEPRECATED);
+ }
+ $this->{$m}($value);
+ } else {
+ ObjectHelpers::strictSet($class, $name);
+ }
+ }
+ /**
+ * @return void
+ * @throws MemberAccessException
+ */
+ public function __unset(string $name)
+ {
+ $class = static::class;
+ if (!ObjectHelpers::hasProperty($class, $name)) {
+ throw new MemberAccessException("Cannot unset the property {$class}::\${$name}.");
+ }
+ }
+ public function __isset(string $name) : bool
+ {
+ return isset(ObjectHelpers::getMagicProperties(static::class)[$name]);
+ }
+}
diff --git a/vendor/nette/utils/src/StaticClass.php b/vendor/nette/utils/src/StaticClass.php
new file mode 100644
index 0000000000..99acdc3ec1
--- /dev/null
+++ b/vendor/nette/utils/src/StaticClass.php
@@ -0,0 +1,32 @@
+
+ * @implements \ArrayAccess
+ */
+class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \IteratorAggregate
+{
+ /**
+ * Transforms array to ArrayHash.
+ * @param array $array
+ * @return static
+ */
+ public static function from(array $array, bool $recursive = \true)
+ {
+ $obj = new static();
+ foreach ($array as $key => $value) {
+ $obj->{$key} = $recursive && \is_array($value) ? static::from($value, \true) : $value;
+ }
+ return $obj;
+ }
+ /**
+ * Returns an iterator over all items.
+ * @return \RecursiveArrayIterator
+ */
+ public function getIterator() : \RecursiveArrayIterator
+ {
+ return new \RecursiveArrayIterator((array) $this);
+ }
+ /**
+ * Returns items count.
+ */
+ public function count() : int
+ {
+ return \count((array) $this);
+ }
+ /**
+ * Replaces or appends a item.
+ * @param array-key $key
+ * @param T $value
+ */
+ public function offsetSet($key, $value) : void
+ {
+ if (!\is_scalar($key)) {
+ // prevents null
+ throw new Nette\InvalidArgumentException(\sprintf('Key must be either a string or an integer, %s given.', \gettype($key)));
+ }
+ $this->{$key} = $value;
+ }
+ /**
+ * Returns a item.
+ * @param array-key $key
+ * @return T
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetGet($key)
+ {
+ return $this->{$key};
+ }
+ /**
+ * Determines whether a item exists.
+ * @param array-key $key
+ */
+ public function offsetExists($key) : bool
+ {
+ return isset($this->{$key});
+ }
+ /**
+ * Removes the element from this list.
+ * @param array-key $key
+ */
+ public function offsetUnset($key) : void
+ {
+ unset($this->{$key});
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/ArrayList.php b/vendor/nette/utils/src/Utils/ArrayList.php
new file mode 100644
index 0000000000..772ff56ec7
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/ArrayList.php
@@ -0,0 +1,111 @@
+
+ * @implements \ArrayAccess
+ */
+class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
+{
+ use Nette\SmartObject;
+ /** @var mixed[] */
+ private $list = [];
+ /**
+ * Transforms array to ArrayList.
+ * @param list $array
+ * @return static
+ */
+ public static function from(array $array)
+ {
+ if (!Arrays::isList($array)) {
+ throw new Nette\InvalidArgumentException('Array is not valid list.');
+ }
+ $obj = new static();
+ $obj->list = $array;
+ return $obj;
+ }
+ /**
+ * Returns an iterator over all items.
+ * @return \ArrayIterator
+ */
+ public function getIterator() : \ArrayIterator
+ {
+ return new \ArrayIterator($this->list);
+ }
+ /**
+ * Returns items count.
+ */
+ public function count() : int
+ {
+ return \count($this->list);
+ }
+ /**
+ * Replaces or appends a item.
+ * @param int|null $index
+ * @param T $value
+ * @throws Nette\OutOfRangeException
+ */
+ public function offsetSet($index, $value) : void
+ {
+ if ($index === null) {
+ $this->list[] = $value;
+ } elseif (!\is_int($index) || $index < 0 || $index >= \count($this->list)) {
+ throw new Nette\OutOfRangeException('Offset invalid or out of range');
+ } else {
+ $this->list[$index] = $value;
+ }
+ }
+ /**
+ * Returns a item.
+ * @param int $index
+ * @return T
+ * @throws Nette\OutOfRangeException
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetGet($index)
+ {
+ if (!\is_int($index) || $index < 0 || $index >= \count($this->list)) {
+ throw new Nette\OutOfRangeException('Offset invalid or out of range');
+ }
+ return $this->list[$index];
+ }
+ /**
+ * Determines whether a item exists.
+ * @param int $index
+ */
+ public function offsetExists($index) : bool
+ {
+ return \is_int($index) && $index >= 0 && $index < \count($this->list);
+ }
+ /**
+ * Removes the element at the specified position in this list.
+ * @param int $index
+ * @throws Nette\OutOfRangeException
+ */
+ public function offsetUnset($index) : void
+ {
+ if (!\is_int($index) || $index < 0 || $index >= \count($this->list)) {
+ throw new Nette\OutOfRangeException('Offset invalid or out of range');
+ }
+ \array_splice($this->list, $index, 1);
+ }
+ /**
+ * Prepends a item.
+ * @param T $value
+ */
+ public function prepend($value) : void
+ {
+ $first = \array_slice($this->list, 0, 1);
+ $this->offsetSet(0, $value);
+ \array_splice($this->list, 1, 0, $first);
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Arrays.php b/vendor/nette/utils/src/Utils/Arrays.php
new file mode 100644
index 0000000000..aecbe8303e
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Arrays.php
@@ -0,0 +1,394 @@
+ $array
+ * @param array-key|array-key[] $key
+ * @param ?T $default
+ * @return ?T
+ * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided
+ */
+ public static function get(array $array, $key, $default = null)
+ {
+ foreach (is_array($key) ? $key : [$key] as $k) {
+ if (is_array($array) && \array_key_exists($k, $array)) {
+ $array = $array[$k];
+ } else {
+ if (\func_num_args() < 3) {
+ throw new Nette\InvalidArgumentException("Missing item '{$k}'.");
+ }
+ return $default;
+ }
+ }
+ return $array;
+ }
+ /**
+ * Returns reference to array item. If the index does not exist, new one is created with value null.
+ * @template T
+ * @param array $array
+ * @param array-key|array-key[] $key
+ * @return ?T
+ * @throws Nette\InvalidArgumentException if traversed item is not an array
+ */
+ public static function &getRef(array &$array, $key)
+ {
+ foreach (is_array($key) ? $key : [$key] as $k) {
+ if (is_array($array) || $array === null) {
+ $array =& $array[$k];
+ } else {
+ throw new Nette\InvalidArgumentException('Traversed item is not an array.');
+ }
+ }
+ return $array;
+ }
+ /**
+ * Recursively merges two fields. It is useful, for example, for merging tree structures. It behaves as
+ * the + operator for array, ie. it adds a key/value pair from the second array to the first one and retains
+ * the value from the first array in the case of a key collision.
+ * @template T1
+ * @template T2
+ * @param array $array1
+ * @param array $array2
+ * @return array
+ */
+ public static function mergeTree(array $array1, array $array2) : array
+ {
+ $res = $array1 + $array2;
+ foreach (\array_intersect_key($array1, $array2) as $k => $v) {
+ if (is_array($v) && is_array($array2[$k])) {
+ $res[$k] = self::mergeTree($v, $array2[$k]);
+ }
+ }
+ return $res;
+ }
+ /**
+ * Returns zero-indexed position of given array key. Returns null if key is not found.
+ * @param array-key $key
+ * @return int|null offset if it is found, null otherwise
+ */
+ public static function getKeyOffset(array $array, $key) : ?int
+ {
+ return Helpers::falseToNull(\array_search(self::toKey($key), \array_keys($array), \true));
+ }
+ /**
+ * @deprecated use getKeyOffset()
+ */
+ public static function searchKey(array $array, $key) : ?int
+ {
+ return self::getKeyOffset($array, $key);
+ }
+ /**
+ * Tests an array for the presence of value.
+ * @param mixed $value
+ */
+ public static function contains(array $array, $value) : bool
+ {
+ return \in_array($value, $array, \true);
+ }
+ /**
+ * Returns the first item from the array or null if array is empty.
+ * @template T
+ * @param array $array
+ * @return ?T
+ */
+ public static function first(array $array)
+ {
+ return count($array) ? \reset($array) : null;
+ }
+ /**
+ * Returns the last item from the array or null if array is empty.
+ * @template T
+ * @param array $array
+ * @return ?T
+ */
+ public static function last(array $array)
+ {
+ return count($array) ? \end($array) : null;
+ }
+ /**
+ * Inserts the contents of the $inserted array into the $array immediately after the $key.
+ * If $key is null (or does not exist), it is inserted at the beginning.
+ * @param array-key|null $key
+ */
+ public static function insertBefore(array &$array, $key, array $inserted) : void
+ {
+ $offset = $key === null ? 0 : (int) self::getKeyOffset($array, $key);
+ $array = \array_slice($array, 0, $offset, \true) + $inserted + \array_slice($array, $offset, count($array), \true);
+ }
+ /**
+ * Inserts the contents of the $inserted array into the $array before the $key.
+ * If $key is null (or does not exist), it is inserted at the end.
+ * @param array-key|null $key
+ */
+ public static function insertAfter(array &$array, $key, array $inserted) : void
+ {
+ if ($key === null || ($offset = self::getKeyOffset($array, $key)) === null) {
+ $offset = count($array) - 1;
+ }
+ $array = \array_slice($array, 0, $offset + 1, \true) + $inserted + \array_slice($array, $offset + 1, count($array), \true);
+ }
+ /**
+ * Renames key in array.
+ * @param array-key $oldKey
+ * @param array-key $newKey
+ */
+ public static function renameKey(array &$array, $oldKey, $newKey) : bool
+ {
+ $offset = self::getKeyOffset($array, $oldKey);
+ if ($offset === null) {
+ return \false;
+ }
+ $val =& $array[$oldKey];
+ $keys = \array_keys($array);
+ $keys[$offset] = $newKey;
+ $array = \array_combine($keys, $array);
+ $array[$newKey] =& $val;
+ return \true;
+ }
+ /**
+ * Returns only those array items, which matches a regular expression $pattern.
+ * @param string[] $array
+ * @return string[]
+ */
+ public static function grep(
+ array $array,
+ /**
+ * @language
+ */
+ string $pattern,
+ int $flags = 0
+ ) : array
+ {
+ return Strings::pcre('preg_grep', [$pattern, $array, $flags]);
+ }
+ /**
+ * Transforms multidimensional array to flat array.
+ */
+ public static function flatten(array $array, bool $preserveKeys = \false) : array
+ {
+ $res = [];
+ $cb = $preserveKeys ? function ($v, $k) use(&$res) : void {
+ $res[$k] = $v;
+ } : function ($v) use(&$res) : void {
+ $res[] = $v;
+ };
+ \array_walk_recursive($array, $cb);
+ return $res;
+ }
+ /**
+ * Checks if the array is indexed in ascending order of numeric keys from zero, a.k.a list.
+ * @param mixed $value
+ */
+ public static function isList($value) : bool
+ {
+ $arrayIsListFunction = function (array $array) : bool {
+ if (\function_exists('array_is_list')) {
+ return \array_is_list($array);
+ }
+ if ($array === []) {
+ return \true;
+ }
+ $current_key = 0;
+ foreach ($array as $key => $noop) {
+ if ($key !== $current_key) {
+ return \false;
+ }
+ ++$current_key;
+ }
+ return \true;
+ };
+ return is_array($value) && (\PHP_VERSION_ID < 80100 ? !$value || \array_keys($value) === \range(0, count($value) - 1) : $arrayIsListFunction($value));
+ }
+ /**
+ * Reformats table to associative tree. Path looks like 'field|field[]field->field=field'.
+ * @param string|string[] $path
+ * @return array|\stdClass
+ */
+ public static function associate(array $array, $path)
+ {
+ $parts = is_array($path) ? $path : \preg_split('#(\\[\\]|->|=|\\|)#', $path, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
+ if (!$parts || $parts === ['->'] || $parts[0] === '=' || $parts[0] === '|') {
+ throw new Nette\InvalidArgumentException("Invalid path '{$path}'.");
+ }
+ $res = $parts[0] === '->' ? new \stdClass() : [];
+ foreach ($array as $rowOrig) {
+ $row = (array) $rowOrig;
+ $x =& $res;
+ for ($i = 0; $i < count($parts); $i++) {
+ $part = $parts[$i];
+ if ($part === '[]') {
+ $x =& $x[];
+ } elseif ($part === '=') {
+ if (isset($parts[++$i])) {
+ $x = $row[$parts[$i]];
+ $row = null;
+ }
+ } elseif ($part === '->') {
+ if (isset($parts[++$i])) {
+ if ($x === null) {
+ $x = new \stdClass();
+ }
+ $x =& $x->{$row[$parts[$i]]};
+ } else {
+ $row = is_object($rowOrig) ? $rowOrig : (object) $row;
+ }
+ } elseif ($part !== '|') {
+ $x =& $x[(string) $row[$part]];
+ }
+ }
+ if ($x === null) {
+ $x = $row;
+ }
+ }
+ return $res;
+ }
+ /**
+ * Normalizes array to associative array. Replace numeric keys with their values, the new value will be $filling.
+ * @param mixed $filling
+ */
+ public static function normalize(array $array, $filling = null) : array
+ {
+ $res = [];
+ foreach ($array as $k => $v) {
+ $res[is_int($k) ? $v : $k] = is_int($k) ? $filling : $v;
+ }
+ return $res;
+ }
+ /**
+ * Returns and removes the value of an item from an array. If it does not exist, it throws an exception,
+ * or returns $default, if provided.
+ * @template T
+ * @param array $array
+ * @param array-key $key
+ * @param ?T $default
+ * @return ?T
+ * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided
+ */
+ public static function pick(array &$array, $key, $default = null)
+ {
+ if (\array_key_exists($key, $array)) {
+ $value = $array[$key];
+ unset($array[$key]);
+ return $value;
+ } elseif (\func_num_args() < 3) {
+ throw new Nette\InvalidArgumentException("Missing item '{$key}'.");
+ } else {
+ return $default;
+ }
+ }
+ /**
+ * Tests whether at least one element in the array passes the test implemented by the
+ * provided callback with signature `function ($value, $key, array $array): bool`.
+ */
+ public static function some(iterable $array, callable $callback) : bool
+ {
+ foreach ($array as $k => $v) {
+ if ($callback($v, $k, $array)) {
+ return \true;
+ }
+ }
+ return \false;
+ }
+ /**
+ * Tests whether all elements in the array pass the test implemented by the provided function,
+ * which has the signature `function ($value, $key, array $array): bool`.
+ */
+ public static function every(iterable $array, callable $callback) : bool
+ {
+ foreach ($array as $k => $v) {
+ if (!$callback($v, $k, $array)) {
+ return \false;
+ }
+ }
+ return \true;
+ }
+ /**
+ * Calls $callback on all elements in the array and returns the array of return values.
+ * The callback has the signature `function ($value, $key, array $array): bool`.
+ */
+ public static function map(iterable $array, callable $callback) : array
+ {
+ $res = [];
+ foreach ($array as $k => $v) {
+ $res[$k] = $callback($v, $k, $array);
+ }
+ return $res;
+ }
+ /**
+ * Invokes all callbacks and returns array of results.
+ * @param callable[] $callbacks
+ */
+ public static function invoke(iterable $callbacks, ...$args) : array
+ {
+ $res = [];
+ foreach ($callbacks as $k => $cb) {
+ $res[$k] = $cb(...$args);
+ }
+ return $res;
+ }
+ /**
+ * Invokes method on every object in an array and returns array of results.
+ * @param object[] $objects
+ */
+ public static function invokeMethod(iterable $objects, string $method, ...$args) : array
+ {
+ $res = [];
+ foreach ($objects as $k => $obj) {
+ $res[$k] = $obj->{$method}(...$args);
+ }
+ return $res;
+ }
+ /**
+ * Copies the elements of the $array array to the $object object and then returns it.
+ * @template T of object
+ * @param T $object
+ * @return T
+ */
+ public static function toObject(iterable $array, $object)
+ {
+ foreach ($array as $k => $v) {
+ $object->{$k} = $v;
+ }
+ return $object;
+ }
+ /**
+ * Converts value to array key.
+ * @param mixed $value
+ * @return array-key
+ */
+ public static function toKey($value)
+ {
+ return \key([$value => null]);
+ }
+ /**
+ * Returns copy of the $array where every item is converted to string
+ * and prefixed by $prefix and suffixed by $suffix.
+ * @param string[] $array
+ * @return string[]
+ */
+ public static function wrap(array $array, string $prefix = '', string $suffix = '') : array
+ {
+ $res = [];
+ foreach ($array as $k => $v) {
+ $res[$k] = $prefix . $v . $suffix;
+ }
+ return $res;
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Callback.php b/vendor/nette/utils/src/Utils/Callback.php
new file mode 100644
index 0000000000..d42957d9dd
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Callback.php
@@ -0,0 +1,151 @@
+getMessage());
+ }
+ }
+ /**
+ * Invokes callback.
+ * @return mixed
+ * @deprecated
+ */
+ public static function invoke($callable, ...$args)
+ {
+ \trigger_error(__METHOD__ . '() is deprecated, use native invoking.', \E_USER_DEPRECATED);
+ self::check($callable);
+ return $callable(...$args);
+ }
+ /**
+ * Invokes callback with an array of parameters.
+ * @return mixed
+ * @deprecated
+ */
+ public static function invokeArgs($callable, array $args = [])
+ {
+ \trigger_error(__METHOD__ . '() is deprecated, use native invoking.', \E_USER_DEPRECATED);
+ self::check($callable);
+ return $callable(...$args);
+ }
+ /**
+ * Invokes internal PHP function with own error handler.
+ * @return mixed
+ */
+ public static function invokeSafe(string $function, array $args, callable $onError)
+ {
+ $prev = \set_error_handler(function ($severity, $message, $file) use($onError, &$prev, $function) : ?bool {
+ if ($file === __FILE__) {
+ $msg = \ini_get('html_errors') ? Html::htmlToText($message) : $message;
+ $msg = \preg_replace("#^{$function}\\(.*?\\): #", '', $msg);
+ if ($onError($msg, $severity) !== \false) {
+ return null;
+ }
+ }
+ return $prev ? $prev(...\func_get_args()) : \false;
+ });
+ try {
+ return $function(...$args);
+ } finally {
+ \restore_error_handler();
+ }
+ }
+ /**
+ * Checks that $callable is valid PHP callback. Otherwise throws exception. If the $syntax is set to true, only verifies
+ * that $callable has a valid structure to be used as a callback, but does not verify if the class or method actually exists.
+ * @param mixed $callable
+ * @return callable
+ * @throws Nette\InvalidArgumentException
+ */
+ public static function check($callable, bool $syntax = \false)
+ {
+ if (!\is_callable($callable, $syntax)) {
+ throw new Nette\InvalidArgumentException($syntax ? 'Given value is not a callable type.' : \sprintf("Callback '%s' is not callable.", self::toString($callable)));
+ }
+ return $callable;
+ }
+ /**
+ * Converts PHP callback to textual form. Class or method may not exists.
+ * @param mixed $callable
+ */
+ public static function toString($callable) : string
+ {
+ if ($callable instanceof \Closure) {
+ $inner = self::unwrap($callable);
+ return '{closure' . ($inner instanceof \Closure ? '}' : ' ' . self::toString($inner) . '}');
+ } elseif (is_string($callable) && $callable[0] === "\x00") {
+ return '{lambda}';
+ } else {
+ \is_callable(is_object($callable) ? [$callable, '__invoke'] : $callable, \true, $textual);
+ return $textual;
+ }
+ }
+ /**
+ * Returns reflection for method or function used in PHP callback.
+ * @param callable $callable type check is escalated to ReflectionException
+ * @return \ReflectionMethod|\ReflectionFunction
+ * @throws \ReflectionException if callback is not valid
+ */
+ public static function toReflection($callable) : \ReflectionFunctionAbstract
+ {
+ if ($callable instanceof \Closure) {
+ $callable = self::unwrap($callable);
+ }
+ if (is_string($callable) && \strpos($callable, '::')) {
+ return new \ReflectionMethod($callable);
+ } elseif (is_array($callable)) {
+ return new \ReflectionMethod($callable[0], $callable[1]);
+ } elseif (is_object($callable) && !$callable instanceof \Closure) {
+ return new \ReflectionMethod($callable, '__invoke');
+ } else {
+ return new \ReflectionFunction($callable);
+ }
+ }
+ /**
+ * Checks whether PHP callback is function or static method.
+ */
+ public static function isStatic(callable $callable) : bool
+ {
+ return is_string(is_array($callable) ? $callable[0] : $callable);
+ }
+ /**
+ * Unwraps closure created by Closure::fromCallable().
+ * @return callable|array
+ */
+ public static function unwrap(\Closure $closure)
+ {
+ $r = new \ReflectionFunction($closure);
+ $class = $r->getClosureScopeClass();
+ if (\substr($r->name, -1) === '}') {
+ return $closure;
+ } elseif (($obj = $r->getClosureThis()) && $class && \get_class($obj) === $class->name) {
+ return [$obj, $r->name];
+ } elseif ($class) {
+ return [$class->name, $r->name];
+ } else {
+ return $r->name;
+ }
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/DateTime.php b/vendor/nette/utils/src/Utils/DateTime.php
new file mode 100644
index 0000000000..189836b6c3
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/DateTime.php
@@ -0,0 +1,105 @@
+format('Y-m-d H:i:s.u'), $time->getTimezone());
+ } elseif (\is_numeric($time)) {
+ if ($time <= self::YEAR) {
+ $time += \time();
+ }
+ return (new static('@' . $time))->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
+ } else {
+ // textual or null
+ return new static((string) $time);
+ }
+ }
+ /**
+ * Creates DateTime object.
+ * @return static
+ * @throws Nette\InvalidArgumentException if the date and time are not valid.
+ */
+ public static function fromParts(int $year, int $month, int $day, int $hour = 0, int $minute = 0, float $second = 0.0)
+ {
+ $s = \sprintf('%04d-%02d-%02d %02d:%02d:%02.5F', $year, $month, $day, $hour, $minute, $second);
+ if (!\checkdate($month, $day, $year) || $hour < 0 || $hour > 23 || $minute < 0 || $minute > 59 || $second < 0 || $second >= 60) {
+ throw new Nette\InvalidArgumentException("Invalid date '{$s}'");
+ }
+ return new static($s);
+ }
+ /**
+ * Returns new DateTime object formatted according to the specified format.
+ * @param string $format The format the $time parameter should be in
+ * @param string $time
+ * @param string|\DateTimeZone $timezone (default timezone is used if null is passed)
+ * @return static|false
+ */
+ #[\ReturnTypeWillChange]
+ public static function createFromFormat($format, $time, $timezone = null)
+ {
+ if ($timezone === null) {
+ $timezone = new \DateTimeZone(\date_default_timezone_get());
+ } elseif (\is_string($timezone)) {
+ $timezone = new \DateTimeZone($timezone);
+ } elseif (!$timezone instanceof \DateTimeZone) {
+ throw new Nette\InvalidArgumentException('Invalid timezone given');
+ }
+ $date = parent::createFromFormat($format, $time, $timezone);
+ return $date ? static::from($date) : \false;
+ }
+ /**
+ * Returns JSON representation in ISO 8601 (used by JavaScript).
+ */
+ public function jsonSerialize() : string
+ {
+ return $this->format('c');
+ }
+ /**
+ * Returns the date and time in the format 'Y-m-d H:i:s'.
+ */
+ public function __toString() : string
+ {
+ return $this->format('Y-m-d H:i:s');
+ }
+ /**
+ * Creates a copy with a modified time.
+ * @return static
+ */
+ public function modifyClone(string $modify = '')
+ {
+ $dolly = clone $this;
+ return $modify ? $dolly->modify($modify) : $dolly;
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/FileSystem.php b/vendor/nette/utils/src/Utils/FileSystem.php
new file mode 100644
index 0000000000..cc9c14cde3
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/FileSystem.php
@@ -0,0 +1,186 @@
+getPathname());
+ }
+ foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($origin, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) {
+ if ($item->isDir()) {
+ static::createDir($target . '/' . $iterator->getSubPathName());
+ } else {
+ static::copy($item->getPathname(), $target . '/' . $iterator->getSubPathName());
+ }
+ }
+ } else {
+ static::createDir(\dirname($target));
+ if (($s = @\fopen($origin, 'rb')) && ($d = @\fopen($target, 'wb')) && @\stream_copy_to_stream($s, $d) === \false) {
+ // @ is escalated to exception
+ throw new Nette\IOException(\sprintf("Unable to copy file '%s' to '%s'. %s", self::normalizePath($origin), self::normalizePath($target), Helpers::getLastError()));
+ }
+ }
+ }
+ /**
+ * Deletes a file or an entire directory if exists. If the directory is not empty, it deletes its contents first.
+ * @throws Nette\IOException on error occurred
+ */
+ public static function delete(string $path) : void
+ {
+ if (\is_file($path) || \is_link($path)) {
+ $func = \DIRECTORY_SEPARATOR === '\\' && \is_dir($path) ? 'rmdir' : 'unlink';
+ if (!@$func($path)) {
+ // @ is escalated to exception
+ throw new Nette\IOException(\sprintf("Unable to delete '%s'. %s", self::normalizePath($path), Helpers::getLastError()));
+ }
+ } elseif (\is_dir($path)) {
+ foreach (new \FilesystemIterator($path) as $item) {
+ static::delete($item->getPathname());
+ }
+ if (!@\rmdir($path)) {
+ // @ is escalated to exception
+ throw new Nette\IOException(\sprintf("Unable to delete directory '%s'. %s", self::normalizePath($path), Helpers::getLastError()));
+ }
+ }
+ }
+ /**
+ * Renames or moves a file or a directory. Overwrites existing files and directories by default.
+ * @throws Nette\IOException on error occurred
+ * @throws Nette\InvalidStateException if $overwrite is set to false and destination already exists
+ */
+ public static function rename(string $origin, string $target, bool $overwrite = \true) : void
+ {
+ if (!$overwrite && \file_exists($target)) {
+ throw new Nette\InvalidStateException(\sprintf("File or directory '%s' already exists.", self::normalizePath($target)));
+ } elseif (!\file_exists($origin)) {
+ throw new Nette\IOException(\sprintf("File or directory '%s' not found.", self::normalizePath($origin)));
+ } else {
+ static::createDir(\dirname($target));
+ if (\realpath($origin) !== \realpath($target)) {
+ static::delete($target);
+ }
+ if (!@\rename($origin, $target)) {
+ // @ is escalated to exception
+ throw new Nette\IOException(\sprintf("Unable to rename file or directory '%s' to '%s'. %s", self::normalizePath($origin), self::normalizePath($target), Helpers::getLastError()));
+ }
+ }
+ }
+ /**
+ * Reads the content of a file.
+ * @throws Nette\IOException on error occurred
+ */
+ public static function read(string $file) : string
+ {
+ $content = @\file_get_contents($file);
+ // @ is escalated to exception
+ if ($content === \false) {
+ throw new Nette\IOException(\sprintf("Unable to read file '%s'. %s", self::normalizePath($file), Helpers::getLastError()));
+ }
+ return $content;
+ }
+ /**
+ * Writes the string to a file.
+ * @throws Nette\IOException on error occurred
+ */
+ public static function write(string $file, string $content, ?int $mode = 0666) : void
+ {
+ static::createDir(\dirname($file));
+ if (@\file_put_contents($file, $content) === \false) {
+ // @ is escalated to exception
+ throw new Nette\IOException(\sprintf("Unable to write file '%s'. %s", self::normalizePath($file), Helpers::getLastError()));
+ }
+ if ($mode !== null && !@\chmod($file, $mode)) {
+ // @ is escalated to exception
+ throw new Nette\IOException(\sprintf("Unable to chmod file '%s' to mode %s. %s", self::normalizePath($file), \decoct($mode), Helpers::getLastError()));
+ }
+ }
+ /**
+ * Sets file permissions to `$fileMode` or directory permissions to `$dirMode`.
+ * Recursively traverses and sets permissions on the entire contents of the directory as well.
+ * @throws Nette\IOException on error occurred
+ */
+ public static function makeWritable(string $path, int $dirMode = 0777, int $fileMode = 0666) : void
+ {
+ if (\is_file($path)) {
+ if (!@\chmod($path, $fileMode)) {
+ // @ is escalated to exception
+ throw new Nette\IOException(\sprintf("Unable to chmod file '%s' to mode %s. %s", self::normalizePath($path), \decoct($fileMode), Helpers::getLastError()));
+ }
+ } elseif (\is_dir($path)) {
+ foreach (new \FilesystemIterator($path) as $item) {
+ static::makeWritable($item->getPathname(), $dirMode, $fileMode);
+ }
+ if (!@\chmod($path, $dirMode)) {
+ // @ is escalated to exception
+ throw new Nette\IOException(\sprintf("Unable to chmod directory '%s' to mode %s. %s", self::normalizePath($path), \decoct($dirMode), Helpers::getLastError()));
+ }
+ } else {
+ throw new Nette\IOException(\sprintf("File or directory '%s' not found.", self::normalizePath($path)));
+ }
+ }
+ /**
+ * Determines if the path is absolute.
+ */
+ public static function isAbsolute(string $path) : bool
+ {
+ return (bool) \preg_match('#([a-z]:)?[/\\\\]|[a-z][a-z0-9+.-]*://#Ai', $path);
+ }
+ /**
+ * Normalizes `..` and `.` and directory separators in path.
+ */
+ public static function normalizePath(string $path) : string
+ {
+ $parts = $path === '' ? [] : \preg_split('~[/\\\\]+~', $path);
+ $res = [];
+ foreach ($parts as $part) {
+ if ($part === '..' && $res && \end($res) !== '..' && \end($res) !== '') {
+ \array_pop($res);
+ } elseif ($part !== '.') {
+ $res[] = $part;
+ }
+ }
+ return $res === [''] ? \DIRECTORY_SEPARATOR : \implode(\DIRECTORY_SEPARATOR, $res);
+ }
+ /**
+ * Joins all segments of the path and normalizes the result.
+ */
+ public static function joinPaths(string ...$paths) : string
+ {
+ return self::normalizePath(\implode('/', $paths));
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Floats.php b/vendor/nette/utils/src/Utils/Floats.php
new file mode 100644
index 0000000000..2405cb40b0
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Floats.php
@@ -0,0 +1,83 @@
+ $b it returns 1
+ * @throws \LogicException if one of parameters is NAN
+ */
+ public static function compare(float $a, float $b) : int
+ {
+ if (\is_nan($a) || \is_nan($b)) {
+ throw new \LogicException('Trying to compare NAN');
+ } elseif (!\is_finite($a) && !\is_finite($b) && $a === $b) {
+ return 0;
+ }
+ $diff = \abs($a - $b);
+ if ($diff < self::Epsilon || $diff / \max(\abs($a), \abs($b)) < self::Epsilon) {
+ return 0;
+ }
+ return $a < $b ? -1 : 1;
+ }
+ /**
+ * Returns true if $a = $b
+ * @throws \LogicException if one of parameters is NAN
+ */
+ public static function areEqual(float $a, float $b) : bool
+ {
+ return self::compare($a, $b) === 0;
+ }
+ /**
+ * Returns true if $a < $b
+ * @throws \LogicException if one of parameters is NAN
+ */
+ public static function isLessThan(float $a, float $b) : bool
+ {
+ return self::compare($a, $b) < 0;
+ }
+ /**
+ * Returns true if $a <= $b
+ * @throws \LogicException if one of parameters is NAN
+ */
+ public static function isLessThanOrEqualTo(float $a, float $b) : bool
+ {
+ return self::compare($a, $b) <= 0;
+ }
+ /**
+ * Returns true if $a > $b
+ * @throws \LogicException if one of parameters is NAN
+ */
+ public static function isGreaterThan(float $a, float $b) : bool
+ {
+ return self::compare($a, $b) > 0;
+ }
+ /**
+ * Returns true if $a >= $b
+ * @throws \LogicException if one of parameters is NAN
+ */
+ public static function isGreaterThanOrEqualTo(float $a, float $b) : bool
+ {
+ return self::compare($a, $b) >= 0;
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Helpers.php b/vendor/nette/utils/src/Utils/Helpers.php
new file mode 100644
index 0000000000..92dd5a700f
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Helpers.php
@@ -0,0 +1,78 @@
+ $max) {
+ throw new Nette\InvalidArgumentException("Minimum ({$min}) is not less than maximum ({$max}).");
+ }
+ return \min(\max($value, $min), $max);
+ }
+ /**
+ * Looks for a string from possibilities that is most similar to value, but not the same (for 8-bit encoding).
+ * @param string[] $possibilities
+ */
+ public static function getSuggestion(array $possibilities, string $value) : ?string
+ {
+ $best = null;
+ $min = (\strlen($value) / 4 + 1) * 10 + 0.1;
+ foreach (\array_unique($possibilities) as $item) {
+ if ($item !== $value && ($len = \levenshtein($item, $value, 10, 11, 10)) < $min) {
+ $min = $len;
+ $best = $item;
+ }
+ }
+ return $best;
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Html.php b/vendor/nette/utils/src/Utils/Html.php
new file mode 100644
index 0000000000..93abd9a420
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Html.php
@@ -0,0 +1,744 @@
+ element's attributes */
+ public $attrs = [];
+ /** @var bool use XHTML syntax? */
+ public static $xhtml = \false;
+ /** @var array void elements */
+ public static $emptyElements = ['img' => 1, 'hr' => 1, 'br' => 1, 'input' => 1, 'meta' => 1, 'area' => 1, 'embed' => 1, 'keygen' => 1, 'source' => 1, 'base' => 1, 'col' => 1, 'link' => 1, 'param' => 1, 'basefont' => 1, 'frame' => 1, 'isindex' => 1, 'wbr' => 1, 'command' => 1, 'track' => 1];
+ /** @var array nodes */
+ protected $children = [];
+ /** @var string element's name */
+ private $name;
+ /** @var bool is element empty? */
+ private $isEmpty;
+ /**
+ * Constructs new HTML element.
+ * @param array|string $attrs element's attributes or plain text content
+ * @return static
+ */
+ public static function el(?string $name = null, $attrs = null)
+ {
+ $el = new static();
+ $parts = \explode(' ', (string) $name, 2);
+ $el->setName($parts[0]);
+ if (is_array($attrs)) {
+ $el->attrs = $attrs;
+ } elseif ($attrs !== null) {
+ $el->setText($attrs);
+ }
+ if (isset($parts[1])) {
+ foreach (Strings::matchAll($parts[1] . ' ', '#([a-z0-9:-]+)(?:=(["\'])?(.*?)(?(2)\\2|\\s))?#i') as $m) {
+ $el->attrs[$m[1]] = $m[3] ?? \true;
+ }
+ }
+ return $el;
+ }
+ /**
+ * Returns an object representing HTML text.
+ */
+ public static function fromHtml(string $html) : self
+ {
+ return (new static())->setHtml($html);
+ }
+ /**
+ * Returns an object representing plain text.
+ */
+ public static function fromText(string $text) : self
+ {
+ return (new static())->setText($text);
+ }
+ /**
+ * Converts to HTML.
+ */
+ public final function toHtml() : string
+ {
+ return $this->render();
+ }
+ /**
+ * Converts to plain text.
+ */
+ public final function toText() : string
+ {
+ return $this->getText();
+ }
+ /**
+ * Converts given HTML code to plain text.
+ */
+ public static function htmlToText(string $html) : string
+ {
+ return \html_entity_decode(\strip_tags($html), \ENT_QUOTES | \ENT_HTML5, 'UTF-8');
+ }
+ /**
+ * Changes element's name.
+ * @return static
+ */
+ public final function setName(string $name, ?bool $isEmpty = null)
+ {
+ $this->name = $name;
+ $this->isEmpty = $isEmpty ?? isset(static::$emptyElements[$name]);
+ return $this;
+ }
+ /**
+ * Returns element's name.
+ */
+ public final function getName() : string
+ {
+ return $this->name;
+ }
+ /**
+ * Is element empty?
+ */
+ public final function isEmpty() : bool
+ {
+ return $this->isEmpty;
+ }
+ /**
+ * Sets multiple attributes.
+ * @return static
+ */
+ public function addAttributes(array $attrs)
+ {
+ $this->attrs = \array_merge($this->attrs, $attrs);
+ return $this;
+ }
+ /**
+ * Appends value to element's attribute.
+ * @param mixed $value
+ * @param mixed $option
+ * @return static
+ */
+ public function appendAttribute(string $name, $value, $option = \true)
+ {
+ if (is_array($value)) {
+ $prev = isset($this->attrs[$name]) ? (array) $this->attrs[$name] : [];
+ $this->attrs[$name] = $value + $prev;
+ } elseif ((string) $value === '') {
+ $tmp =& $this->attrs[$name];
+ // appending empty value? -> ignore, but ensure it exists
+ } elseif (!isset($this->attrs[$name]) || is_array($this->attrs[$name])) {
+ // needs array
+ $this->attrs[$name][$value] = $option;
+ } else {
+ $this->attrs[$name] = [$this->attrs[$name] => \true, $value => $option];
+ }
+ return $this;
+ }
+ /**
+ * Sets element's attribute.
+ * @param mixed $value
+ * @return static
+ */
+ public function setAttribute(string $name, $value)
+ {
+ $this->attrs[$name] = $value;
+ return $this;
+ }
+ /**
+ * Returns element's attribute.
+ * @return mixed
+ */
+ public function getAttribute(string $name)
+ {
+ return $this->attrs[$name] ?? null;
+ }
+ /**
+ * Unsets element's attribute.
+ * @return static
+ */
+ public function removeAttribute(string $name)
+ {
+ unset($this->attrs[$name]);
+ return $this;
+ }
+ /**
+ * Unsets element's attributes.
+ * @return static
+ */
+ public function removeAttributes(array $attributes)
+ {
+ foreach ($attributes as $name) {
+ unset($this->attrs[$name]);
+ }
+ return $this;
+ }
+ /**
+ * Overloaded setter for element's attribute.
+ * @param mixed $value
+ */
+ public final function __set(string $name, $value) : void
+ {
+ $this->attrs[$name] = $value;
+ }
+ /**
+ * Overloaded getter for element's attribute.
+ * @return mixed
+ */
+ public final function &__get(string $name)
+ {
+ return $this->attrs[$name];
+ }
+ /**
+ * Overloaded tester for element's attribute.
+ */
+ public final function __isset(string $name) : bool
+ {
+ return isset($this->attrs[$name]);
+ }
+ /**
+ * Overloaded unsetter for element's attribute.
+ */
+ public final function __unset(string $name) : void
+ {
+ unset($this->attrs[$name]);
+ }
+ /**
+ * Overloaded setter for element's attribute.
+ * @return mixed
+ */
+ public final function __call(string $m, array $args)
+ {
+ $p = \substr($m, 0, 3);
+ if ($p === 'get' || $p === 'set' || $p === 'add') {
+ $m = \substr($m, 3);
+ $m[0] = $m[0] | " ";
+ if ($p === 'get') {
+ return $this->attrs[$m] ?? null;
+ } elseif ($p === 'add') {
+ $args[] = \true;
+ }
+ }
+ if (\count($args) === 0) {
+ // invalid
+ } elseif (\count($args) === 1) {
+ // set
+ $this->attrs[$m] = $args[0];
+ } else {
+ // add
+ $this->appendAttribute($m, $args[0], $args[1]);
+ }
+ return $this;
+ }
+ /**
+ * Special setter for element's attribute.
+ * @return static
+ */
+ public final function href(string $path, ?array $query = null)
+ {
+ if ($query) {
+ $query = \http_build_query($query, '', '&');
+ if ($query !== '') {
+ $path .= '?' . $query;
+ }
+ }
+ $this->attrs['href'] = $path;
+ return $this;
+ }
+ /**
+ * Setter for data-* attributes. Booleans are converted to 'true' resp. 'false'.
+ * @param mixed $value
+ * @return static
+ */
+ public function data(string $name, $value = null)
+ {
+ if (\func_num_args() === 1) {
+ $this->attrs['data'] = $name;
+ } else {
+ $this->attrs["data-{$name}"] = \is_bool($value) ? \json_encode($value) : $value;
+ }
+ return $this;
+ }
+ /**
+ * Sets element's HTML content.
+ * @param HtmlStringable|string $html
+ * @return static
+ */
+ public final function setHtml($html)
+ {
+ $this->children = [(string) $html];
+ return $this;
+ }
+ /**
+ * Returns element's HTML content.
+ */
+ public final function getHtml() : string
+ {
+ return \implode('', $this->children);
+ }
+ /**
+ * Sets element's textual content.
+ * @param HtmlStringable|string|int|float $text
+ * @return static
+ */
+ public final function setText($text)
+ {
+ if (!$text instanceof HtmlStringable) {
+ $text = \htmlspecialchars((string) $text, \ENT_NOQUOTES, 'UTF-8');
+ }
+ $this->children = [(string) $text];
+ return $this;
+ }
+ /**
+ * Returns element's textual content.
+ */
+ public final function getText() : string
+ {
+ return self::htmlToText($this->getHtml());
+ }
+ /**
+ * Adds new element's child.
+ * @param HtmlStringable|string $child Html node or raw HTML string
+ * @return static
+ */
+ public final function addHtml($child)
+ {
+ return $this->insert(null, $child);
+ }
+ /**
+ * Appends plain-text string to element content.
+ * @param HtmlStringable|string|int|float $text
+ * @return static
+ */
+ public function addText($text)
+ {
+ if (!$text instanceof HtmlStringable) {
+ $text = \htmlspecialchars((string) $text, \ENT_NOQUOTES, 'UTF-8');
+ }
+ return $this->insert(null, $text);
+ }
+ /**
+ * Creates and adds a new Html child.
+ * @param array|string $attrs element's attributes or raw HTML string
+ * @return static created element
+ */
+ public final function create(string $name, $attrs = null)
+ {
+ $this->insert(null, $child = static::el($name, $attrs));
+ return $child;
+ }
+ /**
+ * Inserts child node.
+ * @param HtmlStringable|string $child Html node or raw HTML string
+ * @return static
+ */
+ public function insert(?int $index, $child, bool $replace = \false)
+ {
+ $child = $child instanceof self ? $child : (string) $child;
+ if ($index === null) {
+ // append
+ $this->children[] = $child;
+ } else {
+ // insert or replace
+ \array_splice($this->children, $index, $replace ? 1 : 0, [$child]);
+ }
+ return $this;
+ }
+ /**
+ * Inserts (replaces) child node (\ArrayAccess implementation).
+ * @param int|null $index position or null for appending
+ * @param Html|string $child Html node or raw HTML string
+ */
+ public final function offsetSet($index, $child) : void
+ {
+ $this->insert($index, $child, \true);
+ }
+ /**
+ * Returns child node (\ArrayAccess implementation).
+ * @param int $index
+ * @return HtmlStringable|string
+ */
+ #[\ReturnTypeWillChange]
+ public final function offsetGet($index)
+ {
+ return $this->children[$index];
+ }
+ /**
+ * Exists child node? (\ArrayAccess implementation).
+ * @param int $index
+ */
+ public final function offsetExists($index) : bool
+ {
+ return isset($this->children[$index]);
+ }
+ /**
+ * Removes child node (\ArrayAccess implementation).
+ * @param int $index
+ */
+ public function offsetUnset($index) : void
+ {
+ if (isset($this->children[$index])) {
+ \array_splice($this->children, $index, 1);
+ }
+ }
+ /**
+ * Returns children count.
+ */
+ public final function count() : int
+ {
+ return \count($this->children);
+ }
+ /**
+ * Removes all children.
+ */
+ public function removeChildren() : void
+ {
+ $this->children = [];
+ }
+ /**
+ * Iterates over elements.
+ * @return \ArrayIterator
+ */
+ public final function getIterator() : \ArrayIterator
+ {
+ return new \ArrayIterator($this->children);
+ }
+ /**
+ * Returns all children.
+ */
+ public final function getChildren() : array
+ {
+ return $this->children;
+ }
+ /**
+ * Renders element's start tag, content and end tag.
+ */
+ public final function render(?int $indent = null) : string
+ {
+ $s = $this->startTag();
+ if (!$this->isEmpty) {
+ // add content
+ if ($indent !== null) {
+ $indent++;
+ }
+ foreach ($this->children as $child) {
+ if ($child instanceof self) {
+ $s .= $child->render($indent);
+ } else {
+ $s .= $child;
+ }
+ }
+ // add end tag
+ $s .= $this->endTag();
+ }
+ if ($indent !== null) {
+ return "\n" . \str_repeat("\t", $indent - 1) . $s . "\n" . \str_repeat("\t", \max(0, $indent - 2));
+ }
+ return $s;
+ }
+ public final function __toString() : string
+ {
+ try {
+ return $this->render();
+ } catch (\Throwable $e) {
+ if (\PHP_VERSION_ID >= 70400) {
+ throw $e;
+ }
+ \trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", \E_USER_ERROR);
+ return '';
+ }
+ }
+ /**
+ * Returns element's start tag.
+ */
+ public final function startTag() : string
+ {
+ return $this->name ? '<' . $this->name . $this->attributes() . (static::$xhtml && $this->isEmpty ? ' />' : '>') : '';
+ }
+ /**
+ * Returns element's end tag.
+ */
+ public final function endTag() : string
+ {
+ return $this->name && !$this->isEmpty ? '' . $this->name . '>' : '';
+ }
+ /**
+ * Returns element's attributes.
+ * @internal
+ */
+ public final function attributes() : string
+ {
+ if (!is_array($this->attrs)) {
+ return '';
+ }
+ $s = '';
+ $attrs = $this->attrs;
+ foreach ($attrs as $key => $value) {
+ if ($value === null || $value === \false) {
+ continue;
+ } elseif ($value === \true) {
+ if (static::$xhtml) {
+ $s .= ' ' . $key . '="' . $key . '"';
+ } else {
+ $s .= ' ' . $key;
+ }
+ continue;
+ } elseif (is_array($value)) {
+ if (\strncmp($key, 'data-', 5) === 0) {
+ $value = Json::encode($value);
+ } else {
+ $tmp = null;
+ foreach ($value as $k => $v) {
+ if ($v != null) {
+ // intentionally ==, skip nulls & empty string
+ // composite 'style' vs. 'others'
+ $tmp[] = $v === \true ? $k : (is_string($k) ? $k . ':' . $v : $v);
+ }
+ }
+ if ($tmp === null) {
+ continue;
+ }
+ $value = \implode($key === 'style' || !\strncmp($key, 'on', 2) ? ';' : ' ', $tmp);
+ }
+ } elseif (is_float($value)) {
+ $value = \rtrim(\rtrim(\number_format($value, 10, '.', ''), '0'), '.');
+ } else {
+ $value = (string) $value;
+ }
+ $q = \strpos($value, '"') === \false ? '"' : "'";
+ $s .= ' ' . $key . '=' . $q . \str_replace(['&', $q, '<'], ['&', $q === '"' ? '"' : ''', self::$xhtml ? '<' : '<'], $value) . (\strpos($value, '`') !== \false && \strpbrk($value, ' <>"\'') === \false ? ' ' : '') . $q;
+ }
+ $s = \str_replace('@', '@', $s);
+ return $s;
+ }
+ /**
+ * Clones all children too.
+ */
+ public function __clone()
+ {
+ foreach ($this->children as $key => $value) {
+ if (is_object($value)) {
+ $this->children[$key] = clone $value;
+ }
+ }
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Image.php b/vendor/nette/utils/src/Utils/Image.php
new file mode 100644
index 0000000000..542e728833
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Image.php
@@ -0,0 +1,611 @@
+
+ * $image = Image::fromFile('nette.jpg');
+ * $image->resize(150, 100);
+ * $image->sharpen();
+ * $image->send();
+ *
+ *
+ * @method Image affine(array $affine, array $clip = null)
+ * @method array affineMatrixConcat(array $m1, array $m2)
+ * @method array affineMatrixGet(int $type, mixed $options = null)
+ * @method void alphaBlending(bool $on)
+ * @method void antialias(bool $on)
+ * @method void arc($x, $y, $w, $h, $start, $end, $color)
+ * @method void char(int $font, $x, $y, string $char, $color)
+ * @method void charUp(int $font, $x, $y, string $char, $color)
+ * @method int colorAllocate($red, $green, $blue)
+ * @method int colorAllocateAlpha($red, $green, $blue, $alpha)
+ * @method int colorAt($x, $y)
+ * @method int colorClosest($red, $green, $blue)
+ * @method int colorClosestAlpha($red, $green, $blue, $alpha)
+ * @method int colorClosestHWB($red, $green, $blue)
+ * @method void colorDeallocate($color)
+ * @method int colorExact($red, $green, $blue)
+ * @method int colorExactAlpha($red, $green, $blue, $alpha)
+ * @method void colorMatch(Image $image2)
+ * @method int colorResolve($red, $green, $blue)
+ * @method int colorResolveAlpha($red, $green, $blue, $alpha)
+ * @method void colorSet($index, $red, $green, $blue)
+ * @method array colorsForIndex($index)
+ * @method int colorsTotal()
+ * @method int colorTransparent($color = null)
+ * @method void convolution(array $matrix, float $div, float $offset)
+ * @method void copy(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH)
+ * @method void copyMerge(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity)
+ * @method void copyMergeGray(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity)
+ * @method void copyResampled(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
+ * @method void copyResized(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
+ * @method Image cropAuto(int $mode = -1, float $threshold = .5, int $color = -1)
+ * @method void ellipse($cx, $cy, $w, $h, $color)
+ * @method void fill($x, $y, $color)
+ * @method void filledArc($cx, $cy, $w, $h, $s, $e, $color, $style)
+ * @method void filledEllipse($cx, $cy, $w, $h, $color)
+ * @method void filledPolygon(array $points, $numPoints, $color)
+ * @method void filledRectangle($x1, $y1, $x2, $y2, $color)
+ * @method void fillToBorder($x, $y, $border, $color)
+ * @method void filter($filtertype)
+ * @method void flip(int $mode)
+ * @method array ftText($size, $angle, $x, $y, $col, string $fontFile, string $text, array $extrainfo = null)
+ * @method void gammaCorrect(float $inputgamma, float $outputgamma)
+ * @method array getClip()
+ * @method int interlace($interlace = null)
+ * @method bool isTrueColor()
+ * @method void layerEffect($effect)
+ * @method void line($x1, $y1, $x2, $y2, $color)
+ * @method void openPolygon(array $points, int $num_points, int $color)
+ * @method void paletteCopy(Image $source)
+ * @method void paletteToTrueColor()
+ * @method void polygon(array $points, $numPoints, $color)
+ * @method array psText(string $text, $font, $size, $color, $backgroundColor, $x, $y, $space = null, $tightness = null, float $angle = null, $antialiasSteps = null)
+ * @method void rectangle($x1, $y1, $x2, $y2, $col)
+ * @method mixed resolution(int $res_x = null, int $res_y = null)
+ * @method Image rotate(float $angle, $backgroundColor)
+ * @method void saveAlpha(bool $saveflag)
+ * @method Image scale(int $newWidth, int $newHeight = -1, int $mode = IMG_BILINEAR_FIXED)
+ * @method void setBrush(Image $brush)
+ * @method void setClip(int $x1, int $y1, int $x2, int $y2)
+ * @method void setInterpolation(int $method = IMG_BILINEAR_FIXED)
+ * @method void setPixel($x, $y, $color)
+ * @method void setStyle(array $style)
+ * @method void setThickness($thickness)
+ * @method void setTile(Image $tile)
+ * @method void string($font, $x, $y, string $s, $col)
+ * @method void stringUp($font, $x, $y, string $s, $col)
+ * @method void trueColorToPalette(bool $dither, $ncolors)
+ * @method array ttfText($size, $angle, $x, $y, $color, string $fontfile, string $text)
+ * @property-read positive-int $width
+ * @property-read positive-int $height
+ * @property-read resource|\GdImage $imageResource
+ */
+class Image
+{
+ use Nette\SmartObject;
+ /** Prevent from getting resized to a bigger size than the original */
+ public const SHRINK_ONLY = 0b1;
+ /** Resizes to a specified width and height without keeping aspect ratio */
+ public const STRETCH = 0b10;
+ /** Resizes to fit into a specified width and height and preserves aspect ratio */
+ public const FIT = 0b0;
+ /** Resizes while bounding the smaller dimension to the specified width or height and preserves aspect ratio */
+ public const FILL = 0b100;
+ /** Resizes to the smallest possible size to completely cover specified width and height and reserves aspect ratio */
+ public const EXACT = 0b1000;
+ /** image types */
+ public const JPEG = \IMAGETYPE_JPEG, PNG = \IMAGETYPE_PNG, GIF = \IMAGETYPE_GIF, WEBP = \IMAGETYPE_WEBP, AVIF = 19, BMP = \IMAGETYPE_BMP;
+ public const EMPTY_GIF = "GIF89a\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;";
+ private const Formats = [self::JPEG => 'jpeg', self::PNG => 'png', self::GIF => 'gif', self::WEBP => 'webp', self::AVIF => 'avif', self::BMP => 'bmp'];
+ /** @var resource|\GdImage */
+ private $image;
+ /**
+ * Returns RGB color (0..255) and transparency (0..127).
+ */
+ public static function rgb(int $red, int $green, int $blue, int $transparency = 0) : array
+ {
+ return ['red' => \max(0, \min(255, $red)), 'green' => \max(0, \min(255, $green)), 'blue' => \max(0, \min(255, $blue)), 'alpha' => \max(0, \min(127, $transparency))];
+ }
+ /**
+ * Reads an image from a file and returns its type in $type.
+ * @throws Nette\NotSupportedException if gd extension is not loaded
+ * @throws UnknownImageFileException if file not found or file type is not known
+ * @return static
+ */
+ public static function fromFile(string $file, ?int &$type = null)
+ {
+ if (!\extension_loaded('gd')) {
+ throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
+ }
+ $type = self::detectTypeFromFile($file);
+ if (!$type) {
+ throw new UnknownImageFileException(\is_file($file) ? "Unknown type of file '{$file}'." : "File '{$file}' not found.");
+ }
+ return self::invokeSafe('imagecreatefrom' . self::Formats[$type], $file, "Unable to open file '{$file}'.", __METHOD__);
+ }
+ /**
+ * Reads an image from a string and returns its type in $type.
+ * @return static
+ * @throws Nette\NotSupportedException if gd extension is not loaded
+ * @throws ImageException
+ */
+ public static function fromString(string $s, ?int &$type = null)
+ {
+ if (!\extension_loaded('gd')) {
+ throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
+ }
+ $type = self::detectTypeFromString($s);
+ if (!$type) {
+ throw new UnknownImageFileException('Unknown type of image.');
+ }
+ return self::invokeSafe('imagecreatefromstring', $s, 'Unable to open image from string.', __METHOD__);
+ }
+ private static function invokeSafe(string $func, string $arg, string $message, string $callee) : self
+ {
+ $errors = [];
+ $res = Callback::invokeSafe($func, [$arg], function (string $message) use(&$errors) : void {
+ $errors[] = $message;
+ });
+ if (!$res) {
+ throw new ImageException($message . ' Errors: ' . \implode(', ', $errors));
+ } elseif ($errors) {
+ \trigger_error($callee . '(): ' . \implode(', ', $errors), \E_USER_WARNING);
+ }
+ return new static($res);
+ }
+ /**
+ * Creates a new true color image of the given dimensions. The default color is black.
+ * @param positive-int $width
+ * @param positive-int $height
+ * @return static
+ * @throws Nette\NotSupportedException if gd extension is not loaded
+ */
+ public static function fromBlank(int $width, int $height, ?array $color = null)
+ {
+ if (!\extension_loaded('gd')) {
+ throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
+ }
+ if ($width < 1 || $height < 1) {
+ throw new Nette\InvalidArgumentException('Image width and height must be greater than zero.');
+ }
+ $image = \imagecreatetruecolor($width, $height);
+ if ($color) {
+ $color += ['alpha' => 0];
+ $color = \imagecolorresolvealpha($image, $color['red'], $color['green'], $color['blue'], $color['alpha']);
+ \imagealphablending($image, \false);
+ \imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $color);
+ \imagealphablending($image, \true);
+ }
+ return new static($image);
+ }
+ /**
+ * Returns the type of image from file.
+ */
+ public static function detectTypeFromFile(string $file, &$width = null, &$height = null) : ?int
+ {
+ [$width, $height, $type] = @\getimagesize($file);
+ // @ - files smaller than 12 bytes causes read error
+ return isset(self::Formats[$type]) ? $type : null;
+ }
+ /**
+ * Returns the type of image from string.
+ */
+ public static function detectTypeFromString(string $s, &$width = null, &$height = null) : ?int
+ {
+ [$width, $height, $type] = @\getimagesizefromstring($s);
+ // @ - strings smaller than 12 bytes causes read error
+ return isset(self::Formats[$type]) ? $type : null;
+ }
+ /**
+ * Returns the file extension for the given `Image::XXX` constant.
+ */
+ public static function typeToExtension(int $type) : string
+ {
+ if (!isset(self::Formats[$type])) {
+ throw new Nette\InvalidArgumentException("Unsupported image type '{$type}'.");
+ }
+ return self::Formats[$type];
+ }
+ /**
+ * Returns the `Image::XXX` constant for given file extension.
+ */
+ public static function extensionToType(string $extension) : int
+ {
+ $extensions = \array_flip(self::Formats) + ['jpg' => self::JPEG];
+ $extension = \strtolower($extension);
+ if (!isset($extensions[$extension])) {
+ throw new Nette\InvalidArgumentException("Unsupported file extension '{$extension}'.");
+ }
+ return $extensions[$extension];
+ }
+ /**
+ * Returns the mime type for the given `Image::XXX` constant.
+ */
+ public static function typeToMimeType(int $type) : string
+ {
+ return 'image/' . self::typeToExtension($type);
+ }
+ /**
+ * Wraps GD image.
+ * @param resource|\GdImage $image
+ */
+ public function __construct($image)
+ {
+ $this->setImageResource($image);
+ \imagesavealpha($image, \true);
+ }
+ /**
+ * Returns image width.
+ * @return positive-int
+ */
+ public function getWidth() : int
+ {
+ return \imagesx($this->image);
+ }
+ /**
+ * Returns image height.
+ * @return positive-int
+ */
+ public function getHeight() : int
+ {
+ return \imagesy($this->image);
+ }
+ /**
+ * Sets image resource.
+ * @param resource|\GdImage $image
+ * @return static
+ */
+ protected function setImageResource($image)
+ {
+ if (!$image instanceof \GdImage && !(\is_resource($image) && \get_resource_type($image) === 'gd')) {
+ throw new Nette\InvalidArgumentException('Image is not valid.');
+ }
+ $this->image = $image;
+ return $this;
+ }
+ /**
+ * Returns image GD resource.
+ * @return resource|\GdImage
+ */
+ public function getImageResource()
+ {
+ return $this->image;
+ }
+ /**
+ * Scales an image.
+ * @param int|string|null $width in pixels or percent
+ * @param int|string|null $height in pixels or percent
+ * @return static
+ */
+ public function resize($width, $height, int $flags = self::FIT)
+ {
+ if ($flags & self::EXACT) {
+ return $this->resize($width, $height, self::FILL)->crop('50%', '50%', $width, $height);
+ }
+ [$newWidth, $newHeight] = static::calculateSize($this->getWidth(), $this->getHeight(), $width, $height, $flags);
+ if ($newWidth !== $this->getWidth() || $newHeight !== $this->getHeight()) {
+ // resize
+ $newImage = static::fromBlank($newWidth, $newHeight, self::rgb(0, 0, 0, 127))->getImageResource();
+ \imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $newWidth, $newHeight, $this->getWidth(), $this->getHeight());
+ $this->image = $newImage;
+ }
+ if ($width < 0 || $height < 0) {
+ \imageflip($this->image, $width < 0 ? $height < 0 ? \IMG_FLIP_BOTH : \IMG_FLIP_HORIZONTAL : \IMG_FLIP_VERTICAL);
+ }
+ return $this;
+ }
+ /**
+ * Calculates dimensions of resized image.
+ * @param int|string|null $newWidth in pixels or percent
+ * @param int|string|null $newHeight in pixels or percent
+ */
+ public static function calculateSize(int $srcWidth, int $srcHeight, $newWidth, $newHeight, int $flags = self::FIT) : array
+ {
+ if ($newWidth === null) {
+ } elseif (self::isPercent($newWidth)) {
+ $newWidth = (int) \round($srcWidth / 100 * \abs($newWidth));
+ $percents = \true;
+ } else {
+ $newWidth = \abs($newWidth);
+ }
+ if ($newHeight === null) {
+ } elseif (self::isPercent($newHeight)) {
+ $newHeight = (int) \round($srcHeight / 100 * \abs($newHeight));
+ $flags |= empty($percents) ? 0 : self::STRETCH;
+ } else {
+ $newHeight = \abs($newHeight);
+ }
+ if ($flags & self::STRETCH) {
+ // non-proportional
+ if (!$newWidth || !$newHeight) {
+ throw new Nette\InvalidArgumentException('For stretching must be both width and height specified.');
+ }
+ if ($flags & self::SHRINK_ONLY) {
+ $newWidth = (int) \round($srcWidth * \min(1, $newWidth / $srcWidth));
+ $newHeight = (int) \round($srcHeight * \min(1, $newHeight / $srcHeight));
+ }
+ } else {
+ // proportional
+ if (!$newWidth && !$newHeight) {
+ throw new Nette\InvalidArgumentException('At least width or height must be specified.');
+ }
+ $scale = [];
+ if ($newWidth > 0) {
+ // fit width
+ $scale[] = $newWidth / $srcWidth;
+ }
+ if ($newHeight > 0) {
+ // fit height
+ $scale[] = $newHeight / $srcHeight;
+ }
+ if ($flags & self::FILL) {
+ $scale = [\max($scale)];
+ }
+ if ($flags & self::SHRINK_ONLY) {
+ $scale[] = 1;
+ }
+ $scale = \min($scale);
+ $newWidth = (int) \round($srcWidth * $scale);
+ $newHeight = (int) \round($srcHeight * $scale);
+ }
+ return [\max($newWidth, 1), \max($newHeight, 1)];
+ }
+ /**
+ * Crops image.
+ * @param int|string $left in pixels or percent
+ * @param int|string $top in pixels or percent
+ * @param int|string $width in pixels or percent
+ * @param int|string $height in pixels or percent
+ * @return static
+ */
+ public function crop($left, $top, $width, $height)
+ {
+ [$r['x'], $r['y'], $r['width'], $r['height']] = static::calculateCutout($this->getWidth(), $this->getHeight(), $left, $top, $width, $height);
+ if (\gd_info()['GD Version'] === 'bundled (2.1.0 compatible)') {
+ $this->image = \imagecrop($this->image, $r);
+ \imagesavealpha($this->image, \true);
+ } else {
+ $newImage = static::fromBlank($r['width'], $r['height'], self::RGB(0, 0, 0, 127))->getImageResource();
+ \imagecopy($newImage, $this->image, 0, 0, $r['x'], $r['y'], $r['width'], $r['height']);
+ $this->image = $newImage;
+ }
+ return $this;
+ }
+ /**
+ * Calculates dimensions of cutout in image.
+ * @param int|string $left in pixels or percent
+ * @param int|string $top in pixels or percent
+ * @param int|string $newWidth in pixels or percent
+ * @param int|string $newHeight in pixels or percent
+ */
+ public static function calculateCutout(int $srcWidth, int $srcHeight, $left, $top, $newWidth, $newHeight) : array
+ {
+ if (self::isPercent($newWidth)) {
+ $newWidth = (int) \round($srcWidth / 100 * $newWidth);
+ }
+ if (self::isPercent($newHeight)) {
+ $newHeight = (int) \round($srcHeight / 100 * $newHeight);
+ }
+ if (self::isPercent($left)) {
+ $left = (int) \round(($srcWidth - $newWidth) / 100 * $left);
+ }
+ if (self::isPercent($top)) {
+ $top = (int) \round(($srcHeight - $newHeight) / 100 * $top);
+ }
+ if ($left < 0) {
+ $newWidth += $left;
+ $left = 0;
+ }
+ if ($top < 0) {
+ $newHeight += $top;
+ $top = 0;
+ }
+ $newWidth = \min($newWidth, $srcWidth - $left);
+ $newHeight = \min($newHeight, $srcHeight - $top);
+ return [$left, $top, $newWidth, $newHeight];
+ }
+ /**
+ * Sharpens image a little bit.
+ * @return static
+ */
+ public function sharpen()
+ {
+ \imageconvolution($this->image, [
+ // my magic numbers ;)
+ [-1, -1, -1],
+ [-1, 24, -1],
+ [-1, -1, -1],
+ ], 16, 0);
+ return $this;
+ }
+ /**
+ * Puts another image into this image.
+ * @param int|string $left in pixels or percent
+ * @param int|string $top in pixels or percent
+ * @param int<0, 100> $opacity 0..100
+ * @return static
+ */
+ public function place(self $image, $left = 0, $top = 0, int $opacity = 100)
+ {
+ $opacity = \max(0, \min(100, $opacity));
+ if ($opacity === 0) {
+ return $this;
+ }
+ $width = $image->getWidth();
+ $height = $image->getHeight();
+ if (self::isPercent($left)) {
+ $left = (int) \round(($this->getWidth() - $width) / 100 * $left);
+ }
+ if (self::isPercent($top)) {
+ $top = (int) \round(($this->getHeight() - $height) / 100 * $top);
+ }
+ $output = $input = $image->image;
+ if ($opacity < 100) {
+ $tbl = [];
+ for ($i = 0; $i < 128; $i++) {
+ $tbl[$i] = \round(127 - (127 - $i) * $opacity / 100);
+ }
+ $output = \imagecreatetruecolor($width, $height);
+ \imagealphablending($output, \false);
+ if (!$image->isTrueColor()) {
+ $input = $output;
+ \imagefilledrectangle($output, 0, 0, $width, $height, \imagecolorallocatealpha($output, 0, 0, 0, 127));
+ \imagecopy($output, $image->image, 0, 0, 0, 0, $width, $height);
+ }
+ for ($x = 0; $x < $width; $x++) {
+ for ($y = 0; $y < $height; $y++) {
+ $c = \imagecolorat($input, $x, $y);
+ $c = ($c & 0xffffff) + ($tbl[$c >> 24] << 24);
+ \imagesetpixel($output, $x, $y, $c);
+ }
+ }
+ \imagealphablending($output, \true);
+ }
+ \imagecopy($this->image, $output, $left, $top, 0, 0, $width, $height);
+ return $this;
+ }
+ /**
+ * Saves image to the file. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9).
+ * @throws ImageException
+ */
+ public function save(string $file, ?int $quality = null, ?int $type = null) : void
+ {
+ $type = $type ?? self::extensionToType(\pathinfo($file, \PATHINFO_EXTENSION));
+ $this->output($type, $quality, $file);
+ }
+ /**
+ * Outputs image to string. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9).
+ */
+ public function toString(int $type = self::JPEG, ?int $quality = null) : string
+ {
+ return Helpers::capture(function () use($type, $quality) {
+ $this->output($type, $quality);
+ });
+ }
+ /**
+ * Outputs image to string.
+ */
+ public function __toString() : string
+ {
+ try {
+ return $this->toString();
+ } catch (\Throwable $e) {
+ if (\func_num_args() || \PHP_VERSION_ID >= 70400) {
+ throw $e;
+ }
+ \trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", \E_USER_ERROR);
+ return '';
+ }
+ }
+ /**
+ * Outputs image to browser. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9).
+ * @throws ImageException
+ */
+ public function send(int $type = self::JPEG, ?int $quality = null) : void
+ {
+ \header('Content-Type: ' . self::typeToMimeType($type));
+ $this->output($type, $quality);
+ }
+ /**
+ * Outputs image to browser or file.
+ * @throws ImageException
+ */
+ private function output(int $type, ?int $quality, ?string $file = null) : void
+ {
+ switch ($type) {
+ case self::JPEG:
+ $quality = $quality === null ? 85 : \max(0, \min(100, $quality));
+ $success = @\imagejpeg($this->image, $file, $quality);
+ // @ is escalated to exception
+ break;
+ case self::PNG:
+ $quality = $quality === null ? 9 : \max(0, \min(9, $quality));
+ $success = @\imagepng($this->image, $file, $quality);
+ // @ is escalated to exception
+ break;
+ case self::GIF:
+ $success = @\imagegif($this->image, $file);
+ // @ is escalated to exception
+ break;
+ case self::WEBP:
+ $quality = $quality === null ? 80 : \max(0, \min(100, $quality));
+ $success = @\imagewebp($this->image, $file, $quality);
+ // @ is escalated to exception
+ break;
+ case self::AVIF:
+ $quality = $quality === null ? 30 : \max(0, \min(100, $quality));
+ $success = @\imageavif($this->image, $file, $quality);
+ // @ is escalated to exception
+ break;
+ case self::BMP:
+ $success = @\imagebmp($this->image, $file);
+ // @ is escalated to exception
+ break;
+ default:
+ throw new Nette\InvalidArgumentException("Unsupported image type '{$type}'.");
+ }
+ if (!$success) {
+ throw new ImageException(Helpers::getLastError() ?: 'Unknown error');
+ }
+ }
+ /**
+ * Call to undefined method.
+ * @return mixed
+ * @throws Nette\MemberAccessException
+ */
+ public function __call(string $name, array $args)
+ {
+ $function = 'image' . $name;
+ if (!\function_exists($function)) {
+ ObjectHelpers::strictCall(static::class, $name);
+ }
+ foreach ($args as $key => $value) {
+ if ($value instanceof self) {
+ $args[$key] = $value->getImageResource();
+ } elseif (\is_array($value) && isset($value['red'])) {
+ // rgb
+ $args[$key] = \imagecolorallocatealpha($this->image, $value['red'], $value['green'], $value['blue'], $value['alpha']) ?: \imagecolorresolvealpha($this->image, $value['red'], $value['green'], $value['blue'], $value['alpha']);
+ }
+ }
+ $res = $function($this->image, ...$args);
+ return $res instanceof \GdImage || \is_resource($res) && \get_resource_type($res) === 'gd' ? $this->setImageResource($res) : $res;
+ }
+ public function __clone()
+ {
+ \ob_start(function () {
+ });
+ \imagepng($this->image, null, 0);
+ $this->setImageResource(\imagecreatefromstring(\ob_get_clean()));
+ }
+ /**
+ * @param int|string $num in pixels or percent
+ */
+ private static function isPercent(&$num) : bool
+ {
+ if (\is_string($num) && \substr($num, -1) === '%') {
+ $num = (float) \substr($num, 0, -1);
+ return \true;
+ } elseif (\is_int($num) || $num === (string) (int) $num) {
+ $num = (int) $num;
+ return \false;
+ }
+ throw new Nette\InvalidArgumentException("Expected dimension in int|string, '{$num}' given.");
+ }
+ /**
+ * Prevents serialization.
+ */
+ public function __sleep() : array
+ {
+ throw new Nette\NotSupportedException('You cannot serialize or unserialize ' . self::class . ' instances.');
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Json.php b/vendor/nette/utils/src/Utils/Json.php
new file mode 100644
index 0000000000..aea7c53b34
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Json.php
@@ -0,0 +1,49 @@
+getProperties(\ReflectionProperty::IS_PUBLIC), function ($p) {
+ return !$p->isStatic();
+ }), self::parseFullDoc($rc, '~^[ \\t*]*@property(?:-read)?[ \\t]+(?:\\S+[ \\t]+)??\\$(\\w+)~m')), $name);
+ throw new MemberAccessException("Cannot read an undeclared property {$class}::\${$name}" . ($hint ? ", did you mean \${$hint}?" : '.'));
+ }
+ /**
+ * @return never
+ * @throws MemberAccessException
+ */
+ public static function strictSet(string $class, string $name) : void
+ {
+ $rc = new \ReflectionClass($class);
+ $hint = self::getSuggestion(\array_merge(\array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), function ($p) {
+ return !$p->isStatic();
+ }), self::parseFullDoc($rc, '~^[ \\t*]*@property(?:-write)?[ \\t]+(?:\\S+[ \\t]+)??\\$(\\w+)~m')), $name);
+ throw new MemberAccessException("Cannot write to an undeclared property {$class}::\${$name}" . ($hint ? ", did you mean \${$hint}?" : '.'));
+ }
+ /**
+ * @return never
+ * @throws MemberAccessException
+ */
+ public static function strictCall(string $class, string $method, array $additionalMethods = []) : void
+ {
+ $trace = \debug_backtrace(0, 3);
+ // suppose this method is called from __call()
+ $context = ($trace[1]['function'] ?? null) === '__call' ? $trace[2]['class'] ?? null : null;
+ if ($context && \is_a($class, $context, \true) && \method_exists($context, $method)) {
+ // called parent::$method()
+ $class = \get_parent_class($context);
+ }
+ if (\method_exists($class, $method)) {
+ // insufficient visibility
+ $rm = new \ReflectionMethod($class, $method);
+ $visibility = $rm->isPrivate() ? 'private ' : ($rm->isProtected() ? 'protected ' : '');
+ throw new MemberAccessException("Call to {$visibility}method {$class}::{$method}() from " . ($context ? "scope {$context}." : 'global scope.'));
+ } else {
+ $hint = self::getSuggestion(\array_merge(\get_class_methods($class), self::parseFullDoc(new \ReflectionClass($class), '~^[ \\t*]*@method[ \\t]+(?:static[ \\t]+)?(?:\\S+[ \\t]+)??(\\w+)\\(~m'), $additionalMethods), $method);
+ throw new MemberAccessException("Call to undefined method {$class}::{$method}()" . ($hint ? ", did you mean {$hint}()?" : '.'));
+ }
+ }
+ /**
+ * @return never
+ * @throws MemberAccessException
+ */
+ public static function strictStaticCall(string $class, string $method) : void
+ {
+ $trace = \debug_backtrace(0, 3);
+ // suppose this method is called from __callStatic()
+ $context = ($trace[1]['function'] ?? null) === '__callStatic' ? $trace[2]['class'] ?? null : null;
+ if ($context && \is_a($class, $context, \true) && \method_exists($context, $method)) {
+ // called parent::$method()
+ $class = \get_parent_class($context);
+ }
+ if (\method_exists($class, $method)) {
+ // insufficient visibility
+ $rm = new \ReflectionMethod($class, $method);
+ $visibility = $rm->isPrivate() ? 'private ' : ($rm->isProtected() ? 'protected ' : '');
+ throw new MemberAccessException("Call to {$visibility}method {$class}::{$method}() from " . ($context ? "scope {$context}." : 'global scope.'));
+ } else {
+ $hint = self::getSuggestion(\array_filter((new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC), function ($m) {
+ return $m->isStatic();
+ }), $method);
+ throw new MemberAccessException("Call to undefined static method {$class}::{$method}()" . ($hint ? ", did you mean {$hint}()?" : '.'));
+ }
+ }
+ /**
+ * Returns array of magic properties defined by annotation @property.
+ * @return array of [name => bit mask]
+ * @internal
+ */
+ public static function getMagicProperties(string $class) : array
+ {
+ static $cache;
+ $props =& $cache[$class];
+ if ($props !== null) {
+ return $props;
+ }
+ $rc = new \ReflectionClass($class);
+ \preg_match_all('~^ [ \\t*]* @property(|-read|-write|-deprecated) [ \\t]+ [^\\s$]+ [ \\t]+ \\$ (\\w+) ()~mx', (string) $rc->getDocComment(), $matches, \PREG_SET_ORDER);
+ $props = [];
+ foreach ($matches as [, $type, $name]) {
+ $uname = \ucfirst($name);
+ $write = $type !== '-read' && $rc->hasMethod($nm = 'set' . $uname) && ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic();
+ $read = $type !== '-write' && ($rc->hasMethod($nm = 'get' . $uname) || $rc->hasMethod($nm = 'is' . $uname)) && ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic();
+ if ($read || $write) {
+ $props[$name] = $read << 0 | ($nm[0] === 'g') << 1 | $rm->returnsReference() << 2 | $write << 3 | ($type === '-deprecated') << 4;
+ }
+ }
+ foreach ($rc->getTraits() as $trait) {
+ $props += self::getMagicProperties($trait->name);
+ }
+ if ($parent = \get_parent_class($class)) {
+ $props += self::getMagicProperties($parent);
+ }
+ return $props;
+ }
+ /**
+ * Finds the best suggestion (for 8-bit encoding).
+ * @param (\ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionClass|\ReflectionProperty|string)[] $possibilities
+ * @internal
+ */
+ public static function getSuggestion(array $possibilities, string $value) : ?string
+ {
+ $norm = \preg_replace($re = '#^(get|set|has|is|add)(?=[A-Z])#', '+', $value);
+ $best = null;
+ $min = (\strlen($value) / 4 + 1) * 10 + 0.1;
+ foreach (\array_unique($possibilities, \SORT_REGULAR) as $item) {
+ $item = $item instanceof \Reflector ? $item->name : $item;
+ if ($item !== $value && (($len = \levenshtein($item, $value, 10, 11, 10)) < $min || ($len = \levenshtein(\preg_replace($re, '*', $item), $norm, 10, 11, 10)) < $min)) {
+ $min = $len;
+ $best = $item;
+ }
+ }
+ return $best;
+ }
+ private static function parseFullDoc(\ReflectionClass $rc, string $pattern) : array
+ {
+ do {
+ $doc[] = $rc->getDocComment();
+ $traits = $rc->getTraits();
+ while ($trait = \array_pop($traits)) {
+ $doc[] = $trait->getDocComment();
+ $traits += $trait->getTraits();
+ }
+ } while ($rc = $rc->getParentClass());
+ return \preg_match_all($pattern, \implode($doc), $m) ? $m[1] : [];
+ }
+ /**
+ * Checks if the public non-static property exists.
+ * @return bool|string returns 'event' if the property exists and has event like name
+ * @internal
+ */
+ public static function hasProperty(string $class, string $name)
+ {
+ static $cache;
+ $prop =& $cache[$class][$name];
+ if ($prop === null) {
+ $prop = \false;
+ try {
+ $rp = new \ReflectionProperty($class, $name);
+ $rp->setAccessible(\true);
+ if ($rp->isPublic() && !$rp->isStatic()) {
+ $prop = $name >= 'onA' && $name < 'on_' ? 'event' : \true;
+ }
+ } catch (\ReflectionException $e) {
+ }
+ }
+ return $prop;
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/ObjectMixin.php b/vendor/nette/utils/src/Utils/ObjectMixin.php
new file mode 100644
index 0000000000..abd5d3028f
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/ObjectMixin.php
@@ -0,0 +1,32 @@
+ $firstItemOnPage
+ * @property-read int<0,max> $lastItemOnPage
+ * @property int $base
+ * @property-read bool $first
+ * @property-read bool $last
+ * @property-read int<0,max>|null $pageCount
+ * @property positive-int $itemsPerPage
+ * @property int<0,max>|null $itemCount
+ * @property-read int<0,max> $offset
+ * @property-read int<0,max>|null $countdownOffset
+ * @property-read int<0,max> $length
+ */
+class Paginator
+{
+ use Nette\SmartObject;
+ /** @var int */
+ private $base = 1;
+ /** @var int */
+ private $itemsPerPage = 1;
+ /** @var int */
+ private $page = 1;
+ /** @var int|null */
+ private $itemCount;
+ /**
+ * Sets current page number.
+ * @return static
+ */
+ public function setPage(int $page)
+ {
+ $this->page = $page;
+ return $this;
+ }
+ /**
+ * Returns current page number.
+ */
+ public function getPage() : int
+ {
+ return $this->base + $this->getPageIndex();
+ }
+ /**
+ * Returns first page number.
+ */
+ public function getFirstPage() : int
+ {
+ return $this->base;
+ }
+ /**
+ * Returns last page number.
+ */
+ public function getLastPage() : ?int
+ {
+ return $this->itemCount === null ? null : $this->base + \max(0, $this->getPageCount() - 1);
+ }
+ /**
+ * Returns the sequence number of the first element on the page
+ * @return int<0, max>
+ */
+ public function getFirstItemOnPage() : int
+ {
+ return $this->itemCount !== 0 ? $this->offset + 1 : 0;
+ }
+ /**
+ * Returns the sequence number of the last element on the page
+ * @return int<0, max>
+ */
+ public function getLastItemOnPage() : int
+ {
+ return $this->offset + $this->length;
+ }
+ /**
+ * Sets first page (base) number.
+ * @return static
+ */
+ public function setBase(int $base)
+ {
+ $this->base = $base;
+ return $this;
+ }
+ /**
+ * Returns first page (base) number.
+ */
+ public function getBase() : int
+ {
+ return $this->base;
+ }
+ /**
+ * Returns zero-based page number.
+ * @return int<0, max>
+ */
+ protected function getPageIndex() : int
+ {
+ $index = \max(0, $this->page - $this->base);
+ return $this->itemCount === null ? $index : \min($index, \max(0, $this->getPageCount() - 1));
+ }
+ /**
+ * Is the current page the first one?
+ */
+ public function isFirst() : bool
+ {
+ return $this->getPageIndex() === 0;
+ }
+ /**
+ * Is the current page the last one?
+ */
+ public function isLast() : bool
+ {
+ return $this->itemCount === null ? \false : $this->getPageIndex() >= $this->getPageCount() - 1;
+ }
+ /**
+ * Returns the total number of pages.
+ * @return int<0, max>|null
+ */
+ public function getPageCount() : ?int
+ {
+ return $this->itemCount === null ? null : (int) \ceil($this->itemCount / $this->itemsPerPage);
+ }
+ /**
+ * Sets the number of items to display on a single page.
+ * @return static
+ */
+ public function setItemsPerPage(int $itemsPerPage)
+ {
+ $this->itemsPerPage = \max(1, $itemsPerPage);
+ return $this;
+ }
+ /**
+ * Returns the number of items to display on a single page.
+ * @return positive-int
+ */
+ public function getItemsPerPage() : int
+ {
+ return $this->itemsPerPage;
+ }
+ /**
+ * Sets the total number of items.
+ * @return static
+ */
+ public function setItemCount(?int $itemCount = null)
+ {
+ $this->itemCount = $itemCount === null ? null : \max(0, $itemCount);
+ return $this;
+ }
+ /**
+ * Returns the total number of items.
+ * @return int<0, max>|null
+ */
+ public function getItemCount() : ?int
+ {
+ return $this->itemCount;
+ }
+ /**
+ * Returns the absolute index of the first item on current page.
+ * @return int<0, max>
+ */
+ public function getOffset() : int
+ {
+ return $this->getPageIndex() * $this->itemsPerPage;
+ }
+ /**
+ * Returns the absolute index of the first item on current page in countdown paging.
+ * @return int<0, max>|null
+ */
+ public function getCountdownOffset() : ?int
+ {
+ return $this->itemCount === null ? null : \max(0, $this->itemCount - ($this->getPageIndex() + 1) * $this->itemsPerPage);
+ }
+ /**
+ * Returns the number of items on current page.
+ * @return int<0, max>
+ */
+ public function getLength() : int
+ {
+ return $this->itemCount === null ? $this->itemsPerPage : \min($this->itemsPerPage, $this->itemCount - $this->getPageIndex() * $this->itemsPerPage);
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Random.php b/vendor/nette/utils/src/Utils/Random.php
new file mode 100644
index 0000000000..96eec58d7c
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Random.php
@@ -0,0 +1,38 @@
+getReturnType() ?? (\PHP_VERSION_ID >= 80100 && $func instanceof \ReflectionMethod ? $func->getTentativeReturnType() : null);
+ return self::getType($func, $type);
+ }
+ /**
+ * @deprecated
+ */
+ public static function getReturnTypes(\ReflectionFunctionAbstract $func) : array
+ {
+ $type = Type::fromReflection($func);
+ return $type ? $type->getNames() : [];
+ }
+ /**
+ * Returns the type of given parameter and normalizes `self` and `parent` to the actual class names.
+ * If the parameter does not have a type, it returns null.
+ * If the parameter has union or intersection type, it throws Nette\InvalidStateException.
+ * @deprecated use Nette\Utils\Type::fromReflection()
+ */
+ public static function getParameterType(\ReflectionParameter $param) : ?string
+ {
+ return self::getType($param, $param->getType());
+ }
+ /**
+ * @deprecated
+ */
+ public static function getParameterTypes(\ReflectionParameter $param) : array
+ {
+ $type = Type::fromReflection($param);
+ return $type ? $type->getNames() : [];
+ }
+ /**
+ * Returns the type of given property and normalizes `self` and `parent` to the actual class names.
+ * If the property does not have a type, it returns null.
+ * If the property has union or intersection type, it throws Nette\InvalidStateException.
+ * @deprecated use Nette\Utils\Type::fromReflection()
+ */
+ public static function getPropertyType(\ReflectionProperty $prop) : ?string
+ {
+ return self::getType($prop, \PHP_VERSION_ID >= 70400 ? \method_exists($prop, 'getType') ? $prop->getType() : null : null);
+ }
+ /**
+ * @deprecated
+ */
+ public static function getPropertyTypes(\ReflectionProperty $prop) : array
+ {
+ $type = Type::fromReflection($prop);
+ return $type ? $type->getNames() : [];
+ }
+ /**
+ * @param \ReflectionFunction|\ReflectionMethod|\ReflectionParameter|\ReflectionProperty $reflection
+ */
+ private static function getType($reflection, ?\ReflectionType $type) : ?string
+ {
+ if ($type === null) {
+ return null;
+ } elseif ($type instanceof \ReflectionNamedType) {
+ return Type::resolve($type->getName(), $reflection);
+ } elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) {
+ throw new Nette\InvalidStateException('The ' . self::toString($reflection) . ' is not expected to have a union or intersection type.');
+ } else {
+ throw new Nette\InvalidStateException('Unexpected type of ' . self::toString($reflection));
+ }
+ }
+ /**
+ * Returns the default value of parameter. If it is a constant, it returns its value.
+ * @return mixed
+ * @throws \ReflectionException If the parameter does not have a default value or the constant cannot be resolved
+ */
+ public static function getParameterDefaultValue(\ReflectionParameter $param)
+ {
+ if ($param->isDefaultValueConstant()) {
+ $const = $orig = $param->getDefaultValueConstantName();
+ $pair = \explode('::', $const);
+ if (isset($pair[1])) {
+ $pair[0] = Type::resolve($pair[0], $param);
+ try {
+ $rcc = new \ReflectionClassConstant($pair[0], $pair[1]);
+ } catch (\ReflectionException $e) {
+ $name = self::toString($param);
+ throw new \ReflectionException("Unable to resolve constant {$orig} used as default value of {$name}.", 0, $e);
+ }
+ return $rcc->getValue();
+ } elseif (!\defined($const)) {
+ $const = \substr((string) \strrchr($const, '\\'), 1);
+ if (!\defined($const)) {
+ $name = self::toString($param);
+ throw new \ReflectionException("Unable to resolve constant {$orig} used as default value of {$name}.");
+ }
+ }
+ return \constant($const);
+ }
+ return $param->getDefaultValue();
+ }
+ /**
+ * Returns a reflection of a class or trait that contains a declaration of given property. Property can also be declared in the trait.
+ */
+ public static function getPropertyDeclaringClass(\ReflectionProperty $prop) : \ReflectionClass
+ {
+ foreach ($prop->getDeclaringClass()->getTraits() as $trait) {
+ if ($trait->hasProperty($prop->name) && $trait->getProperty($prop->name)->getDocComment() === $prop->getDocComment()) {
+ return self::getPropertyDeclaringClass($trait->getProperty($prop->name));
+ }
+ }
+ return $prop->getDeclaringClass();
+ }
+ /**
+ * Returns a reflection of a method that contains a declaration of $method.
+ * Usually, each method is its own declaration, but the body of the method can also be in the trait and under a different name.
+ */
+ public static function getMethodDeclaringMethod(\ReflectionMethod $method) : \ReflectionMethod
+ {
+ // file & line guessing as workaround for insufficient PHP reflection
+ $decl = $method->getDeclaringClass();
+ if ($decl->getFileName() === $method->getFileName() && $decl->getStartLine() <= $method->getStartLine() && $decl->getEndLine() >= $method->getEndLine()) {
+ return $method;
+ }
+ $hash = [$method->getFileName(), $method->getStartLine(), $method->getEndLine()];
+ if (($alias = $decl->getTraitAliases()[$method->name] ?? null) && ($m = new \ReflectionMethod($alias)) && $hash === [$m->getFileName(), $m->getStartLine(), $m->getEndLine()]) {
+ return self::getMethodDeclaringMethod($m);
+ }
+ foreach ($decl->getTraits() as $trait) {
+ if ($trait->hasMethod($method->name) && ($m = $trait->getMethod($method->name)) && $hash === [$m->getFileName(), $m->getStartLine(), $m->getEndLine()]) {
+ return self::getMethodDeclaringMethod($m);
+ }
+ }
+ return $method;
+ }
+ /**
+ * Finds out if reflection has access to PHPdoc comments. Comments may not be available due to the opcode cache.
+ */
+ public static function areCommentsAvailable() : bool
+ {
+ static $res;
+ return $res ?? ($res = (bool) (new \ReflectionMethod(__METHOD__))->getDocComment());
+ }
+ public static function toString(\Reflector $ref) : string
+ {
+ if ($ref instanceof \ReflectionClass) {
+ return $ref->name;
+ } elseif ($ref instanceof \ReflectionMethod) {
+ return $ref->getDeclaringClass()->name . '::' . $ref->name . '()';
+ } elseif ($ref instanceof \ReflectionFunction) {
+ return $ref->name . '()';
+ } elseif ($ref instanceof \ReflectionProperty) {
+ return self::getPropertyDeclaringClass($ref)->name . '::$' . $ref->name;
+ } elseif ($ref instanceof \ReflectionParameter) {
+ return '$' . $ref->name . ' in ' . self::toString($ref->getDeclaringFunction());
+ } else {
+ throw new Nette\InvalidArgumentException();
+ }
+ }
+ /**
+ * Expands the name of the class to full name in the given context of given class.
+ * Thus, it returns how the PHP parser would understand $name if it were written in the body of the class $context.
+ * @throws Nette\InvalidArgumentException
+ */
+ public static function expandClassName(string $name, \ReflectionClass $context) : string
+ {
+ $lower = \strtolower($name);
+ if (empty($name)) {
+ throw new Nette\InvalidArgumentException('Class name must not be empty.');
+ } elseif (Validators::isBuiltinType($lower)) {
+ return $lower;
+ } elseif ($lower === 'self' || $lower === 'static') {
+ return $context->name;
+ } elseif ($lower === 'parent') {
+ return $context->getParentClass() ? $context->getParentClass()->name : 'parent';
+ } elseif ($name[0] === '\\') {
+ // fully qualified name
+ return \ltrim($name, '\\');
+ }
+ $uses = self::getUseStatements($context);
+ $parts = \explode('\\', $name, 2);
+ if (isset($uses[$parts[0]])) {
+ $parts[0] = $uses[$parts[0]];
+ return \implode('\\', $parts);
+ } elseif ($context->inNamespace()) {
+ return $context->getNamespaceName() . '\\' . $name;
+ } else {
+ return $name;
+ }
+ }
+ /** @return array of [alias => class] */
+ public static function getUseStatements(\ReflectionClass $class) : array
+ {
+ if ($class->isAnonymous()) {
+ throw new Nette\NotImplementedException('Anonymous classes are not supported.');
+ }
+ static $cache = [];
+ if (!isset($cache[$name = $class->name])) {
+ if ($class->isInternal()) {
+ $cache[$name] = [];
+ } else {
+ $code = \file_get_contents($class->getFileName());
+ $cache = self::parseUseStatements($code, $name) + $cache;
+ }
+ }
+ return $cache[$name];
+ }
+ /**
+ * Parses PHP code to [class => [alias => class, ...]]
+ */
+ private static function parseUseStatements(string $code, ?string $forClass = null) : array
+ {
+ try {
+ $tokens = \token_get_all($code, \TOKEN_PARSE);
+ } catch (\ParseError $e) {
+ \trigger_error($e->getMessage(), \E_USER_NOTICE);
+ $tokens = [];
+ }
+ $namespace = $class = null;
+ $classLevel = $level = 0;
+ $res = $uses = [];
+ $nameTokens = \PHP_VERSION_ID < 80000 ? [\T_STRING, \T_NS_SEPARATOR] : [\T_STRING, \T_NS_SEPARATOR, \T_NAME_QUALIFIED, \T_NAME_FULLY_QUALIFIED];
+ while ($token = \current($tokens)) {
+ \next($tokens);
+ switch (\is_array($token) ? $token[0] : $token) {
+ case \T_NAMESPACE:
+ $namespace = \ltrim(self::fetch($tokens, $nameTokens) . '\\', '\\');
+ $uses = [];
+ break;
+ case \T_CLASS:
+ case \T_INTERFACE:
+ case \T_TRAIT:
+ case \PHP_VERSION_ID < 80100 ? \T_CLASS : \T_ENUM:
+ if ($name = self::fetch($tokens, \T_STRING)) {
+ $class = $namespace . $name;
+ $classLevel = $level + 1;
+ $res[$class] = $uses;
+ if ($class === $forClass) {
+ return $res;
+ }
+ }
+ break;
+ case \T_USE:
+ while (!$class && ($name = self::fetch($tokens, $nameTokens))) {
+ $name = \ltrim($name, '\\');
+ if (self::fetch($tokens, '{')) {
+ while ($suffix = self::fetch($tokens, $nameTokens)) {
+ if (self::fetch($tokens, \T_AS)) {
+ $uses[self::fetch($tokens, \T_STRING)] = $name . $suffix;
+ } else {
+ $tmp = \explode('\\', $suffix);
+ $uses[\end($tmp)] = $name . $suffix;
+ }
+ if (!self::fetch($tokens, ',')) {
+ break;
+ }
+ }
+ } elseif (self::fetch($tokens, \T_AS)) {
+ $uses[self::fetch($tokens, \T_STRING)] = $name;
+ } else {
+ $tmp = \explode('\\', $name);
+ $uses[\end($tmp)] = $name;
+ }
+ if (!self::fetch($tokens, ',')) {
+ break;
+ }
+ }
+ break;
+ case \T_CURLY_OPEN:
+ case \T_DOLLAR_OPEN_CURLY_BRACES:
+ case '{':
+ $level++;
+ break;
+ case '}':
+ if ($level === $classLevel) {
+ $class = $classLevel = 0;
+ }
+ $level--;
+ }
+ }
+ return $res;
+ }
+ private static function fetch(array &$tokens, $take) : ?string
+ {
+ $res = null;
+ while ($token = \current($tokens)) {
+ [$token, $s] = \is_array($token) ? $token : [$token, $token];
+ if (\in_array($token, (array) $take, \true)) {
+ $res .= $s;
+ } elseif (!\in_array($token, [\T_DOC_COMMENT, \T_WHITESPACE, \T_COMMENT], \true)) {
+ break;
+ }
+ \next($tokens);
+ }
+ return $res;
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Strings.php b/vendor/nette/utils/src/Utils/Strings.php
new file mode 100644
index 0000000000..cf546be4fd
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Strings.php
@@ -0,0 +1,488 @@
+= 0xd800 && $code <= 0xdfff || $code > 0x10ffff) {
+ throw new Nette\InvalidArgumentException('Code point must be in range 0x0 to 0xD7FF or 0xE000 to 0x10FFFF.');
+ } elseif (!\extension_loaded('iconv')) {
+ throw new Nette\NotSupportedException(__METHOD__ . '() requires ICONV extension that is not loaded.');
+ }
+ return \iconv('UTF-32BE', 'UTF-8//IGNORE', \pack('N', $code));
+ }
+ /**
+ * Starts the $haystack string with the prefix $needle?
+ */
+ public static function startsWith(string $haystack, string $needle) : bool
+ {
+ return \strncmp($haystack, $needle, strlen($needle)) === 0;
+ }
+ /**
+ * Ends the $haystack string with the suffix $needle?
+ */
+ public static function endsWith(string $haystack, string $needle) : bool
+ {
+ return $needle === '' || \substr($haystack, -strlen($needle)) === $needle;
+ }
+ /**
+ * Does $haystack contain $needle?
+ */
+ public static function contains(string $haystack, string $needle) : bool
+ {
+ return \strpos($haystack, $needle) !== \false;
+ }
+ /**
+ * Returns a part of UTF-8 string specified by starting position and length. If start is negative,
+ * the returned string will start at the start'th character from the end of string.
+ */
+ public static function substring(string $s, int $start, ?int $length = null) : string
+ {
+ if (\function_exists('mb_substr')) {
+ return \mb_substr($s, $start, $length, 'UTF-8');
+ // MB is much faster
+ } elseif (!\extension_loaded('iconv')) {
+ throw new Nette\NotSupportedException(__METHOD__ . '() requires extension ICONV or MBSTRING, neither is loaded.');
+ } elseif ($length === null) {
+ $length = self::length($s);
+ } elseif ($start < 0 && $length < 0) {
+ $start += self::length($s);
+ // unifies iconv_substr behavior with mb_substr
+ }
+ return \iconv_substr($s, $start, $length, 'UTF-8');
+ }
+ /**
+ * Removes control characters, normalizes line breaks to `\n`, removes leading and trailing blank lines,
+ * trims end spaces on lines, normalizes UTF-8 to the normal form of NFC.
+ */
+ public static function normalize(string $s) : string
+ {
+ // convert to compressed normal form (NFC)
+ if (\class_exists('Normalizer', \false) && ($n = \Normalizer::normalize($s, \Normalizer::FORM_C)) !== \false) {
+ $s = $n;
+ }
+ $s = self::normalizeNewLines($s);
+ // remove control characters; leave \t + \n
+ $s = self::pcre('preg_replace', ['#[\\x00-\\x08\\x0B-\\x1F\\x7F-\\x9F]+#u', '', $s]);
+ // right trim
+ $s = self::pcre('preg_replace', ['#[\\t ]+$#m', '', $s]);
+ // leading and trailing blank lines
+ $s = \trim($s, "\n");
+ return $s;
+ }
+ /**
+ * Standardize line endings to unix-like.
+ */
+ public static function normalizeNewLines(string $s) : string
+ {
+ return \str_replace(["\r\n", "\r"], "\n", $s);
+ }
+ /**
+ * Converts UTF-8 string to ASCII, ie removes diacritics etc.
+ */
+ public static function toAscii(string $s) : string
+ {
+ $iconv = \defined('ICONV_IMPL') ? \trim(\ICONV_IMPL, '"\'') : null;
+ static $transliterator = null;
+ if ($transliterator === null) {
+ if (\class_exists('Transliterator', \false)) {
+ $transliterator = \Transliterator::create('Any-Latin; Latin-ASCII');
+ } else {
+ \trigger_error(__METHOD__ . "(): it is recommended to enable PHP extensions 'intl'.", \E_USER_NOTICE);
+ $transliterator = \false;
+ }
+ }
+ // remove control characters and check UTF-8 validity
+ $s = self::pcre('preg_replace', ['#[^\\x09\\x0A\\x0D\\x20-\\x7E\\xA0-\\x{2FF}\\x{370}-\\x{10FFFF}]#u', '', $s]);
+ // transliteration (by Transliterator and iconv) is not optimal, replace some characters directly
+ $s = \strtr($s, ["„" => '"', "“" => '"', "”" => '"', "‚" => "'", "‘" => "'", "’" => "'", "°" => '^', "Я" => 'Ya', "я" => 'ya', "Ю" => 'Yu', "ю" => 'yu', "Ä" => 'Ae', "Ö" => 'Oe', "Ü" => 'Ue', "ẞ" => 'Ss', "ä" => 'ae', "ö" => 'oe', "ü" => 'ue', "ß" => 'ss']);
+ // „ “ ” ‚ ‘ ’ ° Я я Ю ю Ä Ö Ü ẞ ä ö ü ß
+ if ($iconv !== 'libiconv') {
+ $s = \strtr($s, ["®" => '(R)', "©" => '(c)', "…" => '...', "«" => '<<', "»" => '>>', "£" => 'lb', "¥" => 'yen', "²" => '^2', "³" => '^3', "µ" => 'u', "¹" => '^1', "º" => 'o', "¿" => '?', "ˊ" => "'", "ˍ" => '_', "˝" => '"', "`" => '', "€" => 'EUR', "™" => 'TM', "℮" => 'e', "←" => '<-', "↑" => '^', "→" => '->', "↓" => 'V', "↔" => '<->']);
+ // ® © … « » £ ¥ ² ³ µ ¹ º ¿ ˊ ˍ ˝ ` € ™ ℮ ← ↑ → ↓ ↔
+ }
+ if ($transliterator) {
+ $s = $transliterator->transliterate($s);
+ // use iconv because The transliterator leaves some characters out of ASCII, eg → ʾ
+ if ($iconv === 'glibc') {
+ $s = \strtr($s, '?', "\x01");
+ // temporarily hide ? to distinguish them from the garbage that iconv creates
+ $s = \iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s);
+ $s = \str_replace(['?', "\x01"], ['', '?'], $s);
+ // remove garbage and restore ? characters
+ } elseif ($iconv === 'libiconv') {
+ $s = \iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s);
+ } else {
+ // null or 'unknown' (#216)
+ $s = self::pcre('preg_replace', ['#[^\\x00-\\x7F]++#', '', $s]);
+ // remove non-ascii chars
+ }
+ } elseif ($iconv === 'glibc' || $iconv === 'libiconv') {
+ // temporarily hide these characters to distinguish them from the garbage that iconv creates
+ $s = \strtr($s, '`\'"^~?', "\x01\x02\x03\x04\x05\x06");
+ if ($iconv === 'glibc') {
+ // glibc implementation is very limited. transliterate into Windows-1250 and then into ASCII, so most Eastern European characters are preserved
+ $s = \iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s);
+ $s = \strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe\x96\xa0\x8b\x97\x9b\xa6\xad\xb7", 'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.');
+ $s = self::pcre('preg_replace', ['#[^\\x00-\\x7F]++#', '', $s]);
+ } else {
+ $s = \iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s);
+ }
+ // remove garbage that iconv creates during transliteration (eg Ý -> Y')
+ $s = \str_replace(['`', "'", '"', '^', '~', '?'], '', $s);
+ // restore temporarily hidden characters
+ $s = \strtr($s, "\x01\x02\x03\x04\x05\x06", '`\'"^~?');
+ } else {
+ $s = self::pcre('preg_replace', ['#[^\\x00-\\x7F]++#', '', $s]);
+ // remove non-ascii chars
+ }
+ return $s;
+ }
+ /**
+ * Modifies the UTF-8 string to the form used in the URL, ie removes diacritics and replaces all characters
+ * except letters of the English alphabet and numbers with a hyphens.
+ */
+ public static function webalize(string $s, ?string $charlist = null, bool $lower = \true) : string
+ {
+ $s = self::toAscii($s);
+ if ($lower) {
+ $s = \strtolower($s);
+ }
+ $s = self::pcre('preg_replace', ['#[^a-z0-9' . ($charlist !== null ? \preg_quote($charlist, '#') : '') . ']+#i', '-', $s]);
+ $s = \trim($s, '-');
+ return $s;
+ }
+ /**
+ * Truncates a UTF-8 string to given maximal length, while trying not to split whole words. Only if the string is truncated,
+ * an ellipsis (or something else set with third argument) is appended to the string.
+ */
+ public static function truncate(string $s, int $maxLen, string $append = "…") : string
+ {
+ if (self::length($s) > $maxLen) {
+ $maxLen -= self::length($append);
+ if ($maxLen < 1) {
+ return $append;
+ } elseif ($matches = self::match($s, '#^.{1,' . $maxLen . '}(?=[\\s\\x00-/:-@\\[-`{-~])#us')) {
+ return $matches[0] . $append;
+ } else {
+ return self::substring($s, 0, $maxLen) . $append;
+ }
+ }
+ return $s;
+ }
+ /**
+ * Indents a multiline text from the left. Second argument sets how many indentation chars should be used,
+ * while the indent itself is the third argument (*tab* by default).
+ */
+ public static function indent(string $s, int $level = 1, string $chars = "\t") : string
+ {
+ if ($level > 0) {
+ $s = self::replace($s, '#(?:^|[\\r\\n]+)(?=[^\\r\\n])#', '$0' . \str_repeat($chars, $level));
+ }
+ return $s;
+ }
+ /**
+ * Converts all characters of UTF-8 string to lower case.
+ */
+ public static function lower(string $s) : string
+ {
+ return \mb_strtolower($s, 'UTF-8');
+ }
+ /**
+ * Converts the first character of a UTF-8 string to lower case and leaves the other characters unchanged.
+ */
+ public static function firstLower(string $s) : string
+ {
+ return self::lower(self::substring($s, 0, 1)) . self::substring($s, 1);
+ }
+ /**
+ * Converts all characters of a UTF-8 string to upper case.
+ */
+ public static function upper(string $s) : string
+ {
+ return \mb_strtoupper($s, 'UTF-8');
+ }
+ /**
+ * Converts the first character of a UTF-8 string to upper case and leaves the other characters unchanged.
+ */
+ public static function firstUpper(string $s) : string
+ {
+ return self::upper(self::substring($s, 0, 1)) . self::substring($s, 1);
+ }
+ /**
+ * Converts the first character of every word of a UTF-8 string to upper case and the others to lower case.
+ */
+ public static function capitalize(string $s) : string
+ {
+ return \mb_convert_case($s, \MB_CASE_TITLE, 'UTF-8');
+ }
+ /**
+ * Compares two UTF-8 strings or their parts, without taking character case into account. If length is null, whole strings are compared,
+ * if it is negative, the corresponding number of characters from the end of the strings is compared,
+ * otherwise the appropriate number of characters from the beginning is compared.
+ */
+ public static function compare(string $left, string $right, ?int $length = null) : bool
+ {
+ if (\class_exists('Normalizer', \false)) {
+ $left = \Normalizer::normalize($left, \Normalizer::FORM_D);
+ // form NFD is faster
+ $right = \Normalizer::normalize($right, \Normalizer::FORM_D);
+ // form NFD is faster
+ }
+ if ($length < 0) {
+ $left = self::substring($left, $length, -$length);
+ $right = self::substring($right, $length, -$length);
+ } elseif ($length !== null) {
+ $left = self::substring($left, 0, $length);
+ $right = self::substring($right, 0, $length);
+ }
+ return self::lower($left) === self::lower($right);
+ }
+ /**
+ * Finds the common prefix of strings or returns empty string if the prefix was not found.
+ * @param string[] $strings
+ */
+ public static function findPrefix(array $strings) : string
+ {
+ $first = \array_shift($strings);
+ for ($i = 0; $i < strlen($first); $i++) {
+ foreach ($strings as $s) {
+ if (!isset($s[$i]) || $first[$i] !== $s[$i]) {
+ while ($i && $first[$i - 1] >= "\x80" && $first[$i] >= "\x80" && $first[$i] < "\xc0") {
+ $i--;
+ }
+ return \substr($first, 0, $i);
+ }
+ }
+ }
+ return $first;
+ }
+ /**
+ * Returns number of characters (not bytes) in UTF-8 string.
+ * That is the number of Unicode code points which may differ from the number of graphemes.
+ */
+ public static function length(string $s) : int
+ {
+ return \function_exists('mb_strlen') ? \mb_strlen($s, 'UTF-8') : strlen(\utf8_decode($s));
+ }
+ /**
+ * Removes all left and right side spaces (or the characters passed as second argument) from a UTF-8 encoded string.
+ */
+ public static function trim(string $s, string $charlist = self::TRIM_CHARACTERS) : string
+ {
+ $charlist = \preg_quote($charlist, '#');
+ return self::replace($s, '#^[' . $charlist . ']+|[' . $charlist . ']+$#Du', '');
+ }
+ /**
+ * Pads a UTF-8 string to given length by prepending the $pad string to the beginning.
+ * @param non-empty-string $pad
+ */
+ public static function padLeft(string $s, int $length, string $pad = ' ') : string
+ {
+ $length = \max(0, $length - self::length($s));
+ $padLen = self::length($pad);
+ return \str_repeat($pad, (int) ($length / $padLen)) . self::substring($pad, 0, $length % $padLen) . $s;
+ }
+ /**
+ * Pads UTF-8 string to given length by appending the $pad string to the end.
+ * @param non-empty-string $pad
+ */
+ public static function padRight(string $s, int $length, string $pad = ' ') : string
+ {
+ $length = \max(0, $length - self::length($s));
+ $padLen = self::length($pad);
+ return $s . \str_repeat($pad, (int) ($length / $padLen)) . self::substring($pad, 0, $length % $padLen);
+ }
+ /**
+ * Reverses UTF-8 string.
+ */
+ public static function reverse(string $s) : string
+ {
+ if (!\extension_loaded('iconv')) {
+ throw new Nette\NotSupportedException(__METHOD__ . '() requires ICONV extension that is not loaded.');
+ }
+ return \iconv('UTF-32LE', 'UTF-8', \strrev(\iconv('UTF-8', 'UTF-32BE', $s)));
+ }
+ /**
+ * Returns part of $haystack before $nth occurence of $needle or returns null if the needle was not found.
+ * Negative value means searching from the end.
+ */
+ public static function before(string $haystack, string $needle, int $nth = 1) : ?string
+ {
+ $pos = self::pos($haystack, $needle, $nth);
+ return $pos === null ? null : \substr($haystack, 0, $pos);
+ }
+ /**
+ * Returns part of $haystack after $nth occurence of $needle or returns null if the needle was not found.
+ * Negative value means searching from the end.
+ */
+ public static function after(string $haystack, string $needle, int $nth = 1) : ?string
+ {
+ $pos = self::pos($haystack, $needle, $nth);
+ return $pos === null ? null : \substr($haystack, $pos + strlen($needle));
+ }
+ /**
+ * Returns position in characters of $nth occurence of $needle in $haystack or null if the $needle was not found.
+ * Negative value of `$nth` means searching from the end.
+ */
+ public static function indexOf(string $haystack, string $needle, int $nth = 1) : ?int
+ {
+ $pos = self::pos($haystack, $needle, $nth);
+ return $pos === null ? null : self::length(\substr($haystack, 0, $pos));
+ }
+ /**
+ * Returns position in characters of $nth occurence of $needle in $haystack or null if the needle was not found.
+ */
+ private static function pos(string $haystack, string $needle, int $nth = 1) : ?int
+ {
+ if (!$nth) {
+ return null;
+ } elseif ($nth > 0) {
+ if ($needle === '') {
+ return 0;
+ }
+ $pos = 0;
+ while (($pos = \strpos($haystack, $needle, $pos)) !== \false && --$nth) {
+ $pos++;
+ }
+ } else {
+ $len = strlen($haystack);
+ if ($needle === '') {
+ return $len;
+ } elseif ($len === 0) {
+ return null;
+ }
+ $pos = $len - 1;
+ while (($pos = \strrpos($haystack, $needle, $pos - $len)) !== \false && ++$nth) {
+ $pos--;
+ }
+ }
+ return Helpers::falseToNull($pos);
+ }
+ /**
+ * Splits a string into array by the regular expression. Parenthesized expression in the delimiter are captured.
+ * Parameter $flags can be any combination of PREG_SPLIT_NO_EMPTY and PREG_OFFSET_CAPTURE flags.
+ */
+ public static function split(
+ string $subject,
+ /**
+ * @language
+ */
+ string $pattern,
+ int $flags = 0
+ ) : array
+ {
+ return self::pcre('preg_split', [$pattern, $subject, -1, $flags | \PREG_SPLIT_DELIM_CAPTURE]);
+ }
+ /**
+ * Checks if given string matches a regular expression pattern and returns an array with first found match and each subpattern.
+ * Parameter $flags can be any combination of PREG_OFFSET_CAPTURE and PREG_UNMATCHED_AS_NULL flags.
+ */
+ public static function match(
+ string $subject,
+ /**
+ * @language
+ */
+ string $pattern,
+ int $flags = 0,
+ int $offset = 0
+ ) : ?array
+ {
+ if ($offset > strlen($subject)) {
+ return null;
+ }
+ return self::pcre('preg_match', [$pattern, $subject, &$m, $flags, $offset]) ? $m : null;
+ }
+ /**
+ * Finds all occurrences matching regular expression pattern and returns a two-dimensional array. Result is array of matches (ie uses by default PREG_SET_ORDER).
+ * Parameter $flags can be any combination of PREG_OFFSET_CAPTURE, PREG_UNMATCHED_AS_NULL and PREG_PATTERN_ORDER flags.
+ */
+ public static function matchAll(
+ string $subject,
+ /**
+ * @language
+ */
+ string $pattern,
+ int $flags = 0,
+ int $offset = 0
+ ) : array
+ {
+ if ($offset > strlen($subject)) {
+ return [];
+ }
+ self::pcre('preg_match_all', [$pattern, $subject, &$m, $flags & \PREG_PATTERN_ORDER ? $flags : $flags | \PREG_SET_ORDER, $offset]);
+ return $m;
+ }
+ /**
+ * Replaces all occurrences matching regular expression $pattern which can be string or array in the form `pattern => replacement`.
+ * @param string|array $pattern
+ * @param string|callable $replacement
+ */
+ public static function replace(
+ string $subject,
+ /**
+ * @language
+ */
+ $pattern,
+ $replacement = '',
+ int $limit = -1
+ ) : string
+ {
+ if (is_object($replacement) || is_array($replacement)) {
+ if (!\is_callable($replacement, \false, $textual)) {
+ throw new Nette\InvalidStateException("Callback '{$textual}' is not callable.");
+ }
+ return self::pcre('preg_replace_callback', [$pattern, $replacement, $subject, $limit]);
+ } elseif (is_array($pattern) && \is_string(\key($pattern))) {
+ $replacement = \array_values($pattern);
+ $pattern = \array_keys($pattern);
+ }
+ return self::pcre('preg_replace', [$pattern, $replacement, $subject, $limit]);
+ }
+ /** @internal */
+ public static function pcre(string $func, array $args)
+ {
+ $res = Callback::invokeSafe($func, $args, function (string $message) use($args) : void {
+ // compile-time error, not detectable by preg_last_error
+ throw new RegexpException($message . ' in pattern: ' . \implode(' or ', (array) $args[0]));
+ });
+ if (($code = \preg_last_error()) && ($res === null || !\in_array($func, ['preg_filter', 'preg_replace_callback', 'preg_replace'], \true))) {
+ throw new RegexpException((RegexpException::MESSAGES[$code] ?? 'Unknown error') . ' (pattern: ' . \implode(' or ', (array) $args[0]) . ')', $code);
+ }
+ return $res;
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Type.php b/vendor/nette/utils/src/Utils/Type.php
new file mode 100644
index 0000000000..5200eabfb8
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Type.php
@@ -0,0 +1,212 @@
+ */
+ private $types;
+ /** @var bool */
+ private $simple;
+ /** @var string |, & */
+ private $kind;
+ /**
+ * Creates a Type object based on reflection. Resolves self, static and parent to the actual class name.
+ * If the subject has no type, it returns null.
+ * @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection
+ */
+ public static function fromReflection($reflection) : ?self
+ {
+ if ($reflection instanceof \ReflectionProperty && \PHP_VERSION_ID < 70400) {
+ return null;
+ } elseif ($reflection instanceof \ReflectionMethod) {
+ $type = $reflection->getReturnType() ?? (\PHP_VERSION_ID >= 80100 ? $reflection->getTentativeReturnType() : null);
+ } else {
+ $type = $reflection instanceof \ReflectionFunctionAbstract ? $reflection->getReturnType() : $reflection->getType();
+ }
+ return $type ? self::fromReflectionType($type, $reflection, \true) : null;
+ }
+ private static function fromReflectionType(\ReflectionType $type, $of, bool $asObject)
+ {
+ if ($type instanceof \ReflectionNamedType) {
+ $name = self::resolve($type->getName(), $of);
+ return $asObject ? new self($type->allowsNull() && $name !== 'mixed' ? [$name, 'null'] : [$name]) : $name;
+ } elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) {
+ return new self(\array_map(function ($t) use($of) {
+ return self::fromReflectionType($t, $of, \false);
+ }, $type->getTypes()), $type instanceof \ReflectionUnionType ? '|' : '&');
+ } else {
+ throw new Nette\InvalidStateException('Unexpected type of ' . Reflection::toString($of));
+ }
+ }
+ /**
+ * Creates the Type object according to the text notation.
+ */
+ public static function fromString(string $type) : self
+ {
+ if (!Validators::isTypeDeclaration($type)) {
+ throw new Nette\InvalidArgumentException("Invalid type '{$type}'.");
+ }
+ if ($type[0] === '?') {
+ return new self([\substr($type, 1), 'null']);
+ }
+ $unions = [];
+ foreach (\explode('|', $type) as $part) {
+ $part = \explode('&', \trim($part, '()'));
+ $unions[] = \count($part) === 1 ? $part[0] : new self($part, '&');
+ }
+ return \count($unions) === 1 && $unions[0] instanceof self ? $unions[0] : new self($unions);
+ }
+ /**
+ * Resolves 'self', 'static' and 'parent' to the actual class name.
+ * @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $of
+ */
+ public static function resolve(string $type, $of) : string
+ {
+ $lower = \strtolower($type);
+ if ($of instanceof \ReflectionFunction) {
+ return $type;
+ } elseif ($lower === 'self' || $lower === 'static') {
+ return $of->getDeclaringClass()->name;
+ } elseif ($lower === 'parent' && $of->getDeclaringClass()->getParentClass()) {
+ return $of->getDeclaringClass()->getParentClass()->name;
+ } else {
+ return $type;
+ }
+ }
+ private function __construct(array $types, string $kind = '|')
+ {
+ $o = \array_search('null', $types, \true);
+ if ($o !== \false) {
+ // null as last
+ \array_splice($types, $o, 1);
+ $types[] = 'null';
+ }
+ $this->types = $types;
+ $this->simple = \is_string($types[0]) && ($types[1] ?? 'null') === 'null';
+ $this->kind = \count($types) > 1 ? $kind : '';
+ }
+ public function __toString() : string
+ {
+ $multi = \count($this->types) > 1;
+ if ($this->simple) {
+ return ($multi ? '?' : '') . $this->types[0];
+ }
+ $res = [];
+ foreach ($this->types as $type) {
+ $res[] = $type instanceof self && $multi ? "({$type})" : $type;
+ }
+ return \implode($this->kind, $res);
+ }
+ /**
+ * Returns the array of subtypes that make up the compound type as strings.
+ * @return array
+ */
+ public function getNames() : array
+ {
+ return \array_map(function ($t) {
+ return $t instanceof self ? $t->getNames() : $t;
+ }, $this->types);
+ }
+ /**
+ * Returns the array of subtypes that make up the compound type as Type objects:
+ * @return self[]
+ */
+ public function getTypes() : array
+ {
+ return \array_map(function ($t) {
+ return $t instanceof self ? $t : new self([$t]);
+ }, $this->types);
+ }
+ /**
+ * Returns the type name for simple types, otherwise null.
+ */
+ public function getSingleName() : ?string
+ {
+ return $this->simple ? $this->types[0] : null;
+ }
+ /**
+ * Returns true whether it is a union type.
+ */
+ public function isUnion() : bool
+ {
+ return $this->kind === '|';
+ }
+ /**
+ * Returns true whether it is an intersection type.
+ */
+ public function isIntersection() : bool
+ {
+ return $this->kind === '&';
+ }
+ /**
+ * Returns true whether it is a simple type. Single nullable types are also considered to be simple types.
+ */
+ public function isSimple() : bool
+ {
+ return $this->simple;
+ }
+ /** @deprecated use isSimple() */
+ public function isSingle() : bool
+ {
+ return $this->simple;
+ }
+ /**
+ * Returns true whether the type is both a simple and a PHP built-in type.
+ */
+ public function isBuiltin() : bool
+ {
+ return $this->simple && Validators::isBuiltinType($this->types[0]);
+ }
+ /**
+ * Returns true whether the type is both a simple and a class name.
+ */
+ public function isClass() : bool
+ {
+ return $this->simple && !Validators::isBuiltinType($this->types[0]);
+ }
+ /**
+ * Determines if type is special class name self/parent/static.
+ */
+ public function isClassKeyword() : bool
+ {
+ return $this->simple && Validators::isClassKeyword($this->types[0]);
+ }
+ /**
+ * Verifies type compatibility. For example, it checks if a value of a certain type could be passed as a parameter.
+ */
+ public function allows(string $subtype) : bool
+ {
+ if ($this->types === ['mixed']) {
+ return \true;
+ }
+ $subtype = self::fromString($subtype);
+ return $subtype->isUnion() ? Arrays::every($subtype->types, function ($t) {
+ return $this->allows2($t instanceof self ? $t->types : [$t]);
+ }) : $this->allows2($subtype->types);
+ }
+ private function allows2(array $subtypes) : bool
+ {
+ return $this->isUnion() ? Arrays::some($this->types, function ($t) use($subtypes) {
+ return $this->allows3($t instanceof self ? $t->types : [$t], $subtypes);
+ }) : $this->allows3($this->types, $subtypes);
+ }
+ private function allows3(array $types, array $subtypes) : bool
+ {
+ return Arrays::every($types, function ($type) use($subtypes) {
+ $builtin = Validators::isBuiltinType($type);
+ return Arrays::some($subtypes, function ($subtype) use($type, $builtin) {
+ return $builtin ? \strcasecmp($type, $subtype) === 0 : \is_a($subtype, $type, \true);
+ });
+ });
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/Validators.php b/vendor/nette/utils/src/Utils/Validators.php
new file mode 100644
index 0000000000..a2e18f6f47
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Validators.php
@@ -0,0 +1,341 @@
+ 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1, 'callable' => 1, 'iterable' => 1, 'void' => 1, 'null' => 1, 'mixed' => 1, 'false' => 1, 'never' => 1, 'true' => 1];
+ /** @var array */
+ protected static $validators = [
+ // PHP types
+ 'array' => 'is_array',
+ 'bool' => 'is_bool',
+ 'boolean' => 'is_bool',
+ 'float' => 'is_float',
+ 'int' => 'is_int',
+ 'integer' => 'is_int',
+ 'null' => 'is_null',
+ 'object' => 'is_object',
+ 'resource' => 'is_resource',
+ 'scalar' => 'is_scalar',
+ 'string' => 'is_string',
+ // pseudo-types
+ 'callable' => [self::class, 'isCallable'],
+ 'iterable' => 'is_iterable',
+ 'list' => [Arrays::class, 'isList'],
+ 'mixed' => [self::class, 'isMixed'],
+ 'none' => [self::class, 'isNone'],
+ 'number' => [self::class, 'isNumber'],
+ 'numeric' => [self::class, 'isNumeric'],
+ 'numericint' => [self::class, 'isNumericInt'],
+ // string patterns
+ 'alnum' => 'ctype_alnum',
+ 'alpha' => 'ctype_alpha',
+ 'digit' => 'ctype_digit',
+ 'lower' => 'ctype_lower',
+ 'pattern' => null,
+ 'space' => 'ctype_space',
+ 'unicode' => [self::class, 'isUnicode'],
+ 'upper' => 'ctype_upper',
+ 'xdigit' => 'ctype_xdigit',
+ // syntax validation
+ 'email' => [self::class, 'isEmail'],
+ 'identifier' => [self::class, 'isPhpIdentifier'],
+ 'uri' => [self::class, 'isUri'],
+ 'url' => [self::class, 'isUrl'],
+ // environment validation
+ 'class' => 'class_exists',
+ 'interface' => 'interface_exists',
+ 'directory' => 'is_dir',
+ 'file' => 'is_file',
+ 'type' => [self::class, 'isType'],
+ ];
+ /** @var array */
+ protected static $counters = ['string' => 'strlen', 'unicode' => [Strings::class, 'length'], 'array' => 'count', 'list' => 'count', 'alnum' => 'strlen', 'alpha' => 'strlen', 'digit' => 'strlen', 'lower' => 'strlen', 'space' => 'strlen', 'upper' => 'strlen', 'xdigit' => 'strlen'];
+ /**
+ * Verifies that the value is of expected types separated by pipe.
+ * @param mixed $value
+ * @throws AssertionException
+ */
+ public static function assert($value, string $expected, string $label = 'variable') : void
+ {
+ if (!static::is($value, $expected)) {
+ $expected = \str_replace(['|', ':'], [' or ', ' in range '], $expected);
+ $translate = ['boolean' => 'bool', 'integer' => 'int', 'double' => 'float', 'NULL' => 'null'];
+ $type = $translate[\gettype($value)] ?? \gettype($value);
+ if (\is_int($value) || \is_float($value) || \is_string($value) && \strlen($value) < 40) {
+ $type .= ' ' . \var_export($value, \true);
+ } elseif (\is_object($value)) {
+ $type .= ' ' . \get_class($value);
+ }
+ throw new AssertionException("The {$label} expects to be {$expected}, {$type} given.");
+ }
+ }
+ /**
+ * Verifies that element $key in array is of expected types separated by pipe.
+ * @param mixed[] $array
+ * @param int|string $key
+ * @throws AssertionException
+ */
+ public static function assertField(array $array, $key, ?string $expected = null, string $label = "item '%' in array") : void
+ {
+ if (!\array_key_exists($key, $array)) {
+ throw new AssertionException('Missing ' . \str_replace('%', $key, $label) . '.');
+ } elseif ($expected) {
+ static::assert($array[$key], $expected, \str_replace('%', $key, $label));
+ }
+ }
+ /**
+ * Verifies that the value is of expected types separated by pipe.
+ * @param mixed $value
+ */
+ public static function is($value, string $expected) : bool
+ {
+ foreach (\explode('|', $expected) as $item) {
+ if (\substr($item, -2) === '[]') {
+ if (\is_iterable($value) && self::everyIs($value, \substr($item, 0, -2))) {
+ return \true;
+ }
+ continue;
+ } elseif (\substr($item, 0, 1) === '?') {
+ $item = \substr($item, 1);
+ if ($value === null) {
+ return \true;
+ }
+ }
+ [$type] = $item = \explode(':', $item, 2);
+ if (isset(static::$validators[$type])) {
+ try {
+ if (!static::$validators[$type]($value)) {
+ continue;
+ }
+ } catch (\TypeError $e) {
+ continue;
+ }
+ } elseif ($type === 'pattern') {
+ if (Strings::match($value, '|^' . ($item[1] ?? '') . '$|D')) {
+ return \true;
+ }
+ continue;
+ } elseif (!$value instanceof $type) {
+ continue;
+ }
+ if (isset($item[1])) {
+ $length = $value;
+ if (isset(static::$counters[$type])) {
+ $length = static::$counters[$type]($value);
+ }
+ $range = \explode('..', $item[1]);
+ if (!isset($range[1])) {
+ $range[1] = $range[0];
+ }
+ if ($range[0] !== '' && $length < $range[0] || $range[1] !== '' && $length > $range[1]) {
+ continue;
+ }
+ }
+ return \true;
+ }
+ return \false;
+ }
+ /**
+ * Finds whether all values are of expected types separated by pipe.
+ * @param mixed[] $values
+ */
+ public static function everyIs(iterable $values, string $expected) : bool
+ {
+ foreach ($values as $value) {
+ if (!static::is($value, $expected)) {
+ return \false;
+ }
+ }
+ return \true;
+ }
+ /**
+ * Checks if the value is an integer or a float.
+ * @param mixed $value
+ */
+ public static function isNumber($value) : bool
+ {
+ return \is_int($value) || \is_float($value);
+ }
+ /**
+ * Checks if the value is an integer or a integer written in a string.
+ * @param mixed $value
+ */
+ public static function isNumericInt($value) : bool
+ {
+ return \is_int($value) || \is_string($value) && \preg_match('#^[+-]?[0-9]+$#D', $value);
+ }
+ /**
+ * Checks if the value is a number or a number written in a string.
+ * @param mixed $value
+ */
+ public static function isNumeric($value) : bool
+ {
+ return \is_float($value) || \is_int($value) || \is_string($value) && \preg_match('#^[+-]?([0-9]++\\.?[0-9]*|\\.[0-9]+)$#D', $value);
+ }
+ /**
+ * Checks if the value is a syntactically correct callback.
+ * @param mixed $value
+ */
+ public static function isCallable($value) : bool
+ {
+ return $value && \is_callable($value, \true);
+ }
+ /**
+ * Checks if the value is a valid UTF-8 string.
+ * @param mixed $value
+ */
+ public static function isUnicode($value) : bool
+ {
+ return \is_string($value) && \preg_match('##u', $value);
+ }
+ /**
+ * Checks if the value is 0, '', false or null.
+ * @param mixed $value
+ */
+ public static function isNone($value) : bool
+ {
+ return $value == null;
+ // intentionally ==
+ }
+ /** @internal */
+ public static function isMixed() : bool
+ {
+ return \true;
+ }
+ /**
+ * Checks if a variable is a zero-based integer indexed array.
+ * @param mixed $value
+ * @deprecated use Nette\Utils\Arrays::isList
+ * @return ($value is list ? true : false)
+ */
+ public static function isList($value) : bool
+ {
+ return Arrays::isList($value);
+ }
+ /**
+ * Checks if the value is in the given range [min, max], where the upper or lower limit can be omitted (null).
+ * Numbers, strings and DateTime objects can be compared.
+ * @param mixed $value
+ */
+ public static function isInRange($value, array $range) : bool
+ {
+ if ($value === null || !(isset($range[0]) || isset($range[1]))) {
+ return \false;
+ }
+ $limit = $range[0] ?? $range[1];
+ if (\is_string($limit)) {
+ $value = (string) $value;
+ } elseif ($limit instanceof \DateTimeInterface) {
+ if (!$value instanceof \DateTimeInterface) {
+ return \false;
+ }
+ } elseif (\is_numeric($value)) {
+ $value *= 1;
+ } else {
+ return \false;
+ }
+ return (!isset($range[0]) || $value >= $range[0]) && (!isset($range[1]) || $value <= $range[1]);
+ }
+ /**
+ * Checks if the value is a valid email address. It does not verify that the domain actually exists, only the syntax is verified.
+ */
+ public static function isEmail(string $value) : bool
+ {
+ $atom = "[-a-z0-9!#\$%&'*+/=?^_`{|}~]";
+ // RFC 5322 unquoted characters in local-part
+ $alpha = "a-z\x80-\xff";
+ // superset of IDN
+ return (bool) \preg_match(<< \\? (? [a-zA-Z_\x7f-\xff][\w\x7f-\xff]*) (\\ (?&name))* ) |
+ (? (?&type) (& (?&type))+ ) |
+ (? (?&type) | \( (?&intersection) \) ) (\| (?&upart))+
+ )$~xAD
+XX
+, $type);
+ }
+}
diff --git a/vendor/nette/utils/src/Utils/exceptions.php b/vendor/nette/utils/src/Utils/exceptions.php
new file mode 100644
index 0000000000..06e5c04b89
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/exceptions.php
@@ -0,0 +1,40 @@
+ 'Internal error', \PREG_BACKTRACK_LIMIT_ERROR => 'Backtrack limit was exhausted', \PREG_RECURSION_LIMIT_ERROR => 'Recursion limit was exhausted', \PREG_BAD_UTF8_ERROR => 'Malformed UTF-8 data', \PREG_BAD_UTF8_OFFSET_ERROR => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', 6 => 'Failed due to limited JIT stack space'];
+}
+/**
+ * The exception that indicates assertion error.
+ */
+class AssertionException extends \Exception
+{
+}
diff --git a/vendor/nette/utils/src/compatibility.php b/vendor/nette/utils/src/compatibility.php
new file mode 100644
index 0000000000..61866389c7
--- /dev/null
+++ b/vendor/nette/utils/src/compatibility.php
@@ -0,0 +1,28 @@
+=7.4.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "EasyCI202401\\Psr\\Container\\": "src\/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ }
+}
\ No newline at end of file
diff --git a/vendor/psr/container/src/ContainerExceptionInterface.php b/vendor/psr/container/src/ContainerExceptionInterface.php
new file mode 100644
index 0000000000..c291e26e1e
--- /dev/null
+++ b/vendor/psr/container/src/ContainerExceptionInterface.php
@@ -0,0 +1,11 @@
+ 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/psr/simple-cache/README.md b/vendor/psr/simple-cache/README.md
new file mode 100644
index 0000000000..43641d175c
--- /dev/null
+++ b/vendor/psr/simple-cache/README.md
@@ -0,0 +1,8 @@
+PHP FIG Simple Cache PSR
+========================
+
+This repository holds all interfaces related to PSR-16.
+
+Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See [the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md) for more details.
+
+You can find implementations of the specification by looking for packages providing the [psr/simple-cache-implementation](https://packagist.org/providers/psr/simple-cache-implementation) virtual package.
diff --git a/vendor/psr/simple-cache/composer.json b/vendor/psr/simple-cache/composer.json
new file mode 100644
index 0000000000..c768a0420e
--- /dev/null
+++ b/vendor/psr/simple-cache/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "psr\/simple-cache",
+ "description": "Common interfaces for simple caching",
+ "keywords": [
+ "psr",
+ "psr-16",
+ "cache",
+ "simple-cache",
+ "caching"
+ ],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https:\/\/www.php-fig.org\/"
+ }
+ ],
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "EasyCI202401\\Psr\\SimpleCache\\": "src\/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ }
+}
\ No newline at end of file
diff --git a/vendor/psr/simple-cache/src/CacheException.php b/vendor/psr/simple-cache/src/CacheException.php
new file mode 100644
index 0000000000..7dc56a7567
--- /dev/null
+++ b/vendor/psr/simple-cache/src/CacheException.php
@@ -0,0 +1,10 @@
+ $keys A list of keys that can be obtained in a single operation.
+ * @param mixed $default Default value to return for keys that do not exist.
+ *
+ * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.
+ *
+ * @throws \Psr\SimpleCache\InvalidArgumentException
+ * MUST be thrown if $keys is neither an array nor a Traversable,
+ * or if any of the $keys are not a legal value.
+ */
+ public function getMultiple(iterable $keys, $default = null) : iterable;
+ /**
+ * Persists a set of key => value pairs in the cache, with an optional TTL.
+ *
+ * @param iterable $values A list of key => value pairs for a multiple-set operation.
+ * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
+ * the driver supports TTL then the library may set a default value
+ * for it or let the driver take care of that.
+ *
+ * @return bool True on success and false on failure.
+ *
+ * @throws \Psr\SimpleCache\InvalidArgumentException
+ * MUST be thrown if $values is neither an array nor a Traversable,
+ * or if any of the $values are not a legal value.
+ */
+ public function setMultiple(iterable $values, $ttl = null) : bool;
+ /**
+ * Deletes multiple cache items in a single operation.
+ *
+ * @param iterable $keys A list of string-based keys to be deleted.
+ *
+ * @return bool True if the items were successfully removed. False if there was an error.
+ *
+ * @throws \Psr\SimpleCache\InvalidArgumentException
+ * MUST be thrown if $keys is neither an array nor a Traversable,
+ * or if any of the $keys are not a legal value.
+ */
+ public function deleteMultiple(iterable $keys) : bool;
+ /**
+ * Determines whether an item is present in the cache.
+ *
+ * NOTE: It is recommended that has() is only to be used for cache warming type purposes
+ * and not to be used within your live applications operations for get/set, as this method
+ * is subject to a race condition where your has() will return true and immediately after,
+ * another script can remove it making the state of your app out of date.
+ *
+ * @param string $key The cache item key.
+ *
+ * @return bool
+ *
+ * @throws \Psr\SimpleCache\InvalidArgumentException
+ * MUST be thrown if the $key string is not a legal value.
+ */
+ public function has(string $key) : bool;
+}
diff --git a/vendor/psr/simple-cache/src/InvalidArgumentException.php b/vendor/psr/simple-cache/src/InvalidArgumentException.php
new file mode 100644
index 0000000000..05f67abc97
--- /dev/null
+++ b/vendor/psr/simple-cache/src/InvalidArgumentException.php
@@ -0,0 +1,13 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Command\CompleteCommand;
+use EasyCI202401\Symfony\Component\Console\Command\DumpCompletionCommand;
+use EasyCI202401\Symfony\Component\Console\Command\HelpCommand;
+use EasyCI202401\Symfony\Component\Console\Command\LazyCommand;
+use EasyCI202401\Symfony\Component\Console\Command\ListCommand;
+use EasyCI202401\Symfony\Component\Console\Command\SignalableCommandInterface;
+use EasyCI202401\Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionInput;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Completion\Suggestion;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleCommandEvent;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleErrorEvent;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleSignalEvent;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleTerminateEvent;
+use EasyCI202401\Symfony\Component\Console\Exception\CommandNotFoundException;
+use EasyCI202401\Symfony\Component\Console\Exception\ExceptionInterface;
+use EasyCI202401\Symfony\Component\Console\Exception\LogicException;
+use EasyCI202401\Symfony\Component\Console\Exception\NamespaceNotFoundException;
+use EasyCI202401\Symfony\Component\Console\Exception\RuntimeException;
+use EasyCI202401\Symfony\Component\Console\Formatter\OutputFormatter;
+use EasyCI202401\Symfony\Component\Console\Helper\DebugFormatterHelper;
+use EasyCI202401\Symfony\Component\Console\Helper\DescriptorHelper;
+use EasyCI202401\Symfony\Component\Console\Helper\FormatterHelper;
+use EasyCI202401\Symfony\Component\Console\Helper\Helper;
+use EasyCI202401\Symfony\Component\Console\Helper\HelperSet;
+use EasyCI202401\Symfony\Component\Console\Helper\ProcessHelper;
+use EasyCI202401\Symfony\Component\Console\Helper\QuestionHelper;
+use EasyCI202401\Symfony\Component\Console\Input\ArgvInput;
+use EasyCI202401\Symfony\Component\Console\Input\ArrayInput;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputAwareInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleOutput;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleOutputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\Console\SignalRegistry\SignalRegistry;
+use EasyCI202401\Symfony\Component\Console\Style\SymfonyStyle;
+use EasyCI202401\Symfony\Component\ErrorHandler\ErrorHandler;
+use EasyCI202401\Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
+use EasyCI202401\Symfony\Contracts\Service\ResetInterface;
+/**
+ * An Application is the container for a collection of commands.
+ *
+ * It is the main entry point of a Console application.
+ *
+ * This class is optimized for a standard CLI environment.
+ *
+ * Usage:
+ *
+ * $app = new Application('myapp', '1.0 (stable)');
+ * $app->add(new SimpleCommand());
+ * $app->run();
+ *
+ * @author Fabien Potencier
+ */
+class Application implements ResetInterface
+{
+ /**
+ * @var mixed[]
+ */
+ private $commands = [];
+ /**
+ * @var bool
+ */
+ private $wantHelps = \false;
+ /**
+ * @var \Symfony\Component\Console\Command\Command|null
+ */
+ private $runningCommand;
+ /**
+ * @var string
+ */
+ private $name;
+ /**
+ * @var string
+ */
+ private $version;
+ /**
+ * @var \Symfony\Component\Console\CommandLoader\CommandLoaderInterface|null
+ */
+ private $commandLoader;
+ /**
+ * @var bool
+ */
+ private $catchExceptions = \true;
+ /**
+ * @var bool
+ */
+ private $catchErrors = \false;
+ /**
+ * @var bool
+ */
+ private $autoExit = \true;
+ /**
+ * @var \Symfony\Component\Console\Input\InputDefinition
+ */
+ private $definition;
+ /**
+ * @var \Symfony\Component\Console\Helper\HelperSet
+ */
+ private $helperSet;
+ /**
+ * @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface|null
+ */
+ private $dispatcher;
+ /**
+ * @var \Symfony\Component\Console\Terminal
+ */
+ private $terminal;
+ /**
+ * @var string
+ */
+ private $defaultCommand;
+ /**
+ * @var bool
+ */
+ private $singleCommand = \false;
+ /**
+ * @var bool
+ */
+ private $initialized = \false;
+ /**
+ * @var \Symfony\Component\Console\SignalRegistry\SignalRegistry|null
+ */
+ private $signalRegistry;
+ /**
+ * @var mixed[]
+ */
+ private $signalsToDispatchEvent = [];
+ public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
+ {
+ $this->name = $name;
+ $this->version = $version;
+ $this->terminal = new Terminal();
+ $this->defaultCommand = 'list';
+ if (\defined('SIGINT') && SignalRegistry::isSupported()) {
+ $this->signalRegistry = new SignalRegistry();
+ $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2];
+ }
+ }
+ /**
+ * @final
+ */
+ public function setDispatcher(EventDispatcherInterface $dispatcher) : void
+ {
+ $this->dispatcher = $dispatcher;
+ }
+ /**
+ * @return void
+ */
+ public function setCommandLoader(CommandLoaderInterface $commandLoader)
+ {
+ $this->commandLoader = $commandLoader;
+ }
+ public function getSignalRegistry() : SignalRegistry
+ {
+ if (!$this->signalRegistry) {
+ throw new RuntimeException('Signals are not supported. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
+ }
+ return $this->signalRegistry;
+ }
+ /**
+ * @return void
+ */
+ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent)
+ {
+ $this->signalsToDispatchEvent = $signalsToDispatchEvent;
+ }
+ /**
+ * Runs the current application.
+ *
+ * @return int 0 if everything went fine, or an error code
+ *
+ * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}.
+ */
+ public function run(InputInterface $input = null, OutputInterface $output = null) : int
+ {
+ if (\function_exists('putenv')) {
+ @\putenv('LINES=' . $this->terminal->getHeight());
+ @\putenv('COLUMNS=' . $this->terminal->getWidth());
+ }
+ $input = $input ?? new ArgvInput();
+ $output = $output ?? new ConsoleOutput();
+ $renderException = function (\Throwable $e) use($output) {
+ if ($output instanceof ConsoleOutputInterface) {
+ $this->renderThrowable($e, $output->getErrorOutput());
+ } else {
+ $this->renderThrowable($e, $output);
+ }
+ };
+ if ($phpHandler = \set_exception_handler($renderException)) {
+ \restore_exception_handler();
+ if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) {
+ $errorHandler = \true;
+ } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
+ $phpHandler[0]->setExceptionHandler($errorHandler);
+ }
+ }
+ $this->configureIO($input, $output);
+ try {
+ $exitCode = $this->doRun($input, $output);
+ } catch (\Throwable $e) {
+ if ($e instanceof \Exception && !$this->catchExceptions) {
+ throw $e;
+ }
+ if (!$e instanceof \Exception && !$this->catchErrors) {
+ throw $e;
+ }
+ $renderException($e);
+ $exitCode = $e->getCode();
+ if (\is_numeric($exitCode)) {
+ $exitCode = (int) $exitCode;
+ if ($exitCode <= 0) {
+ $exitCode = 1;
+ }
+ } else {
+ $exitCode = 1;
+ }
+ } finally {
+ // if the exception handler changed, keep it
+ // otherwise, unregister $renderException
+ if (!$phpHandler) {
+ if (\set_exception_handler($renderException) === $renderException) {
+ \restore_exception_handler();
+ }
+ \restore_exception_handler();
+ } elseif (!$errorHandler) {
+ $finalHandler = $phpHandler[0]->setExceptionHandler(null);
+ if ($finalHandler !== $renderException) {
+ $phpHandler[0]->setExceptionHandler($finalHandler);
+ }
+ }
+ }
+ if ($this->autoExit) {
+ if ($exitCode > 255) {
+ $exitCode = 255;
+ }
+ exit($exitCode);
+ }
+ return $exitCode;
+ }
+ /**
+ * Runs the current application.
+ *
+ * @return int 0 if everything went fine, or an error code
+ */
+ public function doRun(InputInterface $input, OutputInterface $output)
+ {
+ if (\true === $input->hasParameterOption(['--version', '-V'], \true)) {
+ $output->writeln($this->getLongVersion());
+ return 0;
+ }
+ try {
+ // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
+ $input->bind($this->getDefinition());
+ } catch (ExceptionInterface $exception) {
+ // Errors must be ignored, full binding/validation happens later when the command is known.
+ }
+ $name = $this->getCommandName($input);
+ if (\true === $input->hasParameterOption(['--help', '-h'], \true)) {
+ if (!$name) {
+ $name = 'help';
+ $input = new ArrayInput(['command_name' => $this->defaultCommand]);
+ } else {
+ $this->wantHelps = \true;
+ }
+ }
+ if (!$name) {
+ $name = $this->defaultCommand;
+ $definition = $this->getDefinition();
+ $definition->setArguments(\array_merge($definition->getArguments(), ['command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name)]));
+ }
+ try {
+ $this->runningCommand = null;
+ // the command name MUST be the first element of the input
+ $command = $this->find($name);
+ } catch (\Throwable $e) {
+ if ($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException && 1 === \count($alternatives = $e->getAlternatives()) && $input->isInteractive()) {
+ $alternative = $alternatives[0];
+ $style = new SymfonyStyle($input, $output);
+ $output->writeln('');
+ $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', \true);
+ $output->writeln($formattedBlock);
+ if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), \false)) {
+ if (null !== $this->dispatcher) {
+ $event = new ConsoleErrorEvent($input, $output, $e);
+ $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
+ return $event->getExitCode();
+ }
+ return 1;
+ }
+ $command = $this->find($alternative);
+ } else {
+ if (null !== $this->dispatcher) {
+ $event = new ConsoleErrorEvent($input, $output, $e);
+ $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
+ if (0 === $event->getExitCode()) {
+ return 0;
+ }
+ $e = $event->getError();
+ }
+ try {
+ if ($e instanceof CommandNotFoundException && ($namespace = $this->findNamespace($name))) {
+ $helper = new DescriptorHelper();
+ $helper->describe($output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output, $this, ['format' => 'txt', 'raw_text' => \false, 'namespace' => $namespace, 'short' => \false]);
+ return isset($event) ? $event->getExitCode() : 1;
+ }
+ throw $e;
+ } catch (NamespaceNotFoundException $exception) {
+ throw $e;
+ }
+ }
+ }
+ if ($command instanceof LazyCommand) {
+ $command = $command->getCommand();
+ }
+ $this->runningCommand = $command;
+ $exitCode = $this->doRunCommand($command, $input, $output);
+ $this->runningCommand = null;
+ return $exitCode;
+ }
+ /**
+ * @return void
+ */
+ public function reset()
+ {
+ }
+ /**
+ * @return void
+ */
+ public function setHelperSet(HelperSet $helperSet)
+ {
+ $this->helperSet = $helperSet;
+ }
+ /**
+ * Get the helper set associated with the command.
+ */
+ public function getHelperSet() : HelperSet
+ {
+ return $this->helperSet = $this->helperSet ?? $this->getDefaultHelperSet();
+ }
+ /**
+ * @return void
+ */
+ public function setDefinition(InputDefinition $definition)
+ {
+ $this->definition = $definition;
+ }
+ /**
+ * Gets the InputDefinition related to this Application.
+ */
+ public function getDefinition() : InputDefinition
+ {
+ $this->definition = $this->definition ?? $this->getDefaultInputDefinition();
+ if ($this->singleCommand) {
+ $inputDefinition = $this->definition;
+ $inputDefinition->setArguments();
+ return $inputDefinition;
+ }
+ return $this->definition;
+ }
+ /**
+ * Adds suggestions to $suggestions for the current completion input (e.g. option or argument).
+ */
+ public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void
+ {
+ if (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && 'command' === $input->getCompletionName()) {
+ foreach ($this->all() as $name => $command) {
+ // skip hidden commands and aliased commands as they already get added below
+ if ($command->isHidden() || $command->getName() !== $name) {
+ continue;
+ }
+ $suggestions->suggestValue(new Suggestion($command->getName(), $command->getDescription()));
+ foreach ($command->getAliases() as $name) {
+ $suggestions->suggestValue(new Suggestion($name, $command->getDescription()));
+ }
+ }
+ return;
+ }
+ if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) {
+ $suggestions->suggestOptions($this->getDefinition()->getOptions());
+ return;
+ }
+ }
+ /**
+ * Gets the help message.
+ */
+ public function getHelp() : string
+ {
+ return $this->getLongVersion();
+ }
+ /**
+ * Gets whether to catch exceptions or not during commands execution.
+ */
+ public function areExceptionsCaught() : bool
+ {
+ return $this->catchExceptions;
+ }
+ /**
+ * Sets whether to catch exceptions or not during commands execution.
+ *
+ * @return void
+ */
+ public function setCatchExceptions(bool $boolean)
+ {
+ $this->catchExceptions = $boolean;
+ }
+ /**
+ * Sets whether to catch errors or not during commands execution.
+ */
+ public function setCatchErrors(bool $catchErrors = \true) : void
+ {
+ $this->catchErrors = $catchErrors;
+ }
+ /**
+ * Gets whether to automatically exit after a command execution or not.
+ */
+ public function isAutoExitEnabled() : bool
+ {
+ return $this->autoExit;
+ }
+ /**
+ * Sets whether to automatically exit after a command execution or not.
+ *
+ * @return void
+ */
+ public function setAutoExit(bool $boolean)
+ {
+ $this->autoExit = $boolean;
+ }
+ /**
+ * Gets the name of the application.
+ */
+ public function getName() : string
+ {
+ return $this->name;
+ }
+ /**
+ * Sets the application name.
+ *
+ * @return void
+ */
+ public function setName(string $name)
+ {
+ $this->name = $name;
+ }
+ /**
+ * Gets the application version.
+ */
+ public function getVersion() : string
+ {
+ return $this->version;
+ }
+ /**
+ * Sets the application version.
+ *
+ * @return void
+ */
+ public function setVersion(string $version)
+ {
+ $this->version = $version;
+ }
+ /**
+ * Returns the long version of the application.
+ *
+ * @return string
+ */
+ public function getLongVersion()
+ {
+ if ('UNKNOWN' !== $this->getName()) {
+ if ('UNKNOWN' !== $this->getVersion()) {
+ return \sprintf('%s %s', $this->getName(), $this->getVersion());
+ }
+ return $this->getName();
+ }
+ return 'Console Tool';
+ }
+ /**
+ * Registers a new command.
+ */
+ public function register(string $name) : Command
+ {
+ return $this->add(new Command($name));
+ }
+ /**
+ * Adds an array of command objects.
+ *
+ * If a Command is not enabled it will not be added.
+ *
+ * @param Command[] $commands An array of commands
+ *
+ * @return void
+ */
+ public function addCommands(array $commands)
+ {
+ foreach ($commands as $command) {
+ $this->add($command);
+ }
+ }
+ /**
+ * Adds a command object.
+ *
+ * If a command with the same name already exists, it will be overridden.
+ * If the command is not enabled it will not be added.
+ *
+ * @return Command|null
+ */
+ public function add(Command $command)
+ {
+ $this->init();
+ $command->setApplication($this);
+ if (!$command->isEnabled()) {
+ $command->setApplication(null);
+ return null;
+ }
+ if (!$command instanceof LazyCommand) {
+ // Will throw if the command is not correctly initialized.
+ $command->getDefinition();
+ }
+ if (!$command->getName()) {
+ throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', \get_debug_type($command)));
+ }
+ $this->commands[$command->getName()] = $command;
+ foreach ($command->getAliases() as $alias) {
+ $this->commands[$alias] = $command;
+ }
+ return $command;
+ }
+ /**
+ * Returns a registered command by name or alias.
+ *
+ * @return Command
+ *
+ * @throws CommandNotFoundException When given command name does not exist
+ */
+ public function get(string $name)
+ {
+ $this->init();
+ if (!$this->has($name)) {
+ throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name));
+ }
+ // When the command has a different name than the one used at the command loader level
+ if (!isset($this->commands[$name])) {
+ throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name));
+ }
+ $command = $this->commands[$name];
+ if ($this->wantHelps) {
+ $this->wantHelps = \false;
+ $helpCommand = $this->get('help');
+ $helpCommand->setCommand($command);
+ return $helpCommand;
+ }
+ return $command;
+ }
+ /**
+ * Returns true if the command exists, false otherwise.
+ */
+ public function has(string $name) : bool
+ {
+ $this->init();
+ return isset($this->commands[$name]) || (($nullsafeVariable1 = $this->commandLoader) ? $nullsafeVariable1->has($name) : null) && $this->add($this->commandLoader->get($name));
+ }
+ /**
+ * Returns an array of all unique namespaces used by currently registered commands.
+ *
+ * It does not return the global namespace which always exists.
+ *
+ * @return string[]
+ */
+ public function getNamespaces() : array
+ {
+ $namespaces = [];
+ foreach ($this->all() as $command) {
+ if ($command->isHidden()) {
+ continue;
+ }
+ $namespaces[] = $this->extractAllNamespaces($command->getName());
+ foreach ($command->getAliases() as $alias) {
+ $namespaces[] = $this->extractAllNamespaces($alias);
+ }
+ }
+ return \array_values(\array_unique(\array_filter(\array_merge([], ...$namespaces))));
+ }
+ /**
+ * Finds a registered namespace by a name or an abbreviation.
+ *
+ * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous
+ */
+ public function findNamespace(string $namespace) : string
+ {
+ $allNamespaces = $this->getNamespaces();
+ $expr = \implode('[^:]*:', \array_map('preg_quote', \explode(':', $namespace))) . '[^:]*';
+ $namespaces = \preg_grep('{^' . $expr . '}', $allNamespaces);
+ if (empty($namespaces)) {
+ $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace);
+ if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
+ if (1 == \count($alternatives)) {
+ $message .= "\n\nDid you mean this?\n ";
+ } else {
+ $message .= "\n\nDid you mean one of these?\n ";
+ }
+ $message .= \implode("\n ", $alternatives);
+ }
+ throw new NamespaceNotFoundException($message, $alternatives);
+ }
+ $exact = \in_array($namespace, $namespaces, \true);
+ if (\count($namespaces) > 1 && !$exact) {
+ throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(\array_values($namespaces))), \array_values($namespaces));
+ }
+ return $exact ? $namespace : \reset($namespaces);
+ }
+ /**
+ * Finds a command by name or alias.
+ *
+ * Contrary to get, this command tries to find the best
+ * match if you give it an abbreviation of a name or alias.
+ *
+ * @return Command
+ *
+ * @throws CommandNotFoundException When command name is incorrect or ambiguous
+ */
+ public function find(string $name)
+ {
+ $this->init();
+ $aliases = [];
+ foreach ($this->commands as $command) {
+ foreach ($command->getAliases() as $alias) {
+ if (!$this->has($alias)) {
+ $this->commands[$alias] = $command;
+ }
+ }
+ }
+ if ($this->has($name)) {
+ return $this->get($name);
+ }
+ $allCommands = $this->commandLoader ? \array_merge($this->commandLoader->getNames(), \array_keys($this->commands)) : \array_keys($this->commands);
+ $expr = \implode('[^:]*:', \array_map('preg_quote', \explode(':', $name))) . '[^:]*';
+ $commands = \preg_grep('{^' . $expr . '}', $allCommands);
+ if (empty($commands)) {
+ $commands = \preg_grep('{^' . $expr . '}i', $allCommands);
+ }
+ // if no commands matched or we just matched namespaces
+ if (empty($commands) || \count(\preg_grep('{^' . $expr . '$}i', $commands)) < 1) {
+ if (\false !== ($pos = \strrpos($name, ':'))) {
+ // check if a namespace exists and contains commands
+ $this->findNamespace(\substr($name, 0, $pos));
+ }
+ $message = \sprintf('Command "%s" is not defined.', $name);
+ if ($alternatives = $this->findAlternatives($name, $allCommands)) {
+ // remove hidden commands
+ $alternatives = \array_filter($alternatives, function ($name) {
+ return !$this->get($name)->isHidden();
+ });
+ if (1 == \count($alternatives)) {
+ $message .= "\n\nDid you mean this?\n ";
+ } else {
+ $message .= "\n\nDid you mean one of these?\n ";
+ }
+ $message .= \implode("\n ", $alternatives);
+ }
+ throw new CommandNotFoundException($message, \array_values($alternatives));
+ }
+ // filter out aliases for commands which are already on the list
+ if (\count($commands) > 1) {
+ $commandList = $this->commandLoader ? \array_merge(\array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
+ $commands = \array_unique(\array_filter($commands, function ($nameOrAlias) use(&$commandList, $commands, &$aliases) {
+ if (!$commandList[$nameOrAlias] instanceof Command) {
+ $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
+ }
+ $commandName = $commandList[$nameOrAlias]->getName();
+ $aliases[$nameOrAlias] = $commandName;
+ return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
+ }));
+ }
+ if (\count($commands) > 1) {
+ $usableWidth = $this->terminal->getWidth() - 10;
+ $abbrevs = \array_values($commands);
+ $maxLen = 0;
+ foreach ($abbrevs as $abbrev) {
+ $maxLen = \max(Helper::width($abbrev), $maxLen);
+ }
+ $abbrevs = \array_map(function ($cmd) use($commandList, $usableWidth, $maxLen, &$commands) {
+ if ($commandList[$cmd]->isHidden()) {
+ unset($commands[\array_search($cmd, $commands)]);
+ return \false;
+ }
+ $abbrev = \str_pad($cmd, $maxLen, ' ') . ' ' . $commandList[$cmd]->getDescription();
+ return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3) . '...' : $abbrev;
+ }, \array_values($commands));
+ if (\count($commands) > 1) {
+ $suggestions = $this->getAbbreviationSuggestions(\array_filter($abbrevs));
+ throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), \array_values($commands));
+ }
+ }
+ $command = $this->get(\reset($commands));
+ if ($command->isHidden()) {
+ throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name));
+ }
+ return $command;
+ }
+ /**
+ * Gets the commands (registered in the given namespace if provided).
+ *
+ * The array keys are the full names and the values the command instances.
+ *
+ * @return Command[]
+ */
+ public function all(string $namespace = null)
+ {
+ $this->init();
+ if (null === $namespace) {
+ if (!$this->commandLoader) {
+ return $this->commands;
+ }
+ $commands = $this->commands;
+ foreach ($this->commandLoader->getNames() as $name) {
+ if (!isset($commands[$name]) && $this->has($name)) {
+ $commands[$name] = $this->get($name);
+ }
+ }
+ return $commands;
+ }
+ $commands = [];
+ foreach ($this->commands as $name => $command) {
+ if ($namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1)) {
+ $commands[$name] = $command;
+ }
+ }
+ if ($this->commandLoader) {
+ foreach ($this->commandLoader->getNames() as $name) {
+ if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1) && $this->has($name)) {
+ $commands[$name] = $this->get($name);
+ }
+ }
+ }
+ return $commands;
+ }
+ /**
+ * Returns an array of possible abbreviations given a set of names.
+ *
+ * @return string[][]
+ */
+ public static function getAbbreviations(array $names) : array
+ {
+ $abbrevs = [];
+ foreach ($names as $name) {
+ for ($len = \strlen($name); $len > 0; --$len) {
+ $abbrev = \substr($name, 0, $len);
+ $abbrevs[$abbrev][] = $name;
+ }
+ }
+ return $abbrevs;
+ }
+ public function renderThrowable(\Throwable $e, OutputInterface $output) : void
+ {
+ $output->writeln('', OutputInterface::VERBOSITY_QUIET);
+ $this->doRenderThrowable($e, $output);
+ if (null !== $this->runningCommand) {
+ $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET);
+ $output->writeln('', OutputInterface::VERBOSITY_QUIET);
+ }
+ }
+ protected function doRenderThrowable(\Throwable $e, OutputInterface $output) : void
+ {
+ do {
+ $message = \trim($e->getMessage());
+ if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
+ $class = \get_debug_type($e);
+ $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' (' . $code . ')' : '');
+ $len = Helper::width($title);
+ } else {
+ $len = 0;
+ }
+ if (\strpos($message, "@anonymous\x00") !== \false) {
+ $message = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)[0-9a-fA-F]++/', function ($m) {
+ return \class_exists($m[0], \false) ? ((\get_parent_class($m[0]) ?: \key(\class_implements($m[0]))) ?: 'class') . '@anonymous' : $m[0];
+ }, $message);
+ }
+ $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX;
+ $lines = [];
+ foreach ('' !== $message ? \preg_split('/\\r?\\n/', $message) : [] as $line) {
+ foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
+ // pre-format lines to get the right string length
+ $lineLength = Helper::width($line) + 4;
+ $lines[] = [$line, $lineLength];
+ $len = \max($lineLength, $len);
+ }
+ }
+ $messages = [];
+ if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
+ $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', \basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a')));
+ }
+ $messages[] = $emptyLine = \sprintf('%s', \str_repeat(' ', $len));
+ if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
+ $messages[] = \sprintf('%s%s', $title, \str_repeat(' ', \max(0, $len - Helper::width($title))));
+ }
+ foreach ($lines as $line) {
+ $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), \str_repeat(' ', $len - $line[1]));
+ }
+ $messages[] = $emptyLine;
+ $messages[] = '';
+ $output->writeln($messages, OutputInterface::VERBOSITY_QUIET);
+ if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
+ $output->writeln('Exception trace:', OutputInterface::VERBOSITY_QUIET);
+ // exception related properties
+ $trace = $e->getTrace();
+ \array_unshift($trace, ['function' => '', 'file' => $e->getFile() ?: 'n/a', 'line' => $e->getLine() ?: 'n/a', 'args' => []]);
+ for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
+ $class = $trace[$i]['class'] ?? '';
+ $type = $trace[$i]['type'] ?? '';
+ $function = $trace[$i]['function'] ?? '';
+ $file = $trace[$i]['file'] ?? 'n/a';
+ $line = $trace[$i]['line'] ?? 'n/a';
+ $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type . $function . '()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET);
+ }
+ $output->writeln('', OutputInterface::VERBOSITY_QUIET);
+ }
+ } while ($e = $e->getPrevious());
+ }
+ /**
+ * Configures the input and output instances based on the user arguments and options.
+ *
+ * @return void
+ */
+ protected function configureIO(InputInterface $input, OutputInterface $output)
+ {
+ if (\true === $input->hasParameterOption(['--ansi'], \true)) {
+ $output->setDecorated(\true);
+ } elseif (\true === $input->hasParameterOption(['--no-ansi'], \true)) {
+ $output->setDecorated(\false);
+ }
+ if (\true === $input->hasParameterOption(['--no-interaction', '-n'], \true)) {
+ $input->setInteractive(\false);
+ }
+ switch ($shellVerbosity = (int) \getenv('SHELL_VERBOSITY')) {
+ case -1:
+ $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
+ break;
+ case 1:
+ $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
+ break;
+ case 2:
+ $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
+ break;
+ case 3:
+ $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
+ break;
+ default:
+ $shellVerbosity = 0;
+ break;
+ }
+ if (\true === $input->hasParameterOption(['--quiet', '-q'], \true)) {
+ $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
+ $shellVerbosity = -1;
+ } else {
+ if ($input->hasParameterOption('-vvv', \true) || $input->hasParameterOption('--verbose=3', \true) || 3 === $input->getParameterOption('--verbose', \false, \true)) {
+ $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
+ $shellVerbosity = 3;
+ } elseif ($input->hasParameterOption('-vv', \true) || $input->hasParameterOption('--verbose=2', \true) || 2 === $input->getParameterOption('--verbose', \false, \true)) {
+ $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
+ $shellVerbosity = 2;
+ } elseif ($input->hasParameterOption('-v', \true) || $input->hasParameterOption('--verbose=1', \true) || $input->hasParameterOption('--verbose', \true) || $input->getParameterOption('--verbose', \false, \true)) {
+ $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
+ $shellVerbosity = 1;
+ }
+ }
+ if (-1 === $shellVerbosity) {
+ $input->setInteractive(\false);
+ }
+ if (\function_exists('putenv')) {
+ @\putenv('SHELL_VERBOSITY=' . $shellVerbosity);
+ }
+ $_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
+ $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
+ }
+ /**
+ * Runs the current command.
+ *
+ * If an event dispatcher has been attached to the application,
+ * events are also dispatched during the life-cycle of the command.
+ *
+ * @return int 0 if everything went fine, or an error code
+ */
+ protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
+ {
+ foreach ($command->getHelperSet() as $helper) {
+ if ($helper instanceof InputAwareInterface) {
+ $helper->setInput($input);
+ }
+ }
+ $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : [];
+ if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) {
+ if (!$this->signalRegistry) {
+ throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
+ }
+ if (Terminal::hasSttyAvailable()) {
+ $sttyMode = \shell_exec('stty -g');
+ foreach ([\SIGINT, \SIGTERM] as $signal) {
+ $this->signalRegistry->register($signal, static function () use($sttyMode) {
+ return \shell_exec('stty ' . $sttyMode);
+ });
+ }
+ }
+ if ($this->dispatcher) {
+ // We register application signals, so that we can dispatch the event
+ foreach ($this->signalsToDispatchEvent as $signal) {
+ $event = new ConsoleSignalEvent($command, $input, $output, $signal);
+ $this->signalRegistry->register($signal, function ($signal) use($event, $command, $commandSignals) {
+ $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
+ $exitCode = $event->getExitCode();
+ // If the command is signalable, we call the handleSignal() method
+ if (\in_array($signal, $commandSignals, \true)) {
+ $exitCode = $command->handleSignal($signal, $exitCode);
+ // BC layer for Symfony <= 5
+ if (null === $exitCode) {
+ trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', \get_debug_type($command));
+ $exitCode = 0;
+ }
+ }
+ if (\false !== $exitCode) {
+ $event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal);
+ $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
+ exit($event->getExitCode());
+ }
+ });
+ }
+ // then we register command signals, but not if already handled after the dispatcher
+ $commandSignals = \array_diff($commandSignals, $this->signalsToDispatchEvent);
+ }
+ foreach ($commandSignals as $signal) {
+ $this->signalRegistry->register($signal, function (int $signal) use($command) : void {
+ $exitCode = $command->handleSignal($signal);
+ // BC layer for Symfony <= 5
+ if (null === $exitCode) {
+ trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', \get_debug_type($command));
+ $exitCode = 0;
+ }
+ if (\false !== $exitCode) {
+ exit($exitCode);
+ }
+ });
+ }
+ }
+ if (null === $this->dispatcher) {
+ return $command->run($input, $output);
+ }
+ // bind before the console.command event, so the listeners have access to input options/arguments
+ try {
+ $command->mergeApplicationDefinition();
+ $input->bind($command->getDefinition());
+ } catch (ExceptionInterface $exception) {
+ // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition
+ }
+ $event = new ConsoleCommandEvent($command, $input, $output);
+ $e = null;
+ try {
+ $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);
+ if ($event->commandShouldRun()) {
+ $exitCode = $command->run($input, $output);
+ } else {
+ $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
+ }
+ } catch (\Throwable $e) {
+ $event = new ConsoleErrorEvent($input, $output, $e, $command);
+ $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
+ $e = $event->getError();
+ if (0 === ($exitCode = $event->getExitCode())) {
+ $e = null;
+ }
+ }
+ $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
+ $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
+ if (null !== $e) {
+ throw $e;
+ }
+ return $event->getExitCode();
+ }
+ /**
+ * Gets the name of the command based on input.
+ */
+ protected function getCommandName(InputInterface $input) : ?string
+ {
+ return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument();
+ }
+ /**
+ * Gets the default input definition.
+ */
+ protected function getDefaultInputDefinition() : InputDefinition
+ {
+ return new InputDefinition([new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the ' . $this->defaultCommand . ' command'), new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null), new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question')]);
+ }
+ /**
+ * Gets the default commands that should always be available.
+ *
+ * @return Command[]
+ */
+ protected function getDefaultCommands() : array
+ {
+ return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()];
+ }
+ /**
+ * Gets the default helper set with the helpers that should always be available.
+ */
+ protected function getDefaultHelperSet() : HelperSet
+ {
+ return new HelperSet([new FormatterHelper(), new DebugFormatterHelper(), new ProcessHelper(), new QuestionHelper()]);
+ }
+ /**
+ * Returns abbreviated suggestions in string format.
+ */
+ private function getAbbreviationSuggestions(array $abbrevs) : string
+ {
+ return ' ' . \implode("\n ", $abbrevs);
+ }
+ /**
+ * Returns the namespace part of the command name.
+ *
+ * This method is not part of public API and should not be used directly.
+ */
+ public function extractNamespace(string $name, int $limit = null) : string
+ {
+ $parts = \explode(':', $name, -1);
+ return \implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
+ }
+ /**
+ * Finds alternative of $name among $collection,
+ * if nothing is found in $collection, try in $abbrevs.
+ *
+ * @return string[]
+ */
+ private function findAlternatives(string $name, iterable $collection) : array
+ {
+ $threshold = 1000.0;
+ $alternatives = [];
+ $collectionParts = [];
+ foreach ($collection as $item) {
+ $collectionParts[$item] = \explode(':', $item);
+ }
+ foreach (\explode(':', $name) as $i => $subname) {
+ foreach ($collectionParts as $collectionName => $parts) {
+ $exists = isset($alternatives[$collectionName]);
+ if (!isset($parts[$i]) && $exists) {
+ $alternatives[$collectionName] += $threshold;
+ continue;
+ } elseif (!isset($parts[$i])) {
+ continue;
+ }
+ $lev = \levenshtein($subname, $parts[$i]);
+ if ($lev <= \strlen($subname) / 3 || '' !== $subname && \strpos($parts[$i], $subname) !== \false) {
+ $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
+ } elseif ($exists) {
+ $alternatives[$collectionName] += $threshold;
+ }
+ }
+ }
+ foreach ($collection as $item) {
+ $lev = \levenshtein($name, $item);
+ if ($lev <= \strlen($name) / 3 || \strpos($item, $name) !== \false) {
+ $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
+ }
+ }
+ $alternatives = \array_filter($alternatives, function ($lev) use($threshold) {
+ return $lev < 2 * $threshold;
+ });
+ \ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE);
+ return \array_keys($alternatives);
+ }
+ /**
+ * Sets the default Command name.
+ *
+ * @return $this
+ */
+ public function setDefaultCommand(string $commandName, bool $isSingleCommand = \false)
+ {
+ $this->defaultCommand = \explode('|', \ltrim($commandName, '|'))[0];
+ if ($isSingleCommand) {
+ // Ensure the command exist
+ $this->find($commandName);
+ $this->singleCommand = \true;
+ }
+ return $this;
+ }
+ /**
+ * @internal
+ */
+ public function isSingleCommand() : bool
+ {
+ return $this->singleCommand;
+ }
+ private function splitStringByWidth(string $string, int $width) : array
+ {
+ // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.
+ // additionally, array_slice() is not enough as some character has doubled width.
+ // we need a function to split string not by character count but by string width
+ if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) {
+ return \str_split($string, $width);
+ }
+ $utf8String = \mb_convert_encoding($string, 'utf8', $encoding);
+ $lines = [];
+ $line = '';
+ $offset = 0;
+ while (\preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) {
+ $offset += \strlen($m[0]);
+ foreach (\preg_split('//u', $m[0]) as $char) {
+ // test if $char could be appended to current line
+ if (\mb_strwidth($line . $char, 'utf8') <= $width) {
+ $line .= $char;
+ continue;
+ }
+ // if not, push current line to array and make new line
+ $lines[] = \str_pad($line, $width);
+ $line = $char;
+ }
+ }
+ $lines[] = \count($lines) ? \str_pad($line, $width) : $line;
+ \mb_convert_variables($encoding, 'utf8', $lines);
+ return $lines;
+ }
+ /**
+ * Returns all namespaces of the command name.
+ *
+ * @return string[]
+ */
+ private function extractAllNamespaces(string $name) : array
+ {
+ // -1 as third argument is needed to skip the command short name when exploding
+ $parts = \explode(':', $name, -1);
+ $namespaces = [];
+ foreach ($parts as $part) {
+ if (\count($namespaces)) {
+ $namespaces[] = \end($namespaces) . ':' . $part;
+ } else {
+ $namespaces[] = $part;
+ }
+ }
+ return $namespaces;
+ }
+ private function init() : void
+ {
+ if ($this->initialized) {
+ return;
+ }
+ $this->initialized = \true;
+ foreach ($this->getDefaultCommands() as $command) {
+ $this->add($command);
+ }
+ }
+}
diff --git a/vendor/symfony/console/Attribute/AsCommand.php b/vendor/symfony/console/Attribute/AsCommand.php
new file mode 100644
index 0000000000..f3945c3e7e
--- /dev/null
+++ b/vendor/symfony/console/Attribute/AsCommand.php
@@ -0,0 +1,41 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Attribute;
+
+/**
+ * Service tag to autoconfigure commands.
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class AsCommand
+{
+ /**
+ * @var string
+ */
+ public $name;
+ /**
+ * @var string|null
+ */
+ public $description;
+ public function __construct(string $name, ?string $description = null, array $aliases = [], bool $hidden = \false)
+ {
+ $this->name = $name;
+ $this->description = $description;
+ if (!$hidden && !$aliases) {
+ return;
+ }
+ $name = \explode('|', $name);
+ $name = \array_merge($name, $aliases);
+ if ($hidden && '' !== $name[0]) {
+ \array_unshift($name, '');
+ }
+ $this->name = \implode('|', $name);
+ }
+}
diff --git a/vendor/symfony/console/CHANGELOG.md b/vendor/symfony/console/CHANGELOG.md
new file mode 100644
index 0000000000..9ccb41d945
--- /dev/null
+++ b/vendor/symfony/console/CHANGELOG.md
@@ -0,0 +1,261 @@
+CHANGELOG
+=========
+
+6.4
+---
+
+ * Add `SignalMap` to map signal value to its name
+ * Multi-line text in vertical tables is aligned properly
+ * The application can also catch errors with `Application::setCatchErrors(true)`
+ * Add `RunCommandMessage` and `RunCommandMessageHandler`
+ * Dispatch `ConsoleTerminateEvent` after an exit on signal handling and add `ConsoleTerminateEvent::getInterruptingSignal()`
+
+6.3
+---
+
+ * Add support for choosing exit code while handling signal, or to not exit at all
+ * Add `ProgressBar::setPlaceholderFormatter` to set a placeholder attached to a instance, instead of being global.
+ * Add `ReStructuredTextDescriptor`
+
+6.2
+---
+
+ * Improve truecolor terminal detection in some cases
+ * Add support for 256 color terminals (conversion from Ansi24 to Ansi8 if terminal is capable of it)
+ * Deprecate calling `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()`, `Question::setAutocompleterCallback/setValidator()`without any arguments
+ * Change the signature of `OutputFormatterStyleInterface::setForeground/setBackground()` to `setForeground/setBackground(?string)`
+ * Change the signature of `HelperInterface::setHelperSet()` to `setHelperSet(?HelperSet)`
+
+6.1
+---
+
+ * Add support to display table vertically when calling setVertical()
+ * Add method `__toString()` to `InputInterface`
+ * Added `OutputWrapper` to prevent truncated URL in `SymfonyStyle::createBlock`.
+ * Deprecate `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead
+ * Add suggested values for arguments and options in input definition, for input completion
+ * Add `$resumeAt` parameter to `ProgressBar#start()`, so that one can easily 'resume' progress on longer tasks, and still get accurate `getEstimate()` and `getRemaining()` results.
+
+6.0
+---
+
+ * `Command::setHidden()` has a default value (`true`) for `$hidden` parameter and is final
+ * Remove `Helper::strlen()`, use `Helper::width()` instead
+ * Remove `Helper::strlenWithoutDecoration()`, use `Helper::removeDecoration()` instead
+ * `AddConsoleCommandPass` can not be configured anymore
+ * Remove `HelperSet::setCommand()` and `getCommand()` without replacement
+
+5.4
+---
+
+ * Add `TesterTrait::assertCommandIsSuccessful()` to test command
+ * Deprecate `HelperSet::setCommand()` and `getCommand()` without replacement
+
+5.3
+---
+
+ * Add `GithubActionReporter` to render annotations in a Github Action
+ * Add `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options
+ * Add the `Command::$defaultDescription` static property and the `description` attribute
+ on the `console.command` tag to allow the `list` command to instantiate commands lazily
+ * Add option `--short` to the `list` command
+ * Add support for bright colors
+ * Add `#[AsCommand]` attribute for declaring commands on PHP 8
+ * Add `Helper::width()` and `Helper::length()`
+ * The `--ansi` and `--no-ansi` options now default to `null`.
+
+5.2.0
+-----
+
+ * Added `SingleCommandApplication::setAutoExit()` to allow testing via `CommandTester`
+ * added support for multiline responses to questions through `Question::setMultiline()`
+ and `Question::isMultiline()`
+ * Added `SignalRegistry` class to stack signals handlers
+ * Added support for signals:
+ * Added `Application::getSignalRegistry()` and `Application::setSignalsToDispatchEvent()` methods
+ * Added `SignalableCommandInterface` interface
+ * Added `TableCellStyle` class to customize table cell
+ * Removed `php ` prefix invocation from help messages.
+
+5.1.0
+-----
+
+ * `Command::setHidden()` is final since Symfony 5.1
+ * Add `SingleCommandApplication`
+ * Add `Cursor` class
+
+5.0.0
+-----
+
+ * removed support for finding hidden commands using an abbreviation, use the full name instead
+ * removed `TableStyle::setCrossingChar()` method in favor of `TableStyle::setDefaultCrossingChar()`
+ * removed `TableStyle::setHorizontalBorderChar()` method in favor of `TableStyle::setDefaultCrossingChars()`
+ * removed `TableStyle::getHorizontalBorderChar()` method in favor of `TableStyle::getBorderChars()`
+ * removed `TableStyle::setVerticalBorderChar()` method in favor of `TableStyle::setVerticalBorderChars()`
+ * removed `TableStyle::getVerticalBorderChar()` method in favor of `TableStyle::getBorderChars()`
+ * removed support for returning `null` from `Command::execute()`, return `0` instead
+ * `ProcessHelper::run()` accepts only `array|Symfony\Component\Process\Process` for its `command` argument
+ * `Application::setDispatcher` accepts only `Symfony\Contracts\EventDispatcher\EventDispatcherInterface`
+ for its `dispatcher` argument
+ * renamed `Application::renderException()` and `Application::doRenderException()`
+ to `renderThrowable()` and `doRenderThrowable()` respectively.
+
+4.4.0
+-----
+
+ * deprecated finding hidden commands using an abbreviation, use the full name instead
+ * added `Question::setTrimmable` default to true to allow the answer to be trimmed
+ * added method `minSecondsBetweenRedraws()` and `maxSecondsBetweenRedraws()` on `ProgressBar`
+ * `Application` implements `ResetInterface`
+ * marked all dispatched event classes as `@final`
+ * added support for displaying table horizontally
+ * deprecated returning `null` from `Command::execute()`, return `0` instead
+ * Deprecated the `Application::renderException()` and `Application::doRenderException()` methods,
+ use `renderThrowable()` and `doRenderThrowable()` instead.
+ * added support for the `NO_COLOR` env var (https://no-color.org/)
+
+4.3.0
+-----
+
+ * added support for hyperlinks
+ * added `ProgressBar::iterate()` method that simplify updating the progress bar when iterating
+ * added `Question::setAutocompleterCallback()` to provide a callback function
+ that dynamically generates suggestions as the user types
+
+4.2.0
+-----
+
+ * allowed passing commands as `[$process, 'ENV_VAR' => 'value']` to
+ `ProcessHelper::run()` to pass environment variables
+ * deprecated passing a command as a string to `ProcessHelper::run()`,
+ pass it the command as an array of its arguments instead
+ * made the `ProcessHelper` class final
+ * added `WrappableOutputFormatterInterface::formatAndWrap()` (implemented in `OutputFormatter`)
+ * added `capture_stderr_separately` option to `CommandTester::execute()`
+
+4.1.0
+-----
+
+ * added option to run suggested command if command is not found and only 1 alternative is available
+ * added option to modify console output and print multiple modifiable sections
+ * added support for iterable messages in output `write` and `writeln` methods
+
+4.0.0
+-----
+
+ * `OutputFormatter` throws an exception when unknown options are used
+ * removed `QuestionHelper::setInputStream()/getInputStream()`
+ * removed `Application::getTerminalWidth()/getTerminalHeight()` and
+ `Application::setTerminalDimensions()/getTerminalDimensions()`
+ * removed `ConsoleExceptionEvent`
+ * removed `ConsoleEvents::EXCEPTION`
+
+3.4.0
+-----
+
+ * added `SHELL_VERBOSITY` env var to control verbosity
+ * added `CommandLoaderInterface`, `FactoryCommandLoader` and PSR-11
+ `ContainerCommandLoader` for commands lazy-loading
+ * added a case-insensitive command name matching fallback
+ * added static `Command::$defaultName/getDefaultName()`, allowing for
+ commands to be registered at compile time in the application command loader.
+ Setting the `$defaultName` property avoids the need for filling the `command`
+ attribute on the `console.command` tag when using `AddConsoleCommandPass`.
+
+3.3.0
+-----
+
+ * added `ExceptionListener`
+ * added `AddConsoleCommandPass` (originally in FrameworkBundle)
+ * [BC BREAK] `Input::getOption()` no longer returns the default value for options
+ with value optional explicitly passed empty
+ * added console.error event to catch exceptions thrown by other listeners
+ * deprecated console.exception event in favor of console.error
+ * added ability to handle `CommandNotFoundException` through the
+ `console.error` event
+ * deprecated default validation in `SymfonyQuestionHelper::ask`
+
+3.2.0
+------
+
+ * added `setInputs()` method to CommandTester for ease testing of commands expecting inputs
+ * added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface)
+ * added StreamableInputInterface
+ * added LockableTrait
+
+3.1.0
+-----
+
+ * added truncate method to FormatterHelper
+ * added setColumnWidth(s) method to Table
+
+2.8.3
+-----
+
+ * remove readline support from the question helper as it caused issues
+
+2.8.0
+-----
+
+ * use readline for user input in the question helper when available to allow
+ the use of arrow keys
+
+2.6.0
+-----
+
+ * added a Process helper
+ * added a DebugFormatter helper
+
+2.5.0
+-----
+
+ * deprecated the dialog helper (use the question helper instead)
+ * deprecated TableHelper in favor of Table
+ * deprecated ProgressHelper in favor of ProgressBar
+ * added ConsoleLogger
+ * added a question helper
+ * added a way to set the process name of a command
+ * added a way to set a default command instead of `ListCommand`
+
+2.4.0
+-----
+
+ * added a way to force terminal dimensions
+ * added a convenient method to detect verbosity level
+ * [BC BREAK] made descriptors use output instead of returning a string
+
+2.3.0
+-----
+
+ * added multiselect support to the select dialog helper
+ * added Table Helper for tabular data rendering
+ * added support for events in `Application`
+ * added a way to normalize EOLs in `ApplicationTester::getDisplay()` and `CommandTester::getDisplay()`
+ * added a way to set the progress bar progress via the `setCurrent` method
+ * added support for multiple InputOption shortcuts, written as `'-a|-b|-c'`
+ * added two additional verbosity levels, VERBOSITY_VERY_VERBOSE and VERBOSITY_DEBUG
+
+2.2.0
+-----
+
+ * added support for colorization on Windows via ConEmu
+ * add a method to Dialog Helper to ask for a question and hide the response
+ * added support for interactive selections in console (DialogHelper::select())
+ * added support for autocompletion as you type in Dialog Helper
+
+2.1.0
+-----
+
+ * added ConsoleOutputInterface
+ * added the possibility to disable a command (Command::isEnabled())
+ * added suggestions when a command does not exist
+ * added a --raw option to the list command
+ * added support for STDERR in the console output class (errors are now sent
+ to STDERR)
+ * made the defaults (helper set, commands, input definition) in Application
+ more easily customizable
+ * added support for the shell even if readline is not available
+ * added support for process isolation in Symfony shell via
+ `--process-isolation` switch
+ * added support for `--`, which disables options parsing after that point
+ (tokens will be parsed as arguments)
diff --git a/vendor/symfony/console/CI/GithubActionReporter.php b/vendor/symfony/console/CI/GithubActionReporter.php
new file mode 100644
index 0000000000..e08ae4b389
--- /dev/null
+++ b/vendor/symfony/console/CI/GithubActionReporter.php
@@ -0,0 +1,79 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\CI;
+
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Utility class for Github actions.
+ *
+ * @author Maxime Steinhausser
+ */
+class GithubActionReporter
+{
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ private $output;
+ /**
+ * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85
+ */
+ private const ESCAPED_DATA = ['%' => '%25', "\r" => '%0D', "\n" => '%0A'];
+ /**
+ * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L87-L94
+ */
+ private const ESCAPED_PROPERTIES = ['%' => '%25', "\r" => '%0D', "\n" => '%0A', ':' => '%3A', ',' => '%2C'];
+ public function __construct(OutputInterface $output)
+ {
+ $this->output = $output;
+ }
+ public static function isGithubActionEnvironment() : bool
+ {
+ return \false !== \getenv('GITHUB_ACTIONS');
+ }
+ /**
+ * Output an error using the Github annotations format.
+ *
+ * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
+ */
+ public function error(string $message, string $file = null, int $line = null, int $col = null) : void
+ {
+ $this->log('error', $message, $file, $line, $col);
+ }
+ /**
+ * Output a warning using the Github annotations format.
+ *
+ * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message
+ */
+ public function warning(string $message, string $file = null, int $line = null, int $col = null) : void
+ {
+ $this->log('warning', $message, $file, $line, $col);
+ }
+ /**
+ * Output a debug log using the Github annotations format.
+ *
+ * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message
+ */
+ public function debug(string $message, string $file = null, int $line = null, int $col = null) : void
+ {
+ $this->log('debug', $message, $file, $line, $col);
+ }
+ private function log(string $type, string $message, string $file = null, int $line = null, int $col = null) : void
+ {
+ // Some values must be encoded.
+ $message = \strtr($message, self::ESCAPED_DATA);
+ if (!$file) {
+ // No file provided, output the message solely:
+ $this->output->writeln(\sprintf('::%s::%s', $type, $message));
+ return;
+ }
+ $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, \strtr($file, self::ESCAPED_PROPERTIES), \strtr($line ?? 1, self::ESCAPED_PROPERTIES), \strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message));
+ }
+}
diff --git a/vendor/symfony/console/Color.php b/vendor/symfony/console/Color.php
new file mode 100644
index 0000000000..a8e87ad595
--- /dev/null
+++ b/vendor/symfony/console/Color.php
@@ -0,0 +1,99 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+/**
+ * @author Fabien Potencier
+ */
+final class Color
+{
+ private const COLORS = ['black' => 0, 'red' => 1, 'green' => 2, 'yellow' => 3, 'blue' => 4, 'magenta' => 5, 'cyan' => 6, 'white' => 7, 'default' => 9];
+ private const BRIGHT_COLORS = ['gray' => 0, 'bright-red' => 1, 'bright-green' => 2, 'bright-yellow' => 3, 'bright-blue' => 4, 'bright-magenta' => 5, 'bright-cyan' => 6, 'bright-white' => 7];
+ private const AVAILABLE_OPTIONS = ['bold' => ['set' => 1, 'unset' => 22], 'underscore' => ['set' => 4, 'unset' => 24], 'blink' => ['set' => 5, 'unset' => 25], 'reverse' => ['set' => 7, 'unset' => 27], 'conceal' => ['set' => 8, 'unset' => 28]];
+ /**
+ * @var string
+ */
+ private $foreground;
+ /**
+ * @var string
+ */
+ private $background;
+ /**
+ * @var mixed[]
+ */
+ private $options = [];
+ public function __construct(string $foreground = '', string $background = '', array $options = [])
+ {
+ $this->foreground = $this->parseColor($foreground);
+ $this->background = $this->parseColor($background, \true);
+ foreach ($options as $option) {
+ if (!isset(self::AVAILABLE_OPTIONS[$option])) {
+ throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, \implode(', ', \array_keys(self::AVAILABLE_OPTIONS))));
+ }
+ $this->options[$option] = self::AVAILABLE_OPTIONS[$option];
+ }
+ }
+ public function apply(string $text) : string
+ {
+ return $this->set() . $text . $this->unset();
+ }
+ public function set() : string
+ {
+ $setCodes = [];
+ if ('' !== $this->foreground) {
+ $setCodes[] = $this->foreground;
+ }
+ if ('' !== $this->background) {
+ $setCodes[] = $this->background;
+ }
+ foreach ($this->options as $option) {
+ $setCodes[] = $option['set'];
+ }
+ if (0 === \count($setCodes)) {
+ return '';
+ }
+ return \sprintf("\x1b[%sm", \implode(';', $setCodes));
+ }
+ public function unset() : string
+ {
+ $unsetCodes = [];
+ if ('' !== $this->foreground) {
+ $unsetCodes[] = 39;
+ }
+ if ('' !== $this->background) {
+ $unsetCodes[] = 49;
+ }
+ foreach ($this->options as $option) {
+ $unsetCodes[] = $option['unset'];
+ }
+ if (0 === \count($unsetCodes)) {
+ return '';
+ }
+ return \sprintf("\x1b[%sm", \implode(';', $unsetCodes));
+ }
+ private function parseColor(string $color, bool $background = \false) : string
+ {
+ if ('' === $color) {
+ return '';
+ }
+ if ('#' === $color[0]) {
+ return ($background ? '4' : '3') . Terminal::getColorMode()->convertFromHexToAnsiColorCode($color);
+ }
+ if (isset(self::COLORS[$color])) {
+ return ($background ? '4' : '3') . self::COLORS[$color];
+ }
+ if (isset(self::BRIGHT_COLORS[$color])) {
+ return ($background ? '10' : '9') . self::BRIGHT_COLORS[$color];
+ }
+ throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, \implode(', ', \array_merge(\array_keys(self::COLORS), \array_keys(self::BRIGHT_COLORS)))));
+ }
+}
diff --git a/vendor/symfony/console/Command/Command.php b/vendor/symfony/console/Command/Command.php
new file mode 100644
index 0000000000..2bf5c60134
--- /dev/null
+++ b/vendor/symfony/console/Command/Command.php
@@ -0,0 +1,677 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Attribute\AsCommand;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionInput;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Completion\Suggestion;
+use EasyCI202401\Symfony\Component\Console\Exception\ExceptionInterface;
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\Console\Exception\LogicException;
+use EasyCI202401\Symfony\Component\Console\Helper\HelperInterface;
+use EasyCI202401\Symfony\Component\Console\Helper\HelperSet;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Base class for all commands.
+ *
+ * @author Fabien Potencier
+ */
+class Command
+{
+ // see https://tldp.org/LDP/abs/html/exitcodes.html
+ public const SUCCESS = 0;
+ public const FAILURE = 1;
+ public const INVALID = 2;
+ /**
+ * @var string|null The default command name
+ *
+ * @deprecated since Symfony 6.1, use the AsCommand attribute instead
+ */
+ protected static $defaultName;
+ /**
+ * @var string|null The default command description
+ *
+ * @deprecated since Symfony 6.1, use the AsCommand attribute instead
+ */
+ protected static $defaultDescription;
+ /**
+ * @var \Symfony\Component\Console\Application|null
+ */
+ private $application;
+ /**
+ * @var string|null
+ */
+ private $name;
+ /**
+ * @var string|null
+ */
+ private $processTitle;
+ /**
+ * @var mixed[]
+ */
+ private $aliases = [];
+ /**
+ * @var \Symfony\Component\Console\Input\InputDefinition
+ */
+ private $definition;
+ /**
+ * @var bool
+ */
+ private $hidden = \false;
+ /**
+ * @var string
+ */
+ private $help = '';
+ /**
+ * @var string
+ */
+ private $description = '';
+ /**
+ * @var \Symfony\Component\Console\Input\InputDefinition|null
+ */
+ private $fullDefinition;
+ /**
+ * @var bool
+ */
+ private $ignoreValidationErrors = \false;
+ /**
+ * @var \Closure|null
+ */
+ private $code;
+ /**
+ * @var mixed[]
+ */
+ private $synopsis = [];
+ /**
+ * @var mixed[]
+ */
+ private $usages = [];
+ /**
+ * @var \Symfony\Component\Console\Helper\HelperSet|null
+ */
+ private $helperSet;
+ public static function getDefaultName() : ?string
+ {
+ $class = static::class;
+ if ($attribute = \method_exists(new \ReflectionClass($class), 'getAttributes') ? (new \ReflectionClass($class))->getAttributes(AsCommand::class) : []) {
+ return $attribute[0]->newInstance()->name;
+ }
+ $r = new \ReflectionProperty($class, 'defaultName');
+ $r->setAccessible(\true);
+ if ($class !== $r->class || null === static::$defaultName) {
+ return null;
+ }
+ trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class);
+ return static::$defaultName;
+ }
+ public static function getDefaultDescription() : ?string
+ {
+ $class = static::class;
+ if ($attribute = \method_exists(new \ReflectionClass($class), 'getAttributes') ? (new \ReflectionClass($class))->getAttributes(AsCommand::class) : []) {
+ return $attribute[0]->newInstance()->description;
+ }
+ $r = new \ReflectionProperty($class, 'defaultDescription');
+ $r->setAccessible(\true);
+ if ($class !== $r->class || null === static::$defaultDescription) {
+ return null;
+ }
+ trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class);
+ return static::$defaultDescription;
+ }
+ /**
+ * @param string|null $name The name of the command; passing null means it must be set in configure()
+ *
+ * @throws LogicException When the command name is empty
+ */
+ public function __construct(string $name = null)
+ {
+ $this->definition = new InputDefinition();
+ if (null === $name && null !== ($name = static::getDefaultName())) {
+ $aliases = \explode('|', $name);
+ if ('' === ($name = \array_shift($aliases))) {
+ $this->setHidden(\true);
+ $name = \array_shift($aliases);
+ }
+ $this->setAliases($aliases);
+ }
+ if (null !== $name) {
+ $this->setName($name);
+ }
+ if ('' === $this->description) {
+ $this->setDescription(static::getDefaultDescription() ?? '');
+ }
+ $this->configure();
+ }
+ /**
+ * Ignores validation errors.
+ *
+ * This is mainly useful for the help command.
+ *
+ * @return void
+ */
+ public function ignoreValidationErrors()
+ {
+ $this->ignoreValidationErrors = \true;
+ }
+ /**
+ * @return void
+ */
+ public function setApplication(Application $application = null)
+ {
+ if (1 > \func_num_args()) {
+ trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
+ }
+ $this->application = $application;
+ if ($application) {
+ $this->setHelperSet($application->getHelperSet());
+ } else {
+ $this->helperSet = null;
+ }
+ $this->fullDefinition = null;
+ }
+ /**
+ * @return void
+ */
+ public function setHelperSet(HelperSet $helperSet)
+ {
+ $this->helperSet = $helperSet;
+ }
+ /**
+ * Gets the helper set.
+ */
+ public function getHelperSet() : ?HelperSet
+ {
+ return $this->helperSet;
+ }
+ /**
+ * Gets the application instance for this command.
+ */
+ public function getApplication() : ?Application
+ {
+ return $this->application;
+ }
+ /**
+ * Checks whether the command is enabled or not in the current environment.
+ *
+ * Override this to check for x or y and return false if the command cannot
+ * run properly under the current conditions.
+ *
+ * @return bool
+ */
+ public function isEnabled()
+ {
+ return \true;
+ }
+ /**
+ * Configures the current command.
+ *
+ * @return void
+ */
+ protected function configure()
+ {
+ }
+ /**
+ * Executes the current command.
+ *
+ * This method is not abstract because you can use this class
+ * as a concrete class. In this case, instead of defining the
+ * execute() method, you set the code to execute by passing
+ * a Closure to the setCode() method.
+ *
+ * @return int 0 if everything went fine, or an exit code
+ *
+ * @throws LogicException When this abstract method is not implemented
+ *
+ * @see setCode()
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ throw new LogicException('You must override the execute() method in the concrete command class.');
+ }
+ /**
+ * Interacts with the user.
+ *
+ * This method is executed before the InputDefinition is validated.
+ * This means that this is the only place where the command can
+ * interactively ask for values of missing required arguments.
+ *
+ * @return void
+ */
+ protected function interact(InputInterface $input, OutputInterface $output)
+ {
+ }
+ /**
+ * Initializes the command after the input has been bound and before the input
+ * is validated.
+ *
+ * This is mainly useful when a lot of commands extends one main command
+ * where some things need to be initialized based on the input arguments and options.
+ *
+ * @see InputInterface::bind()
+ * @see InputInterface::validate()
+ *
+ * @return void
+ */
+ protected function initialize(InputInterface $input, OutputInterface $output)
+ {
+ }
+ /**
+ * Runs the command.
+ *
+ * The code to execute is either defined directly with the
+ * setCode() method or by overriding the execute() method
+ * in a sub-class.
+ *
+ * @return int The command exit code
+ *
+ * @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}.
+ *
+ * @see setCode()
+ * @see execute()
+ */
+ public function run(InputInterface $input, OutputInterface $output) : int
+ {
+ // add the application arguments and options
+ $this->mergeApplicationDefinition();
+ // bind the input against the command specific arguments/options
+ try {
+ $input->bind($this->getDefinition());
+ } catch (ExceptionInterface $e) {
+ if (!$this->ignoreValidationErrors) {
+ throw $e;
+ }
+ }
+ $this->initialize($input, $output);
+ if (null !== $this->processTitle) {
+ if (\function_exists('cli_set_process_title')) {
+ if (!@\cli_set_process_title($this->processTitle)) {
+ if ('Darwin' === \PHP_OS) {
+ $output->writeln('Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.', OutputInterface::VERBOSITY_VERY_VERBOSE);
+ } else {
+ \cli_set_process_title($this->processTitle);
+ }
+ }
+ } elseif (\function_exists('setproctitle')) {
+ \setproctitle($this->processTitle);
+ } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
+ $output->writeln('Install the proctitle PECL to be able to change the process title.');
+ }
+ }
+ if ($input->isInteractive()) {
+ $this->interact($input, $output);
+ }
+ // The command name argument is often omitted when a command is executed directly with its run() method.
+ // It would fail the validation if we didn't make sure the command argument is present,
+ // since it's required by the application.
+ if ($input->hasArgument('command') && null === $input->getArgument('command')) {
+ $input->setArgument('command', $this->getName());
+ }
+ $input->validate();
+ if ($this->code) {
+ $statusCode = ($this->code)($input, $output);
+ } else {
+ $statusCode = $this->execute($input, $output);
+ if (!\is_int($statusCode)) {
+ throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, \get_debug_type($statusCode)));
+ }
+ }
+ return \is_numeric($statusCode) ? (int) $statusCode : 0;
+ }
+ /**
+ * Adds suggestions to $suggestions for the current completion input (e.g. option or argument).
+ */
+ public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void
+ {
+ $definition = $this->getDefinition();
+ if (CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType() && $definition->hasOption($input->getCompletionName())) {
+ $definition->getOption($input->getCompletionName())->complete($input, $suggestions);
+ } elseif (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && $definition->hasArgument($input->getCompletionName())) {
+ $definition->getArgument($input->getCompletionName())->complete($input, $suggestions);
+ }
+ }
+ /**
+ * Sets the code to execute when running this command.
+ *
+ * If this method is used, it overrides the code defined
+ * in the execute() method.
+ *
+ * @param callable $code A callable(InputInterface $input, OutputInterface $output)
+ *
+ * @return $this
+ *
+ * @throws InvalidArgumentException
+ *
+ * @see execute()
+ */
+ public function setCode(callable $code)
+ {
+ if ($code instanceof \Closure) {
+ $r = new \ReflectionFunction($code);
+ if (null === $r->getClosureThis()) {
+ \set_error_handler(static function () {
+ });
+ try {
+ if ($c = \Closure::bind($code, $this)) {
+ $code = $c;
+ }
+ } finally {
+ \restore_error_handler();
+ }
+ }
+ } else {
+ $code = \Closure::fromCallable($code);
+ }
+ $this->code = $code;
+ return $this;
+ }
+ /**
+ * Merges the application definition with the command definition.
+ *
+ * This method is not part of public API and should not be used directly.
+ *
+ * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments
+ *
+ * @internal
+ */
+ public function mergeApplicationDefinition(bool $mergeArgs = \true) : void
+ {
+ if (null === $this->application) {
+ return;
+ }
+ $this->fullDefinition = new InputDefinition();
+ $this->fullDefinition->setOptions($this->definition->getOptions());
+ $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions());
+ if ($mergeArgs) {
+ $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments());
+ $this->fullDefinition->addArguments($this->definition->getArguments());
+ } else {
+ $this->fullDefinition->setArguments($this->definition->getArguments());
+ }
+ }
+ /**
+ * Sets an array of argument and option instances.
+ *
+ * @return $this
+ * @param mixed[]|\Symfony\Component\Console\Input\InputDefinition $definition
+ */
+ public function setDefinition($definition)
+ {
+ if ($definition instanceof InputDefinition) {
+ $this->definition = $definition;
+ } else {
+ $this->definition->setDefinition($definition);
+ }
+ $this->fullDefinition = null;
+ return $this;
+ }
+ /**
+ * Gets the InputDefinition attached to this Command.
+ */
+ public function getDefinition() : InputDefinition
+ {
+ return $this->fullDefinition ?? $this->getNativeDefinition();
+ }
+ /**
+ * Gets the InputDefinition to be used to create representations of this Command.
+ *
+ * Can be overridden to provide the original command representation when it would otherwise
+ * be changed by merging with the application InputDefinition.
+ *
+ * This method is not part of public API and should not be used directly.
+ */
+ public function getNativeDefinition() : InputDefinition
+ {
+ if (!isset($this->definition)) {
+ throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
+ }
+ return $this->definition;
+ }
+ /**
+ * Adds an argument.
+ *
+ * @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
+ * @param $default The default value (for InputArgument::OPTIONAL mode only)
+ * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
+ *
+ * @return $this
+ *
+ * @throws InvalidArgumentException When argument mode is not valid
+ * @param mixed $default
+ */
+ public function addArgument(string $name, int $mode = null, string $description = '', $default = null)
+ {
+ $suggestedValues = 5 <= \func_num_args() ? \func_get_arg(4) : [];
+ if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) {
+ throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \\Closure, "%s" given.', __METHOD__, \get_debug_type($suggestedValues)));
+ }
+ $this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues));
+ ($nullsafeVariable1 = $this->fullDefinition) ? $nullsafeVariable1->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)) : null;
+ return $this;
+ }
+ /**
+ * Adds an option.
+ *
+ * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
+ * @param $mode The option mode: One of the InputOption::VALUE_* constants
+ * @param $default The default value (must be null for InputOption::VALUE_NONE)
+ * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
+ *
+ * @return $this
+ *
+ * @throws InvalidArgumentException If option mode is invalid or incompatible
+ * @param string|mixed[] $shortcut
+ * @param mixed $default
+ */
+ public function addOption(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null)
+ {
+ $suggestedValues = 6 <= \func_num_args() ? \func_get_arg(5) : [];
+ if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) {
+ throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \\Closure, "%s" given.', __METHOD__, \get_debug_type($suggestedValues)));
+ }
+ $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues));
+ ($nullsafeVariable2 = $this->fullDefinition) ? $nullsafeVariable2->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)) : null;
+ return $this;
+ }
+ /**
+ * Sets the name of the command.
+ *
+ * This method can set both the namespace and the name if
+ * you separate them by a colon (:)
+ *
+ * $command->setName('foo:bar');
+ *
+ * @return $this
+ *
+ * @throws InvalidArgumentException When the name is invalid
+ */
+ public function setName(string $name)
+ {
+ $this->validateName($name);
+ $this->name = $name;
+ return $this;
+ }
+ /**
+ * Sets the process title of the command.
+ *
+ * This feature should be used only when creating a long process command,
+ * like a daemon.
+ *
+ * @return $this
+ */
+ public function setProcessTitle(string $title)
+ {
+ $this->processTitle = $title;
+ return $this;
+ }
+ /**
+ * Returns the command name.
+ */
+ public function getName() : ?string
+ {
+ return $this->name;
+ }
+ /**
+ * @param bool $hidden Whether or not the command should be hidden from the list of commands
+ *
+ * @return $this
+ */
+ public function setHidden(bool $hidden = \true)
+ {
+ $this->hidden = $hidden;
+ return $this;
+ }
+ /**
+ * @return bool whether the command should be publicly shown or not
+ */
+ public function isHidden() : bool
+ {
+ return $this->hidden;
+ }
+ /**
+ * Sets the description for the command.
+ *
+ * @return $this
+ */
+ public function setDescription(string $description)
+ {
+ $this->description = $description;
+ return $this;
+ }
+ /**
+ * Returns the description for the command.
+ */
+ public function getDescription() : string
+ {
+ return $this->description;
+ }
+ /**
+ * Sets the help for the command.
+ *
+ * @return $this
+ */
+ public function setHelp(string $help)
+ {
+ $this->help = $help;
+ return $this;
+ }
+ /**
+ * Returns the help for the command.
+ */
+ public function getHelp() : string
+ {
+ return $this->help;
+ }
+ /**
+ * Returns the processed help for the command replacing the %command.name% and
+ * %command.full_name% patterns with the real values dynamically.
+ */
+ public function getProcessedHelp() : string
+ {
+ $name = $this->name;
+ $isSingleCommand = ($nullsafeVariable3 = $this->application) ? $nullsafeVariable3->isSingleCommand() : null;
+ $placeholders = ['%command.name%', '%command.full_name%'];
+ $replacements = [$name, $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'] . ' ' . $name];
+ return \str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
+ }
+ /**
+ * Sets the aliases for the command.
+ *
+ * @param string[] $aliases An array of aliases for the command
+ *
+ * @return $this
+ *
+ * @throws InvalidArgumentException When an alias is invalid
+ */
+ public function setAliases(iterable $aliases)
+ {
+ $list = [];
+ foreach ($aliases as $alias) {
+ $this->validateName($alias);
+ $list[] = $alias;
+ }
+ $this->aliases = \is_array($aliases) ? $aliases : $list;
+ return $this;
+ }
+ /**
+ * Returns the aliases for the command.
+ */
+ public function getAliases() : array
+ {
+ return $this->aliases;
+ }
+ /**
+ * Returns the synopsis for the command.
+ *
+ * @param bool $short Whether to show the short version of the synopsis (with options folded) or not
+ */
+ public function getSynopsis(bool $short = \false) : string
+ {
+ $key = $short ? 'short' : 'long';
+ if (!isset($this->synopsis[$key])) {
+ $this->synopsis[$key] = \trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
+ }
+ return $this->synopsis[$key];
+ }
+ /**
+ * Add a command usage example, it'll be prefixed with the command name.
+ *
+ * @return $this
+ */
+ public function addUsage(string $usage)
+ {
+ if (\strncmp($usage, $this->name, \strlen($this->name)) !== 0) {
+ $usage = \sprintf('%s %s', $this->name, $usage);
+ }
+ $this->usages[] = $usage;
+ return $this;
+ }
+ /**
+ * Returns alternative usages of the command.
+ */
+ public function getUsages() : array
+ {
+ return $this->usages;
+ }
+ /**
+ * Gets a helper instance by name.
+ *
+ * @return HelperInterface
+ *
+ * @throws LogicException if no HelperSet is defined
+ * @throws InvalidArgumentException if the helper is not defined
+ */
+ public function getHelper(string $name)
+ {
+ if (null === $this->helperSet) {
+ throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
+ }
+ return $this->helperSet->get($name);
+ }
+ /**
+ * Validates a command name.
+ *
+ * It must be non-empty and parts can optionally be separated by ":".
+ *
+ * @throws InvalidArgumentException When the name is invalid
+ */
+ private function validateName(string $name) : void
+ {
+ if (!\preg_match('/^[^\\:]++(\\:[^\\:]++)*$/', $name)) {
+ throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name));
+ }
+ }
+}
diff --git a/vendor/symfony/console/Command/CompleteCommand.php b/vendor/symfony/console/Command/CompleteCommand.php
new file mode 100644
index 0000000000..c647472db0
--- /dev/null
+++ b/vendor/symfony/console/Command/CompleteCommand.php
@@ -0,0 +1,164 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+use EasyCI202401\Symfony\Component\Console\Attribute\AsCommand;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionInput;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Completion\Output\BashCompletionOutput;
+use EasyCI202401\Symfony\Component\Console\Completion\Output\CompletionOutputInterface;
+use EasyCI202401\Symfony\Component\Console\Completion\Output\FishCompletionOutput;
+use EasyCI202401\Symfony\Component\Console\Completion\Output\ZshCompletionOutput;
+use EasyCI202401\Symfony\Component\Console\Exception\CommandNotFoundException;
+use EasyCI202401\Symfony\Component\Console\Exception\ExceptionInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Responsible for providing the values to the shell completion.
+ *
+ * @author Wouter de Jong
+ */
+final class CompleteCommand extends Command
+{
+ public const COMPLETION_API_VERSION = '1';
+ /**
+ * @deprecated since Symfony 6.1
+ */
+ protected static $defaultName = '|_complete';
+ /**
+ * @deprecated since Symfony 6.1
+ */
+ protected static $defaultDescription = 'Internal command to provide shell completion suggestions';
+ /**
+ * @var mixed[]
+ */
+ private $completionOutputs;
+ /**
+ * @var bool
+ */
+ private $isDebug = \false;
+ /**
+ * @param array> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value
+ */
+ public function __construct(array $completionOutputs = [])
+ {
+ // must be set before the parent constructor, as the property value is used in configure()
+ $this->completionOutputs = $completionOutputs + ['bash' => BashCompletionOutput::class, 'fish' => FishCompletionOutput::class, 'zsh' => ZshCompletionOutput::class];
+ parent::__construct();
+ }
+ protected function configure() : void
+ {
+ $this->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("' . \implode('", "', \array_keys($this->completionOutputs)) . '")')->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)')->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)')->addOption('api-version', 'a', InputOption::VALUE_REQUIRED, 'The API version of the completion script')->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'deprecated');
+ }
+ protected function initialize(InputInterface $input, OutputInterface $output) : void
+ {
+ $this->isDebug = \filter_var(\getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOL);
+ }
+ protected function execute(InputInterface $input, OutputInterface $output) : int
+ {
+ try {
+ // "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1
+ $version = $input->getOption('symfony') ? '1' : $input->getOption('api-version');
+ if ($version && \version_compare($version, self::COMPLETION_API_VERSION, '<')) {
+ $message = \sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION);
+ $this->log($message);
+ $output->writeln($message . ' Install the Symfony completion script again by using the "completion" command.');
+ return 126;
+ }
+ $shell = $input->getOption('shell');
+ if (!$shell) {
+ throw new \RuntimeException('The "--shell" option must be set.');
+ }
+ if (!($completionOutput = $this->completionOutputs[$shell] ?? \false)) {
+ throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, \implode('", "', \array_keys($this->completionOutputs))));
+ }
+ $completionInput = $this->createCompletionInput($input);
+ $suggestions = new CompletionSuggestions();
+ $this->log(['', '' . \date('Y-m-d H:i:s') . '>', 'Input:> ("|" indicates the cursor position)>', ' ' . (string) $completionInput, 'Command:>', ' ' . (string) \implode(' ', $_SERVER['argv']), 'Messages:>']);
+ $command = $this->findCommand($completionInput, $output);
+ if (null === $command) {
+ $this->log(' No command found, completing using the Application class.');
+ $this->getApplication()->complete($completionInput, $suggestions);
+ } elseif ($completionInput->mustSuggestArgumentValuesFor('command') && $command->getName() !== $completionInput->getCompletionValue() && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), \true)) {
+ $this->log(' No command found, completing using the Application class.');
+ // expand shortcut names ("cache:cl") into their full name ("cache:clear")
+ $suggestions->suggestValues(\array_filter(\array_merge([$command->getName()], $command->getAliases())));
+ } else {
+ $command->mergeApplicationDefinition();
+ $completionInput->bind($command->getDefinition());
+ if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) {
+ $this->log(' Completing option names for the ' . \get_class($command instanceof LazyCommand ? $command->getCommand() : $command) . '> command.');
+ $suggestions->suggestOptions($command->getDefinition()->getOptions());
+ } else {
+ $this->log([' Completing using the ' . \get_class($command instanceof LazyCommand ? $command->getCommand() : $command) . '> class.', ' Completing ' . $completionInput->getCompletionType() . '> for ' . $completionInput->getCompletionName() . '>']);
+ if (null !== ($compval = $completionInput->getCompletionValue())) {
+ $this->log(' Current value: ' . $compval . '>');
+ }
+ $command->complete($completionInput, $suggestions);
+ }
+ }
+ /** @var CompletionOutputInterface $completionOutput */
+ $completionOutput = new $completionOutput();
+ $this->log('Suggestions:>');
+ if ($options = $suggestions->getOptionSuggestions()) {
+ $this->log(' --' . \implode(' --', \array_map(function ($o) {
+ return $o->getName();
+ }, $options)));
+ } elseif ($values = $suggestions->getValueSuggestions()) {
+ $this->log(' ' . \implode(' ', $values));
+ } else {
+ $this->log(' No suggestions were provided>');
+ }
+ $completionOutput->write($suggestions, $output);
+ } catch (\Throwable $e) {
+ $this->log(['Error!', (string) $e]);
+ if ($output->isDebug()) {
+ throw $e;
+ }
+ return 2;
+ }
+ return 0;
+ }
+ private function createCompletionInput(InputInterface $input) : CompletionInput
+ {
+ $currentIndex = $input->getOption('current');
+ if (!$currentIndex || !\ctype_digit($currentIndex)) {
+ throw new \RuntimeException('The "--current" option must be set and it must be an integer.');
+ }
+ $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex);
+ try {
+ $completionInput->bind($this->getApplication()->getDefinition());
+ } catch (ExceptionInterface $exception) {
+ }
+ return $completionInput;
+ }
+ private function findCommand(CompletionInput $completionInput, OutputInterface $output) : ?Command
+ {
+ try {
+ $inputName = $completionInput->getFirstArgument();
+ if (null === $inputName) {
+ return null;
+ }
+ return $this->getApplication()->find($inputName);
+ } catch (CommandNotFoundException $exception) {
+ }
+ return null;
+ }
+ private function log($messages) : void
+ {
+ if (!$this->isDebug) {
+ return;
+ }
+ $commandName = \basename($_SERVER['argv'][0]);
+ \file_put_contents(\sys_get_temp_dir() . '/sf_' . $commandName . '.log', \implode(\PHP_EOL, (array) $messages) . \PHP_EOL, \FILE_APPEND);
+ }
+}
diff --git a/vendor/symfony/console/Command/DumpCompletionCommand.php b/vendor/symfony/console/Command/DumpCompletionCommand.php
new file mode 100644
index 0000000000..0342ebaa84
--- /dev/null
+++ b/vendor/symfony/console/Command/DumpCompletionCommand.php
@@ -0,0 +1,143 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+use EasyCI202401\Symfony\Component\Console\Attribute\AsCommand;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleOutputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\Process\Process;
+/**
+ * Dumps the completion script for the current shell.
+ *
+ * @author Wouter de Jong
+ */
+final class DumpCompletionCommand extends Command
+{
+ /**
+ * @deprecated since Symfony 6.1
+ */
+ protected static $defaultName = 'completion';
+ /**
+ * @deprecated since Symfony 6.1
+ */
+ protected static $defaultDescription = 'Dump the shell completion script';
+ /**
+ * @var mixed[]
+ */
+ private $supportedShells;
+ protected function configure() : void
+ {
+ $fullCommand = $_SERVER['PHP_SELF'];
+ $commandName = \basename($fullCommand);
+ $fullCommand = @\realpath($fullCommand) ?: $fullCommand;
+ $shell = $this->guessShell();
+ switch ($shell) {
+ case 'fish':
+ [$rcFile, $completionFile] = ['~/.config/fish/config.fish', "/etc/fish/completions/{$commandName}.fish"];
+ break;
+ case 'zsh':
+ [$rcFile, $completionFile] = ['~/.zshrc', '$fpath[1]/_' . $commandName];
+ break;
+ default:
+ [$rcFile, $completionFile] = ['~/.bashrc', "/etc/bash_completion.d/{$commandName}"];
+ break;
+ }
+ $supportedShells = \implode(', ', $this->getSupportedShells());
+ $this->setHelp(<<%command.name%> command dumps the shell completion script required
+to use shell autocompletion (currently, {$supportedShells} completion are supported).
+
+Static installation
+------------------->
+
+Dump the script to a global completion file and restart your shell:
+
+ %command.full_name% {$shell} | sudo tee {$completionFile}>
+
+Or dump the script to a local file and source it:
+
+ %command.full_name% {$shell} > completion.sh>
+
+ # source the file whenever you use the project>
+ source completion.sh>
+
+ # or add this line at the end of your "{$rcFile}" file:>
+ source /path/to/completion.sh>
+
+Dynamic installation
+-------------------->
+
+Add this to the end of your shell configuration file (e.g. "{$rcFile}">):
+
+ eval "\$({$fullCommand} completion {$shell})">
+EOH
+)->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given', null, \Closure::fromCallable([$this, 'getSupportedShells']))->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log');
+ }
+ protected function execute(InputInterface $input, OutputInterface $output) : int
+ {
+ $commandName = \basename($_SERVER['argv'][0]);
+ if ($input->getOption('debug')) {
+ $this->tailDebugLog($commandName, $output);
+ return 0;
+ }
+ $shell = $input->getArgument('shell') ?? self::guessShell();
+ $completionFile = __DIR__ . '/../Resources/completion.' . $shell;
+ if (!\file_exists($completionFile)) {
+ $supportedShells = $this->getSupportedShells();
+ if ($output instanceof ConsoleOutputInterface) {
+ $output = $output->getErrorOutput();
+ }
+ if ($shell) {
+ $output->writeln(\sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").>', $shell, \implode('", "', $supportedShells)));
+ } else {
+ $output->writeln(\sprintf('Shell not detected, Symfony shell completion only supports "%s").>', \implode('", "', $supportedShells)));
+ }
+ return 2;
+ }
+ $output->write(\str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, CompleteCommand::COMPLETION_API_VERSION], \file_get_contents($completionFile)));
+ return 0;
+ }
+ private static function guessShell() : string
+ {
+ return \basename($_SERVER['SHELL'] ?? '');
+ }
+ private function tailDebugLog(string $commandName, OutputInterface $output) : void
+ {
+ $debugFile = \sys_get_temp_dir() . '/sf_' . $commandName . '.log';
+ if (!\file_exists($debugFile)) {
+ \touch($debugFile);
+ }
+ $process = new Process(['tail', '-f', $debugFile], null, null, null, 0);
+ $process->run(function (string $type, string $line) use($output) : void {
+ $output->write($line);
+ });
+ }
+ /**
+ * @return string[]
+ */
+ private function getSupportedShells() : array
+ {
+ if (isset($this->supportedShells)) {
+ return $this->supportedShells;
+ }
+ $shells = [];
+ foreach (new \DirectoryIterator(__DIR__ . '/../Resources/') as $file) {
+ if (\strncmp($file->getBasename(), 'completion.', \strlen('completion.')) === 0 && $file->isFile()) {
+ $shells[] = $file->getExtension();
+ }
+ }
+ \sort($shells);
+ return $this->supportedShells = $shells;
+ }
+}
diff --git a/vendor/symfony/console/Command/HelpCommand.php b/vendor/symfony/console/Command/HelpCommand.php
new file mode 100644
index 0000000000..b662d94b5e
--- /dev/null
+++ b/vendor/symfony/console/Command/HelpCommand.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+use EasyCI202401\Symfony\Component\Console\Descriptor\ApplicationDescription;
+use EasyCI202401\Symfony\Component\Console\Helper\DescriptorHelper;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * HelpCommand displays the help for a given command.
+ *
+ * @author Fabien Potencier
+ */
+class HelpCommand extends Command
+{
+ /**
+ * @var \Symfony\Component\Console\Command\Command
+ */
+ private $command;
+ /**
+ * @return void
+ */
+ protected function configure()
+ {
+ $this->ignoreValidationErrors();
+ $this->setName('help')->setDefinition([new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', function () {
+ return \array_keys((new ApplicationDescription($this->getApplication()))->getCommands());
+ }), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () {
+ return (new DescriptorHelper())->getFormats();
+ }), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help')])->setDescription('Display help for a command')->setHelp(<<<'EOF'
+The %command.name% command displays help for a given command:
+
+ %command.full_name% list
+
+You can also output the help in other formats by using the --format option:
+
+ %command.full_name% --format=xml list
+
+To display the list of available commands, please use the list command.
+EOF
+);
+ }
+ /**
+ * @return void
+ */
+ public function setCommand(Command $command)
+ {
+ $this->command = $command;
+ }
+ protected function execute(InputInterface $input, OutputInterface $output) : int
+ {
+ $this->command = $this->command ?? $this->getApplication()->find($input->getArgument('command_name'));
+ $helper = new DescriptorHelper();
+ $helper->describe($output, $this->command, ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw')]);
+ unset($this->command);
+ return 0;
+ }
+}
diff --git a/vendor/symfony/console/Command/LazyCommand.php b/vendor/symfony/console/Command/LazyCommand.php
new file mode 100644
index 0000000000..0eb5d36878
--- /dev/null
+++ b/vendor/symfony/console/Command/LazyCommand.php
@@ -0,0 +1,188 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionInput;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Completion\Suggestion;
+use EasyCI202401\Symfony\Component\Console\Helper\HelperInterface;
+use EasyCI202401\Symfony\Component\Console\Helper\HelperSet;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @author Nicolas Grekas
+ */
+final class LazyCommand extends Command
+{
+ /**
+ * @var \Closure|\Symfony\Component\Console\Command\Command
+ */
+ private $command;
+ /**
+ * @var bool|null
+ */
+ private $isEnabled;
+ public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = \true)
+ {
+ $this->setName($name)->setAliases($aliases)->setHidden($isHidden)->setDescription($description);
+ $this->command = $commandFactory;
+ $this->isEnabled = $isEnabled;
+ }
+ public function ignoreValidationErrors() : void
+ {
+ $this->getCommand()->ignoreValidationErrors();
+ }
+ public function setApplication(Application $application = null) : void
+ {
+ if (1 > \func_num_args()) {
+ trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
+ }
+ if ($this->command instanceof parent) {
+ $this->command->setApplication($application);
+ }
+ parent::setApplication($application);
+ }
+ public function setHelperSet(HelperSet $helperSet) : void
+ {
+ if ($this->command instanceof parent) {
+ $this->command->setHelperSet($helperSet);
+ }
+ parent::setHelperSet($helperSet);
+ }
+ public function isEnabled() : bool
+ {
+ return $this->isEnabled ?? $this->getCommand()->isEnabled();
+ }
+ public function run(InputInterface $input, OutputInterface $output) : int
+ {
+ return $this->getCommand()->run($input, $output);
+ }
+ public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void
+ {
+ $this->getCommand()->complete($input, $suggestions);
+ }
+ /**
+ * @return static
+ */
+ public function setCode(callable $code)
+ {
+ $this->getCommand()->setCode($code);
+ return $this;
+ }
+ /**
+ * @internal
+ */
+ public function mergeApplicationDefinition(bool $mergeArgs = \true) : void
+ {
+ $this->getCommand()->mergeApplicationDefinition($mergeArgs);
+ }
+ /**
+ * @param mixed[]|\Symfony\Component\Console\Input\InputDefinition $definition
+ * @return static
+ */
+ public function setDefinition($definition)
+ {
+ $this->getCommand()->setDefinition($definition);
+ return $this;
+ }
+ public function getDefinition() : InputDefinition
+ {
+ return $this->getCommand()->getDefinition();
+ }
+ public function getNativeDefinition() : InputDefinition
+ {
+ return $this->getCommand()->getNativeDefinition();
+ }
+ /**
+ * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
+ * @param mixed $default
+ * @return static
+ */
+ public function addArgument(string $name, int $mode = null, string $description = '', $default = null)
+ {
+ $suggestedValues = 5 <= \func_num_args() ? \func_get_arg(4) : [];
+ $this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues);
+ return $this;
+ }
+ /**
+ * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
+ * @param string|mixed[] $shortcut
+ * @param mixed $default
+ * @return static
+ */
+ public function addOption(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null)
+ {
+ $suggestedValues = 6 <= \func_num_args() ? \func_get_arg(5) : [];
+ $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);
+ return $this;
+ }
+ /**
+ * @return static
+ */
+ public function setProcessTitle(string $title)
+ {
+ $this->getCommand()->setProcessTitle($title);
+ return $this;
+ }
+ /**
+ * @return static
+ */
+ public function setHelp(string $help)
+ {
+ $this->getCommand()->setHelp($help);
+ return $this;
+ }
+ public function getHelp() : string
+ {
+ return $this->getCommand()->getHelp();
+ }
+ public function getProcessedHelp() : string
+ {
+ return $this->getCommand()->getProcessedHelp();
+ }
+ public function getSynopsis(bool $short = \false) : string
+ {
+ return $this->getCommand()->getSynopsis($short);
+ }
+ /**
+ * @return static
+ */
+ public function addUsage(string $usage)
+ {
+ $this->getCommand()->addUsage($usage);
+ return $this;
+ }
+ public function getUsages() : array
+ {
+ return $this->getCommand()->getUsages();
+ }
+ public function getHelper(string $name) : HelperInterface
+ {
+ return $this->getCommand()->getHelper($name);
+ }
+ public function getCommand() : parent
+ {
+ if (!$this->command instanceof \Closure) {
+ return $this->command;
+ }
+ $command = $this->command = ($this->command)();
+ $command->setApplication($this->getApplication());
+ if (null !== $this->getHelperSet()) {
+ $command->setHelperSet($this->getHelperSet());
+ }
+ $command->setName($this->getName())->setAliases($this->getAliases())->setHidden($this->isHidden())->setDescription($this->getDescription());
+ // Will throw if the command is not correctly initialized.
+ $command->getDefinition();
+ return $command;
+ }
+}
diff --git a/vendor/symfony/console/Command/ListCommand.php b/vendor/symfony/console/Command/ListCommand.php
new file mode 100644
index 0000000000..46a036273b
--- /dev/null
+++ b/vendor/symfony/console/Command/ListCommand.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+use EasyCI202401\Symfony\Component\Console\Descriptor\ApplicationDescription;
+use EasyCI202401\Symfony\Component\Console\Helper\DescriptorHelper;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * ListCommand displays the list of all available commands for the application.
+ *
+ * @author Fabien Potencier
+ */
+class ListCommand extends Command
+{
+ /**
+ * @return void
+ */
+ protected function configure()
+ {
+ $this->setName('list')->setDefinition([new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, function () {
+ return \array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces());
+ }), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () {
+ return (new DescriptorHelper())->getFormats();
+ }), new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments')])->setDescription('List commands')->setHelp(<<<'EOF'
+The %command.name% command lists all commands:
+
+ %command.full_name%
+
+You can also display the commands for a specific namespace:
+
+ %command.full_name% test
+
+You can also output the information in other formats by using the --format option:
+
+ %command.full_name% --format=xml
+
+It's also possible to get raw list of commands (useful for embedding command runner):
+
+ %command.full_name% --raw
+EOF
+);
+ }
+ protected function execute(InputInterface $input, OutputInterface $output) : int
+ {
+ $helper = new DescriptorHelper();
+ $helper->describe($output, $this->getApplication(), ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw'), 'namespace' => $input->getArgument('namespace'), 'short' => $input->getOption('short')]);
+ return 0;
+ }
+}
diff --git a/vendor/symfony/console/Command/LockableTrait.php b/vendor/symfony/console/Command/LockableTrait.php
new file mode 100644
index 0000000000..939f76f0cf
--- /dev/null
+++ b/vendor/symfony/console/Command/LockableTrait.php
@@ -0,0 +1,62 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+use EasyCI202401\Symfony\Component\Console\Exception\LogicException;
+use EasyCI202401\Symfony\Component\Lock\LockFactory;
+use EasyCI202401\Symfony\Component\Lock\LockInterface;
+use EasyCI202401\Symfony\Component\Lock\Store\FlockStore;
+use EasyCI202401\Symfony\Component\Lock\Store\SemaphoreStore;
+/**
+ * Basic lock feature for commands.
+ *
+ * @author Geoffrey Brier
+ */
+trait LockableTrait
+{
+ /**
+ * @var \Symfony\Component\Lock\LockInterface|null
+ */
+ private $lock;
+ /**
+ * Locks a command.
+ */
+ private function lock(string $name = null, bool $blocking = \false) : bool
+ {
+ if (!\class_exists(SemaphoreStore::class)) {
+ throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".');
+ }
+ if (null !== $this->lock) {
+ throw new LogicException('A lock is already in place.');
+ }
+ if (SemaphoreStore::isSupported()) {
+ $store = new SemaphoreStore();
+ } else {
+ $store = new FlockStore();
+ }
+ $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName());
+ if (!$this->lock->acquire($blocking)) {
+ $this->lock = null;
+ return \false;
+ }
+ return \true;
+ }
+ /**
+ * Releases the command lock if there is one.
+ */
+ private function release() : void
+ {
+ if ($this->lock) {
+ $this->lock->release();
+ $this->lock = null;
+ }
+ }
+}
diff --git a/vendor/symfony/console/Command/SignalableCommandInterface.php b/vendor/symfony/console/Command/SignalableCommandInterface.php
new file mode 100644
index 0000000000..9e35b3316c
--- /dev/null
+++ b/vendor/symfony/console/Command/SignalableCommandInterface.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+/**
+ * Interface for command reacting to signal.
+ *
+ * @author Grégoire Pineau
+ */
+interface SignalableCommandInterface
+{
+ /**
+ * Returns the list of signals to subscribe.
+ */
+ public function getSubscribedSignals() : array;
+ /**
+ * The method will be called when the application is signaled.
+ *
+ * @param int|false $previousExitCode
+ *
+ * @return int|false The exit code to return or false to continue the normal execution
+ */
+ public function handleSignal(int $signal);
+}
diff --git a/vendor/symfony/console/Command/TraceableCommand.php b/vendor/symfony/console/Command/TraceableCommand.php
new file mode 100644
index 0000000000..25878979fe
--- /dev/null
+++ b/vendor/symfony/console/Command/TraceableCommand.php
@@ -0,0 +1,340 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Command;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionInput;
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Helper\HelperInterface;
+use EasyCI202401\Symfony\Component\Console\Helper\HelperSet;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleOutputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\Stopwatch\Stopwatch;
+/**
+ * @internal
+ *
+ * @author Jules Pietri
+ */
+final class TraceableCommand extends Command implements SignalableCommandInterface
+{
+ /**
+ * @readonly
+ * @var \Symfony\Component\Stopwatch\Stopwatch
+ */
+ private $stopwatch;
+ /**
+ * @readonly
+ * @var \Symfony\Component\Console\Command\Command
+ */
+ public $command;
+ /**
+ * @var int
+ */
+ public $exitCode;
+ /**
+ * @var int|null
+ */
+ public $interruptedBySignal;
+ /**
+ * @var bool
+ */
+ public $ignoreValidation;
+ /**
+ * @var bool
+ */
+ public $isInteractive = \false;
+ /**
+ * @var string
+ */
+ public $duration = 'n/a';
+ /**
+ * @var string
+ */
+ public $maxMemoryUsage = 'n/a';
+ /**
+ * @var \Symfony\Component\Console\Input\InputInterface
+ */
+ public $input;
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ public $output;
+ /** @var array */
+ public $arguments;
+ /** @var array */
+ public $options;
+ /** @var array */
+ public $interactiveInputs = [];
+ /**
+ * @var mixed[]
+ */
+ public $handledSignals = [];
+ public function __construct(Command $command, Stopwatch $stopwatch)
+ {
+ $this->stopwatch = $stopwatch;
+ if ($command instanceof LazyCommand) {
+ $command = $command->getCommand();
+ }
+ $this->command = $command;
+ // prevent call to self::getDefaultDescription()
+ $this->setDescription($command->getDescription());
+ parent::__construct($command->getName());
+ // init below enables calling {@see parent::run()}
+ [$code, $processTitle, $ignoreValidationErrors] = \Closure::bind(function () {
+ return [$this->code, $this->processTitle, $this->ignoreValidationErrors];
+ }, $command, Command::class)();
+ if (\is_callable($code)) {
+ $this->setCode($code);
+ }
+ if ($processTitle) {
+ parent::setProcessTitle($processTitle);
+ }
+ if ($ignoreValidationErrors) {
+ parent::ignoreValidationErrors();
+ }
+ $this->ignoreValidation = $ignoreValidationErrors;
+ }
+ /**
+ * @return mixed
+ */
+ public function __call(string $name, array $arguments)
+ {
+ return $this->command->{$name}(...$arguments);
+ }
+ public function getSubscribedSignals() : array
+ {
+ return $this->command instanceof SignalableCommandInterface ? $this->command->getSubscribedSignals() : [];
+ }
+ /**
+ * @param int|false $previousExitCode
+ * @return int|false
+ */
+ public function handleSignal(int $signal, $previousExitCode = 0)
+ {
+ if (!$this->command instanceof SignalableCommandInterface) {
+ return \false;
+ }
+ $event = $this->stopwatch->start($this->getName() . '.handle_signal');
+ $exit = $this->command->handleSignal($signal, $previousExitCode);
+ $event->stop();
+ if (!isset($this->handledSignals[$signal])) {
+ $this->handledSignals[$signal] = ['handled' => 0, 'duration' => 0, 'memory' => 0];
+ }
+ ++$this->handledSignals[$signal]['handled'];
+ $this->handledSignals[$signal]['duration'] += $event->getDuration();
+ $this->handledSignals[$signal]['memory'] = \max($this->handledSignals[$signal]['memory'], $event->getMemory() >> 20);
+ return $exit;
+ }
+ /**
+ * {@inheritdoc}
+ *
+ * Calling parent method is required to be used in {@see parent::run()}.
+ */
+ public function ignoreValidationErrors() : void
+ {
+ $this->ignoreValidation = \true;
+ $this->command->ignoreValidationErrors();
+ parent::ignoreValidationErrors();
+ }
+ public function setApplication(Application $application = null) : void
+ {
+ $this->command->setApplication($application);
+ }
+ public function getApplication() : ?Application
+ {
+ return $this->command->getApplication();
+ }
+ public function setHelperSet(HelperSet $helperSet) : void
+ {
+ $this->command->setHelperSet($helperSet);
+ }
+ public function getHelperSet() : ?HelperSet
+ {
+ return $this->command->getHelperSet();
+ }
+ public function isEnabled() : bool
+ {
+ return $this->command->isEnabled();
+ }
+ public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void
+ {
+ $this->command->complete($input, $suggestions);
+ }
+ /**
+ * {@inheritdoc}
+ *
+ * Calling parent method is required to be used in {@see parent::run()}.
+ * @return static
+ */
+ public function setCode(callable $code)
+ {
+ $this->command->setCode($code);
+ return parent::setCode(function (InputInterface $input, OutputInterface $output) use($code) : int {
+ $event = $this->stopwatch->start($this->getName() . '.code');
+ $this->exitCode = $code($input, $output);
+ $event->stop();
+ return $this->exitCode;
+ });
+ }
+ /**
+ * @internal
+ */
+ public function mergeApplicationDefinition(bool $mergeArgs = \true) : void
+ {
+ $this->command->mergeApplicationDefinition($mergeArgs);
+ }
+ /**
+ * @param mixed[]|\Symfony\Component\Console\Input\InputDefinition $definition
+ * @return static
+ */
+ public function setDefinition($definition)
+ {
+ $this->command->setDefinition($definition);
+ return $this;
+ }
+ public function getDefinition() : InputDefinition
+ {
+ return $this->command->getDefinition();
+ }
+ public function getNativeDefinition() : InputDefinition
+ {
+ return $this->command->getNativeDefinition();
+ }
+ /**
+ * @param mixed[]|\Closure $suggestedValues
+ * @param mixed $default
+ * @return static
+ */
+ public function addArgument(string $name, int $mode = null, string $description = '', $default = null, $suggestedValues = [])
+ {
+ $this->command->addArgument($name, $mode, $description, $default, $suggestedValues);
+ return $this;
+ }
+ /**
+ * @param string|mixed[] $shortcut
+ * @param mixed[]|\Closure $suggestedValues
+ * @param mixed $default
+ * @return static
+ */
+ public function addOption(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null, $suggestedValues = [])
+ {
+ $this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);
+ return $this;
+ }
+ /**
+ * {@inheritdoc}
+ *
+ * Calling parent method is required to be used in {@see parent::run()}.
+ * @return static
+ */
+ public function setProcessTitle(string $title)
+ {
+ $this->command->setProcessTitle($title);
+ return parent::setProcessTitle($title);
+ }
+ /**
+ * @return static
+ */
+ public function setHelp(string $help)
+ {
+ $this->command->setHelp($help);
+ return $this;
+ }
+ public function getHelp() : string
+ {
+ return $this->command->getHelp();
+ }
+ public function getProcessedHelp() : string
+ {
+ return $this->command->getProcessedHelp();
+ }
+ public function getSynopsis(bool $short = \false) : string
+ {
+ return $this->command->getSynopsis($short);
+ }
+ /**
+ * @return static
+ */
+ public function addUsage(string $usage)
+ {
+ $this->command->addUsage($usage);
+ return $this;
+ }
+ public function getUsages() : array
+ {
+ return $this->command->getUsages();
+ }
+ public function getHelper(string $name) : HelperInterface
+ {
+ return $this->command->getHelper($name);
+ }
+ public function run(InputInterface $input, OutputInterface $output) : int
+ {
+ $this->input = $input;
+ $this->output = $output;
+ $this->arguments = $input->getArguments();
+ $this->options = $input->getOptions();
+ $event = $this->stopwatch->start($this->getName(), 'command');
+ try {
+ $this->exitCode = parent::run($input, $output);
+ } finally {
+ $event->stop();
+ if ($output instanceof ConsoleOutputInterface && $output->isDebug()) {
+ $output->getErrorOutput()->writeln((string) $event);
+ }
+ $this->duration = $event->getDuration() . ' ms';
+ $this->maxMemoryUsage = ($event->getMemory() >> 20) . ' MiB';
+ if ($this->isInteractive) {
+ $this->extractInteractiveInputs($input->getArguments(), $input->getOptions());
+ }
+ }
+ return $this->exitCode;
+ }
+ protected function initialize(InputInterface $input, OutputInterface $output) : void
+ {
+ $event = $this->stopwatch->start($this->getName() . '.init', 'command');
+ $this->command->initialize($input, $output);
+ $event->stop();
+ }
+ protected function interact(InputInterface $input, OutputInterface $output) : void
+ {
+ if (!($this->isInteractive = Command::class !== (new \ReflectionMethod($this->command, 'interact'))->getDeclaringClass()->getName())) {
+ return;
+ }
+ $event = $this->stopwatch->start($this->getName() . '.interact', 'command');
+ $this->command->interact($input, $output);
+ $event->stop();
+ }
+ protected function execute(InputInterface $input, OutputInterface $output) : int
+ {
+ $event = $this->stopwatch->start($this->getName() . '.execute', 'command');
+ $exitCode = $this->command->execute($input, $output);
+ $event->stop();
+ return $exitCode;
+ }
+ private function extractInteractiveInputs(array $arguments, array $options) : void
+ {
+ foreach ($arguments as $argName => $argValue) {
+ if (\array_key_exists($argName, $this->arguments) && $this->arguments[$argName] === $argValue) {
+ continue;
+ }
+ $this->interactiveInputs[$argName] = $argValue;
+ }
+ foreach ($options as $optName => $optValue) {
+ if (\array_key_exists($optName, $this->options) && $this->options[$optName] === $optValue) {
+ continue;
+ }
+ $this->interactiveInputs['--' . $optName] = $optValue;
+ }
+ }
+}
diff --git a/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php b/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php
new file mode 100644
index 0000000000..b54d63af4f
--- /dev/null
+++ b/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\CommandLoader;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Exception\CommandNotFoundException;
+/**
+ * @author Robin Chalas
+ */
+interface CommandLoaderInterface
+{
+ /**
+ * Loads a command.
+ *
+ * @throws CommandNotFoundException
+ */
+ public function get(string $name) : Command;
+ /**
+ * Checks if a command exists.
+ */
+ public function has(string $name) : bool;
+ /**
+ * @return string[]
+ */
+ public function getNames() : array;
+}
diff --git a/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php
new file mode 100644
index 0000000000..b7a6b0b250
--- /dev/null
+++ b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\CommandLoader;
+
+use EasyCI202401\Psr\Container\ContainerInterface;
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Exception\CommandNotFoundException;
+/**
+ * Loads commands from a PSR-11 container.
+ *
+ * @author Robin Chalas
+ */
+class ContainerCommandLoader implements CommandLoaderInterface
+{
+ /**
+ * @var \Psr\Container\ContainerInterface
+ */
+ private $container;
+ /**
+ * @var mixed[]
+ */
+ private $commandMap;
+ /**
+ * @param array $commandMap An array with command names as keys and service ids as values
+ */
+ public function __construct(ContainerInterface $container, array $commandMap)
+ {
+ $this->container = $container;
+ $this->commandMap = $commandMap;
+ }
+ public function get(string $name) : Command
+ {
+ if (!$this->has($name)) {
+ throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
+ }
+ return $this->container->get($this->commandMap[$name]);
+ }
+ public function has(string $name) : bool
+ {
+ return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
+ }
+ public function getNames() : array
+ {
+ return \array_keys($this->commandMap);
+ }
+}
diff --git a/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php
new file mode 100644
index 0000000000..c22c6c5fbe
--- /dev/null
+++ b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\CommandLoader;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Exception\CommandNotFoundException;
+/**
+ * A simple command loader using factories to instantiate commands lazily.
+ *
+ * @author Maxime Steinhausser
+ */
+class FactoryCommandLoader implements CommandLoaderInterface
+{
+ /**
+ * @var mixed[]
+ */
+ private $factories;
+ /**
+ * @param callable[] $factories Indexed by command names
+ */
+ public function __construct(array $factories)
+ {
+ $this->factories = $factories;
+ }
+ public function has(string $name) : bool
+ {
+ return isset($this->factories[$name]);
+ }
+ public function get(string $name) : Command
+ {
+ if (!isset($this->factories[$name])) {
+ throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
+ }
+ $factory = $this->factories[$name];
+ return $factory();
+ }
+ public function getNames() : array
+ {
+ return \array_keys($this->factories);
+ }
+}
diff --git a/vendor/symfony/console/Completion/CompletionInput.php b/vendor/symfony/console/Completion/CompletionInput.php
new file mode 100644
index 0000000000..0a2cc2b0ad
--- /dev/null
+++ b/vendor/symfony/console/Completion/CompletionInput.php
@@ -0,0 +1,227 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Completion;
+
+use EasyCI202401\Symfony\Component\Console\Exception\RuntimeException;
+use EasyCI202401\Symfony\Component\Console\Input\ArgvInput;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+/**
+ * An input specialized for shell completion.
+ *
+ * This input allows unfinished option names or values and exposes what kind of
+ * completion is expected.
+ *
+ * @author Wouter de Jong
+ */
+final class CompletionInput extends ArgvInput
+{
+ public const TYPE_ARGUMENT_VALUE = 'argument_value';
+ public const TYPE_OPTION_VALUE = 'option_value';
+ public const TYPE_OPTION_NAME = 'option_name';
+ public const TYPE_NONE = 'none';
+ /**
+ * @var mixed[]
+ */
+ private $tokens;
+ /**
+ * @var int
+ */
+ private $currentIndex;
+ /**
+ * @var string
+ */
+ private $completionType;
+ /**
+ * @var string|null
+ */
+ private $completionName;
+ /**
+ * @var string
+ */
+ private $completionValue = '';
+ /**
+ * Converts a terminal string into tokens.
+ *
+ * This is required for shell completions without COMP_WORDS support.
+ */
+ public static function fromString(string $inputStr, int $currentIndex) : self
+ {
+ \preg_match_all('/(?<=^|\\s)([\'"]?)(.+?)(?tokens = $tokens;
+ $input->currentIndex = $currentIndex;
+ return $input;
+ }
+ public function bind(InputDefinition $definition) : void
+ {
+ parent::bind($definition);
+ $relevantToken = $this->getRelevantToken();
+ if ('-' === $relevantToken[0]) {
+ // the current token is an input option: complete either option name or option value
+ [$optionToken, $optionValue] = \explode('=', $relevantToken, 2) + ['', ''];
+ $option = $this->getOptionFromToken($optionToken);
+ if (null === $option && !$this->isCursorFree()) {
+ $this->completionType = self::TYPE_OPTION_NAME;
+ $this->completionValue = $relevantToken;
+ return;
+ }
+ if (($nullsafeVariable1 = $option) ? $nullsafeVariable1->acceptValue() : null) {
+ $this->completionType = self::TYPE_OPTION_VALUE;
+ $this->completionName = $option->getName();
+ $this->completionValue = $optionValue ?: (\strncmp($optionToken, '--', \strlen('--')) !== 0 ? \substr($optionToken, 2) : '');
+ return;
+ }
+ }
+ $previousToken = $this->tokens[$this->currentIndex - 1];
+ if ('-' === $previousToken[0] && '' !== \trim($previousToken, '-')) {
+ // check if previous option accepted a value
+ $previousOption = $this->getOptionFromToken($previousToken);
+ if (($nullsafeVariable2 = $previousOption) ? $nullsafeVariable2->acceptValue() : null) {
+ $this->completionType = self::TYPE_OPTION_VALUE;
+ $this->completionName = $previousOption->getName();
+ $this->completionValue = $relevantToken;
+ return;
+ }
+ }
+ // complete argument value
+ $this->completionType = self::TYPE_ARGUMENT_VALUE;
+ foreach ($this->definition->getArguments() as $argumentName => $argument) {
+ if (!isset($this->arguments[$argumentName])) {
+ break;
+ }
+ $argumentValue = $this->arguments[$argumentName];
+ $this->completionName = $argumentName;
+ if (\is_array($argumentValue)) {
+ \end($argumentValue);
+ $this->completionValue = $argumentValue ? $argumentValue[\key($argumentValue)] : null;
+ } else {
+ $this->completionValue = $argumentValue;
+ }
+ }
+ if ($this->currentIndex >= \count($this->tokens)) {
+ if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) {
+ $this->completionName = $argumentName;
+ $this->completionValue = '';
+ } else {
+ // we've reached the end
+ $this->completionType = self::TYPE_NONE;
+ $this->completionName = null;
+ $this->completionValue = '';
+ }
+ }
+ }
+ /**
+ * Returns the type of completion required.
+ *
+ * TYPE_ARGUMENT_VALUE when completing the value of an input argument
+ * TYPE_OPTION_VALUE when completing the value of an input option
+ * TYPE_OPTION_NAME when completing the name of an input option
+ * TYPE_NONE when nothing should be completed
+ *
+ * TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component.
+ *
+ * @return self::TYPE_*
+ */
+ public function getCompletionType() : string
+ {
+ return $this->completionType;
+ }
+ /**
+ * The name of the input option or argument when completing a value.
+ *
+ * @return string|null returns null when completing an option name
+ */
+ public function getCompletionName() : ?string
+ {
+ return $this->completionName;
+ }
+ /**
+ * The value already typed by the user (or empty string).
+ */
+ public function getCompletionValue() : string
+ {
+ return $this->completionValue;
+ }
+ public function mustSuggestOptionValuesFor(string $optionName) : bool
+ {
+ return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName();
+ }
+ public function mustSuggestArgumentValuesFor(string $argumentName) : bool
+ {
+ return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName();
+ }
+ protected function parseToken(string $token, bool $parseOptions) : bool
+ {
+ try {
+ return parent::parseToken($token, $parseOptions);
+ } catch (RuntimeException $exception) {
+ // suppress errors, completed input is almost never valid
+ }
+ return $parseOptions;
+ }
+ private function getOptionFromToken(string $optionToken) : ?InputOption
+ {
+ $optionName = \ltrim($optionToken, '-');
+ if (!$optionName) {
+ return null;
+ }
+ if ('-' === ($optionToken[1] ?? ' ')) {
+ // long option name
+ return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null;
+ }
+ // short option name
+ return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null;
+ }
+ /**
+ * The token of the cursor, or the last token if the cursor is at the end of the input.
+ */
+ private function getRelevantToken() : string
+ {
+ return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex];
+ }
+ /**
+ * Whether the cursor is "free" (i.e. at the end of the input preceded by a space).
+ */
+ private function isCursorFree() : bool
+ {
+ $nrOfTokens = \count($this->tokens);
+ if ($this->currentIndex > $nrOfTokens) {
+ throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.');
+ }
+ return $this->currentIndex >= $nrOfTokens;
+ }
+ public function __toString() : string
+ {
+ $str = '';
+ foreach ($this->tokens as $i => $token) {
+ $str .= $token;
+ if ($this->currentIndex === $i) {
+ $str .= '|';
+ }
+ $str .= ' ';
+ }
+ if ($this->currentIndex > $i) {
+ $str .= '|';
+ }
+ return \rtrim($str);
+ }
+}
diff --git a/vendor/symfony/console/Completion/CompletionSuggestions.php b/vendor/symfony/console/Completion/CompletionSuggestions.php
new file mode 100644
index 0000000000..f632bc4bb7
--- /dev/null
+++ b/vendor/symfony/console/Completion/CompletionSuggestions.php
@@ -0,0 +1,92 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Completion;
+
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+/**
+ * Stores all completion suggestions for the current input.
+ *
+ * @author Wouter de Jong
+ */
+final class CompletionSuggestions
+{
+ /**
+ * @var mixed[]
+ */
+ private $valueSuggestions = [];
+ /**
+ * @var mixed[]
+ */
+ private $optionSuggestions = [];
+ /**
+ * Add a suggested value for an input option or argument.
+ *
+ * @return $this
+ * @param string|\Symfony\Component\Console\Completion\Suggestion $value
+ */
+ public function suggestValue($value)
+ {
+ $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value;
+ return $this;
+ }
+ /**
+ * Add multiple suggested values at once for an input option or argument.
+ *
+ * @param list $values
+ *
+ * @return $this
+ */
+ public function suggestValues(array $values)
+ {
+ foreach ($values as $value) {
+ $this->suggestValue($value);
+ }
+ return $this;
+ }
+ /**
+ * Add a suggestion for an input option name.
+ *
+ * @return $this
+ */
+ public function suggestOption(InputOption $option)
+ {
+ $this->optionSuggestions[] = $option;
+ return $this;
+ }
+ /**
+ * Add multiple suggestions for input option names at once.
+ *
+ * @param InputOption[] $options
+ *
+ * @return $this
+ */
+ public function suggestOptions(array $options)
+ {
+ foreach ($options as $option) {
+ $this->suggestOption($option);
+ }
+ return $this;
+ }
+ /**
+ * @return InputOption[]
+ */
+ public function getOptionSuggestions() : array
+ {
+ return $this->optionSuggestions;
+ }
+ /**
+ * @return Suggestion[]
+ */
+ public function getValueSuggestions() : array
+ {
+ return $this->valueSuggestions;
+ }
+}
diff --git a/vendor/symfony/console/Completion/Output/BashCompletionOutput.php b/vendor/symfony/console/Completion/Output/BashCompletionOutput.php
new file mode 100644
index 0000000000..0a39a7b067
--- /dev/null
+++ b/vendor/symfony/console/Completion/Output/BashCompletionOutput.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Completion\Output;
+
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @author Wouter de Jong
+ */
+class BashCompletionOutput implements CompletionOutputInterface
+{
+ public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void
+ {
+ $values = $suggestions->getValueSuggestions();
+ foreach ($suggestions->getOptionSuggestions() as $option) {
+ $values[] = '--' . $option->getName();
+ if ($option->isNegatable()) {
+ $values[] = '--no-' . $option->getName();
+ }
+ }
+ $output->writeln(\implode("\n", $values));
+ }
+}
diff --git a/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php b/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php
new file mode 100644
index 0000000000..d8256f765e
--- /dev/null
+++ b/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Completion\Output;
+
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Transforms the {@see CompletionSuggestions} object into output readable by the shell completion.
+ *
+ * @author Wouter de Jong
+ */
+interface CompletionOutputInterface
+{
+ public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void;
+}
diff --git a/vendor/symfony/console/Completion/Output/FishCompletionOutput.php b/vendor/symfony/console/Completion/Output/FishCompletionOutput.php
new file mode 100644
index 0000000000..695d77ad5f
--- /dev/null
+++ b/vendor/symfony/console/Completion/Output/FishCompletionOutput.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Completion\Output;
+
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @author Guillaume Aveline
+ */
+class FishCompletionOutput implements CompletionOutputInterface
+{
+ public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void
+ {
+ $values = $suggestions->getValueSuggestions();
+ foreach ($suggestions->getOptionSuggestions() as $option) {
+ $values[] = '--' . $option->getName();
+ if ($option->isNegatable()) {
+ $values[] = '--no-' . $option->getName();
+ }
+ }
+ $output->write(\implode("\n", $values));
+ }
+}
diff --git a/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php b/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php
new file mode 100644
index 0000000000..ac5439eedb
--- /dev/null
+++ b/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Completion\Output;
+
+use EasyCI202401\Symfony\Component\Console\Completion\CompletionSuggestions;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @author Jitendra A
+ */
+class ZshCompletionOutput implements CompletionOutputInterface
+{
+ public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void
+ {
+ $values = [];
+ foreach ($suggestions->getValueSuggestions() as $value) {
+ $values[] = $value->getValue() . ($value->getDescription() ? "\t" . $value->getDescription() : '');
+ }
+ foreach ($suggestions->getOptionSuggestions() as $option) {
+ $values[] = '--' . $option->getName() . ($option->getDescription() ? "\t" . $option->getDescription() : '');
+ if ($option->isNegatable()) {
+ $values[] = '--no-' . $option->getName() . ($option->getDescription() ? "\t" . $option->getDescription() : '');
+ }
+ }
+ $output->write(\implode("\n", $values) . "\n");
+ }
+}
diff --git a/vendor/symfony/console/Completion/Suggestion.php b/vendor/symfony/console/Completion/Suggestion.php
new file mode 100644
index 0000000000..ba625fbbee
--- /dev/null
+++ b/vendor/symfony/console/Completion/Suggestion.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Completion;
+
+/**
+ * Represents a single suggested value.
+ *
+ * @author Wouter de Jong
+ */
+class Suggestion
+{
+ /**
+ * @readonly
+ * @var string
+ */
+ private $value;
+ /**
+ * @readonly
+ * @var string
+ */
+ private $description = '';
+ public function __construct(string $value, string $description = '')
+ {
+ $this->value = $value;
+ $this->description = $description;
+ }
+ public function getValue() : string
+ {
+ return $this->value;
+ }
+ public function getDescription() : string
+ {
+ return $this->description;
+ }
+ public function __toString() : string
+ {
+ return $this->getValue();
+ }
+}
diff --git a/vendor/symfony/console/ConsoleEvents.php b/vendor/symfony/console/ConsoleEvents.php
new file mode 100644
index 0000000000..2f78765f35
--- /dev/null
+++ b/vendor/symfony/console/ConsoleEvents.php
@@ -0,0 +1,61 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console;
+
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleCommandEvent;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleErrorEvent;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleSignalEvent;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleTerminateEvent;
+/**
+ * Contains all events dispatched by an Application.
+ *
+ * @author Francesco Levorato
+ */
+final class ConsoleEvents
+{
+ /**
+ * The COMMAND event allows you to attach listeners before any command is
+ * executed by the console. It also allows you to modify the command, input and output
+ * before they are handed to the command.
+ *
+ * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent")
+ */
+ public const COMMAND = 'console.command';
+ /**
+ * The SIGNAL event allows you to perform some actions
+ * after the command execution was interrupted.
+ *
+ * @Event("Symfony\Component\Console\Event\ConsoleSignalEvent")
+ */
+ public const SIGNAL = 'console.signal';
+ /**
+ * The TERMINATE event allows you to attach listeners after a command is
+ * executed by the console.
+ *
+ * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent")
+ */
+ public const TERMINATE = 'console.terminate';
+ /**
+ * The ERROR event occurs when an uncaught exception or error appears.
+ *
+ * This event allows you to deal with the exception/error or
+ * to modify the thrown exception.
+ *
+ * @Event("Symfony\Component\Console\Event\ConsoleErrorEvent")
+ */
+ public const ERROR = 'console.error';
+ /**
+ * Event aliases.
+ *
+ * These aliases can be consumed by RegisterListenersPass.
+ */
+ public const ALIASES = [ConsoleCommandEvent::class => self::COMMAND, ConsoleErrorEvent::class => self::ERROR, ConsoleSignalEvent::class => self::SIGNAL, ConsoleTerminateEvent::class => self::TERMINATE];
+}
diff --git a/vendor/symfony/console/Cursor.php b/vendor/symfony/console/Cursor.php
new file mode 100644
index 0000000000..771a957000
--- /dev/null
+++ b/vendor/symfony/console/Cursor.php
@@ -0,0 +1,168 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console;
+
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @author Pierre du Plessis
+ */
+final class Cursor
+{
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ private $output;
+ /** @var resource */
+ private $input;
+ /**
+ * @param resource|null $input
+ */
+ public function __construct(OutputInterface $output, $input = null)
+ {
+ $this->output = $output;
+ $this->input = $input ?? (\defined('STDIN') ? \STDIN : \fopen('php://input', 'r+'));
+ }
+ /**
+ * @return $this
+ */
+ public function moveUp(int $lines = 1)
+ {
+ $this->output->write(\sprintf("\x1b[%dA", $lines));
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function moveDown(int $lines = 1)
+ {
+ $this->output->write(\sprintf("\x1b[%dB", $lines));
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function moveRight(int $columns = 1)
+ {
+ $this->output->write(\sprintf("\x1b[%dC", $columns));
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function moveLeft(int $columns = 1)
+ {
+ $this->output->write(\sprintf("\x1b[%dD", $columns));
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function moveToColumn(int $column)
+ {
+ $this->output->write(\sprintf("\x1b[%dG", $column));
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function moveToPosition(int $column, int $row)
+ {
+ $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column));
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function savePosition()
+ {
+ $this->output->write("\x1b7");
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function restorePosition()
+ {
+ $this->output->write("\x1b8");
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function hide()
+ {
+ $this->output->write("\x1b[?25l");
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function show()
+ {
+ $this->output->write("\x1b[?25h\x1b[?0c");
+ return $this;
+ }
+ /**
+ * Clears all the output from the current line.
+ *
+ * @return $this
+ */
+ public function clearLine()
+ {
+ $this->output->write("\x1b[2K");
+ return $this;
+ }
+ /**
+ * Clears all the output from the current line after the current position.
+ */
+ public function clearLineAfter() : self
+ {
+ $this->output->write("\x1b[K");
+ return $this;
+ }
+ /**
+ * Clears all the output from the cursors' current position to the end of the screen.
+ *
+ * @return $this
+ */
+ public function clearOutput()
+ {
+ $this->output->write("\x1b[0J");
+ return $this;
+ }
+ /**
+ * Clears the entire screen.
+ *
+ * @return $this
+ */
+ public function clearScreen()
+ {
+ $this->output->write("\x1b[2J");
+ return $this;
+ }
+ /**
+ * Returns the current cursor position as x,y coordinates.
+ */
+ public function getCurrentPosition() : array
+ {
+ static $isTtySupported;
+ if (!($isTtySupported = $isTtySupported ?? '/' === \DIRECTORY_SEPARATOR && \stream_isatty(\STDOUT))) {
+ return [1, 1];
+ }
+ $sttyMode = \shell_exec('stty -g');
+ \shell_exec('stty -icanon -echo');
+ @\fwrite($this->input, "\x1b[6n");
+ $code = \trim(\fread($this->input, 1024));
+ \shell_exec(\sprintf('stty %s', $sttyMode));
+ \sscanf($code, "\x1b[%d;%dR", $row, $col);
+ return [$col, $row];
+ }
+}
diff --git a/vendor/symfony/console/DataCollector/CommandDataCollector.php b/vendor/symfony/console/DataCollector/CommandDataCollector.php
new file mode 100644
index 0000000000..c9e142cdd7
--- /dev/null
+++ b/vendor/symfony/console/DataCollector/CommandDataCollector.php
@@ -0,0 +1,182 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\DataCollector;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Debug\CliRequest;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\Console\SignalRegistry\SignalMap;
+use EasyCI202401\Symfony\Component\HttpFoundation\Request;
+use EasyCI202401\Symfony\Component\HttpFoundation\Response;
+use EasyCI202401\Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use EasyCI202401\Symfony\Component\VarDumper\Cloner\Data;
+/**
+ * @internal
+ *
+ * @author Jules Pietri
+ */
+final class CommandDataCollector extends DataCollector
+{
+ public function collect(Request $request, Response $response, \Throwable $exception = null) : void
+ {
+ if (!$request instanceof CliRequest) {
+ return;
+ }
+ $command = $request->command;
+ $application = $command->getApplication();
+ $this->data = ['command' => $this->cloneVar($command->command), 'exit_code' => $command->exitCode, 'interrupted_by_signal' => $command->interruptedBySignal, 'duration' => $command->duration, 'max_memory_usage' => $command->maxMemoryUsage, 'verbosity_level' => (function () use($command) {
+ switch ($command->output->getVerbosity()) {
+ case OutputInterface::VERBOSITY_QUIET:
+ return 'quiet';
+ case OutputInterface::VERBOSITY_NORMAL:
+ return 'normal';
+ case OutputInterface::VERBOSITY_VERBOSE:
+ return 'verbose';
+ case OutputInterface::VERBOSITY_VERY_VERBOSE:
+ return 'very verbose';
+ case OutputInterface::VERBOSITY_DEBUG:
+ return 'debug';
+ }
+ })(), 'interactive' => $command->isInteractive, 'validate_input' => !$command->ignoreValidation, 'enabled' => $command->isEnabled(), 'visible' => !$command->isHidden(), 'input' => $this->cloneVar($command->input), 'output' => $this->cloneVar($command->output), 'interactive_inputs' => \array_map(\Closure::fromCallable([$this, 'cloneVar']), $command->interactiveInputs), 'signalable' => $command->getSubscribedSignals(), 'handled_signals' => $command->handledSignals, 'helper_set' => \array_map(\Closure::fromCallable([$this, 'cloneVar']), \iterator_to_array($command->getHelperSet()))];
+ $baseDefinition = $application->getDefinition();
+ foreach ($command->arguments as $argName => $argValue) {
+ if ($baseDefinition->hasArgument($argName)) {
+ $this->data['application_inputs'][$argName] = $this->cloneVar($argValue);
+ } else {
+ $this->data['arguments'][$argName] = $this->cloneVar($argValue);
+ }
+ }
+ foreach ($command->options as $optName => $optValue) {
+ if ($baseDefinition->hasOption($optName)) {
+ $this->data['application_inputs']['--' . $optName] = $this->cloneVar($optValue);
+ } else {
+ $this->data['options'][$optName] = $this->cloneVar($optValue);
+ }
+ }
+ }
+ public function getName() : string
+ {
+ return 'command';
+ }
+ /**
+ * @return array{
+ * class?: class-string,
+ * executor?: string,
+ * file: string,
+ * line: int,
+ * }
+ */
+ public function getCommand() : array
+ {
+ $class = $this->data['command']->getType();
+ $r = new \ReflectionMethod($class, 'execute');
+ if (Command::class !== $r->getDeclaringClass()) {
+ return ['executor' => $class . '::' . $r->name, 'file' => $r->getFileName(), 'line' => $r->getStartLine()];
+ }
+ $r = new \ReflectionClass($class);
+ return ['class' => $class, 'file' => $r->getFileName(), 'line' => $r->getStartLine()];
+ }
+ public function getInterruptedBySignal() : ?string
+ {
+ if (isset($this->data['interrupted_by_signal'])) {
+ return \sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']);
+ }
+ return null;
+ }
+ public function getDuration() : string
+ {
+ return $this->data['duration'];
+ }
+ public function getMaxMemoryUsage() : string
+ {
+ return $this->data['max_memory_usage'];
+ }
+ public function getVerbosityLevel() : string
+ {
+ return $this->data['verbosity_level'];
+ }
+ public function getInteractive() : bool
+ {
+ return $this->data['interactive'];
+ }
+ public function getValidateInput() : bool
+ {
+ return $this->data['validate_input'];
+ }
+ public function getEnabled() : bool
+ {
+ return $this->data['enabled'];
+ }
+ public function getVisible() : bool
+ {
+ return $this->data['visible'];
+ }
+ public function getInput() : Data
+ {
+ return $this->data['input'];
+ }
+ public function getOutput() : Data
+ {
+ return $this->data['output'];
+ }
+ /**
+ * @return Data[]
+ */
+ public function getArguments() : array
+ {
+ return $this->data['arguments'] ?? [];
+ }
+ /**
+ * @return Data[]
+ */
+ public function getOptions() : array
+ {
+ return $this->data['options'] ?? [];
+ }
+ /**
+ * @return Data[]
+ */
+ public function getApplicationInputs() : array
+ {
+ return $this->data['application_inputs'] ?? [];
+ }
+ /**
+ * @return Data[]
+ */
+ public function getInteractiveInputs() : array
+ {
+ return $this->data['interactive_inputs'] ?? [];
+ }
+ public function getSignalable() : array
+ {
+ return \array_map(static function (int $signal) : string {
+ return \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal);
+ }, $this->data['signalable']);
+ }
+ public function getHandledSignals() : array
+ {
+ $keys = \array_map(static function (int $signal) : string {
+ return \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal);
+ }, \array_keys($this->data['handled_signals']));
+ return \array_combine($keys, \array_values($this->data['handled_signals']));
+ }
+ /**
+ * @return Data[]
+ */
+ public function getHelperSet() : array
+ {
+ return $this->data['helper_set'] ?? [];
+ }
+ public function reset() : void
+ {
+ $this->data = [];
+ }
+}
diff --git a/vendor/symfony/console/Debug/CliRequest.php b/vendor/symfony/console/Debug/CliRequest.php
new file mode 100644
index 0000000000..03a10ca773
--- /dev/null
+++ b/vendor/symfony/console/Debug/CliRequest.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Debug;
+
+use EasyCI202401\Symfony\Component\Console\Command\TraceableCommand;
+use EasyCI202401\Symfony\Component\HttpFoundation\Request;
+use EasyCI202401\Symfony\Component\HttpFoundation\Response;
+/**
+ * @internal
+ */
+final class CliRequest extends Request
+{
+ /**
+ * @readonly
+ * @var \Symfony\Component\Console\Command\TraceableCommand
+ */
+ public $command;
+ public function __construct(TraceableCommand $command)
+ {
+ $this->command = $command;
+ parent::__construct(attributes: ['_controller' => \get_class($command->command), '_virtual_type' => 'command'], server: $_SERVER);
+ }
+ // Methods below allow to populate a profile, thus enable search and filtering
+ public function getUri() : string
+ {
+ if ($this->server->has('SYMFONY_CLI_BINARY_NAME')) {
+ $binary = $this->server->get('SYMFONY_CLI_BINARY_NAME') . ' console';
+ } else {
+ $binary = $this->server->get('argv')[0];
+ }
+ return $binary . ' ' . $this->command->input;
+ }
+ public function getMethod() : string
+ {
+ return $this->command->isInteractive ? 'INTERACTIVE' : 'BATCH';
+ }
+ public function getResponse() : Response
+ {
+ return new class($this->command->exitCode) extends Response
+ {
+ /**
+ * @readonly
+ * @var int
+ */
+ private $exitCode;
+ public function __construct(int $exitCode)
+ {
+ $this->exitCode = $exitCode;
+ parent::__construct();
+ }
+ public function getStatusCode() : int
+ {
+ return $this->exitCode;
+ }
+ };
+ }
+ public function getClientIp() : string
+ {
+ $application = $this->command->getApplication();
+ return $application->getName() . ' ' . $application->getVersion();
+ }
+}
diff --git a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php
new file mode 100644
index 0000000000..71bd062075
--- /dev/null
+++ b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php
@@ -0,0 +1,107 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\DependencyInjection;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Command\LazyCommand;
+use EasyCI202401\Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
+use EasyCI202401\Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
+use EasyCI202401\Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use EasyCI202401\Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
+use EasyCI202401\Symfony\Component\DependencyInjection\ContainerBuilder;
+use EasyCI202401\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\DependencyInjection\Reference;
+use EasyCI202401\Symfony\Component\DependencyInjection\TypedReference;
+/**
+ * Registers console commands.
+ *
+ * @author Grégoire Pineau
+ */
+class AddConsoleCommandPass implements CompilerPassInterface
+{
+ /**
+ * @return void
+ */
+ public function process(ContainerBuilder $container)
+ {
+ $commandServices = $container->findTaggedServiceIds('console.command', \true);
+ $lazyCommandMap = [];
+ $lazyCommandRefs = [];
+ $serviceIds = [];
+ foreach ($commandServices as $id => $tags) {
+ $definition = $container->getDefinition($id);
+ $definition->addTag('container.no_preload');
+ $class = $container->getParameterBag()->resolveValue($definition->getClass());
+ if (isset($tags[0]['command'])) {
+ $aliases = $tags[0]['command'];
+ } else {
+ if (!($r = $container->getReflectionClass($class))) {
+ throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
+ }
+ if (!$r->isSubclassOf(Command::class)) {
+ throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class));
+ }
+ $aliases = \str_replace('%', '%%', $class::getDefaultName() ?? '');
+ }
+ $aliases = \explode('|', $aliases ?? '');
+ $commandName = \array_shift($aliases);
+ if ($isHidden = '' === $commandName) {
+ $commandName = \array_shift($aliases);
+ }
+ if (null === $commandName) {
+ if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag('container.private')) {
+ $commandId = 'console.command.public_alias.' . $id;
+ $container->setAlias($commandId, $id)->setPublic(\true);
+ $id = $commandId;
+ }
+ $serviceIds[] = $id;
+ continue;
+ }
+ $description = $tags[0]['description'] ?? null;
+ unset($tags[0]);
+ $lazyCommandMap[$commandName] = $id;
+ $lazyCommandRefs[$id] = new TypedReference($id, $class);
+ foreach ($aliases as $alias) {
+ $lazyCommandMap[$alias] = $id;
+ }
+ foreach ($tags as $tag) {
+ if (isset($tag['command'])) {
+ $aliases[] = $tag['command'];
+ $lazyCommandMap[$tag['command']] = $id;
+ }
+ $description = $description ?? $tag['description'] ?? null;
+ }
+ $definition->addMethodCall('setName', [$commandName]);
+ if ($aliases) {
+ $definition->addMethodCall('setAliases', [$aliases]);
+ }
+ if ($isHidden) {
+ $definition->addMethodCall('setHidden', [\true]);
+ }
+ if (!$description) {
+ if (!($r = $container->getReflectionClass($class))) {
+ throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
+ }
+ if (!$r->isSubclassOf(Command::class)) {
+ throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class));
+ }
+ $description = \str_replace('%', '%%', $class::getDefaultDescription() ?? '');
+ }
+ if ($description) {
+ $definition->addMethodCall('setDescription', [$description]);
+ $container->register('.' . $id . '.lazy', LazyCommand::class)->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]);
+ $lazyCommandRefs[$id] = new Reference('.' . $id . '.lazy');
+ }
+ }
+ $container->register('console.command_loader', ContainerCommandLoader::class)->setPublic(\true)->addTag('container.no_preload')->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);
+ $container->setParameter('console.command.ids', $serviceIds);
+ }
+}
diff --git a/vendor/symfony/console/Descriptor/ApplicationDescription.php b/vendor/symfony/console/Descriptor/ApplicationDescription.php
new file mode 100644
index 0000000000..928b34871f
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/ApplicationDescription.php
@@ -0,0 +1,129 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Descriptor;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Exception\CommandNotFoundException;
+/**
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class ApplicationDescription
+{
+ public const GLOBAL_NAMESPACE = '_global';
+ /**
+ * @var \Symfony\Component\Console\Application
+ */
+ private $application;
+ /**
+ * @var string|null
+ */
+ private $namespace;
+ /**
+ * @var bool
+ */
+ private $showHidden;
+ /**
+ * @var mixed[]
+ */
+ private $namespaces;
+ /**
+ * @var array
+ */
+ private $commands;
+ /**
+ * @var array
+ */
+ private $aliases = [];
+ public function __construct(Application $application, string $namespace = null, bool $showHidden = \false)
+ {
+ $this->application = $application;
+ $this->namespace = $namespace;
+ $this->showHidden = $showHidden;
+ }
+ public function getNamespaces() : array
+ {
+ if (!isset($this->namespaces)) {
+ $this->inspectApplication();
+ }
+ return $this->namespaces;
+ }
+ /**
+ * @return Command[]
+ */
+ public function getCommands() : array
+ {
+ if (!isset($this->commands)) {
+ $this->inspectApplication();
+ }
+ return $this->commands;
+ }
+ /**
+ * @throws CommandNotFoundException
+ */
+ public function getCommand(string $name) : Command
+ {
+ if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
+ throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
+ }
+ return $this->commands[$name] ?? $this->aliases[$name];
+ }
+ private function inspectApplication() : void
+ {
+ $this->commands = [];
+ $this->namespaces = [];
+ $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
+ foreach ($this->sortCommands($all) as $namespace => $commands) {
+ $names = [];
+ /** @var Command $command */
+ foreach ($commands as $name => $command) {
+ if (!$command->getName() || !$this->showHidden && $command->isHidden()) {
+ continue;
+ }
+ if ($command->getName() === $name) {
+ $this->commands[$name] = $command;
+ } else {
+ $this->aliases[$name] = $command;
+ }
+ $names[] = $name;
+ }
+ $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];
+ }
+ }
+ private function sortCommands(array $commands) : array
+ {
+ $namespacedCommands = [];
+ $globalCommands = [];
+ $sortedCommands = [];
+ foreach ($commands as $name => $command) {
+ $key = $this->application->extractNamespace($name, 1);
+ if (\in_array($key, ['', self::GLOBAL_NAMESPACE], \true)) {
+ $globalCommands[$name] = $command;
+ } else {
+ $namespacedCommands[$key][$name] = $command;
+ }
+ }
+ if ($globalCommands) {
+ \ksort($globalCommands);
+ $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands;
+ }
+ if ($namespacedCommands) {
+ \ksort($namespacedCommands, \SORT_STRING);
+ foreach ($namespacedCommands as $key => $commandsSet) {
+ \ksort($commandsSet);
+ $sortedCommands[$key] = $commandsSet;
+ }
+ }
+ return $sortedCommands;
+ }
+}
diff --git a/vendor/symfony/console/Descriptor/Descriptor.php b/vendor/symfony/console/Descriptor/Descriptor.php
new file mode 100644
index 0000000000..3d4b64958e
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/Descriptor.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Descriptor;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+abstract class Descriptor implements DescriptorInterface
+{
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ protected $output;
+ public function describe(OutputInterface $output, object $object, array $options = []) : void
+ {
+ $this->output = $output;
+ switch (\true) {
+ case $object instanceof InputArgument:
+ $this->describeInputArgument($object, $options);
+ break;
+ case $object instanceof InputOption:
+ $this->describeInputOption($object, $options);
+ break;
+ case $object instanceof InputDefinition:
+ $this->describeInputDefinition($object, $options);
+ break;
+ case $object instanceof Command:
+ $this->describeCommand($object, $options);
+ break;
+ case $object instanceof Application:
+ $this->describeApplication($object, $options);
+ break;
+ default:
+ throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', \get_debug_type($object)));
+ }
+ }
+ protected function write(string $content, bool $decorated = \false) : void
+ {
+ $this->output->write($content, \false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
+ }
+ /**
+ * Describes an InputArgument instance.
+ */
+ protected abstract function describeInputArgument(InputArgument $argument, array $options = []) : void;
+ /**
+ * Describes an InputOption instance.
+ */
+ protected abstract function describeInputOption(InputOption $option, array $options = []) : void;
+ /**
+ * Describes an InputDefinition instance.
+ */
+ protected abstract function describeInputDefinition(InputDefinition $definition, array $options = []) : void;
+ /**
+ * Describes a Command instance.
+ */
+ protected abstract function describeCommand(Command $command, array $options = []) : void;
+ /**
+ * Describes an Application instance.
+ */
+ protected abstract function describeApplication(Application $application, array $options = []) : void;
+}
diff --git a/vendor/symfony/console/Descriptor/DescriptorInterface.php b/vendor/symfony/console/Descriptor/DescriptorInterface.php
new file mode 100644
index 0000000000..4bae829dbf
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/DescriptorInterface.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Descriptor;
+
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Descriptor interface.
+ *
+ * @author Jean-François Simon
+ */
+interface DescriptorInterface
+{
+ /**
+ * @return void
+ */
+ public function describe(OutputInterface $output, object $object, array $options = []);
+}
diff --git a/vendor/symfony/console/Descriptor/JsonDescriptor.php b/vendor/symfony/console/Descriptor/JsonDescriptor.php
new file mode 100644
index 0000000000..e537d8c03f
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/JsonDescriptor.php
@@ -0,0 +1,112 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Descriptor;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+/**
+ * JSON descriptor.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class JsonDescriptor extends Descriptor
+{
+ protected function describeInputArgument(InputArgument $argument, array $options = []) : void
+ {
+ $this->writeData($this->getInputArgumentData($argument), $options);
+ }
+ protected function describeInputOption(InputOption $option, array $options = []) : void
+ {
+ $this->writeData($this->getInputOptionData($option), $options);
+ if ($option->isNegatable()) {
+ $this->writeData($this->getInputOptionData($option, \true), $options);
+ }
+ }
+ protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void
+ {
+ $this->writeData($this->getInputDefinitionData($definition), $options);
+ }
+ protected function describeCommand(Command $command, array $options = []) : void
+ {
+ $this->writeData($this->getCommandData($command, $options['short'] ?? \false), $options);
+ }
+ protected function describeApplication(Application $application, array $options = []) : void
+ {
+ $describedNamespace = $options['namespace'] ?? null;
+ $description = new ApplicationDescription($application, $describedNamespace, \true);
+ $commands = [];
+ foreach ($description->getCommands() as $command) {
+ $commands[] = $this->getCommandData($command, $options['short'] ?? \false);
+ }
+ $data = [];
+ if ('UNKNOWN' !== $application->getName()) {
+ $data['application']['name'] = $application->getName();
+ if ('UNKNOWN' !== $application->getVersion()) {
+ $data['application']['version'] = $application->getVersion();
+ }
+ }
+ $data['commands'] = $commands;
+ if ($describedNamespace) {
+ $data['namespace'] = $describedNamespace;
+ } else {
+ $data['namespaces'] = \array_values($description->getNamespaces());
+ }
+ $this->writeData($data, $options);
+ }
+ /**
+ * Writes data as json.
+ */
+ private function writeData(array $data, array $options) : void
+ {
+ $flags = $options['json_encoding'] ?? 0;
+ $this->write(\json_encode($data, $flags));
+ }
+ private function getInputArgumentData(InputArgument $argument) : array
+ {
+ return ['name' => $argument->getName(), 'is_required' => $argument->isRequired(), 'is_array' => $argument->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $argument->getDescription()), 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault()];
+ }
+ private function getInputOptionData(InputOption $option, bool $negated = \false) : array
+ {
+ return $negated ? ['name' => '--no-' . $option->getName(), 'shortcut' => '', 'accept_value' => \false, 'is_value_required' => \false, 'is_multiple' => \false, 'description' => 'Negate the "--' . $option->getName() . '" option', 'default' => \false] : ['name' => '--' . $option->getName(), 'shortcut' => $option->getShortcut() ? '-' . \str_replace('|', '|-', $option->getShortcut()) : '', 'accept_value' => $option->acceptValue(), 'is_value_required' => $option->isValueRequired(), 'is_multiple' => $option->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $option->getDescription()), 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault()];
+ }
+ private function getInputDefinitionData(InputDefinition $definition) : array
+ {
+ $inputArguments = [];
+ foreach ($definition->getArguments() as $name => $argument) {
+ $inputArguments[$name] = $this->getInputArgumentData($argument);
+ }
+ $inputOptions = [];
+ foreach ($definition->getOptions() as $name => $option) {
+ $inputOptions[$name] = $this->getInputOptionData($option);
+ if ($option->isNegatable()) {
+ $inputOptions['no-' . $name] = $this->getInputOptionData($option, \true);
+ }
+ }
+ return ['arguments' => $inputArguments, 'options' => $inputOptions];
+ }
+ private function getCommandData(Command $command, bool $short = \false) : array
+ {
+ $data = ['name' => $command->getName(), 'description' => $command->getDescription()];
+ if ($short) {
+ $data += ['usage' => $command->getAliases()];
+ } else {
+ $command->mergeApplicationDefinition(\false);
+ $data += ['usage' => \array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()), 'help' => $command->getProcessedHelp(), 'definition' => $this->getInputDefinitionData($command->getDefinition())];
+ }
+ $data['hidden'] = $command->isHidden();
+ return $data;
+ }
+}
diff --git a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php
new file mode 100644
index 0000000000..8b9053db9c
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php
@@ -0,0 +1,128 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Descriptor;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Helper\Helper;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Markdown descriptor.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class MarkdownDescriptor extends Descriptor
+{
+ public function describe(OutputInterface $output, object $object, array $options = []) : void
+ {
+ $decorated = $output->isDecorated();
+ $output->setDecorated(\false);
+ parent::describe($output, $object, $options);
+ $output->setDecorated($decorated);
+ }
+ protected function write(string $content, bool $decorated = \true) : void
+ {
+ parent::write($content, $decorated);
+ }
+ protected function describeInputArgument(InputArgument $argument, array $options = []) : void
+ {
+ $this->write('#### `' . ($argument->getName() ?: '') . "`\n\n" . ($argument->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $argument->getDescription()) . "\n\n" : '') . '* Is required: ' . ($argument->isRequired() ? 'yes' : 'no') . "\n" . '* Is array: ' . ($argument->isArray() ? 'yes' : 'no') . "\n" . '* Default: `' . \str_replace("\n", '', \var_export($argument->getDefault(), \true)) . '`');
+ }
+ protected function describeInputOption(InputOption $option, array $options = []) : void
+ {
+ $name = '--' . $option->getName();
+ if ($option->isNegatable()) {
+ $name .= '|--no-' . $option->getName();
+ }
+ if ($option->getShortcut()) {
+ $name .= '|-' . \str_replace('|', '|-', $option->getShortcut()) . '';
+ }
+ $this->write('#### `' . $name . '`' . "\n\n" . ($option->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $option->getDescription()) . "\n\n" : '') . '* Accept value: ' . ($option->acceptValue() ? 'yes' : 'no') . "\n" . '* Is value required: ' . ($option->isValueRequired() ? 'yes' : 'no') . "\n" . '* Is multiple: ' . ($option->isArray() ? 'yes' : 'no') . "\n" . '* Is negatable: ' . ($option->isNegatable() ? 'yes' : 'no') . "\n" . '* Default: `' . \str_replace("\n", '', \var_export($option->getDefault(), \true)) . '`');
+ }
+ protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void
+ {
+ if ($showArguments = \count($definition->getArguments()) > 0) {
+ $this->write('### Arguments');
+ foreach ($definition->getArguments() as $argument) {
+ $this->write("\n\n");
+ $this->describeInputArgument($argument);
+ }
+ }
+ if (\count($definition->getOptions()) > 0) {
+ if ($showArguments) {
+ $this->write("\n\n");
+ }
+ $this->write('### Options');
+ foreach ($definition->getOptions() as $option) {
+ $this->write("\n\n");
+ $this->describeInputOption($option);
+ }
+ }
+ }
+ protected function describeCommand(Command $command, array $options = []) : void
+ {
+ if ($options['short'] ?? \false) {
+ $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::width($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage' . "\n\n" . \array_reduce($command->getAliases(), function ($carry, $usage) {
+ return $carry . '* `' . $usage . '`' . "\n";
+ }));
+ return;
+ }
+ $command->mergeApplicationDefinition(\false);
+ $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::width($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage' . "\n\n" . \array_reduce(\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
+ return $carry . '* `' . $usage . '`' . "\n";
+ }));
+ if ($help = $command->getProcessedHelp()) {
+ $this->write("\n");
+ $this->write($help);
+ }
+ $definition = $command->getDefinition();
+ if ($definition->getOptions() || $definition->getArguments()) {
+ $this->write("\n\n");
+ $this->describeInputDefinition($definition);
+ }
+ }
+ protected function describeApplication(Application $application, array $options = []) : void
+ {
+ $describedNamespace = $options['namespace'] ?? null;
+ $description = new ApplicationDescription($application, $describedNamespace);
+ $title = $this->getApplicationTitle($application);
+ $this->write($title . "\n" . \str_repeat('=', Helper::width($title)));
+ foreach ($description->getNamespaces() as $namespace) {
+ if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
+ $this->write("\n\n");
+ $this->write('**' . $namespace['id'] . ':**');
+ }
+ $this->write("\n\n");
+ $this->write(\implode("\n", \array_map(function ($commandName) use($description) {
+ return \sprintf('* [`%s`](#%s)', $commandName, \str_replace(':', '', $description->getCommand($commandName)->getName()));
+ }, $namespace['commands'])));
+ }
+ foreach ($description->getCommands() as $command) {
+ $this->write("\n\n");
+ $this->describeCommand($command, $options);
+ }
+ }
+ private function getApplicationTitle(Application $application) : string
+ {
+ if ('UNKNOWN' !== $application->getName()) {
+ if ('UNKNOWN' !== $application->getVersion()) {
+ return \sprintf('%s %s', $application->getName(), $application->getVersion());
+ }
+ return $application->getName();
+ }
+ return 'Console Tool';
+ }
+}
diff --git a/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php
new file mode 100644
index 0000000000..b3a52ab475
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php
@@ -0,0 +1,234 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Descriptor;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Helper\Helper;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\String\UnicodeString;
+class ReStructuredTextDescriptor extends Descriptor
+{
+ //
+ /**
+ * @var string
+ */
+ private $partChar = '=';
+ //
+ /**
+ * @var string
+ */
+ private $chapterChar = '-';
+ //
+ /**
+ * @var string
+ */
+ private $sectionChar = '~';
+ //
+ /**
+ * @var string
+ */
+ private $subsectionChar = '.';
+ //
+ /**
+ * @var string
+ */
+ private $subsubsectionChar = '^';
+ //
+ /**
+ * @var string
+ */
+ private $paragraphsChar = '"';
+ /**
+ * @var mixed[]
+ */
+ private $visibleNamespaces = [];
+ public function describe(OutputInterface $output, object $object, array $options = []) : void
+ {
+ $decorated = $output->isDecorated();
+ $output->setDecorated(\false);
+ parent::describe($output, $object, $options);
+ $output->setDecorated($decorated);
+ }
+ /**
+ * Override parent method to set $decorated = true.
+ */
+ protected function write(string $content, bool $decorated = \true) : void
+ {
+ parent::write($content, $decorated);
+ }
+ protected function describeInputArgument(InputArgument $argument, array $options = []) : void
+ {
+ $this->write($argument->getName() ?: '' . "\n" . \str_repeat($this->paragraphsChar, Helper::width($argument->getName())) . "\n\n" . ($argument->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $argument->getDescription()) . "\n\n" : '') . '- **Is required**: ' . ($argument->isRequired() ? 'yes' : 'no') . "\n" . '- **Is array**: ' . ($argument->isArray() ? 'yes' : 'no') . "\n" . '- **Default**: ``' . \str_replace("\n", '', \var_export($argument->getDefault(), \true)) . '``');
+ }
+ protected function describeInputOption(InputOption $option, array $options = []) : void
+ {
+ $name = '\\-\\-' . $option->getName();
+ if ($option->isNegatable()) {
+ $name .= '|\\-\\-no-' . $option->getName();
+ }
+ if ($option->getShortcut()) {
+ $name .= '|-' . \str_replace('|', '|-', $option->getShortcut());
+ }
+ $optionDescription = $option->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n\n", $option->getDescription()) . "\n\n" : '';
+ $optionDescription = (new UnicodeString($optionDescription))->ascii();
+ $this->write($name . "\n" . \str_repeat($this->paragraphsChar, Helper::width($name)) . "\n\n" . $optionDescription . '- **Accept value**: ' . ($option->acceptValue() ? 'yes' : 'no') . "\n" . '- **Is value required**: ' . ($option->isValueRequired() ? 'yes' : 'no') . "\n" . '- **Is multiple**: ' . ($option->isArray() ? 'yes' : 'no') . "\n" . '- **Is negatable**: ' . ($option->isNegatable() ? 'yes' : 'no') . "\n" . '- **Default**: ``' . \str_replace("\n", '', \var_export($option->getDefault(), \true)) . '``' . "\n");
+ }
+ protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void
+ {
+ if ($showArguments = (bool) $definition->getArguments()) {
+ $this->write("Arguments\n" . \str_repeat($this->subsubsectionChar, 9)) . "\n\n";
+ foreach ($definition->getArguments() as $argument) {
+ $this->write("\n\n");
+ $this->describeInputArgument($argument);
+ }
+ }
+ if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) {
+ if ($showArguments) {
+ $this->write("\n\n");
+ }
+ $this->write("Options\n" . \str_repeat($this->subsubsectionChar, 7) . "\n\n");
+ foreach ($nonDefaultOptions as $option) {
+ $this->describeInputOption($option);
+ $this->write("\n");
+ }
+ }
+ }
+ protected function describeCommand(Command $command, array $options = []) : void
+ {
+ if ($options['short'] ?? \false) {
+ $this->write('``' . $command->getName() . "``\n" . \str_repeat($this->subsectionChar, Helper::width($command->getName())) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . "Usage\n" . \str_repeat($this->paragraphsChar, 5) . "\n\n" . \array_reduce($command->getAliases(), static function ($carry, $usage) {
+ return $carry . '- ``' . $usage . '``' . "\n";
+ }));
+ return;
+ }
+ $command->mergeApplicationDefinition(\false);
+ foreach ($command->getAliases() as $alias) {
+ $this->write('.. _' . $alias . ":\n\n");
+ }
+ $this->write($command->getName() . "\n" . \str_repeat($this->subsectionChar, Helper::width($command->getName())) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . "Usage\n" . \str_repeat($this->subsubsectionChar, 5) . "\n\n" . \array_reduce(\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static function ($carry, $usage) {
+ return $carry . '- ``' . $usage . '``' . "\n";
+ }));
+ if ($help = $command->getProcessedHelp()) {
+ $this->write("\n");
+ $this->write($help);
+ }
+ $definition = $command->getDefinition();
+ if ($definition->getOptions() || $definition->getArguments()) {
+ $this->write("\n\n");
+ $this->describeInputDefinition($definition);
+ }
+ }
+ protected function describeApplication(Application $application, array $options = []) : void
+ {
+ $description = new ApplicationDescription($application, $options['namespace'] ?? null);
+ $title = $this->getApplicationTitle($application);
+ $this->write($title . "\n" . \str_repeat($this->partChar, Helper::width($title)));
+ $this->createTableOfContents($description, $application);
+ $this->describeCommands($application, $options);
+ }
+ private function getApplicationTitle(Application $application) : string
+ {
+ if ('UNKNOWN' === $application->getName()) {
+ return 'Console Tool';
+ }
+ if ('UNKNOWN' !== $application->getVersion()) {
+ return \sprintf('%s %s', $application->getName(), $application->getVersion());
+ }
+ return $application->getName();
+ }
+ private function describeCommands($application, array $options) : void
+ {
+ $title = 'Commands';
+ $this->write("\n\n{$title}\n" . \str_repeat($this->chapterChar, Helper::width($title)) . "\n\n");
+ foreach ($this->visibleNamespaces as $namespace) {
+ if ('_global' === $namespace) {
+ $commands = $application->all('');
+ $this->write('Global' . "\n" . \str_repeat($this->sectionChar, Helper::width('Global')) . "\n\n");
+ } else {
+ $commands = $application->all($namespace);
+ $this->write($namespace . "\n" . \str_repeat($this->sectionChar, Helper::width($namespace)) . "\n\n");
+ }
+ foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) {
+ $this->describeCommand($command, $options);
+ $this->write("\n\n");
+ }
+ }
+ }
+ private function createTableOfContents(ApplicationDescription $description, Application $application) : void
+ {
+ $this->setVisibleNamespaces($description);
+ $chapterTitle = 'Table of Contents';
+ $this->write("\n\n{$chapterTitle}\n" . \str_repeat($this->chapterChar, Helper::width($chapterTitle)) . "\n\n");
+ foreach ($this->visibleNamespaces as $namespace) {
+ if ('_global' === $namespace) {
+ $commands = $application->all('');
+ } else {
+ $commands = $application->all($namespace);
+ $this->write("\n\n");
+ $this->write($namespace . "\n" . \str_repeat($this->sectionChar, Helper::width($namespace)) . "\n\n");
+ }
+ $commands = $this->removeAliasesAndHiddenCommands($commands);
+ $this->write("\n\n");
+ $this->write(\implode("\n", \array_map(static function ($commandName) {
+ return \sprintf('- `%s`_', $commandName);
+ }, \array_keys($commands))));
+ }
+ }
+ private function getNonDefaultOptions(InputDefinition $definition) : array
+ {
+ $globalOptions = ['help', 'quiet', 'verbose', 'version', 'ansi', 'no-interaction'];
+ $nonDefaultOptions = [];
+ foreach ($definition->getOptions() as $option) {
+ // Skip global options.
+ if (!\in_array($option->getName(), $globalOptions)) {
+ $nonDefaultOptions[] = $option;
+ }
+ }
+ return $nonDefaultOptions;
+ }
+ private function setVisibleNamespaces(ApplicationDescription $description) : void
+ {
+ $commands = $description->getCommands();
+ foreach ($description->getNamespaces() as $namespace) {
+ try {
+ $namespaceCommands = $namespace['commands'];
+ foreach ($namespaceCommands as $key => $commandName) {
+ if (!\array_key_exists($commandName, $commands)) {
+ // If the array key does not exist, then this is an alias.
+ unset($namespaceCommands[$key]);
+ } elseif ($commands[$commandName]->isHidden()) {
+ unset($namespaceCommands[$key]);
+ }
+ }
+ if (!$namespaceCommands) {
+ // If the namespace contained only aliases or hidden commands, skip the namespace.
+ continue;
+ }
+ } catch (\Exception $exception) {
+ }
+ $this->visibleNamespaces[] = $namespace['id'];
+ }
+ }
+ private function removeAliasesAndHiddenCommands(array $commands) : array
+ {
+ foreach ($commands as $key => $command) {
+ if ($command->isHidden() || \in_array($key, $command->getAliases(), \true)) {
+ unset($commands[$key]);
+ }
+ }
+ unset($commands['completion']);
+ return $commands;
+ }
+}
diff --git a/vendor/symfony/console/Descriptor/TextDescriptor.php b/vendor/symfony/console/Descriptor/TextDescriptor.php
new file mode 100644
index 0000000000..b2cdf82bea
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/TextDescriptor.php
@@ -0,0 +1,274 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Descriptor;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Formatter\OutputFormatter;
+use EasyCI202401\Symfony\Component\Console\Helper\Helper;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+/**
+ * Text descriptor.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class TextDescriptor extends Descriptor
+{
+ protected function describeInputArgument(InputArgument $argument, array $options = []) : void
+ {
+ if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
+ $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault()));
+ } else {
+ $default = '';
+ }
+ $totalWidth = $options['total_width'] ?? Helper::width($argument->getName());
+ $spacingWidth = $totalWidth - \strlen($argument->getName());
+ $this->writeText(\sprintf(
+ ' %s %s%s%s',
+ $argument->getName(),
+ \str_repeat(' ', $spacingWidth),
+ // + 4 = 2 spaces before , 2 spaces after
+ \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
+ $default
+ ), $options);
+ }
+ protected function describeInputOption(InputOption $option, array $options = []) : void
+ {
+ if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
+ $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault()));
+ } else {
+ $default = '';
+ }
+ $value = '';
+ if ($option->acceptValue()) {
+ $value = '=' . \strtoupper($option->getName());
+ if ($option->isValueOptional()) {
+ $value = '[' . $value . ']';
+ }
+ }
+ $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
+ $synopsis = \sprintf('%s%s', $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value));
+ $spacingWidth = $totalWidth - Helper::width($synopsis);
+ $this->writeText(\sprintf(
+ ' %s %s%s%s%s',
+ $synopsis,
+ \str_repeat(' ', $spacingWidth),
+ // + 4 = 2 spaces before , 2 spaces after
+ \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $option->getDescription()),
+ $default,
+ $option->isArray() ? ' (multiple values allowed)' : ''
+ ), $options);
+ }
+ protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void
+ {
+ $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
+ foreach ($definition->getArguments() as $argument) {
+ $totalWidth = \max($totalWidth, Helper::width($argument->getName()));
+ }
+ if ($definition->getArguments()) {
+ $this->writeText('Arguments:', $options);
+ $this->writeText("\n");
+ foreach ($definition->getArguments() as $argument) {
+ $this->describeInputArgument($argument, \array_merge($options, ['total_width' => $totalWidth]));
+ $this->writeText("\n");
+ }
+ }
+ if ($definition->getArguments() && $definition->getOptions()) {
+ $this->writeText("\n");
+ }
+ if ($definition->getOptions()) {
+ $laterOptions = [];
+ $this->writeText('Options:', $options);
+ foreach ($definition->getOptions() as $option) {
+ if (\strlen($option->getShortcut() ?? '') > 1) {
+ $laterOptions[] = $option;
+ continue;
+ }
+ $this->writeText("\n");
+ $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth]));
+ }
+ foreach ($laterOptions as $option) {
+ $this->writeText("\n");
+ $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth]));
+ }
+ }
+ }
+ protected function describeCommand(Command $command, array $options = []) : void
+ {
+ $command->mergeApplicationDefinition(\false);
+ if ($description = $command->getDescription()) {
+ $this->writeText('Description:', $options);
+ $this->writeText("\n");
+ $this->writeText(' ' . $description);
+ $this->writeText("\n\n");
+ }
+ $this->writeText('Usage:', $options);
+ foreach (\array_merge([$command->getSynopsis(\true)], $command->getAliases(), $command->getUsages()) as $usage) {
+ $this->writeText("\n");
+ $this->writeText(' ' . OutputFormatter::escape($usage), $options);
+ }
+ $this->writeText("\n");
+ $definition = $command->getDefinition();
+ if ($definition->getOptions() || $definition->getArguments()) {
+ $this->writeText("\n");
+ $this->describeInputDefinition($definition, $options);
+ $this->writeText("\n");
+ }
+ $help = $command->getProcessedHelp();
+ if ($help && $help !== $description) {
+ $this->writeText("\n");
+ $this->writeText('Help:', $options);
+ $this->writeText("\n");
+ $this->writeText(' ' . \str_replace("\n", "\n ", $help), $options);
+ $this->writeText("\n");
+ }
+ }
+ protected function describeApplication(Application $application, array $options = []) : void
+ {
+ $describedNamespace = $options['namespace'] ?? null;
+ $description = new ApplicationDescription($application, $describedNamespace);
+ if (isset($options['raw_text']) && $options['raw_text']) {
+ $width = $this->getColumnWidth($description->getCommands());
+ foreach ($description->getCommands() as $command) {
+ $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
+ $this->writeText("\n");
+ }
+ } else {
+ if ('' != ($help = $application->getHelp())) {
+ $this->writeText("{$help}\n\n", $options);
+ }
+ $this->writeText("Usage:\n", $options);
+ $this->writeText(" command [options] [arguments]\n\n", $options);
+ $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);
+ $this->writeText("\n");
+ $this->writeText("\n");
+ $commands = $description->getCommands();
+ $namespaces = $description->getNamespaces();
+ if ($describedNamespace && $namespaces) {
+ // make sure all alias commands are included when describing a specific namespace
+ $describedNamespaceInfo = \reset($namespaces);
+ foreach ($describedNamespaceInfo['commands'] as $name) {
+ $commands[$name] = $description->getCommand($name);
+ }
+ }
+ // calculate max. width based on available commands per namespace
+ $width = $this->getColumnWidth(\array_merge(...\array_values(\array_map(function ($namespace) use($commands) {
+ return \array_intersect($namespace['commands'], \array_keys($commands));
+ }, \array_values($namespaces)))));
+ if ($describedNamespace) {
+ $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options);
+ } else {
+ $this->writeText('Available commands:', $options);
+ }
+ foreach ($namespaces as $namespace) {
+ $namespace['commands'] = \array_filter($namespace['commands'], function ($name) use($commands) {
+ return isset($commands[$name]);
+ });
+ if (!$namespace['commands']) {
+ continue;
+ }
+ if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
+ $this->writeText("\n");
+ $this->writeText(' ' . $namespace['id'] . '', $options);
+ }
+ foreach ($namespace['commands'] as $name) {
+ $this->writeText("\n");
+ $spacingWidth = $width - Helper::width($name);
+ $command = $commands[$name];
+ $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';
+ $this->writeText(\sprintf(' %s%s%s', $name, \str_repeat(' ', $spacingWidth), $commandAliases . $command->getDescription()), $options);
+ }
+ }
+ $this->writeText("\n");
+ }
+ }
+ private function writeText(string $content, array $options = []) : void
+ {
+ $this->write(isset($options['raw_text']) && $options['raw_text'] ? \strip_tags($content) : $content, isset($options['raw_output']) ? !$options['raw_output'] : \true);
+ }
+ /**
+ * Formats command aliases to show them in the command description.
+ */
+ private function getCommandAliasesText(Command $command) : string
+ {
+ $text = '';
+ $aliases = $command->getAliases();
+ if ($aliases) {
+ $text = '[' . \implode('|', $aliases) . '] ';
+ }
+ return $text;
+ }
+ /**
+ * Formats input option/argument default value.
+ * @param mixed $default
+ */
+ private function formatDefaultValue($default) : string
+ {
+ if (\INF === $default) {
+ return 'INF';
+ }
+ if (\is_string($default)) {
+ $default = OutputFormatter::escape($default);
+ } elseif (\is_array($default)) {
+ foreach ($default as $key => $value) {
+ if (\is_string($value)) {
+ $default[$key] = OutputFormatter::escape($value);
+ }
+ }
+ }
+ return \str_replace('\\\\', '\\', \json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
+ }
+ /**
+ * @param array $commands
+ */
+ private function getColumnWidth(array $commands) : int
+ {
+ $widths = [];
+ foreach ($commands as $command) {
+ if ($command instanceof Command) {
+ $widths[] = Helper::width($command->getName());
+ foreach ($command->getAliases() as $alias) {
+ $widths[] = Helper::width($alias);
+ }
+ } else {
+ $widths[] = Helper::width($command);
+ }
+ }
+ return $widths ? \max($widths) + 2 : 0;
+ }
+ /**
+ * @param InputOption[] $options
+ */
+ private function calculateTotalWidthForOptions(array $options) : int
+ {
+ $totalWidth = 0;
+ foreach ($options as $option) {
+ // "-" + shortcut + ", --" + name
+ $nameLength = 1 + \max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName());
+ if ($option->isNegatable()) {
+ $nameLength += 6 + Helper::width($option->getName());
+ // |--no- + name
+ } elseif ($option->acceptValue()) {
+ $valueLength = 1 + Helper::width($option->getName());
+ // = + value
+ $valueLength += $option->isValueOptional() ? 2 : 0;
+ // [ + ]
+ $nameLength += $valueLength;
+ }
+ $totalWidth = \max($totalWidth, $nameLength);
+ }
+ return $totalWidth;
+ }
+}
diff --git a/vendor/symfony/console/Descriptor/XmlDescriptor.php b/vendor/symfony/console/Descriptor/XmlDescriptor.php
new file mode 100644
index 0000000000..5d2479c6e9
--- /dev/null
+++ b/vendor/symfony/console/Descriptor/XmlDescriptor.php
@@ -0,0 +1,191 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Descriptor;
+
+use EasyCI202401\Symfony\Component\Console\Application;
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Input\InputArgument;
+use EasyCI202401\Symfony\Component\Console\Input\InputDefinition;
+use EasyCI202401\Symfony\Component\Console\Input\InputOption;
+/**
+ * XML descriptor.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class XmlDescriptor extends Descriptor
+{
+ public function getInputDefinitionDocument(InputDefinition $definition) : \DOMDocument
+ {
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->appendChild($definitionXML = $dom->createElement('definition'));
+ $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
+ foreach ($definition->getArguments() as $argument) {
+ $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
+ }
+ $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
+ foreach ($definition->getOptions() as $option) {
+ $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
+ }
+ return $dom;
+ }
+ public function getCommandDocument(Command $command, bool $short = \false) : \DOMDocument
+ {
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->appendChild($commandXML = $dom->createElement('command'));
+ $commandXML->setAttribute('id', $command->getName());
+ $commandXML->setAttribute('name', $command->getName());
+ $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);
+ $commandXML->appendChild($usagesXML = $dom->createElement('usages'));
+ $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
+ $descriptionXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getDescription())));
+ if ($short) {
+ foreach ($command->getAliases() as $usage) {
+ $usagesXML->appendChild($dom->createElement('usage', $usage));
+ }
+ } else {
+ $command->mergeApplicationDefinition(\false);
+ foreach (\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
+ $usagesXML->appendChild($dom->createElement('usage', $usage));
+ }
+ $commandXML->appendChild($helpXML = $dom->createElement('help'));
+ $helpXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getProcessedHelp())));
+ $definitionXML = $this->getInputDefinitionDocument($command->getDefinition());
+ $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
+ }
+ return $dom;
+ }
+ public function getApplicationDocument(Application $application, string $namespace = null, bool $short = \false) : \DOMDocument
+ {
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->appendChild($rootXml = $dom->createElement('symfony'));
+ if ('UNKNOWN' !== $application->getName()) {
+ $rootXml->setAttribute('name', $application->getName());
+ if ('UNKNOWN' !== $application->getVersion()) {
+ $rootXml->setAttribute('version', $application->getVersion());
+ }
+ }
+ $rootXml->appendChild($commandsXML = $dom->createElement('commands'));
+ $description = new ApplicationDescription($application, $namespace, \true);
+ if ($namespace) {
+ $commandsXML->setAttribute('namespace', $namespace);
+ }
+ foreach ($description->getCommands() as $command) {
+ $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short));
+ }
+ if (!$namespace) {
+ $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));
+ foreach ($description->getNamespaces() as $namespaceDescription) {
+ $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
+ $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);
+ foreach ($namespaceDescription['commands'] as $name) {
+ $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
+ $commandXML->appendChild($dom->createTextNode($name));
+ }
+ }
+ }
+ return $dom;
+ }
+ protected function describeInputArgument(InputArgument $argument, array $options = []) : void
+ {
+ $this->writeDocument($this->getInputArgumentDocument($argument));
+ }
+ protected function describeInputOption(InputOption $option, array $options = []) : void
+ {
+ $this->writeDocument($this->getInputOptionDocument($option));
+ }
+ protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void
+ {
+ $this->writeDocument($this->getInputDefinitionDocument($definition));
+ }
+ protected function describeCommand(Command $command, array $options = []) : void
+ {
+ $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? \false));
+ }
+ protected function describeApplication(Application $application, array $options = []) : void
+ {
+ $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? \false));
+ }
+ /**
+ * Appends document children to parent node.
+ */
+ private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) : void
+ {
+ foreach ($importedParent->childNodes as $childNode) {
+ $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, \true));
+ }
+ }
+ /**
+ * Writes DOM document.
+ */
+ private function writeDocument(\DOMDocument $dom) : void
+ {
+ $dom->formatOutput = \true;
+ $this->write($dom->saveXML());
+ }
+ private function getInputArgumentDocument(InputArgument $argument) : \DOMDocument
+ {
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->appendChild($objectXML = $dom->createElement('argument'));
+ $objectXML->setAttribute('name', $argument->getName());
+ $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
+ $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
+ $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
+ $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
+ $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
+ $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [\var_export($argument->getDefault(), \true)] : ($argument->getDefault() ? [$argument->getDefault()] : []));
+ foreach ($defaults as $default) {
+ $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
+ $defaultXML->appendChild($dom->createTextNode($default));
+ }
+ return $dom;
+ }
+ private function getInputOptionDocument(InputOption $option) : \DOMDocument
+ {
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->appendChild($objectXML = $dom->createElement('option'));
+ $objectXML->setAttribute('name', '--' . $option->getName());
+ $pos = \strpos($option->getShortcut() ?? '', '|');
+ if (\false !== $pos) {
+ $objectXML->setAttribute('shortcut', '-' . \substr($option->getShortcut(), 0, $pos));
+ $objectXML->setAttribute('shortcuts', '-' . \str_replace('|', '|-', $option->getShortcut()));
+ } else {
+ $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-' . $option->getShortcut() : '');
+ }
+ $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
+ $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
+ $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
+ $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
+ $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
+ if ($option->acceptValue()) {
+ $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [\var_export($option->getDefault(), \true)] : ($option->getDefault() ? [$option->getDefault()] : []));
+ $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
+ if (!empty($defaults)) {
+ foreach ($defaults as $default) {
+ $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
+ $defaultXML->appendChild($dom->createTextNode($default));
+ }
+ }
+ }
+ if ($option->isNegatable()) {
+ $dom->appendChild($objectXML = $dom->createElement('option'));
+ $objectXML->setAttribute('name', '--no-' . $option->getName());
+ $objectXML->setAttribute('shortcut', '');
+ $objectXML->setAttribute('accept_value', 0);
+ $objectXML->setAttribute('is_value_required', 0);
+ $objectXML->setAttribute('is_multiple', 0);
+ $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
+ $descriptionXML->appendChild($dom->createTextNode('Negate the "--' . $option->getName() . '" option'));
+ }
+ return $dom;
+ }
+}
diff --git a/vendor/symfony/console/Event/ConsoleCommandEvent.php b/vendor/symfony/console/Event/ConsoleCommandEvent.php
new file mode 100644
index 0000000000..9aaf9d2965
--- /dev/null
+++ b/vendor/symfony/console/Event/ConsoleCommandEvent.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Event;
+
+/**
+ * Allows to do things before the command is executed, like skipping the command or executing code before the command is
+ * going to be executed.
+ *
+ * Changing the input arguments will have no effect.
+ *
+ * @author Fabien Potencier
+ */
+final class ConsoleCommandEvent extends ConsoleEvent
+{
+ /**
+ * The return code for skipped commands, this will also be passed into the terminate event.
+ */
+ public const RETURN_CODE_DISABLED = 113;
+ /**
+ * Indicates if the command should be run or skipped.
+ * @var bool
+ */
+ private $commandShouldRun = \true;
+ /**
+ * Disables the command, so it won't be run.
+ */
+ public function disableCommand() : bool
+ {
+ return $this->commandShouldRun = \false;
+ }
+ public function enableCommand() : bool
+ {
+ return $this->commandShouldRun = \true;
+ }
+ /**
+ * Returns true if the command is runnable, false otherwise.
+ */
+ public function commandShouldRun() : bool
+ {
+ return $this->commandShouldRun;
+ }
+}
diff --git a/vendor/symfony/console/Event/ConsoleErrorEvent.php b/vendor/symfony/console/Event/ConsoleErrorEvent.php
new file mode 100644
index 0000000000..a797cfd27c
--- /dev/null
+++ b/vendor/symfony/console/Event/ConsoleErrorEvent.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Event;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Allows to handle throwables thrown while running a command.
+ *
+ * @author Wouter de Jong
+ */
+final class ConsoleErrorEvent extends ConsoleEvent
+{
+ /**
+ * @var \Throwable
+ */
+ private $error;
+ /**
+ * @var int
+ */
+ private $exitCode;
+ public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null)
+ {
+ parent::__construct($command, $input, $output);
+ $this->error = $error;
+ }
+ public function getError() : \Throwable
+ {
+ return $this->error;
+ }
+ public function setError(\Throwable $error) : void
+ {
+ $this->error = $error;
+ }
+ public function setExitCode(int $exitCode) : void
+ {
+ $this->exitCode = $exitCode;
+ $r = new \ReflectionProperty($this->error, 'code');
+ $r->setAccessible(\true);
+ $r->setValue($this->error, $this->exitCode);
+ }
+ public function getExitCode() : int
+ {
+ return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);
+ }
+}
diff --git a/vendor/symfony/console/Event/ConsoleEvent.php b/vendor/symfony/console/Event/ConsoleEvent.php
new file mode 100644
index 0000000000..1672c2ccd5
--- /dev/null
+++ b/vendor/symfony/console/Event/ConsoleEvent.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Event;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Contracts\EventDispatcher\Event;
+/**
+ * Allows to inspect input and output of a command.
+ *
+ * @author Francesco Levorato
+ */
+class ConsoleEvent extends Event
+{
+ protected $command;
+ /**
+ * @var \Symfony\Component\Console\Input\InputInterface
+ */
+ private $input;
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ private $output;
+ public function __construct(?Command $command, InputInterface $input, OutputInterface $output)
+ {
+ $this->command = $command;
+ $this->input = $input;
+ $this->output = $output;
+ }
+ /**
+ * Gets the command that is executed.
+ */
+ public function getCommand() : ?Command
+ {
+ return $this->command;
+ }
+ /**
+ * Gets the input instance.
+ */
+ public function getInput() : InputInterface
+ {
+ return $this->input;
+ }
+ /**
+ * Gets the output instance.
+ */
+ public function getOutput() : OutputInterface
+ {
+ return $this->output;
+ }
+}
diff --git a/vendor/symfony/console/Event/ConsoleSignalEvent.php b/vendor/symfony/console/Event/ConsoleSignalEvent.php
new file mode 100644
index 0000000000..9369814614
--- /dev/null
+++ b/vendor/symfony/console/Event/ConsoleSignalEvent.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Event;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @author marie
+ */
+final class ConsoleSignalEvent extends ConsoleEvent
+{
+ /**
+ * @var int
+ */
+ private $handlingSignal;
+ /**
+ * @var int|false
+ */
+ private $exitCode;
+ /**
+ * @param int|false $exitCode
+ */
+ public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, $exitCode = 0)
+ {
+ parent::__construct($command, $input, $output);
+ $this->handlingSignal = $handlingSignal;
+ $this->exitCode = $exitCode;
+ }
+ public function getHandlingSignal() : int
+ {
+ return $this->handlingSignal;
+ }
+ public function setExitCode(int $exitCode) : void
+ {
+ if ($exitCode < 0 || $exitCode > 255) {
+ throw new \InvalidArgumentException('Exit code must be between 0 and 255.');
+ }
+ $this->exitCode = $exitCode;
+ }
+ public function abortExit() : void
+ {
+ $this->exitCode = \false;
+ }
+ /**
+ * @return int|false
+ */
+ public function getExitCode()
+ {
+ return $this->exitCode;
+ }
+}
diff --git a/vendor/symfony/console/Event/ConsoleTerminateEvent.php b/vendor/symfony/console/Event/ConsoleTerminateEvent.php
new file mode 100644
index 0000000000..9ae6e6ec48
--- /dev/null
+++ b/vendor/symfony/console/Event/ConsoleTerminateEvent.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Event;
+
+use EasyCI202401\Symfony\Component\Console\Command\Command;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Allows to manipulate the exit code of a command after its execution.
+ *
+ * @author Francesco Levorato
+ * @author Jules Pietri
+ */
+final class ConsoleTerminateEvent extends ConsoleEvent
+{
+ /**
+ * @var int
+ */
+ private $exitCode;
+ /**
+ * @readonly
+ * @var int|null
+ */
+ private $interruptingSignal;
+ public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode, ?int $interruptingSignal = null)
+ {
+ $this->exitCode = $exitCode;
+ $this->interruptingSignal = $interruptingSignal;
+ parent::__construct($command, $input, $output);
+ }
+ public function setExitCode(int $exitCode) : void
+ {
+ $this->exitCode = $exitCode;
+ }
+ public function getExitCode() : int
+ {
+ return $this->exitCode;
+ }
+ public function getInterruptingSignal() : ?int
+ {
+ return $this->interruptingSignal;
+ }
+}
diff --git a/vendor/symfony/console/EventListener/ErrorListener.php b/vendor/symfony/console/EventListener/ErrorListener.php
new file mode 100644
index 0000000000..cdf07e8a64
--- /dev/null
+++ b/vendor/symfony/console/EventListener/ErrorListener.php
@@ -0,0 +1,82 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\EventListener;
+
+use EasyCI202401\Psr\Log\LoggerInterface;
+use EasyCI202401\Symfony\Component\Console\ConsoleEvents;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleErrorEvent;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleEvent;
+use EasyCI202401\Symfony\Component\Console\Event\ConsoleTerminateEvent;
+use EasyCI202401\Symfony\Component\EventDispatcher\EventSubscriberInterface;
+/**
+ * @author James Halsall
+ * @author Robin Chalas
+ */
+class ErrorListener implements EventSubscriberInterface
+{
+ /**
+ * @var \Psr\Log\LoggerInterface|null
+ */
+ private $logger;
+ public function __construct(LoggerInterface $logger = null)
+ {
+ $this->logger = $logger;
+ }
+ /**
+ * @return void
+ */
+ public function onConsoleError(ConsoleErrorEvent $event)
+ {
+ if (null === $this->logger) {
+ return;
+ }
+ $error = $event->getError();
+ if (!($inputString = $this->getInputString($event))) {
+ $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]);
+ return;
+ }
+ $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);
+ }
+ /**
+ * @return void
+ */
+ public function onConsoleTerminate(ConsoleTerminateEvent $event)
+ {
+ if (null === $this->logger) {
+ return;
+ }
+ $exitCode = $event->getExitCode();
+ if (0 === $exitCode) {
+ return;
+ }
+ if (!($inputString = $this->getInputString($event))) {
+ $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]);
+ return;
+ }
+ $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]);
+ }
+ public static function getSubscribedEvents() : array
+ {
+ return [ConsoleEvents::ERROR => ['onConsoleError', -128], ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128]];
+ }
+ private static function getInputString(ConsoleEvent $event) : ?string
+ {
+ $commandName = ($nullsafeVariable1 = $event->getCommand()) ? $nullsafeVariable1->getName() : null;
+ $input = $event->getInput();
+ if ($input instanceof \Stringable) {
+ if ($commandName) {
+ return \str_replace(["'{$commandName}'", "\"{$commandName}\""], $commandName, (string) $input);
+ }
+ return (string) $input;
+ }
+ return $commandName;
+ }
+}
diff --git a/vendor/symfony/console/Exception/CommandNotFoundException.php b/vendor/symfony/console/Exception/CommandNotFoundException.php
new file mode 100644
index 0000000000..f4edccd0a9
--- /dev/null
+++ b/vendor/symfony/console/Exception/CommandNotFoundException.php
@@ -0,0 +1,42 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+/**
+ * Represents an incorrect command name typed in the console.
+ *
+ * @author Jérôme Tamarelle
+ */
+class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
+{
+ /**
+ * @var mixed[]
+ */
+ private $alternatives;
+ /**
+ * @param string $message Exception message to throw
+ * @param string[] $alternatives List of similar defined names
+ * @param int $code Exception code
+ * @param \Throwable|null $previous Previous exception used for the exception chaining
+ */
+ public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ $this->alternatives = $alternatives;
+ }
+ /**
+ * @return string[]
+ */
+ public function getAlternatives() : array
+ {
+ return $this->alternatives;
+ }
+}
diff --git a/vendor/symfony/console/Exception/ExceptionInterface.php b/vendor/symfony/console/Exception/ExceptionInterface.php
new file mode 100644
index 0000000000..38e858bcd6
--- /dev/null
+++ b/vendor/symfony/console/Exception/ExceptionInterface.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+/**
+ * ExceptionInterface.
+ *
+ * @author Jérôme Tamarelle
+ */
+interface ExceptionInterface extends \Throwable
+{
+}
diff --git a/vendor/symfony/console/Exception/InvalidArgumentException.php b/vendor/symfony/console/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000000..46b63f8b03
--- /dev/null
+++ b/vendor/symfony/console/Exception/InvalidArgumentException.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+/**
+ * @author Jérôme Tamarelle
+ */
+class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/console/Exception/InvalidOptionException.php b/vendor/symfony/console/Exception/InvalidOptionException.php
new file mode 100644
index 0000000000..d2c53a5dbf
--- /dev/null
+++ b/vendor/symfony/console/Exception/InvalidOptionException.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+/**
+ * Represents an incorrect option name or value typed in the console.
+ *
+ * @author Jérôme Tamarelle
+ */
+class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/console/Exception/LogicException.php b/vendor/symfony/console/Exception/LogicException.php
new file mode 100644
index 0000000000..7140ed7f2e
--- /dev/null
+++ b/vendor/symfony/console/Exception/LogicException.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+/**
+ * @author Jérôme Tamarelle
+ */
+class LogicException extends \LogicException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/console/Exception/MissingInputException.php b/vendor/symfony/console/Exception/MissingInputException.php
new file mode 100644
index 0000000000..cc14983fdb
--- /dev/null
+++ b/vendor/symfony/console/Exception/MissingInputException.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+/**
+ * Represents failure to read input from stdin.
+ *
+ * @author Gabriel Ostrolucký
+ */
+class MissingInputException extends RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/console/Exception/NamespaceNotFoundException.php b/vendor/symfony/console/Exception/NamespaceNotFoundException.php
new file mode 100644
index 0000000000..132f487825
--- /dev/null
+++ b/vendor/symfony/console/Exception/NamespaceNotFoundException.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+/**
+ * Represents an incorrect namespace typed in the console.
+ *
+ * @author Pierre du Plessis
+ */
+class NamespaceNotFoundException extends CommandNotFoundException
+{
+}
diff --git a/vendor/symfony/console/Exception/RunCommandFailedException.php b/vendor/symfony/console/Exception/RunCommandFailedException.php
new file mode 100644
index 0000000000..4d763de30b
--- /dev/null
+++ b/vendor/symfony/console/Exception/RunCommandFailedException.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+use EasyCI202401\Symfony\Component\Console\Messenger\RunCommandContext;
+/**
+ * @author Kevin Bond
+ */
+final class RunCommandFailedException extends RuntimeException
+{
+ /**
+ * @readonly
+ * @var \Symfony\Component\Console\Messenger\RunCommandContext
+ */
+ public $context;
+ /**
+ * @param \Throwable|string $exception
+ */
+ public function __construct($exception, RunCommandContext $context)
+ {
+ $this->context = $context;
+ parent::__construct($exception instanceof \Throwable ? $exception->getMessage() : $exception, $exception instanceof \Throwable ? $exception->getCode() : 0, $exception instanceof \Throwable ? $exception : null);
+ }
+}
diff --git a/vendor/symfony/console/Exception/RuntimeException.php b/vendor/symfony/console/Exception/RuntimeException.php
new file mode 100644
index 0000000000..79494f066a
--- /dev/null
+++ b/vendor/symfony/console/Exception/RuntimeException.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Exception;
+
+/**
+ * @author Jérôme Tamarelle
+ */
+class RuntimeException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/console/Formatter/NullOutputFormatter.php b/vendor/symfony/console/Formatter/NullOutputFormatter.php
new file mode 100644
index 0000000000..7ea023da1b
--- /dev/null
+++ b/vendor/symfony/console/Formatter/NullOutputFormatter.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Formatter;
+
+/**
+ * @author Tien Xuan Vo
+ */
+final class NullOutputFormatter implements OutputFormatterInterface
+{
+ /**
+ * @var \Symfony\Component\Console\Formatter\NullOutputFormatterStyle
+ */
+ private $style;
+ public function format(?string $message) : ?string
+ {
+ return null;
+ }
+ public function getStyle(string $name) : OutputFormatterStyleInterface
+ {
+ // to comply with the interface we must return a OutputFormatterStyleInterface
+ return $this->style = $this->style ?? new NullOutputFormatterStyle();
+ }
+ public function hasStyle(string $name) : bool
+ {
+ return \false;
+ }
+ public function isDecorated() : bool
+ {
+ return \false;
+ }
+ public function setDecorated(bool $decorated) : void
+ {
+ // do nothing
+ }
+ public function setStyle(string $name, OutputFormatterStyleInterface $style) : void
+ {
+ // do nothing
+ }
+}
diff --git a/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php b/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php
new file mode 100644
index 0000000000..4b6ae26592
--- /dev/null
+++ b/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Formatter;
+
+/**
+ * @author Tien Xuan Vo
+ */
+final class NullOutputFormatterStyle implements OutputFormatterStyleInterface
+{
+ public function apply(string $text) : string
+ {
+ return $text;
+ }
+ public function setBackground(string $color = null) : void
+ {
+ if (1 > \func_num_args()) {
+ trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
+ }
+ // do nothing
+ }
+ public function setForeground(string $color = null) : void
+ {
+ if (1 > \func_num_args()) {
+ trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
+ }
+ // do nothing
+ }
+ public function setOption(string $option) : void
+ {
+ // do nothing
+ }
+ public function setOptions(array $options) : void
+ {
+ // do nothing
+ }
+ public function unsetOption(string $option) : void
+ {
+ // do nothing
+ }
+}
diff --git a/vendor/symfony/console/Formatter/OutputFormatter.php b/vendor/symfony/console/Formatter/OutputFormatter.php
new file mode 100644
index 0000000000..7e433ce65d
--- /dev/null
+++ b/vendor/symfony/console/Formatter/OutputFormatter.php
@@ -0,0 +1,241 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Formatter;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use function EasyCI202401\Symfony\Component\String\b;
+/**
+ * Formatter class for console output.
+ *
+ * @author Konstantin Kudryashov
+ * @author Roland Franssen
+ */
+class OutputFormatter implements WrappableOutputFormatterInterface
+{
+ /**
+ * @var bool
+ */
+ private $decorated;
+ /**
+ * @var mixed[]
+ */
+ private $styles = [];
+ /**
+ * @var \Symfony\Component\Console\Formatter\OutputFormatterStyleStack
+ */
+ private $styleStack;
+ public function __clone()
+ {
+ $this->styleStack = clone $this->styleStack;
+ foreach ($this->styles as $key => $value) {
+ $this->styles[$key] = clone $value;
+ }
+ }
+ /**
+ * Escapes "<" and ">" special chars in given text.
+ */
+ public static function escape(string $text) : string
+ {
+ $text = \preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text);
+ return self::escapeTrailingBackslash($text);
+ }
+ /**
+ * Escapes trailing "\" in given text.
+ *
+ * @internal
+ */
+ public static function escapeTrailingBackslash(string $text) : string
+ {
+ if (\substr_compare($text, '\\', -\strlen('\\')) === 0) {
+ $len = \strlen($text);
+ $text = \rtrim($text, '\\');
+ $text = \str_replace("\x00", '', $text);
+ $text .= \str_repeat("\x00", $len - \strlen($text));
+ }
+ return $text;
+ }
+ /**
+ * Initializes console output formatter.
+ *
+ * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances
+ */
+ public function __construct(bool $decorated = \false, array $styles = [])
+ {
+ $this->decorated = $decorated;
+ $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
+ $this->setStyle('info', new OutputFormatterStyle('green'));
+ $this->setStyle('comment', new OutputFormatterStyle('yellow'));
+ $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
+ foreach ($styles as $name => $style) {
+ $this->setStyle($name, $style);
+ }
+ $this->styleStack = new OutputFormatterStyleStack();
+ }
+ /**
+ * @return void
+ */
+ public function setDecorated(bool $decorated)
+ {
+ $this->decorated = $decorated;
+ }
+ public function isDecorated() : bool
+ {
+ return $this->decorated;
+ }
+ /**
+ * @return void
+ */
+ public function setStyle(string $name, OutputFormatterStyleInterface $style)
+ {
+ $this->styles[\strtolower($name)] = $style;
+ }
+ public function hasStyle(string $name) : bool
+ {
+ return isset($this->styles[\strtolower($name)]);
+ }
+ public function getStyle(string $name) : OutputFormatterStyleInterface
+ {
+ if (!$this->hasStyle($name)) {
+ throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name));
+ }
+ return $this->styles[\strtolower($name)];
+ }
+ public function format(?string $message) : ?string
+ {
+ return $this->formatAndWrap($message, 0);
+ }
+ /**
+ * @return string
+ */
+ public function formatAndWrap(?string $message, int $width)
+ {
+ if (null === $message) {
+ return '';
+ }
+ $offset = 0;
+ $output = '';
+ $openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
+ $closeTagRegex = '[a-z][^<>]*+';
+ $currentLineLength = 0;
+ \preg_match_all("#<(({$openTagRegex}) | /({$closeTagRegex})?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE);
+ foreach ($matches[0] as $i => $match) {
+ $pos = $match[1];
+ $text = $match[0];
+ if (0 != $pos && '\\' == $message[$pos - 1]) {
+ continue;
+ }
+ // add the text up to the next tag
+ $output .= $this->applyCurrentStyle(\substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
+ $offset = $pos + \strlen($text);
+ // opening tag?
+ if ($open = '/' !== $text[1]) {
+ $tag = $matches[1][$i][0];
+ } else {
+ $tag = $matches[3][$i][0] ?? '';
+ }
+ if (!$open && !$tag) {
+ // >
+ $this->styleStack->pop();
+ } elseif (null === ($style = $this->createStyleFromString($tag))) {
+ $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength);
+ } elseif ($open) {
+ $this->styleStack->push($style);
+ } else {
+ $this->styleStack->pop($style);
+ }
+ }
+ $output .= $this->applyCurrentStyle(\substr($message, $offset), $output, $width, $currentLineLength);
+ return \strtr($output, ["\x00" => '\\', '\\<' => '<', '\\>' => '>']);
+ }
+ public function getStyleStack() : OutputFormatterStyleStack
+ {
+ return $this->styleStack;
+ }
+ /**
+ * Tries to create new style instance from string.
+ */
+ private function createStyleFromString(string $string) : ?OutputFormatterStyleInterface
+ {
+ if (isset($this->styles[$string])) {
+ return $this->styles[$string];
+ }
+ if (!\preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) {
+ return null;
+ }
+ $style = new OutputFormatterStyle();
+ foreach ($matches as $match) {
+ \array_shift($match);
+ $match[0] = \strtolower($match[0]);
+ if ('fg' == $match[0]) {
+ $style->setForeground(\strtolower($match[1]));
+ } elseif ('bg' == $match[0]) {
+ $style->setBackground(\strtolower($match[1]));
+ } elseif ('href' === $match[0]) {
+ $url = \preg_replace('{\\\\([<>])}', '$1', $match[1]);
+ $style->setHref($url);
+ } elseif ('options' === $match[0]) {
+ \preg_match_all('([^,;]+)', \strtolower($match[1]), $options);
+ $options = \array_shift($options);
+ foreach ($options as $option) {
+ $style->setOption($option);
+ }
+ } else {
+ return null;
+ }
+ }
+ return $style;
+ }
+ /**
+ * Applies current style from stack to text, if must be applied.
+ */
+ private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength) : string
+ {
+ if ('' === $text) {
+ return '';
+ }
+ if (!$width) {
+ return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text;
+ }
+ if (!$currentLineLength && '' !== $current) {
+ $text = \ltrim($text);
+ }
+ if ($currentLineLength) {
+ $prefix = \substr($text, 0, $i = $width - $currentLineLength) . "\n";
+ $text = \substr($text, $i);
+ } else {
+ $prefix = '';
+ }
+ \preg_match('~(\\n)$~', $text, $matches);
+ $text = $prefix . $this->addLineBreaks($text, $width);
+ $text = \rtrim($text, "\n") . ($matches[1] ?? '');
+ if (!$currentLineLength && '' !== $current && \substr_compare($current, "\n", -\strlen("\n")) !== 0) {
+ $text = "\n" . $text;
+ }
+ $lines = \explode("\n", $text);
+ foreach ($lines as $line) {
+ $currentLineLength += \strlen($line);
+ if ($width <= $currentLineLength) {
+ $currentLineLength = 0;
+ }
+ }
+ if ($this->isDecorated()) {
+ foreach ($lines as $i => $line) {
+ $lines[$i] = $this->styleStack->getCurrent()->apply($line);
+ }
+ }
+ return \implode("\n", $lines);
+ }
+ private function addLineBreaks(string $text, int $width) : string
+ {
+ $encoding = \mb_detect_encoding($text, null, \true) ?: 'UTF-8';
+ return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", \true)->toByteString($encoding);
+ }
+}
diff --git a/vendor/symfony/console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Formatter/OutputFormatterInterface.php
new file mode 100644
index 0000000000..f49abaf6d7
--- /dev/null
+++ b/vendor/symfony/console/Formatter/OutputFormatterInterface.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Formatter;
+
+/**
+ * Formatter interface for console output.
+ *
+ * @author Konstantin Kudryashov
+ */
+interface OutputFormatterInterface
+{
+ /**
+ * Sets the decorated flag.
+ *
+ * @return void
+ */
+ public function setDecorated(bool $decorated);
+ /**
+ * Whether the output will decorate messages.
+ */
+ public function isDecorated() : bool;
+ /**
+ * Sets a new style.
+ *
+ * @return void
+ */
+ public function setStyle(string $name, OutputFormatterStyleInterface $style);
+ /**
+ * Checks if output formatter has style with specified name.
+ */
+ public function hasStyle(string $name) : bool;
+ /**
+ * Gets style options from style with specified name.
+ *
+ * @throws \InvalidArgumentException When style isn't defined
+ */
+ public function getStyle(string $name) : OutputFormatterStyleInterface;
+ /**
+ * Formats a message according to the given styles.
+ */
+ public function format(?string $message) : ?string;
+}
diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Formatter/OutputFormatterStyle.php
new file mode 100644
index 0000000000..18d6065310
--- /dev/null
+++ b/vendor/symfony/console/Formatter/OutputFormatterStyle.php
@@ -0,0 +1,113 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Formatter;
+
+use EasyCI202401\Symfony\Component\Console\Color;
+/**
+ * Formatter style class for defining styles.
+ *
+ * @author Konstantin Kudryashov
+ */
+class OutputFormatterStyle implements OutputFormatterStyleInterface
+{
+ /**
+ * @var \Symfony\Component\Console\Color
+ */
+ private $color;
+ /**
+ * @var string
+ */
+ private $foreground;
+ /**
+ * @var string
+ */
+ private $background;
+ /**
+ * @var mixed[]
+ */
+ private $options;
+ /**
+ * @var string|null
+ */
+ private $href;
+ /**
+ * @var bool
+ */
+ private $handlesHrefGracefully;
+ /**
+ * Initializes output formatter style.
+ *
+ * @param string|null $foreground The style foreground color name
+ * @param string|null $background The style background color name
+ */
+ public function __construct(string $foreground = null, string $background = null, array $options = [])
+ {
+ $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options);
+ }
+ /**
+ * @return void
+ */
+ public function setForeground(string $color = null)
+ {
+ if (1 > \func_num_args()) {
+ trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
+ }
+ $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options);
+ }
+ /**
+ * @return void
+ */
+ public function setBackground(string $color = null)
+ {
+ if (1 > \func_num_args()) {
+ trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
+ }
+ $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options);
+ }
+ public function setHref(string $url) : void
+ {
+ $this->href = $url;
+ }
+ /**
+ * @return void
+ */
+ public function setOption(string $option)
+ {
+ $this->options[] = $option;
+ $this->color = new Color($this->foreground, $this->background, $this->options);
+ }
+ /**
+ * @return void
+ */
+ public function unsetOption(string $option)
+ {
+ $pos = \array_search($option, $this->options);
+ if (\false !== $pos) {
+ unset($this->options[$pos]);
+ }
+ $this->color = new Color($this->foreground, $this->background, $this->options);
+ }
+ /**
+ * @return void
+ */
+ public function setOptions(array $options)
+ {
+ $this->color = new Color($this->foreground, $this->background, $this->options = $options);
+ }
+ public function apply(string $text) : string
+ {
+ $this->handlesHrefGracefully = $this->handlesHrefGracefully ?? 'JetBrains-JediTerm' !== \getenv('TERMINAL_EMULATOR') && (!\getenv('KONSOLE_VERSION') || (int) \getenv('KONSOLE_VERSION') > 201100) && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']);
+ if (null !== $this->href && $this->handlesHrefGracefully) {
+ $text = "\x1b]8;;{$this->href}\x1b\\{$text}\x1b]8;;\x1b\\";
+ }
+ return $this->color->apply($text);
+ }
+}
diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php
new file mode 100644
index 0000000000..b9b886cf72
--- /dev/null
+++ b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Formatter;
+
+/**
+ * Formatter style interface for defining styles.
+ *
+ * @author Konstantin Kudryashov
+ */
+interface OutputFormatterStyleInterface
+{
+ /**
+ * Sets style foreground color.
+ *
+ * @return void
+ */
+ public function setForeground(?string $color);
+ /**
+ * Sets style background color.
+ *
+ * @return void
+ */
+ public function setBackground(?string $color);
+ /**
+ * Sets some specific style option.
+ *
+ * @return void
+ */
+ public function setOption(string $option);
+ /**
+ * Unsets some specific style option.
+ *
+ * @return void
+ */
+ public function unsetOption(string $option);
+ /**
+ * Sets multiple style options at once.
+ *
+ * @return void
+ */
+ public function setOptions(array $options);
+ /**
+ * Applies the style to a given text.
+ */
+ public function apply(string $text) : string;
+}
diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php
new file mode 100644
index 0000000000..6287a2d189
--- /dev/null
+++ b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php
@@ -0,0 +1,94 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Formatter;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Contracts\Service\ResetInterface;
+/**
+ * @author Jean-François Simon
+ */
+class OutputFormatterStyleStack implements ResetInterface
+{
+ /**
+ * @var OutputFormatterStyleInterface[]
+ */
+ private $styles = [];
+ /**
+ * @var \Symfony\Component\Console\Formatter\OutputFormatterStyleInterface
+ */
+ private $emptyStyle;
+ public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
+ {
+ $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();
+ $this->reset();
+ }
+ /**
+ * Resets stack (ie. empty internal arrays).
+ *
+ * @return void
+ */
+ public function reset()
+ {
+ $this->styles = [];
+ }
+ /**
+ * Pushes a style in the stack.
+ *
+ * @return void
+ */
+ public function push(OutputFormatterStyleInterface $style)
+ {
+ $this->styles[] = $style;
+ }
+ /**
+ * Pops a style from the stack.
+ *
+ * @throws InvalidArgumentException When style tags incorrectly nested
+ */
+ public function pop(OutputFormatterStyleInterface $style = null) : OutputFormatterStyleInterface
+ {
+ if (!$this->styles) {
+ return $this->emptyStyle;
+ }
+ if (null === $style) {
+ return \array_pop($this->styles);
+ }
+ foreach (\array_reverse($this->styles, \true) as $index => $stackedStyle) {
+ if ($style->apply('') === $stackedStyle->apply('')) {
+ $this->styles = \array_slice($this->styles, 0, $index);
+ return $stackedStyle;
+ }
+ }
+ throw new InvalidArgumentException('Incorrectly nested style tag found.');
+ }
+ /**
+ * Computes current style with stacks top codes.
+ */
+ public function getCurrent() : OutputFormatterStyleInterface
+ {
+ if (!$this->styles) {
+ return $this->emptyStyle;
+ }
+ return $this->styles[\count($this->styles) - 1];
+ }
+ /**
+ * @return $this
+ */
+ public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
+ {
+ $this->emptyStyle = $emptyStyle;
+ return $this;
+ }
+ public function getEmptyStyle() : OutputFormatterStyleInterface
+ {
+ return $this->emptyStyle;
+ }
+}
diff --git a/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php b/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php
new file mode 100644
index 0000000000..c44ec3fdc1
--- /dev/null
+++ b/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Formatter;
+
+/**
+ * Formatter interface for console output that supports word wrapping.
+ *
+ * @author Roland Franssen
+ */
+interface WrappableOutputFormatterInterface extends OutputFormatterInterface
+{
+ /**
+ * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping).
+ *
+ * @return string
+ */
+ public function formatAndWrap(?string $message, int $width);
+}
diff --git a/vendor/symfony/console/Helper/DebugFormatterHelper.php b/vendor/symfony/console/Helper/DebugFormatterHelper.php
new file mode 100644
index 0000000000..0ba60938ec
--- /dev/null
+++ b/vendor/symfony/console/Helper/DebugFormatterHelper.php
@@ -0,0 +1,89 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+/**
+ * Helps outputting debug information when running an external program from a command.
+ *
+ * An external program can be a Process, an HTTP request, or anything else.
+ *
+ * @author Fabien Potencier
+ */
+class DebugFormatterHelper extends Helper
+{
+ private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
+ /**
+ * @var mixed[]
+ */
+ private $started = [];
+ /**
+ * @var int
+ */
+ private $count = -1;
+ /**
+ * Starts a debug formatting session.
+ */
+ public function start(string $id, string $message, string $prefix = 'RUN') : string
+ {
+ $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)];
+ return \sprintf("%s %s > %s>\n", $this->getBorder($id), $prefix, $message);
+ }
+ /**
+ * Adds progress to a formatting session.
+ */
+ public function progress(string $id, string $buffer, bool $error = \false, string $prefix = 'OUT', string $errorPrefix = 'ERR') : string
+ {
+ $message = '';
+ if ($error) {
+ if (isset($this->started[$id]['out'])) {
+ $message .= "\n";
+ unset($this->started[$id]['out']);
+ }
+ if (!isset($this->started[$id]['err'])) {
+ $message .= \sprintf('%s %s > ', $this->getBorder($id), $errorPrefix);
+ $this->started[$id]['err'] = \true;
+ }
+ $message .= \str_replace("\n", \sprintf("\n%s %s > ", $this->getBorder($id), $errorPrefix), $buffer);
+ } else {
+ if (isset($this->started[$id]['err'])) {
+ $message .= "\n";
+ unset($this->started[$id]['err']);
+ }
+ if (!isset($this->started[$id]['out'])) {
+ $message .= \sprintf('%s %s > ', $this->getBorder($id), $prefix);
+ $this->started[$id]['out'] = \true;
+ }
+ $message .= \str_replace("\n", \sprintf("\n%s %s > ", $this->getBorder($id), $prefix), $buffer);
+ }
+ return $message;
+ }
+ /**
+ * Stops a formatting session.
+ */
+ public function stop(string $id, string $message, bool $successful, string $prefix = 'RES') : string
+ {
+ $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
+ if ($successful) {
+ return \sprintf("%s%s %s > %s>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
+ }
+ $message = \sprintf("%s%s %s > %s>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
+ unset($this->started[$id]['out'], $this->started[$id]['err']);
+ return $message;
+ }
+ private function getBorder(string $id) : string
+ {
+ return \sprintf(' >', self::COLORS[$this->started[$id]['border']]);
+ }
+ public function getName() : string
+ {
+ return 'debug_formatter';
+ }
+}
diff --git a/vendor/symfony/console/Helper/DescriptorHelper.php b/vendor/symfony/console/Helper/DescriptorHelper.php
new file mode 100644
index 0000000000..4bf19c0640
--- /dev/null
+++ b/vendor/symfony/console/Helper/DescriptorHelper.php
@@ -0,0 +1,74 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Descriptor\DescriptorInterface;
+use EasyCI202401\Symfony\Component\Console\Descriptor\JsonDescriptor;
+use EasyCI202401\Symfony\Component\Console\Descriptor\MarkdownDescriptor;
+use EasyCI202401\Symfony\Component\Console\Descriptor\ReStructuredTextDescriptor;
+use EasyCI202401\Symfony\Component\Console\Descriptor\TextDescriptor;
+use EasyCI202401\Symfony\Component\Console\Descriptor\XmlDescriptor;
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * This class adds helper method to describe objects in various formats.
+ *
+ * @author Jean-François Simon
+ */
+class DescriptorHelper extends Helper
+{
+ /**
+ * @var DescriptorInterface[]
+ */
+ private $descriptors = [];
+ public function __construct()
+ {
+ $this->register('txt', new TextDescriptor())->register('xml', new XmlDescriptor())->register('json', new JsonDescriptor())->register('md', new MarkdownDescriptor())->register('rst', new ReStructuredTextDescriptor());
+ }
+ /**
+ * Describes an object if supported.
+ *
+ * Available options are:
+ * * format: string, the output format name
+ * * raw_text: boolean, sets output type as raw
+ *
+ * @return void
+ *
+ * @throws InvalidArgumentException when the given format is not supported
+ */
+ public function describe(OutputInterface $output, ?object $object, array $options = [])
+ {
+ $options = \array_merge(['raw_text' => \false, 'format' => 'txt'], $options);
+ if (!isset($this->descriptors[$options['format']])) {
+ throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format']));
+ }
+ $descriptor = $this->descriptors[$options['format']];
+ $descriptor->describe($output, $object, $options);
+ }
+ /**
+ * Registers a descriptor.
+ *
+ * @return $this
+ */
+ public function register(string $format, DescriptorInterface $descriptor)
+ {
+ $this->descriptors[$format] = $descriptor;
+ return $this;
+ }
+ public function getName() : string
+ {
+ return 'descriptor';
+ }
+ public function getFormats() : array
+ {
+ return \array_keys($this->descriptors);
+ }
+}
diff --git a/vendor/symfony/console/Helper/Dumper.php b/vendor/symfony/console/Helper/Dumper.php
new file mode 100644
index 0000000000..ddc13c59f2
--- /dev/null
+++ b/vendor/symfony/console/Helper/Dumper.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\VarDumper\Cloner\ClonerInterface;
+use EasyCI202401\Symfony\Component\VarDumper\Cloner\VarCloner;
+use EasyCI202401\Symfony\Component\VarDumper\Dumper\CliDumper;
+/**
+ * @author Roland Franssen
+ */
+final class Dumper
+{
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ private $output;
+ /**
+ * @var \Symfony\Component\VarDumper\Dumper\CliDumper|null
+ */
+ private $dumper;
+ /**
+ * @var \Symfony\Component\VarDumper\Cloner\ClonerInterface|null
+ */
+ private $cloner;
+ /**
+ * @var \Closure
+ */
+ private $handler;
+ public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null)
+ {
+ $this->output = $output;
+ $this->dumper = $dumper;
+ $this->cloner = $cloner;
+ if (\class_exists(CliDumper::class)) {
+ $this->handler = function ($var) : string {
+ $dumper = $this->dumper = $this->dumper ?? new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
+ $dumper->setColors($this->output->isDecorated());
+ return \rtrim($dumper->dump(($this->cloner = $this->cloner ?? new VarCloner())->cloneVar($var)->withRefHandles(\false), \true));
+ };
+ } else {
+ $this->handler = function ($var) : string {
+ switch (\true) {
+ case null === $var:
+ return 'null';
+ case \true === $var:
+ return 'true';
+ case \false === $var:
+ return 'false';
+ case \is_string($var):
+ return '"' . $var . '"';
+ default:
+ return \rtrim(\print_r($var, \true));
+ }
+ };
+ }
+ }
+ /**
+ * @param mixed $var
+ */
+ public function __invoke($var) : string
+ {
+ return ($this->handler)($var);
+ }
+}
diff --git a/vendor/symfony/console/Helper/FormatterHelper.php b/vendor/symfony/console/Helper/FormatterHelper.php
new file mode 100644
index 0000000000..4bc7ed455c
--- /dev/null
+++ b/vendor/symfony/console/Helper/FormatterHelper.php
@@ -0,0 +1,71 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Formatter\OutputFormatter;
+/**
+ * The Formatter class provides helpers to format messages.
+ *
+ * @author Fabien Potencier
+ */
+class FormatterHelper extends Helper
+{
+ /**
+ * Formats a message within a section.
+ */
+ public function formatSection(string $section, string $message, string $style = 'info') : string
+ {
+ return \sprintf('<%s>[%s]%s> %s', $style, $section, $style, $message);
+ }
+ /**
+ * Formats a message as a block of text.
+ * @param string|mixed[] $messages
+ */
+ public function formatBlock($messages, string $style, bool $large = \false) : string
+ {
+ if (!\is_array($messages)) {
+ $messages = [$messages];
+ }
+ $len = 0;
+ $lines = [];
+ foreach ($messages as $message) {
+ $message = OutputFormatter::escape($message);
+ $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message);
+ $len = \max(self::width($message) + ($large ? 4 : 2), $len);
+ }
+ $messages = $large ? [\str_repeat(' ', $len)] : [];
+ for ($i = 0; isset($lines[$i]); ++$i) {
+ $messages[] = $lines[$i] . \str_repeat(' ', $len - self::width($lines[$i]));
+ }
+ if ($large) {
+ $messages[] = \str_repeat(' ', $len);
+ }
+ for ($i = 0; isset($messages[$i]); ++$i) {
+ $messages[$i] = \sprintf('<%s>%s%s>', $style, $messages[$i], $style);
+ }
+ return \implode("\n", $messages);
+ }
+ /**
+ * Truncates a message to the given length.
+ */
+ public function truncate(string $message, int $length, string $suffix = '...') : string
+ {
+ $computedLength = $length - self::width($suffix);
+ if ($computedLength > self::width($message)) {
+ return $message;
+ }
+ return self::substr($message, 0, $length) . $suffix;
+ }
+ public function getName() : string
+ {
+ return 'formatter';
+ }
+}
diff --git a/vendor/symfony/console/Helper/Helper.php b/vendor/symfony/console/Helper/Helper.php
new file mode 100644
index 0000000000..a0251b70c1
--- /dev/null
+++ b/vendor/symfony/console/Helper/Helper.php
@@ -0,0 +1,139 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Formatter\OutputFormatterInterface;
+use EasyCI202401\Symfony\Component\String\UnicodeString;
+/**
+ * Helper is the base class for all helper classes.
+ *
+ * @author Fabien Potencier
+ */
+abstract class Helper implements HelperInterface
+{
+ protected $helperSet;
+ /**
+ * @return void
+ */
+ public function setHelperSet(HelperSet $helperSet = null)
+ {
+ if (1 > \func_num_args()) {
+ trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
+ }
+ $this->helperSet = $helperSet;
+ }
+ public function getHelperSet() : ?HelperSet
+ {
+ return $this->helperSet;
+ }
+ /**
+ * Returns the width of a string, using mb_strwidth if it is available.
+ * The width is how many characters positions the string will use.
+ */
+ public static function width(?string $string) : int
+ {
+ $string = $string ?? '';
+ if (\preg_match('//u', $string)) {
+ return (new UnicodeString($string))->width(\false);
+ }
+ if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) {
+ return \strlen($string);
+ }
+ return \mb_strwidth($string, $encoding);
+ }
+ /**
+ * Returns the length of a string, using mb_strlen if it is available.
+ * The length is related to how many bytes the string will use.
+ */
+ public static function length(?string $string) : int
+ {
+ $string = $string ?? '';
+ if (\preg_match('//u', $string)) {
+ return (new UnicodeString($string))->length();
+ }
+ if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) {
+ return \strlen($string);
+ }
+ return \mb_strlen($string, $encoding);
+ }
+ /**
+ * Returns the subset of a string, using mb_substr if it is available.
+ */
+ public static function substr(?string $string, int $from, int $length = null) : string
+ {
+ $string = $string ?? '';
+ if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) {
+ return \substr($string, $from, $length);
+ }
+ return \mb_substr($string, $from, $length, $encoding);
+ }
+ /**
+ * @return string
+ * @param int|float $secs
+ */
+ public static function formatTime($secs, int $precision = 1)
+ {
+ $secs = (int) \floor($secs);
+ if (0 === $secs) {
+ return '< 1 sec';
+ }
+ static $timeFormats = [[1, '1 sec', 'secs'], [60, '1 min', 'mins'], [3600, '1 hr', 'hrs'], [86400, '1 day', 'days']];
+ $times = [];
+ foreach ($timeFormats as $index => $format) {
+ $seconds = isset($timeFormats[$index + 1]) ? $secs % $timeFormats[$index + 1][0] : $secs;
+ if (isset($times[$index - $precision])) {
+ unset($times[$index - $precision]);
+ }
+ if (0 === $seconds) {
+ continue;
+ }
+ $unitCount = $seconds / $format[0];
+ $times[$index] = 1 === $unitCount ? $format[1] : $unitCount . ' ' . $format[2];
+ if ($secs === $seconds) {
+ break;
+ }
+ $secs -= $seconds;
+ }
+ return \implode(', ', \array_reverse($times));
+ }
+ /**
+ * @return string
+ */
+ public static function formatMemory(int $memory)
+ {
+ if ($memory >= 1024 * 1024 * 1024) {
+ return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
+ }
+ if ($memory >= 1024 * 1024) {
+ return \sprintf('%.1f MiB', $memory / 1024 / 1024);
+ }
+ if ($memory >= 1024) {
+ return \sprintf('%d KiB', $memory / 1024);
+ }
+ return \sprintf('%d B', $memory);
+ }
+ /**
+ * @return string
+ */
+ public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string)
+ {
+ $isDecorated = $formatter->isDecorated();
+ $formatter->setDecorated(\false);
+ // remove <...> formatting
+ $string = $formatter->format($string ?? '');
+ // remove already formatted characters
+ $string = \preg_replace("/\x1b\\[[^m]*m/", '', $string ?? '');
+ // remove terminal hyperlinks
+ $string = \preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string ?? '');
+ $formatter->setDecorated($isDecorated);
+ return $string;
+ }
+}
diff --git a/vendor/symfony/console/Helper/HelperInterface.php b/vendor/symfony/console/Helper/HelperInterface.php
new file mode 100644
index 0000000000..4a8d1eedcd
--- /dev/null
+++ b/vendor/symfony/console/Helper/HelperInterface.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+/**
+ * HelperInterface is the interface all helpers must implement.
+ *
+ * @author Fabien Potencier
+ */
+interface HelperInterface
+{
+ /**
+ * Sets the helper set associated with this helper.
+ *
+ * @return void
+ */
+ public function setHelperSet(?HelperSet $helperSet);
+ /**
+ * Gets the helper set associated with this helper.
+ */
+ public function getHelperSet() : ?HelperSet;
+ /**
+ * Returns the canonical name of this helper.
+ *
+ * @return string
+ */
+ public function getName();
+}
diff --git a/vendor/symfony/console/Helper/HelperSet.php b/vendor/symfony/console/Helper/HelperSet.php
new file mode 100644
index 0000000000..1486f1db4b
--- /dev/null
+++ b/vendor/symfony/console/Helper/HelperSet.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+/**
+ * HelperSet represents a set of helpers to be used with a command.
+ *
+ * @author Fabien Potencier
+ *
+ * @implements \IteratorAggregate
+ */
+class HelperSet implements \IteratorAggregate
+{
+ /** @var array */
+ private $helpers = [];
+ /**
+ * @param HelperInterface[] $helpers
+ */
+ public function __construct(array $helpers = [])
+ {
+ foreach ($helpers as $alias => $helper) {
+ $this->set($helper, \is_int($alias) ? null : $alias);
+ }
+ }
+ /**
+ * @return void
+ */
+ public function set(HelperInterface $helper, string $alias = null)
+ {
+ $this->helpers[$helper->getName()] = $helper;
+ if (null !== $alias) {
+ $this->helpers[$alias] = $helper;
+ }
+ $helper->setHelperSet($this);
+ }
+ /**
+ * Returns true if the helper if defined.
+ */
+ public function has(string $name) : bool
+ {
+ return isset($this->helpers[$name]);
+ }
+ /**
+ * Gets a helper value.
+ *
+ * @throws InvalidArgumentException if the helper is not defined
+ */
+ public function get(string $name) : HelperInterface
+ {
+ if (!$this->has($name)) {
+ throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name));
+ }
+ return $this->helpers[$name];
+ }
+ public function getIterator() : \Traversable
+ {
+ return new \ArrayIterator($this->helpers);
+ }
+}
diff --git a/vendor/symfony/console/Helper/InputAwareHelper.php b/vendor/symfony/console/Helper/InputAwareHelper.php
new file mode 100644
index 0000000000..2b948f578b
--- /dev/null
+++ b/vendor/symfony/console/Helper/InputAwareHelper.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Input\InputAwareInterface;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+/**
+ * An implementation of InputAwareInterface for Helpers.
+ *
+ * @author Wouter J
+ */
+abstract class InputAwareHelper extends Helper implements InputAwareInterface
+{
+ protected $input;
+ /**
+ * @return void
+ */
+ public function setInput(InputInterface $input)
+ {
+ $this->input = $input;
+ }
+}
diff --git a/vendor/symfony/console/Helper/OutputWrapper.php b/vendor/symfony/console/Helper/OutputWrapper.php
new file mode 100644
index 0000000000..49d5acaa2a
--- /dev/null
+++ b/vendor/symfony/console/Helper/OutputWrapper.php
@@ -0,0 +1,75 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+/**
+ * Simple output wrapper for "tagged outputs" instead of wordwrap(). This solution is based on a StackOverflow
+ * answer: https://stackoverflow.com/a/20434776/1476819 from user557597 (alias SLN).
+ *
+ * (?:
+ * # -- Words/Characters
+ * ( # (1 start)
+ * (?> # Atomic Group - Match words with valid breaks
+ * .{1,16} # 1-N characters
+ * # Followed by one of 4 prioritized, non-linebreak whitespace
+ * (?: # break types:
+ * (?<= [^\S\r\n] ) # 1. - Behind a non-linebreak whitespace
+ * [^\S\r\n]? # ( optionally accept an extra non-linebreak whitespace )
+ * | (?= \r? \n ) # 2. - Ahead a linebreak
+ * | $ # 3. - EOS
+ * | [^\S\r\n] # 4. - Accept an extra non-linebreak whitespace
+ * )
+ * ) # End atomic group
+ * |
+ * .{1,16} # No valid word breaks, just break on the N'th character
+ * ) # (1 end)
+ * (?: \r? \n )? # Optional linebreak after Words/Characters
+ * |
+ * # -- Or, Linebreak
+ * (?: \r? \n | $ ) # Stand alone linebreak or at EOS
+ * )
+ *
+ * @author Krisztián Ferenczi
+ *
+ * @see https://stackoverflow.com/a/20434776/1476819
+ */
+final class OutputWrapper
+{
+ /**
+ * @var bool
+ */
+ private $allowCutUrls = \false;
+ private const TAG_OPEN_REGEX_SEGMENT = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
+ private const TAG_CLOSE_REGEX_SEGMENT = '[a-z][^<>]*+';
+ private const URL_PATTERN = 'https?://\\S+';
+ public function __construct(bool $allowCutUrls = \false)
+ {
+ $this->allowCutUrls = $allowCutUrls;
+ }
+ public function wrap(string $text, int $width, string $break = "\n") : string
+ {
+ if (!$width) {
+ return $text;
+ }
+ $tagPattern = \sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT);
+ $limitPattern = "{1,{$width}}";
+ $patternBlocks = [$tagPattern];
+ if (!$this->allowCutUrls) {
+ $patternBlocks[] = self::URL_PATTERN;
+ }
+ $patternBlocks[] = '.';
+ $blocks = \implode('|', $patternBlocks);
+ $rowPattern = "(?:{$blocks}){$limitPattern}";
+ $pattern = \sprintf('#(?:((?>(%1$s)((?<=[^\\S\\r\\n])[^\\S\\r\\n]?|(?=\\r?\\n)|$|[^\\S\\r\\n]))|(%1$s))(?:\\r?\\n)?|(?:\\r?\\n|$))#imux', $rowPattern);
+ $output = \rtrim(\preg_replace($pattern, '\\1' . $break, $text), $break);
+ return \str_replace(' ' . $break, $break, $output);
+ }
+}
diff --git a/vendor/symfony/console/Helper/ProcessHelper.php b/vendor/symfony/console/Helper/ProcessHelper.php
new file mode 100644
index 0000000000..606f7391c7
--- /dev/null
+++ b/vendor/symfony/console/Helper/ProcessHelper.php
@@ -0,0 +1,116 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleOutputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\Process\Exception\ProcessFailedException;
+use EasyCI202401\Symfony\Component\Process\Process;
+/**
+ * The ProcessHelper class provides helpers to run external processes.
+ *
+ * @author Fabien Potencier
+ *
+ * @final
+ */
+class ProcessHelper extends Helper
+{
+ /**
+ * Runs an external process.
+ *
+ * @param array|Process $cmd An instance of Process or an array of the command and arguments
+ * @param callable|null $callback A PHP callback to run whenever there is some
+ * output available on STDOUT or STDERR
+ */
+ public function run(OutputInterface $output, $cmd, string $error = null, callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) : Process
+ {
+ if (!\class_exists(Process::class)) {
+ throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
+ }
+ if ($output instanceof ConsoleOutputInterface) {
+ $output = $output->getErrorOutput();
+ }
+ $formatter = $this->getHelperSet()->get('debug_formatter');
+ if ($cmd instanceof Process) {
+ $cmd = [$cmd];
+ }
+ if (\is_string($cmd[0] ?? null)) {
+ $process = new Process($cmd);
+ $cmd = [];
+ } elseif (($cmd[0] ?? null) instanceof Process) {
+ $process = $cmd[0];
+ unset($cmd[0]);
+ } else {
+ throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__));
+ }
+ if ($verbosity <= $output->getVerbosity()) {
+ $output->write($formatter->start(\spl_object_hash($process), $this->escapeString($process->getCommandLine())));
+ }
+ if ($output->isDebug()) {
+ $callback = $this->wrapCallback($output, $process, $callback);
+ }
+ $process->run($callback, $cmd);
+ if ($verbosity <= $output->getVerbosity()) {
+ $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode());
+ $output->write($formatter->stop(\spl_object_hash($process), $message, $process->isSuccessful()));
+ }
+ if (!$process->isSuccessful() && null !== $error) {
+ $output->writeln(\sprintf('%s', $this->escapeString($error)));
+ }
+ return $process;
+ }
+ /**
+ * Runs the process.
+ *
+ * This is identical to run() except that an exception is thrown if the process
+ * exits with a non-zero exit code.
+ *
+ * @param array|Process $cmd An instance of Process or a command to run
+ * @param callable|null $callback A PHP callback to run whenever there is some
+ * output available on STDOUT or STDERR
+ *
+ * @throws ProcessFailedException
+ *
+ * @see run()
+ */
+ public function mustRun(OutputInterface $output, $cmd, string $error = null, callable $callback = null) : Process
+ {
+ $process = $this->run($output, $cmd, $error, $callback);
+ if (!$process->isSuccessful()) {
+ throw new ProcessFailedException($process);
+ }
+ return $process;
+ }
+ /**
+ * Wraps a Process callback to add debugging output.
+ */
+ public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null) : callable
+ {
+ if ($output instanceof ConsoleOutputInterface) {
+ $output = $output->getErrorOutput();
+ }
+ $formatter = $this->getHelperSet()->get('debug_formatter');
+ return function ($type, $buffer) use($output, $process, $callback, $formatter) {
+ $output->write($formatter->progress(\spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));
+ if (null !== $callback) {
+ $callback($type, $buffer);
+ }
+ };
+ }
+ private function escapeString(string $str) : string
+ {
+ return \str_replace('<', '\\<', $str);
+ }
+ public function getName() : string
+ {
+ return 'process';
+ }
+}
diff --git a/vendor/symfony/console/Helper/ProgressBar.php b/vendor/symfony/console/Helper/ProgressBar.php
new file mode 100644
index 0000000000..1dc7cca9fb
--- /dev/null
+++ b/vendor/symfony/console/Helper/ProgressBar.php
@@ -0,0 +1,597 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Cursor;
+use EasyCI202401\Symfony\Component\Console\Exception\LogicException;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleOutputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleSectionOutput;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\Console\Terminal;
+/**
+ * The ProgressBar provides helpers to display progress output.
+ *
+ * @author Fabien Potencier
+ * @author Chris Jones
+ */
+final class ProgressBar
+{
+ public const FORMAT_VERBOSE = 'verbose';
+ public const FORMAT_VERY_VERBOSE = 'very_verbose';
+ public const FORMAT_DEBUG = 'debug';
+ public const FORMAT_NORMAL = 'normal';
+ private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax';
+ private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax';
+ private const FORMAT_DEBUG_NOMAX = 'debug_nomax';
+ private const FORMAT_NORMAL_NOMAX = 'normal_nomax';
+ /**
+ * @var int
+ */
+ private $barWidth = 28;
+ /**
+ * @var string
+ */
+ private $barChar;
+ /**
+ * @var string
+ */
+ private $emptyBarChar = '-';
+ /**
+ * @var string
+ */
+ private $progressChar = '>';
+ /**
+ * @var string|null
+ */
+ private $format;
+ /**
+ * @var string|null
+ */
+ private $internalFormat;
+ /**
+ * @var int|null
+ */
+ private $redrawFreq = 1;
+ /**
+ * @var int
+ */
+ private $writeCount = 0;
+ /**
+ * @var float
+ */
+ private $lastWriteTime = 0;
+ /**
+ * @var float
+ */
+ private $minSecondsBetweenRedraws = 0;
+ /**
+ * @var float
+ */
+ private $maxSecondsBetweenRedraws = 1;
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ private $output;
+ /**
+ * @var int
+ */
+ private $step = 0;
+ /**
+ * @var int
+ */
+ private $startingStep = 0;
+ /**
+ * @var int|null
+ */
+ private $max;
+ /**
+ * @var int
+ */
+ private $startTime;
+ /**
+ * @var int
+ */
+ private $stepWidth;
+ /**
+ * @var float
+ */
+ private $percent = 0.0;
+ /**
+ * @var mixed[]
+ */
+ private $messages = [];
+ /**
+ * @var bool
+ */
+ private $overwrite = \true;
+ /**
+ * @var \Symfony\Component\Console\Terminal
+ */
+ private $terminal;
+ /**
+ * @var string|null
+ */
+ private $previousMessage;
+ /**
+ * @var \Symfony\Component\Console\Cursor
+ */
+ private $cursor;
+ /**
+ * @var mixed[]
+ */
+ private $placeholders = [];
+ /**
+ * @var mixed[]
+ */
+ private static $formatters;
+ /**
+ * @var mixed[]
+ */
+ private static $formats;
+ /**
+ * @param int $max Maximum steps (0 if unknown)
+ */
+ public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25)
+ {
+ if ($output instanceof ConsoleOutputInterface) {
+ $output = $output->getErrorOutput();
+ }
+ $this->output = $output;
+ $this->setMaxSteps($max);
+ $this->terminal = new Terminal();
+ if (0 < $minSecondsBetweenRedraws) {
+ $this->redrawFreq = null;
+ $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws;
+ }
+ if (!$this->output->isDecorated()) {
+ // disable overwrite when output does not support ANSI codes.
+ $this->overwrite = \false;
+ // set a reasonable redraw frequency so output isn't flooded
+ $this->redrawFreq = null;
+ }
+ $this->startTime = \time();
+ $this->cursor = new Cursor($output);
+ }
+ /**
+ * Sets a placeholder formatter for a given name, globally for all instances of ProgressBar.
+ *
+ * This method also allow you to override an existing placeholder.
+ *
+ * @param string $name The placeholder name (including the delimiter char like %)
+ * @param callable(ProgressBar):string $callable A PHP callable
+ */
+ public static function setPlaceholderFormatterDefinition(string $name, callable $callable) : void
+ {
+ self::$formatters = self::$formatters ?? self::initPlaceholderFormatters();
+ self::$formatters[$name] = $callable;
+ }
+ /**
+ * Gets the placeholder formatter for a given name.
+ *
+ * @param string $name The placeholder name (including the delimiter char like %)
+ */
+ public static function getPlaceholderFormatterDefinition(string $name) : ?callable
+ {
+ self::$formatters = self::$formatters ?? self::initPlaceholderFormatters();
+ return self::$formatters[$name] ?? null;
+ }
+ /**
+ * Sets a placeholder formatter for a given name, for this instance only.
+ *
+ * @param callable(ProgressBar):string $callable A PHP callable
+ */
+ public function setPlaceholderFormatter(string $name, callable $callable) : void
+ {
+ $this->placeholders[$name] = $callable;
+ }
+ /**
+ * Gets the placeholder formatter for a given name.
+ *
+ * @param string $name The placeholder name (including the delimiter char like %)
+ */
+ public function getPlaceholderFormatter(string $name) : ?callable
+ {
+ return $this->placeholders[$name] ?? $this::getPlaceholderFormatterDefinition($name);
+ }
+ /**
+ * Sets a format for a given name.
+ *
+ * This method also allow you to override an existing format.
+ *
+ * @param string $name The format name
+ * @param string $format A format string
+ */
+ public static function setFormatDefinition(string $name, string $format) : void
+ {
+ self::$formats = self::$formats ?? self::initFormats();
+ self::$formats[$name] = $format;
+ }
+ /**
+ * Gets the format for a given name.
+ *
+ * @param string $name The format name
+ */
+ public static function getFormatDefinition(string $name) : ?string
+ {
+ self::$formats = self::$formats ?? self::initFormats();
+ return self::$formats[$name] ?? null;
+ }
+ /**
+ * Associates a text with a named placeholder.
+ *
+ * The text is displayed when the progress bar is rendered but only
+ * when the corresponding placeholder is part of the custom format line
+ * (by wrapping the name with %).
+ *
+ * @param string $message The text to associate with the placeholder
+ * @param string $name The name of the placeholder
+ */
+ public function setMessage(string $message, string $name = 'message') : void
+ {
+ $this->messages[$name] = $message;
+ }
+ public function getMessage(string $name = 'message') : string
+ {
+ return $this->messages[$name];
+ }
+ public function getStartTime() : int
+ {
+ return $this->startTime;
+ }
+ public function getMaxSteps() : int
+ {
+ return $this->max;
+ }
+ public function getProgress() : int
+ {
+ return $this->step;
+ }
+ private function getStepWidth() : int
+ {
+ return $this->stepWidth;
+ }
+ public function getProgressPercent() : float
+ {
+ return $this->percent;
+ }
+ public function getBarOffset() : float
+ {
+ return \floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (\min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
+ }
+ public function getEstimated() : float
+ {
+ if (0 === $this->step || $this->step === $this->startingStep) {
+ return 0;
+ }
+ return \round((\time() - $this->startTime) / ($this->step - $this->startingStep) * $this->max);
+ }
+ public function getRemaining() : float
+ {
+ if (!$this->step) {
+ return 0;
+ }
+ return \round((\time() - $this->startTime) / ($this->step - $this->startingStep) * ($this->max - $this->step));
+ }
+ public function setBarWidth(int $size) : void
+ {
+ $this->barWidth = \max(1, $size);
+ }
+ public function getBarWidth() : int
+ {
+ return $this->barWidth;
+ }
+ public function setBarCharacter(string $char) : void
+ {
+ $this->barChar = $char;
+ }
+ public function getBarCharacter() : string
+ {
+ return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar);
+ }
+ public function setEmptyBarCharacter(string $char) : void
+ {
+ $this->emptyBarChar = $char;
+ }
+ public function getEmptyBarCharacter() : string
+ {
+ return $this->emptyBarChar;
+ }
+ public function setProgressCharacter(string $char) : void
+ {
+ $this->progressChar = $char;
+ }
+ public function getProgressCharacter() : string
+ {
+ return $this->progressChar;
+ }
+ public function setFormat(string $format) : void
+ {
+ $this->format = null;
+ $this->internalFormat = $format;
+ }
+ /**
+ * Sets the redraw frequency.
+ *
+ * @param int|null $freq The frequency in steps
+ */
+ public function setRedrawFrequency(?int $freq) : void
+ {
+ $this->redrawFreq = null !== $freq ? \max(1, $freq) : null;
+ }
+ public function minSecondsBetweenRedraws(float $seconds) : void
+ {
+ $this->minSecondsBetweenRedraws = $seconds;
+ }
+ public function maxSecondsBetweenRedraws(float $seconds) : void
+ {
+ $this->maxSecondsBetweenRedraws = $seconds;
+ }
+ /**
+ * Returns an iterator that will automatically update the progress bar when iterated.
+ *
+ * @template TKey
+ * @template TValue
+ *
+ * @param iterable $iterable
+ * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable
+ *
+ * @return iterable
+ */
+ public function iterate(iterable $iterable, int $max = null) : iterable
+ {
+ $this->start($max ?? (\is_array($iterable) || $iterable instanceof \Countable ? \count($iterable) : 0));
+ foreach ($iterable as $key => $value) {
+ (yield $key => $value);
+ $this->advance();
+ }
+ $this->finish();
+ }
+ /**
+ * Starts the progress output.
+ *
+ * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
+ * @param int $startAt The starting point of the bar (useful e.g. when resuming a previously started bar)
+ */
+ public function start(int $max = null, int $startAt = 0) : void
+ {
+ $this->startTime = \time();
+ $this->step = $startAt;
+ $this->startingStep = $startAt;
+ $startAt > 0 ? $this->setProgress($startAt) : ($this->percent = 0.0);
+ if (null !== $max) {
+ $this->setMaxSteps($max);
+ }
+ $this->display();
+ }
+ /**
+ * Advances the progress output X steps.
+ *
+ * @param int $step Number of steps to advance
+ */
+ public function advance(int $step = 1) : void
+ {
+ $this->setProgress($this->step + $step);
+ }
+ /**
+ * Sets whether to overwrite the progressbar, false for new line.
+ */
+ public function setOverwrite(bool $overwrite) : void
+ {
+ $this->overwrite = $overwrite;
+ }
+ public function setProgress(int $step) : void
+ {
+ if ($this->max && $step > $this->max) {
+ $this->max = $step;
+ } elseif ($step < 0) {
+ $step = 0;
+ }
+ $redrawFreq = $this->redrawFreq ?? ($this->max ?: 10) / 10;
+ $prevPeriod = (int) ($this->step / $redrawFreq);
+ $currPeriod = (int) ($step / $redrawFreq);
+ $this->step = $step;
+ $this->percent = $this->max ? (float) $this->step / $this->max : 0;
+ $timeInterval = \microtime(\true) - $this->lastWriteTime;
+ // Draw regardless of other limits
+ if ($this->max === $step) {
+ $this->display();
+ return;
+ }
+ // Throttling
+ if ($timeInterval < $this->minSecondsBetweenRedraws) {
+ return;
+ }
+ // Draw each step period, but not too late
+ if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) {
+ $this->display();
+ }
+ }
+ public function setMaxSteps(int $max) : void
+ {
+ $this->format = null;
+ $this->max = \max(0, $max);
+ $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4;
+ }
+ /**
+ * Finishes the progress output.
+ */
+ public function finish() : void
+ {
+ if (!$this->max) {
+ $this->max = $this->step;
+ }
+ if ($this->step === $this->max && !$this->overwrite) {
+ // prevent double 100% output
+ return;
+ }
+ $this->setProgress($this->max);
+ }
+ /**
+ * Outputs the current progress string.
+ */
+ public function display() : void
+ {
+ if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
+ return;
+ }
+ if (null === $this->format) {
+ $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
+ }
+ $this->overwrite($this->buildLine());
+ }
+ /**
+ * Removes the progress bar from the current line.
+ *
+ * This is useful if you wish to write some output
+ * while a progress bar is running.
+ * Call display() to show the progress bar again.
+ */
+ public function clear() : void
+ {
+ if (!$this->overwrite) {
+ return;
+ }
+ if (null === $this->format) {
+ $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
+ }
+ $this->overwrite('');
+ }
+ private function setRealFormat(string $format) : void
+ {
+ // try to use the _nomax variant if available
+ if (!$this->max && null !== self::getFormatDefinition($format . '_nomax')) {
+ $this->format = self::getFormatDefinition($format . '_nomax');
+ } elseif (null !== self::getFormatDefinition($format)) {
+ $this->format = self::getFormatDefinition($format);
+ } else {
+ $this->format = $format;
+ }
+ }
+ /**
+ * Overwrites a previous message to the output.
+ */
+ private function overwrite(string $message) : void
+ {
+ if ($this->previousMessage === $message) {
+ return;
+ }
+ $originalMessage = $message;
+ if ($this->overwrite) {
+ if (null !== $this->previousMessage) {
+ if ($this->output instanceof ConsoleSectionOutput) {
+ $messageLines = \explode("\n", $this->previousMessage);
+ $lineCount = \count($messageLines);
+ foreach ($messageLines as $messageLine) {
+ $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine));
+ if ($messageLineLength > $this->terminal->getWidth()) {
+ $lineCount += \floor($messageLineLength / $this->terminal->getWidth());
+ }
+ }
+ $this->output->clear($lineCount);
+ } else {
+ $lineCount = \substr_count($this->previousMessage, "\n");
+ for ($i = 0; $i < $lineCount; ++$i) {
+ $this->cursor->moveToColumn(1);
+ $this->cursor->clearLine();
+ $this->cursor->moveUp();
+ }
+ $this->cursor->moveToColumn(1);
+ $this->cursor->clearLine();
+ }
+ }
+ } elseif ($this->step > 0) {
+ $message = \PHP_EOL . $message;
+ }
+ $this->previousMessage = $originalMessage;
+ $this->lastWriteTime = \microtime(\true);
+ $this->output->write($message);
+ ++$this->writeCount;
+ }
+ private function determineBestFormat() : string
+ {
+ switch ($this->output->getVerbosity()) {
+ case OutputInterface::VERBOSITY_VERBOSE:
+ return $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX;
+ case OutputInterface::VERBOSITY_VERY_VERBOSE:
+ return $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX;
+ case OutputInterface::VERBOSITY_DEBUG:
+ return $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX;
+ default:
+ return $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX;
+ }
+ }
+ private static function initPlaceholderFormatters() : array
+ {
+ return ['bar' => function (self $bar, OutputInterface $output) {
+ $completeBars = $bar->getBarOffset();
+ $display = \str_repeat($bar->getBarCharacter(), $completeBars);
+ if ($completeBars < $bar->getBarWidth()) {
+ $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter()));
+ $display .= $bar->getProgressCharacter() . \str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
+ }
+ return $display;
+ }, 'elapsed' => function (self $bar) {
+ return Helper::formatTime(\time() - $bar->getStartTime(), 2);
+ }, 'remaining' => function (self $bar) {
+ if (!$bar->getMaxSteps()) {
+ throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
+ }
+ return Helper::formatTime($bar->getRemaining(), 2);
+ }, 'estimated' => function (self $bar) {
+ if (!$bar->getMaxSteps()) {
+ throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
+ }
+ return Helper::formatTime($bar->getEstimated(), 2);
+ }, 'memory' => function (self $bar) {
+ return Helper::formatMemory(\memory_get_usage(\true));
+ }, 'current' => function (self $bar) {
+ return \str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT);
+ }, 'max' => function (self $bar) {
+ return $bar->getMaxSteps();
+ }, 'percent' => function (self $bar) {
+ return \floor($bar->getProgressPercent() * 100);
+ }];
+ }
+ private static function initFormats() : array
+ {
+ return [self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%', self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]', self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%', self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%', self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%', self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%'];
+ }
+ private function buildLine() : string
+ {
+ \assert(null !== $this->format);
+ $regex = "{%([a-z\\-_]+)(?:\\:([^%]+))?%}i";
+ $callback = function ($matches) {
+ if ($formatter = $this->getPlaceholderFormatter($matches[1])) {
+ $text = $formatter($this, $this->output);
+ } elseif (isset($this->messages[$matches[1]])) {
+ $text = $this->messages[$matches[1]];
+ } else {
+ return $matches[0];
+ }
+ if (isset($matches[2])) {
+ $text = \sprintf('%' . $matches[2], $text);
+ }
+ return $text;
+ };
+ $line = \preg_replace_callback($regex, $callback, $this->format);
+ // gets string length for each sub line with multiline format
+ $linesLength = \array_map(function ($subLine) {
+ return Helper::width(Helper::removeDecoration($this->output->getFormatter(), \rtrim($subLine, "\r")));
+ }, \explode("\n", $line));
+ $linesWidth = \max($linesLength);
+ $terminalWidth = $this->terminal->getWidth();
+ if ($linesWidth <= $terminalWidth) {
+ return $line;
+ }
+ $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);
+ return \preg_replace_callback($regex, $callback, $this->format);
+ }
+}
diff --git a/vendor/symfony/console/Helper/ProgressIndicator.php b/vendor/symfony/console/Helper/ProgressIndicator.php
new file mode 100644
index 0000000000..b1ad89cdda
--- /dev/null
+++ b/vendor/symfony/console/Helper/ProgressIndicator.php
@@ -0,0 +1,225 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\Console\Exception\LogicException;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @author Kevin Bond
+ */
+class ProgressIndicator
+{
+ private const FORMATS = ['normal' => ' %indicator% %message%', 'normal_no_ansi' => ' %message%', 'verbose' => ' %indicator% %message% (%elapsed:6s%)', 'verbose_no_ansi' => ' %message% (%elapsed:6s%)', 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)', 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)'];
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ private $output;
+ /**
+ * @var int
+ */
+ private $startTime;
+ /**
+ * @var string|null
+ */
+ private $format;
+ /**
+ * @var string|null
+ */
+ private $message;
+ /**
+ * @var mixed[]
+ */
+ private $indicatorValues;
+ /**
+ * @var int
+ */
+ private $indicatorCurrent;
+ /**
+ * @var int
+ */
+ private $indicatorChangeInterval;
+ /**
+ * @var float
+ */
+ private $indicatorUpdateTime;
+ /**
+ * @var bool
+ */
+ private $started = \false;
+ /**
+ * @var array
+ */
+ private static $formatters;
+ /**
+ * @param int $indicatorChangeInterval Change interval in milliseconds
+ * @param array|null $indicatorValues Animated indicator characters
+ */
+ public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null)
+ {
+ $this->output = $output;
+ $format = $format ?? $this->determineBestFormat();
+ $indicatorValues = $indicatorValues ?? ['-', '\\', '|', '/'];
+ $indicatorValues = \array_values($indicatorValues);
+ if (2 > \count($indicatorValues)) {
+ throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
+ }
+ $this->format = self::getFormatDefinition($format);
+ $this->indicatorChangeInterval = $indicatorChangeInterval;
+ $this->indicatorValues = $indicatorValues;
+ $this->startTime = \time();
+ }
+ /**
+ * Sets the current indicator message.
+ *
+ * @return void
+ */
+ public function setMessage(?string $message)
+ {
+ $this->message = $message;
+ $this->display();
+ }
+ /**
+ * Starts the indicator output.
+ *
+ * @return void
+ */
+ public function start(string $message)
+ {
+ if ($this->started) {
+ throw new LogicException('Progress indicator already started.');
+ }
+ $this->message = $message;
+ $this->started = \true;
+ $this->startTime = \time();
+ $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
+ $this->indicatorCurrent = 0;
+ $this->display();
+ }
+ /**
+ * Advances the indicator.
+ *
+ * @return void
+ */
+ public function advance()
+ {
+ if (!$this->started) {
+ throw new LogicException('Progress indicator has not yet been started.');
+ }
+ if (!$this->output->isDecorated()) {
+ return;
+ }
+ $currentTime = $this->getCurrentTimeInMilliseconds();
+ if ($currentTime < $this->indicatorUpdateTime) {
+ return;
+ }
+ $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
+ ++$this->indicatorCurrent;
+ $this->display();
+ }
+ /**
+ * Finish the indicator with message.
+ *
+ * @return void
+ */
+ public function finish(string $message)
+ {
+ if (!$this->started) {
+ throw new LogicException('Progress indicator has not yet been started.');
+ }
+ $this->message = $message;
+ $this->display();
+ $this->output->writeln('');
+ $this->started = \false;
+ }
+ /**
+ * Gets the format for a given name.
+ */
+ public static function getFormatDefinition(string $name) : ?string
+ {
+ return self::FORMATS[$name] ?? null;
+ }
+ /**
+ * Sets a placeholder formatter for a given name.
+ *
+ * This method also allow you to override an existing placeholder.
+ *
+ * @return void
+ */
+ public static function setPlaceholderFormatterDefinition(string $name, callable $callable)
+ {
+ self::$formatters = self::$formatters ?? self::initPlaceholderFormatters();
+ self::$formatters[$name] = $callable;
+ }
+ /**
+ * Gets the placeholder formatter for a given name (including the delimiter char like %).
+ */
+ public static function getPlaceholderFormatterDefinition(string $name) : ?callable
+ {
+ self::$formatters = self::$formatters ?? self::initPlaceholderFormatters();
+ return self::$formatters[$name] ?? null;
+ }
+ private function display() : void
+ {
+ if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
+ return;
+ }
+ $this->overwrite(\preg_replace_callback("{%([a-z\\-_]+)(?:\\:([^%]+))?%}i", function ($matches) {
+ if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) {
+ return $formatter($this);
+ }
+ return $matches[0];
+ }, $this->format ?? ''));
+ }
+ private function determineBestFormat() : string
+ {
+ switch ($this->output->getVerbosity()) {
+ case OutputInterface::VERBOSITY_VERBOSE:
+ return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
+ case OutputInterface::VERBOSITY_VERY_VERBOSE:
+ case OutputInterface::VERBOSITY_DEBUG:
+ return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
+ default:
+ return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
+ }
+ }
+ /**
+ * Overwrites a previous message to the output.
+ */
+ private function overwrite(string $message) : void
+ {
+ if ($this->output->isDecorated()) {
+ $this->output->write("\r\x1b[2K");
+ $this->output->write($message);
+ } else {
+ $this->output->writeln($message);
+ }
+ }
+ private function getCurrentTimeInMilliseconds() : float
+ {
+ return \round(\microtime(\true) * 1000);
+ }
+ /**
+ * @return array
+ */
+ private static function initPlaceholderFormatters() : array
+ {
+ return ['indicator' => function (self $indicator) {
+ return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)];
+ }, 'message' => function (self $indicator) {
+ return $indicator->message;
+ }, 'elapsed' => function (self $indicator) {
+ return Helper::formatTime(\time() - $indicator->startTime, 2);
+ }, 'memory' => function () {
+ return Helper::formatMemory(\memory_get_usage(\true));
+ }];
+ }
+}
diff --git a/vendor/symfony/console/Helper/QuestionHelper.php b/vendor/symfony/console/Helper/QuestionHelper.php
new file mode 100644
index 0000000000..0172df354f
--- /dev/null
+++ b/vendor/symfony/console/Helper/QuestionHelper.php
@@ -0,0 +1,517 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Cursor;
+use EasyCI202401\Symfony\Component\Console\Exception\MissingInputException;
+use EasyCI202401\Symfony\Component\Console\Exception\RuntimeException;
+use EasyCI202401\Symfony\Component\Console\Formatter\OutputFormatter;
+use EasyCI202401\Symfony\Component\Console\Formatter\OutputFormatterStyle;
+use EasyCI202401\Symfony\Component\Console\Input\InputInterface;
+use EasyCI202401\Symfony\Component\Console\Input\StreamableInputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleOutputInterface;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleSectionOutput;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\Console\Question\ChoiceQuestion;
+use EasyCI202401\Symfony\Component\Console\Question\Question;
+use EasyCI202401\Symfony\Component\Console\Terminal;
+use function EasyCI202401\Symfony\Component\String\s;
+/**
+ * The QuestionHelper class provides helpers to interact with the user.
+ *
+ * @author Fabien Potencier
+ */
+class QuestionHelper extends Helper
+{
+ /**
+ * @var resource|null
+ */
+ private $inputStream;
+ /**
+ * @var bool
+ */
+ private static $stty = \true;
+ /**
+ * @var bool
+ */
+ private static $stdinIsInteractive;
+ /**
+ * Asks a question to the user.
+ *
+ * @return mixed The user answer
+ *
+ * @throws RuntimeException If there is no data to read in the input stream
+ */
+ public function ask(InputInterface $input, OutputInterface $output, Question $question)
+ {
+ if ($output instanceof ConsoleOutputInterface) {
+ $output = $output->getErrorOutput();
+ }
+ if (!$input->isInteractive()) {
+ return $this->getDefaultAnswer($question);
+ }
+ if ($input instanceof StreamableInputInterface && ($stream = $input->getStream())) {
+ $this->inputStream = $stream;
+ }
+ try {
+ if (!$question->getValidator()) {
+ return $this->doAsk($output, $question);
+ }
+ $interviewer = function () use($output, $question) {
+ return $this->doAsk($output, $question);
+ };
+ return $this->validateAttempts($interviewer, $output, $question);
+ } catch (MissingInputException $exception) {
+ $input->setInteractive(\false);
+ if (null === ($fallbackOutput = $this->getDefaultAnswer($question))) {
+ throw $exception;
+ }
+ return $fallbackOutput;
+ }
+ }
+ public function getName() : string
+ {
+ return 'question';
+ }
+ /**
+ * Prevents usage of stty.
+ *
+ * @return void
+ */
+ public static function disableStty()
+ {
+ self::$stty = \false;
+ }
+ /**
+ * Asks the question to the user.
+ *
+ * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
+ * @return mixed
+ */
+ private function doAsk(OutputInterface $output, Question $question)
+ {
+ $this->writePrompt($output, $question);
+ $inputStream = $this->inputStream ?: \STDIN;
+ $autocomplete = $question->getAutocompleterCallback();
+ if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {
+ $ret = \false;
+ if ($question->isHidden()) {
+ try {
+ $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());
+ $ret = $question->isTrimmable() ? \trim($hiddenResponse) : $hiddenResponse;
+ } catch (RuntimeException $e) {
+ if (!$question->isHiddenFallback()) {
+ throw $e;
+ }
+ }
+ }
+ if (\false === $ret) {
+ $isBlocked = \stream_get_meta_data($inputStream)['blocked'] ?? \true;
+ if (!$isBlocked) {
+ \stream_set_blocking($inputStream, \true);
+ }
+ $ret = $this->readInput($inputStream, $question);
+ if (!$isBlocked) {
+ \stream_set_blocking($inputStream, \false);
+ }
+ if (\false === $ret) {
+ throw new MissingInputException('Aborted.');
+ }
+ if ($question->isTrimmable()) {
+ $ret = \trim($ret);
+ }
+ }
+ } else {
+ $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);
+ $ret = $question->isTrimmable() ? \trim($autocomplete) : $autocomplete;
+ }
+ if ($output instanceof ConsoleSectionOutput) {
+ $output->addContent('');
+ // add EOL to the question
+ $output->addContent($ret);
+ }
+ $ret = \strlen($ret) > 0 ? $ret : $question->getDefault();
+ if ($normalizer = $question->getNormalizer()) {
+ return $normalizer($ret);
+ }
+ return $ret;
+ }
+ /**
+ * @return mixed
+ */
+ private function getDefaultAnswer(Question $question)
+ {
+ $default = $question->getDefault();
+ if (null === $default) {
+ return $default;
+ }
+ if ($validator = $question->getValidator()) {
+ return \call_user_func($validator, $default);
+ } elseif ($question instanceof ChoiceQuestion) {
+ $choices = $question->getChoices();
+ if (!$question->isMultiselect()) {
+ return $choices[$default] ?? $default;
+ }
+ $default = \explode(',', $default);
+ foreach ($default as $k => $v) {
+ $v = $question->isTrimmable() ? \trim($v) : $v;
+ $default[$k] = $choices[$v] ?? $v;
+ }
+ }
+ return $default;
+ }
+ /**
+ * Outputs the question prompt.
+ *
+ * @return void
+ */
+ protected function writePrompt(OutputInterface $output, Question $question)
+ {
+ $message = $question->getQuestion();
+ if ($question instanceof ChoiceQuestion) {
+ $output->writeln(\array_merge([$question->getQuestion()], $this->formatChoiceQuestionChoices($question, 'info')));
+ $message = $question->getPrompt();
+ }
+ $output->write($message);
+ }
+ /**
+ * @return string[]
+ */
+ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag) : array
+ {
+ $messages = [];
+ $maxWidth = \max(\array_map([__CLASS__, 'width'], \array_keys($choices = $question->getChoices())));
+ foreach ($choices as $key => $value) {
+ $padding = \str_repeat(' ', $maxWidth - self::width($key));
+ $messages[] = \sprintf(" [<{$tag}>%s{$padding}{$tag}>] %s", $key, $value);
+ }
+ return $messages;
+ }
+ /**
+ * Outputs an error message.
+ *
+ * @return void
+ */
+ protected function writeError(OutputInterface $output, \Exception $error)
+ {
+ if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
+ $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
+ } else {
+ $message = '' . $error->getMessage() . '';
+ }
+ $output->writeln($message);
+ }
+ /**
+ * Autocompletes a question.
+ *
+ * @param resource $inputStream
+ */
+ private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete) : string
+ {
+ $cursor = new Cursor($output, $inputStream);
+ $fullChoice = '';
+ $ret = '';
+ $i = 0;
+ $ofs = -1;
+ $matches = $autocomplete($ret);
+ $numMatches = \count($matches);
+ $sttyMode = \shell_exec('stty -g');
+ $isStdin = 'php://stdin' === (\stream_get_meta_data($inputStream)['uri'] ?? null);
+ $r = [$inputStream];
+ $w = [];
+ // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
+ \shell_exec('stty -icanon -echo');
+ // Add highlighted text style
+ $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
+ // Read a keypress
+ while (!\feof($inputStream)) {
+ while ($isStdin && 0 === @\stream_select($r, $w, $w, 0, 100)) {
+ // Give signal handlers a chance to run
+ $r = [$inputStream];
+ }
+ $c = \fread($inputStream, 1);
+ // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false.
+ if (\false === $c || '' === $ret && '' === $c && null === $question->getDefault()) {
+ \shell_exec('stty ' . $sttyMode);
+ throw new MissingInputException('Aborted.');
+ } elseif ("" === $c) {
+ // Backspace Character
+ if (0 === $numMatches && 0 !== $i) {
+ --$i;
+ $cursor->moveLeft(s($fullChoice)->slice(-1)->width(\false));
+ $fullChoice = self::substr($fullChoice, 0, $i);
+ }
+ if (0 === $i) {
+ $ofs = -1;
+ $matches = $autocomplete($ret);
+ $numMatches = \count($matches);
+ } else {
+ $numMatches = 0;
+ }
+ // Pop the last character off the end of our string
+ $ret = self::substr($ret, 0, $i);
+ } elseif ("\x1b" === $c) {
+ // Did we read an escape sequence?
+ $c .= \fread($inputStream, 2);
+ // A = Up Arrow. B = Down Arrow
+ if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
+ if ('A' === $c[2] && -1 === $ofs) {
+ $ofs = 0;
+ }
+ if (0 === $numMatches) {
+ continue;
+ }
+ $ofs += 'A' === $c[2] ? -1 : 1;
+ $ofs = ($numMatches + $ofs) % $numMatches;
+ }
+ } elseif (\ord($c) < 32) {
+ if ("\t" === $c || "\n" === $c) {
+ if ($numMatches > 0 && -1 !== $ofs) {
+ $ret = (string) $matches[$ofs];
+ // Echo out remaining chars for current match
+ $remainingCharacters = \substr($ret, \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice))));
+ $output->write($remainingCharacters);
+ $fullChoice .= $remainingCharacters;
+ $i = \false === ($encoding = \mb_detect_encoding($fullChoice, null, \true)) ? \strlen($fullChoice) : \mb_strlen($fullChoice, $encoding);
+ $matches = \array_filter($autocomplete($ret), function ($match) use($ret) {
+ return '' === $ret || \strncmp($match, $ret, \strlen($ret)) === 0;
+ });
+ $numMatches = \count($matches);
+ $ofs = -1;
+ }
+ if ("\n" === $c) {
+ $output->write($c);
+ break;
+ }
+ $numMatches = 0;
+ }
+ continue;
+ } else {
+ if ("\x80" <= $c) {
+ $c .= \fread($inputStream, ["\xc0" => 1, "\xd0" => 1, "\xe0" => 2, "\xf0" => 3][$c & "\xf0"]);
+ }
+ $output->write($c);
+ $ret .= $c;
+ $fullChoice .= $c;
+ ++$i;
+ $tempRet = $ret;
+ if ($question instanceof ChoiceQuestion && $question->isMultiselect()) {
+ $tempRet = $this->mostRecentlyEnteredValue($fullChoice);
+ }
+ $numMatches = 0;
+ $ofs = 0;
+ foreach ($autocomplete($ret) as $value) {
+ // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
+ if (\strncmp($value, $tempRet, \strlen($tempRet)) === 0) {
+ $matches[$numMatches++] = $value;
+ }
+ }
+ }
+ $cursor->clearLineAfter();
+ if ($numMatches > 0 && -1 !== $ofs) {
+ $cursor->savePosition();
+ // Write highlighted text, complete the partially entered response
+ $charactersEntered = \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice)));
+ $output->write('' . OutputFormatter::escapeTrailingBackslash(\substr($matches[$ofs], $charactersEntered)) . '');
+ $cursor->restorePosition();
+ }
+ }
+ // Reset stty so it behaves normally again
+ \shell_exec('stty ' . $sttyMode);
+ return $fullChoice;
+ }
+ private function mostRecentlyEnteredValue(string $entered) : string
+ {
+ // Determine the most recent value that the user entered
+ if (\strpos($entered, ',') === \false) {
+ return $entered;
+ }
+ $choices = \explode(',', $entered);
+ if ('' !== ($lastChoice = \trim($choices[\count($choices) - 1]))) {
+ return $lastChoice;
+ }
+ return $entered;
+ }
+ /**
+ * Gets a hidden response from user.
+ *
+ * @param resource $inputStream The handler resource
+ * @param bool $trimmable Is the answer trimmable
+ *
+ * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
+ */
+ private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = \true) : string
+ {
+ if ('\\' === \DIRECTORY_SEPARATOR) {
+ $exe = __DIR__ . '/../Resources/bin/hiddeninput.exe';
+ // handle code running from a phar
+ if (\strncmp(__FILE__, 'phar:', \strlen('phar:')) === 0) {
+ $tmpExe = \sys_get_temp_dir() . '/hiddeninput.exe';
+ \copy($exe, $tmpExe);
+ $exe = $tmpExe;
+ }
+ $sExec = \shell_exec('"' . $exe . '"');
+ $value = $trimmable ? \rtrim($sExec) : $sExec;
+ $output->writeln('');
+ if (isset($tmpExe)) {
+ \unlink($tmpExe);
+ }
+ return $value;
+ }
+ if (self::$stty && Terminal::hasSttyAvailable()) {
+ $sttyMode = \shell_exec('stty -g');
+ \shell_exec('stty -echo');
+ } elseif ($this->isInteractiveInput($inputStream)) {
+ throw new RuntimeException('Unable to hide the response.');
+ }
+ $value = \fgets($inputStream, 4096);
+ if (4095 === \strlen($value)) {
+ $errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
+ $errOutput->warning('The value was possibly truncated by your shell or terminal emulator');
+ }
+ if (self::$stty && Terminal::hasSttyAvailable()) {
+ \shell_exec('stty ' . $sttyMode);
+ }
+ if (\false === $value) {
+ throw new MissingInputException('Aborted.');
+ }
+ if ($trimmable) {
+ $value = \trim($value);
+ }
+ $output->writeln('');
+ return $value;
+ }
+ /**
+ * Validates an attempt.
+ *
+ * @param callable $interviewer A callable that will ask for a question and return the result
+ *
+ * @throws \Exception In case the max number of attempts has been reached and no valid response has been given
+ * @return mixed
+ */
+ private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question)
+ {
+ $error = null;
+ $attempts = $question->getMaxAttempts();
+ while (null === $attempts || $attempts--) {
+ if (null !== $error) {
+ $this->writeError($output, $error);
+ }
+ try {
+ return $question->getValidator()($interviewer());
+ } catch (RuntimeException $e) {
+ throw $e;
+ } catch (\Exception $error) {
+ }
+ }
+ throw $error;
+ }
+ private function isInteractiveInput($inputStream) : bool
+ {
+ if ('php://stdin' !== (\stream_get_meta_data($inputStream)['uri'] ?? null)) {
+ return \false;
+ }
+ if (isset(self::$stdinIsInteractive)) {
+ return self::$stdinIsInteractive;
+ }
+ if (\function_exists('stream_isatty')) {
+ return self::$stdinIsInteractive = @\stream_isatty(\fopen('php://stdin', 'r'));
+ }
+ if (\function_exists('posix_isatty')) {
+ return self::$stdinIsInteractive = @\posix_isatty(\fopen('php://stdin', 'r'));
+ }
+ if (!\function_exists('shell_exec')) {
+ return self::$stdinIsInteractive = \true;
+ }
+ return self::$stdinIsInteractive = (bool) \shell_exec('stty 2> ' . ('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));
+ }
+ /**
+ * Reads one or more lines of input and returns what is read.
+ *
+ * @param resource $inputStream The handler resource
+ * @param Question $question The question being asked
+ * @return string|false
+ */
+ private function readInput($inputStream, Question $question)
+ {
+ if (!$question->isMultiline()) {
+ $cp = $this->setIOCodepage();
+ $ret = \fgets($inputStream, 4096);
+ return $this->resetIOCodepage($cp, $ret);
+ }
+ $multiLineStreamReader = $this->cloneInputStream($inputStream);
+ if (null === $multiLineStreamReader) {
+ return \false;
+ }
+ $ret = '';
+ $cp = $this->setIOCodepage();
+ while (\false !== ($char = \fgetc($multiLineStreamReader))) {
+ if (\PHP_EOL === "{$ret}{$char}") {
+ break;
+ }
+ $ret .= $char;
+ }
+ return $this->resetIOCodepage($cp, $ret);
+ }
+ private function setIOCodepage() : int
+ {
+ if (\function_exists('sapi_windows_cp_set')) {
+ $cp = \sapi_windows_cp_get();
+ \sapi_windows_cp_set(\sapi_windows_cp_get('oem'));
+ return $cp;
+ }
+ return 0;
+ }
+ /**
+ * Sets console I/O to the specified code page and converts the user input.
+ * @param string|false $input
+ * @return string|false
+ */
+ private function resetIOCodepage(int $cp, $input)
+ {
+ if (0 !== $cp) {
+ \sapi_windows_cp_set($cp);
+ if (\false !== $input && '' !== $input) {
+ $input = \sapi_windows_cp_conv(\sapi_windows_cp_get('oem'), $cp, $input);
+ }
+ }
+ return $input;
+ }
+ /**
+ * Clones an input stream in order to act on one instance of the same
+ * stream without affecting the other instance.
+ *
+ * @param resource $inputStream The handler resource
+ *
+ * @return resource|null The cloned resource, null in case it could not be cloned
+ */
+ private function cloneInputStream($inputStream)
+ {
+ $streamMetaData = \stream_get_meta_data($inputStream);
+ $seekable = $streamMetaData['seekable'] ?? \false;
+ $mode = $streamMetaData['mode'] ?? 'rb';
+ $uri = $streamMetaData['uri'] ?? null;
+ if (null === $uri) {
+ return null;
+ }
+ $cloneStream = \fopen($uri, $mode);
+ // For seekable and writable streams, add all the same data to the
+ // cloned stream and then seek to the same offset.
+ if (\true === $seekable && !\in_array($mode, ['r', 'rb', 'rt'])) {
+ $offset = \ftell($inputStream);
+ \rewind($inputStream);
+ \stream_copy_to_stream($inputStream, $cloneStream);
+ \fseek($inputStream, $offset);
+ \fseek($cloneStream, $offset);
+ }
+ return $cloneStream;
+ }
+}
diff --git a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php
new file mode 100644
index 0000000000..1477161946
--- /dev/null
+++ b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php
@@ -0,0 +1,85 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Formatter\OutputFormatter;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+use EasyCI202401\Symfony\Component\Console\Question\ChoiceQuestion;
+use EasyCI202401\Symfony\Component\Console\Question\ConfirmationQuestion;
+use EasyCI202401\Symfony\Component\Console\Question\Question;
+use EasyCI202401\Symfony\Component\Console\Style\SymfonyStyle;
+/**
+ * Symfony Style Guide compliant question helper.
+ *
+ * @author Kevin Bond
+ */
+class SymfonyQuestionHelper extends QuestionHelper
+{
+ /**
+ * @return void
+ */
+ protected function writePrompt(OutputInterface $output, Question $question)
+ {
+ $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
+ $default = $question->getDefault();
+ if ($question->isMultiline()) {
+ $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut());
+ }
+ switch (\true) {
+ case null === $default:
+ $text = \sprintf(' %s:', $text);
+ break;
+ case $question instanceof ConfirmationQuestion:
+ $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no');
+ break;
+ case $question instanceof ChoiceQuestion && $question->isMultiselect():
+ $choices = $question->getChoices();
+ $default = \explode(',', $default);
+ foreach ($default as $key => $value) {
+ $default[$key] = $choices[\trim($value)];
+ }
+ $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(\implode(', ', $default)));
+ break;
+ case $question instanceof ChoiceQuestion:
+ $choices = $question->getChoices();
+ $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default));
+ break;
+ default:
+ $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default));
+ }
+ $output->writeln($text);
+ $prompt = ' > ';
+ if ($question instanceof ChoiceQuestion) {
+ $output->writeln($this->formatChoiceQuestionChoices($question, 'comment'));
+ $prompt = $question->getPrompt();
+ }
+ $output->write($prompt);
+ }
+ /**
+ * @return void
+ */
+ protected function writeError(OutputInterface $output, \Exception $error)
+ {
+ if ($output instanceof SymfonyStyle) {
+ $output->newLine();
+ $output->error($error->getMessage());
+ return;
+ }
+ parent::writeError($output, $error);
+ }
+ private function getEofShortcut() : string
+ {
+ if ('Windows' === \PHP_OS_FAMILY) {
+ return 'Ctrl+Z then Enter';
+ }
+ return 'Ctrl+D';
+ }
+}
diff --git a/vendor/symfony/console/Helper/Table.php b/vendor/symfony/console/Helper/Table.php
new file mode 100644
index 0000000000..48a2935ac8
--- /dev/null
+++ b/vendor/symfony/console/Helper/Table.php
@@ -0,0 +1,808 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\Console\Exception\RuntimeException;
+use EasyCI202401\Symfony\Component\Console\Formatter\OutputFormatter;
+use EasyCI202401\Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface;
+use EasyCI202401\Symfony\Component\Console\Output\ConsoleSectionOutput;
+use EasyCI202401\Symfony\Component\Console\Output\OutputInterface;
+/**
+ * Provides helpers to display a table.
+ *
+ * @author Fabien Potencier
+ * @author Саша Стаменковић
+ * @author Abdellatif Ait boudad
+ * @author Max Grigorian
+ * @author Dany Maillard
+ */
+class Table
+{
+ private const SEPARATOR_TOP = 0;
+ private const SEPARATOR_TOP_BOTTOM = 1;
+ private const SEPARATOR_MID = 2;
+ private const SEPARATOR_BOTTOM = 3;
+ private const BORDER_OUTSIDE = 0;
+ private const BORDER_INSIDE = 1;
+ private const DISPLAY_ORIENTATION_DEFAULT = 'default';
+ private const DISPLAY_ORIENTATION_HORIZONTAL = 'horizontal';
+ private const DISPLAY_ORIENTATION_VERTICAL = 'vertical';
+ /**
+ * @var string|null
+ */
+ private $headerTitle;
+ /**
+ * @var string|null
+ */
+ private $footerTitle;
+ /**
+ * @var mixed[]
+ */
+ private $headers = [];
+ /**
+ * @var mixed[]
+ */
+ private $rows = [];
+ /**
+ * @var mixed[]
+ */
+ private $effectiveColumnWidths = [];
+ /**
+ * @var int
+ */
+ private $numberOfColumns;
+ /**
+ * @var \Symfony\Component\Console\Output\OutputInterface
+ */
+ private $output;
+ /**
+ * @var \Symfony\Component\Console\Helper\TableStyle
+ */
+ private $style;
+ /**
+ * @var mixed[]
+ */
+ private $columnStyles = [];
+ /**
+ * @var mixed[]
+ */
+ private $columnWidths = [];
+ /**
+ * @var mixed[]
+ */
+ private $columnMaxWidths = [];
+ /**
+ * @var bool
+ */
+ private $rendered = \false;
+ /**
+ * @var string
+ */
+ private $displayOrientation = self::DISPLAY_ORIENTATION_DEFAULT;
+ /**
+ * @var mixed[]
+ */
+ private static $styles;
+ public function __construct(OutputInterface $output)
+ {
+ $this->output = $output;
+ self::$styles = self::$styles ?? self::initStyles();
+ $this->setStyle('default');
+ }
+ /**
+ * Sets a style definition.
+ *
+ * @return void
+ */
+ public static function setStyleDefinition(string $name, TableStyle $style)
+ {
+ self::$styles = self::$styles ?? self::initStyles();
+ self::$styles[$name] = $style;
+ }
+ /**
+ * Gets a style definition by name.
+ */
+ public static function getStyleDefinition(string $name) : TableStyle
+ {
+ self::$styles = self::$styles ?? self::initStyles();
+ if (!isset(self::$styles[$name])) {
+ throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name));
+ }
+ return self::$styles[$name];
+ }
+ /**
+ * Sets table style.
+ *
+ * @return $this
+ * @param \Symfony\Component\Console\Helper\TableStyle|string $name
+ */
+ public function setStyle($name)
+ {
+ $this->style = $this->resolveStyle($name);
+ return $this;
+ }
+ /**
+ * Gets the current table style.
+ */
+ public function getStyle() : TableStyle
+ {
+ return $this->style;
+ }
+ /**
+ * Sets table column style.
+ *
+ * @param TableStyle|string $name The style name or a TableStyle instance
+ *
+ * @return $this
+ */
+ public function setColumnStyle(int $columnIndex, $name)
+ {
+ $this->columnStyles[$columnIndex] = $this->resolveStyle($name);
+ return $this;
+ }
+ /**
+ * Gets the current style for a column.
+ *
+ * If style was not set, it returns the global table style.
+ */
+ public function getColumnStyle(int $columnIndex) : TableStyle
+ {
+ return $this->columnStyles[$columnIndex] ?? $this->getStyle();
+ }
+ /**
+ * Sets the minimum width of a column.
+ *
+ * @return $this
+ */
+ public function setColumnWidth(int $columnIndex, int $width)
+ {
+ $this->columnWidths[$columnIndex] = $width;
+ return $this;
+ }
+ /**
+ * Sets the minimum width of all columns.
+ *
+ * @return $this
+ */
+ public function setColumnWidths(array $widths)
+ {
+ $this->columnWidths = [];
+ foreach ($widths as $index => $width) {
+ $this->setColumnWidth($index, $width);
+ }
+ return $this;
+ }
+ /**
+ * Sets the maximum width of a column.
+ *
+ * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while
+ * formatted strings are preserved.
+ *
+ * @return $this
+ */
+ public function setColumnMaxWidth(int $columnIndex, int $width)
+ {
+ if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) {
+ throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, \get_debug_type($this->output->getFormatter())));
+ }
+ $this->columnMaxWidths[$columnIndex] = $width;
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function setHeaders(array $headers)
+ {
+ $headers = \array_values($headers);
+ if ($headers && !\is_array($headers[0])) {
+ $headers = [$headers];
+ }
+ $this->headers = $headers;
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function setRows(array $rows)
+ {
+ $this->rows = [];
+ return $this->addRows($rows);
+ }
+ /**
+ * @return $this
+ */
+ public function addRows(array $rows)
+ {
+ foreach ($rows as $row) {
+ $this->addRow($row);
+ }
+ return $this;
+ }
+ /**
+ * @return $this
+ * @param \Symfony\Component\Console\Helper\TableSeparator|mixed[] $row
+ */
+ public function addRow($row)
+ {
+ if ($row instanceof TableSeparator) {
+ $this->rows[] = $row;
+ return $this;
+ }
+ $this->rows[] = \array_values($row);
+ return $this;
+ }
+ /**
+ * Adds a row to the table, and re-renders the table.
+ *
+ * @return $this
+ * @param \Symfony\Component\Console\Helper\TableSeparator|mixed[] $row
+ */
+ public function appendRow($row)
+ {
+ if (!$this->output instanceof ConsoleSectionOutput) {
+ throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__));
+ }
+ if ($this->rendered) {
+ $this->output->clear($this->calculateRowCount());
+ }
+ $this->addRow($row);
+ $this->render();
+ return $this;
+ }
+ /**
+ * @return $this
+ * @param int|string $column
+ */
+ public function setRow($column, array $row)
+ {
+ $this->rows[$column] = $row;
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function setHeaderTitle(?string $title)
+ {
+ $this->headerTitle = $title;
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function setFooterTitle(?string $title)
+ {
+ $this->footerTitle = $title;
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function setHorizontal(bool $horizontal = \true)
+ {
+ $this->displayOrientation = $horizontal ? self::DISPLAY_ORIENTATION_HORIZONTAL : self::DISPLAY_ORIENTATION_DEFAULT;
+ return $this;
+ }
+ /**
+ * @return $this
+ */
+ public function setVertical(bool $vertical = \true)
+ {
+ $this->displayOrientation = $vertical ? self::DISPLAY_ORIENTATION_VERTICAL : self::DISPLAY_ORIENTATION_DEFAULT;
+ return $this;
+ }
+ /**
+ * Renders table to output.
+ *
+ * Example:
+ *
+ * +---------------+-----------------------+------------------+
+ * | ISBN | Title | Author |
+ * +---------------+-----------------------+------------------+
+ * | 99921-58-10-7 | Divine Comedy | Dante Alighieri |
+ * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
+ * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
+ * +---------------+-----------------------+------------------+
+ *
+ * @return void
+ */
+ public function render()
+ {
+ $divider = new TableSeparator();
+ $isCellWithColspan = static function ($cell) {
+ return $cell instanceof TableCell && $cell->getColspan() >= 2;
+ };
+ $horizontal = self::DISPLAY_ORIENTATION_HORIZONTAL === $this->displayOrientation;
+ $vertical = self::DISPLAY_ORIENTATION_VERTICAL === $this->displayOrientation;
+ $rows = [];
+ if ($horizontal) {
+ foreach ($this->headers[0] ?? [] as $i => $header) {
+ $rows[$i] = [$header];
+ foreach ($this->rows as $row) {
+ if ($row instanceof TableSeparator) {
+ continue;
+ }
+ if (isset($row[$i])) {
+ $rows[$i][] = $row[$i];
+ } elseif ($isCellWithColspan($rows[$i][0])) {
+ // Noop, there is a "title"
+ } else {
+ $rows[$i][] = null;
+ }
+ }
+ }
+ } elseif ($vertical) {
+ $formatter = $this->output->getFormatter();
+ $maxHeaderLength = \array_reduce($this->headers[0] ?? [], static function ($max, $header) use($formatter) {
+ return \max($max, Helper::width(Helper::removeDecoration($formatter, $header)));
+ }, 0);
+ foreach ($this->rows as $row) {
+ if ($row instanceof TableSeparator) {
+ continue;
+ }
+ if ($rows) {
+ $rows[] = [$divider];
+ }
+ $containsColspan = \false;
+ foreach ($row as $cell) {
+ if ($containsColspan = $isCellWithColspan($cell)) {
+ break;
+ }
+ }
+ $headers = $this->headers[0] ?? [];
+ $maxRows = \max(\count($headers), \count($row));
+ for ($i = 0; $i < $maxRows; ++$i) {
+ $cell = (string) ($row[$i] ?? '');
+ $parts = \explode("\n", $cell);
+ foreach ($parts as $idx => $part) {
+ if ($headers && !$containsColspan) {
+ if (0 === $idx) {
+ $rows[] = [\sprintf('%s>: %s', \str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), $part)];
+ } else {
+ $rows[] = [\sprintf('%s %s', \str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), $part)];
+ }
+ } elseif ('' !== $cell) {
+ $rows[] = [$part];
+ }
+ }
+ }
+ }
+ } else {
+ $rows = \array_merge($this->headers, [$divider], $this->rows);
+ }
+ $this->calculateNumberOfColumns($rows);
+ $rowGroups = $this->buildTableRows($rows);
+ $this->calculateColumnsWidth($rowGroups);
+ $isHeader = !$horizontal;
+ $isFirstRow = $horizontal;
+ $hasTitle = (bool) $this->headerTitle;
+ foreach ($rowGroups as $rowGroup) {
+ $isHeaderSeparatorRendered = \false;
+ foreach ($rowGroup as $row) {
+ if ($divider === $row) {
+ $isHeader = \false;
+ $isFirstRow = \true;
+ continue;
+ }
+ if ($row instanceof TableSeparator) {
+ $this->renderRowSeparator();
+ continue;
+ }
+ if (!$row) {
+ continue;
+ }
+ if ($isHeader && !$isHeaderSeparatorRendered) {
+ $this->renderRowSeparator(self::SEPARATOR_TOP, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null);
+ $hasTitle = \false;
+ $isHeaderSeparatorRendered = \true;
+ }
+ if ($isFirstRow) {
+ $this->renderRowSeparator($horizontal ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null);
+ $isFirstRow = \false;
+ $hasTitle = \false;
+ }
+ if ($vertical) {
+ $isHeader = \false;
+ $isFirstRow = \false;
+ }
+ if ($horizontal) {
+ $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
+ } else {
+ $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
+ }
+ }
+ }
+ $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());
+ $this->cleanup();
+ $this->rendered = \true;
+ }
+ /**
+ * Renders horizontal header separator.
+ *
+ * Example:
+ *
+ * +-----+-----------+-------+
+ */
+ private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null) : void
+ {
+ if (!($count = $this->numberOfColumns)) {
+ return;
+ }
+ $borders = $this->style->getBorderChars();
+ if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) {
+ return;
+ }
+ $crossings = $this->style->getCrossingChars();
+ if (self::SEPARATOR_MID === $type) {
+ [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]];
+ } elseif (self::SEPARATOR_TOP === $type) {
+ [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]];
+ } elseif (self::SEPARATOR_TOP_BOTTOM === $type) {
+ [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]];
+ } else {
+ [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]];
+ }
+ $markup = $leftChar;
+ for ($column = 0; $column < $count; ++$column) {
+ $markup .= \str_repeat($horizontal, $this->effectiveColumnWidths[$column]);
+ $markup .= $column === $count - 1 ? $rightChar : $midChar;
+ }
+ if (null !== $title) {
+ $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title)));
+ $markupLength = Helper::width($markup);
+ if ($titleLength > ($limit = $markupLength - 4)) {
+ $titleLength = $limit;
+ $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, '')));
+ $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3) . '...');
+ }
+ $titleStart = \intdiv($markupLength - $titleLength, 2);
+ if (\false === \mb_detect_encoding($markup, null, \true)) {
+ $markup = \substr_replace($markup, $formattedTitle, $titleStart, $titleLength);
+ } else {
+ $markup = \mb_substr($markup, 0, $titleStart) . $formattedTitle . \mb_substr($markup, $titleStart + $titleLength);
+ }
+ }
+ $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup));
+ }
+ /**
+ * Renders vertical column separator.
+ */
+ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE) : string
+ {
+ $borders = $this->style->getBorderChars();
+ return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]);
+ }
+ /**
+ * Renders table row.
+ *
+ * Example:
+ *
+ * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
+ */
+ private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null) : void
+ {
+ $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
+ $columns = $this->getRowColumns($row);
+ $last = \count($columns) - 1;
+ foreach ($columns as $i => $column) {
+ if ($firstCellFormat && 0 === $i) {
+ $rowContent .= $this->renderCell($row, $column, $firstCellFormat);
+ } else {
+ $rowContent .= $this->renderCell($row, $column, $cellFormat);
+ }
+ $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);
+ }
+ $this->output->writeln($rowContent);
+ }
+ /**
+ * Renders table cell with padding.
+ */
+ private function renderCell(array $row, int $column, string $cellFormat) : string
+ {
+ $cell = $row[$column] ?? '';
+ $width = $this->effectiveColumnWidths[$column];
+ if ($cell instanceof TableCell && $cell->getColspan() > 1) {
+ // add the width of the following columns(numbers of colspan).
+ foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
+ $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];
+ }
+ }
+ // str_pad won't work properly with multi-byte strings, we need to fix the padding
+ if (\false !== ($encoding = \mb_detect_encoding($cell, null, \true))) {
+ $width += \strlen($cell) - \mb_strwidth($cell, $encoding);
+ }
+ $style = $this->getColumnStyle($column);
+ if ($cell instanceof TableSeparator) {
+ return \sprintf($style->getBorderFormat(), \str_repeat($style->getBorderChars()[2], $width));
+ }
+ $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell));
+ $content = \sprintf($style->getCellRowContentFormat(), $cell);
+ $padType = $style->getPadType();
+ if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) {
+ $isNotStyledByTag = !\preg_match('/^<(\\w+|(\\w+=[\\w,]+;?)*)>.+<\\/(\\w+|(\\w+=\\w+;?)*)?>$/', $cell);
+ if ($isNotStyledByTag) {
+ $cellFormat = $cell->getStyle()->getCellFormat();
+ if (!\is_string($cellFormat)) {
+ $tag = \http_build_query($cell->getStyle()->getTagOptions(), '', ';');
+ $cellFormat = '<' . $tag . '>%s>';
+ }
+ if (\strpos($content, '>') !== \false) {
+ $content = \str_replace('>', '', $content);
+ $width -= 3;
+ }
+ if (\strpos($content, '') !== \false) {
+ $content = \str_replace('', '', $content);
+ $width -= \strlen('');
+ }
+ }
+ $padType = $cell->getStyle()->getPadByAlign();
+ }
+ return \sprintf($cellFormat, \str_pad($content, $width, $style->getPaddingChar(), $padType));
+ }
+ /**
+ * Calculate number of columns for this table.
+ */
+ private function calculateNumberOfColumns(array $rows) : void
+ {
+ $columns = [0];
+ foreach ($rows as $row) {
+ if ($row instanceof TableSeparator) {
+ continue;
+ }
+ $columns[] = $this->getNumberOfColumns($row);
+ }
+ $this->numberOfColumns = \max($columns);
+ }
+ private function buildTableRows(array $rows) : TableRows
+ {
+ /** @var WrappableOutputFormatterInterface $formatter */
+ $formatter = $this->output->getFormatter();
+ $unmergedRows = [];
+ for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
+ $rows = $this->fillNextRows($rows, $rowKey);
+ // Remove any new line breaks and replace it with a new line
+ foreach ($rows[$rowKey] as $column => $cell) {
+ $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;
+ if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) {
+ $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);
+ }
+ if (\strpos($cell ?? '', "\n") === \false) {
+ continue;
+ }
+ $escaped = \implode("\n", \array_map(\Closure::fromCallable([OutputFormatter::class, 'escapeTrailingBackslash']), \explode("\n", $cell)));
+ $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;
+ $lines = \explode("\n", \str_replace("\n", ">\n", $cell));
+ foreach ($lines as $lineKey => $line) {
+ if ($colspan > 1) {
+ $line = new TableCell($line, ['colspan' => $colspan]);
+ }
+ if (0 === $lineKey) {
+ $rows[$rowKey][$column] = $line;
+ } else {
+ if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) {
+ $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey);
+ }
+ $unmergedRows[$rowKey][$lineKey][$column] = $line;
+ }
+ }
+ }
+ }
+ return new TableRows(function () use($rows, $unmergedRows) : \Traversable {
+ foreach ($rows as $rowKey => $row) {
+ $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)];
+ if (isset($unmergedRows[$rowKey])) {
+ foreach ($unmergedRows[$rowKey] as $row) {
+ $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row);
+ }
+ }
+ (yield $rowGroup);
+ }
+ });
+ }
+ private function calculateRowCount() : int
+ {
+ $numberOfRows = \count(\iterator_to_array($this->buildTableRows(\array_merge($this->headers, [new TableSeparator()], $this->rows))));
+ if ($this->headers) {
+ ++$numberOfRows;
+ // Add row for header separator
+ }
+ if ($this->rows) {
+ ++$numberOfRows;
+ // Add row for footer separator
+ }
+ return $numberOfRows;
+ }
+ /**
+ * fill rows that contains rowspan > 1.
+ *
+ * @throws InvalidArgumentException
+ */
+ private function fillNextRows(array $rows, int $line) : array
+ {
+ $unmergedRows = [];
+ foreach ($rows[$line] as $column => $cell) {
+ if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) {
+ throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \get_debug_type($cell)));
+ }
+ if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
+ $nbLines = $cell->getRowspan() - 1;
+ $lines = [$cell];
+ if (\strpos($cell, "\n") !== \false) {
+ $lines = \explode("\n", \str_replace("\n", "\n>", $cell));
+ $nbLines = \count($lines) > $nbLines ? \substr_count($cell, "\n") : $nbLines;
+ $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);
+ unset($lines[0]);
+ }
+ // create a two dimensional array (rowspan x colspan)
+ $unmergedRows = \array_replace_recursive(\array_fill($line + 1, $nbLines, []), $unmergedRows);
+ foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
+ $value = $lines[$unmergedRowKey - $line] ?? '';
+ $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);
+ if ($nbLines === $unmergedRowKey - $line) {
+ break;
+ }
+ }
+ }
+ }
+ foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
+ // we need to know if $unmergedRow will be merged or inserted into $rows
+ if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && $this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns) {
+ foreach ($unmergedRow as $cellKey => $cell) {
+ // insert cell into row at cellKey position
+ \array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);
+ }
+ } else {
+ $row = $this->copyRow($rows, $unmergedRowKey - 1);
+ foreach ($unmergedRow as $column => $cell) {
+ if (!empty($cell)) {
+ $row[$column] = $unmergedRow[$column];
+ }
+ }
+ \array_splice($rows, $unmergedRowKey, 0, [$row]);
+ }
+ }
+ return $rows;
+ }
+ /**
+ * fill cells for a row that contains colspan > 1.
+ */
+ private function fillCells(iterable $row) : iterable
+ {
+ $newRow = [];
+ foreach ($row as $column => $cell) {
+ $newRow[] = $cell;
+ if ($cell instanceof TableCell && $cell->getColspan() > 1) {
+ foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $position) {
+ // insert empty value at column position
+ $newRow[] = '';
+ }
+ }
+ }
+ return $newRow ?: $row;
+ }
+ private function copyRow(array $rows, int $line) : array
+ {
+ $row = $rows[$line];
+ foreach ($row as $cellKey => $cellValue) {
+ $row[$cellKey] = '';
+ if ($cellValue instanceof TableCell) {
+ $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);
+ }
+ }
+ return $row;
+ }
+ /**
+ * Gets number of columns by row.
+ */
+ private function getNumberOfColumns(array $row) : int
+ {
+ $columns = \count($row);
+ foreach ($row as $column) {
+ $columns += $column instanceof TableCell ? $column->getColspan() - 1 : 0;
+ }
+ return $columns;
+ }
+ /**
+ * Gets list of columns for the given row.
+ */
+ private function getRowColumns(array $row) : array
+ {
+ $columns = \range(0, $this->numberOfColumns - 1);
+ foreach ($row as $cellKey => $cell) {
+ if ($cell instanceof TableCell && $cell->getColspan() > 1) {
+ // exclude grouped columns.
+ $columns = \array_diff($columns, \range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
+ }
+ }
+ return $columns;
+ }
+ /**
+ * Calculates columns widths.
+ */
+ private function calculateColumnsWidth(iterable $groups) : void
+ {
+ for ($column = 0; $column < $this->numberOfColumns; ++$column) {
+ $lengths = [];
+ foreach ($groups as $group) {
+ foreach ($group as $row) {
+ if ($row instanceof TableSeparator) {
+ continue;
+ }
+ foreach ($row as $i => $cell) {
+ if ($cell instanceof TableCell) {
+ $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
+ $textLength = Helper::width($textContent);
+ if ($textLength > 0) {
+ $contentColumns = \mb_str_split($textContent, \ceil($textLength / $cell->getColspan()));
+ foreach ($contentColumns as $position => $content) {
+ $row[$i + $position] = $content;
+ }
+ }
+ }
+ }
+ $lengths[] = $this->getCellWidth($row, $column);
+ }
+ }
+ $this->effectiveColumnWidths[$column] = \max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2;
+ }
+ }
+ private function getColumnSeparatorWidth() : int
+ {
+ return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));
+ }
+ private function getCellWidth(array $row, int $column) : int
+ {
+ $cellWidth = 0;
+ if (isset($row[$column])) {
+ $cell = $row[$column];
+ $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell));
+ }
+ $columnWidth = $this->columnWidths[$column] ?? 0;
+ $cellWidth = \max($cellWidth, $columnWidth);
+ return isset($this->columnMaxWidths[$column]) ? \min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth;
+ }
+ /**
+ * Called after rendering to cleanup cache data.
+ */
+ private function cleanup() : void
+ {
+ $this->effectiveColumnWidths = [];
+ unset($this->numberOfColumns);
+ }
+ /**
+ * @return array
+ */
+ private static function initStyles() : array
+ {
+ $borderless = new TableStyle();
+ $borderless->setHorizontalBorderChars('=')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' ');
+ $compact = new TableStyle();
+ $compact->setHorizontalBorderChars('')->setVerticalBorderChars('')->setDefaultCrossingChar('')->setCellRowContentFormat('%s ');
+ $styleGuide = new TableStyle();
+ $styleGuide->setHorizontalBorderChars('-')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' ')->setCellHeaderFormat('%s');
+ $box = (new TableStyle())->setHorizontalBorderChars('─')->setVerticalBorderChars('│')->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├');
+ $boxDouble = (new TableStyle())->setHorizontalBorderChars('═', '─')->setVerticalBorderChars('║', '│')->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣');
+ return ['default' => new TableStyle(), 'borderless' => $borderless, 'compact' => $compact, 'symfony-style-guide' => $styleGuide, 'box' => $box, 'box-double' => $boxDouble];
+ }
+ /**
+ * @param \Symfony\Component\Console\Helper\TableStyle|string $name
+ */
+ private function resolveStyle($name) : TableStyle
+ {
+ if ($name instanceof TableStyle) {
+ return $name;
+ }
+ if (!isset(self::$styles[$name])) {
+ throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name));
+ }
+ return self::$styles[$name];
+ }
+}
diff --git a/vendor/symfony/console/Helper/TableCell.php b/vendor/symfony/console/Helper/TableCell.php
new file mode 100644
index 0000000000..7b1c389403
--- /dev/null
+++ b/vendor/symfony/console/Helper/TableCell.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+/**
+ * @author Abdellatif Ait boudad
+ */
+class TableCell
+{
+ /**
+ * @var string
+ */
+ private $value;
+ /**
+ * @var mixed[]
+ */
+ private $options = ['rowspan' => 1, 'colspan' => 1, 'style' => null];
+ public function __construct(string $value = '', array $options = [])
+ {
+ $this->value = $value;
+ // check option names
+ if ($diff = \array_diff(\array_keys($options), \array_keys($this->options))) {
+ throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', \implode('\', \'', $diff)));
+ }
+ if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) {
+ throw new InvalidArgumentException('The style option must be an instance of "TableCellStyle".');
+ }
+ $this->options = \array_merge($this->options, $options);
+ }
+ /**
+ * Returns the cell value.
+ */
+ public function __toString() : string
+ {
+ return $this->value;
+ }
+ /**
+ * Gets number of colspan.
+ */
+ public function getColspan() : int
+ {
+ return (int) $this->options['colspan'];
+ }
+ /**
+ * Gets number of rowspan.
+ */
+ public function getRowspan() : int
+ {
+ return (int) $this->options['rowspan'];
+ }
+ public function getStyle() : ?TableCellStyle
+ {
+ return $this->options['style'];
+ }
+}
diff --git a/vendor/symfony/console/Helper/TableCellStyle.php b/vendor/symfony/console/Helper/TableCellStyle.php
new file mode 100644
index 0000000000..13d687059f
--- /dev/null
+++ b/vendor/symfony/console/Helper/TableCellStyle.php
@@ -0,0 +1,59 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+/**
+ * @author Yewhen Khoptynskyi
+ */
+class TableCellStyle
+{
+ public const DEFAULT_ALIGN = 'left';
+ private const TAG_OPTIONS = ['fg', 'bg', 'options'];
+ private const ALIGN_MAP = ['left' => \STR_PAD_RIGHT, 'center' => \STR_PAD_BOTH, 'right' => \STR_PAD_LEFT];
+ /**
+ * @var mixed[]
+ */
+ private $options = ['fg' => 'default', 'bg' => 'default', 'options' => null, 'align' => self::DEFAULT_ALIGN, 'cellFormat' => null];
+ public function __construct(array $options = [])
+ {
+ if ($diff = \array_diff(\array_keys($options), \array_keys($this->options))) {
+ throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', \implode('\', \'', $diff)));
+ }
+ if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) {
+ throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', \implode('\', \'', \array_keys(self::ALIGN_MAP))));
+ }
+ $this->options = \array_merge($this->options, $options);
+ }
+ public function getOptions() : array
+ {
+ return $this->options;
+ }
+ /**
+ * Gets options we need for tag for example fg, bg.
+ *
+ * @return string[]
+ */
+ public function getTagOptions() : array
+ {
+ return \array_filter($this->getOptions(), function ($key) {
+ return \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]);
+ }, \ARRAY_FILTER_USE_KEY);
+ }
+ public function getPadByAlign() : int
+ {
+ return self::ALIGN_MAP[$this->getOptions()['align']];
+ }
+ public function getCellFormat() : ?string
+ {
+ return $this->getOptions()['cellFormat'];
+ }
+}
diff --git a/vendor/symfony/console/Helper/TableRows.php b/vendor/symfony/console/Helper/TableRows.php
new file mode 100644
index 0000000000..5a7cc82768
--- /dev/null
+++ b/vendor/symfony/console/Helper/TableRows.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+/**
+ * @internal
+ */
+class TableRows implements \IteratorAggregate
+{
+ /**
+ * @var \Closure
+ */
+ private $generator;
+ public function __construct(\Closure $generator)
+ {
+ $this->generator = $generator;
+ }
+ public function getIterator() : \Traversable
+ {
+ return ($this->generator)();
+ }
+}
diff --git a/vendor/symfony/console/Helper/TableSeparator.php b/vendor/symfony/console/Helper/TableSeparator.php
new file mode 100644
index 0000000000..817c47a233
--- /dev/null
+++ b/vendor/symfony/console/Helper/TableSeparator.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+/**
+ * Marks a row as being a separator.
+ *
+ * @author Fabien Potencier
+ */
+class TableSeparator extends TableCell
+{
+ public function __construct(array $options = [])
+ {
+ parent::__construct('', $options);
+ }
+}
diff --git a/vendor/symfony/console/Helper/TableStyle.php b/vendor/symfony/console/Helper/TableStyle.php
new file mode 100644
index 0000000000..d2b2041347
--- /dev/null
+++ b/vendor/symfony/console/Helper/TableStyle.php
@@ -0,0 +1,378 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Helper;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\Console\Exception\LogicException;
+/**
+ * Defines the styles for a Table.
+ *
+ * @author Fabien Potencier
+ * @author Саша Стаменковић
+ * @author Dany Maillard
+ */
+class TableStyle
+{
+ /**
+ * @var string
+ */
+ private $paddingChar = ' ';
+ /**
+ * @var string
+ */
+ private $horizontalOutsideBorderChar = '-';
+ /**
+ * @var string
+ */
+ private $horizontalInsideBorderChar = '-';
+ /**
+ * @var string
+ */
+ private $verticalOutsideBorderChar = '|';
+ /**
+ * @var string
+ */
+ private $verticalInsideBorderChar = '|';
+ /**
+ * @var string
+ */
+ private $crossingChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingTopRightChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingTopMidChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingTopLeftChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingMidRightChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingBottomRightChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingBottomMidChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingBottomLeftChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingMidLeftChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingTopLeftBottomChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingTopMidBottomChar = '+';
+ /**
+ * @var string
+ */
+ private $crossingTopRightBottomChar = '+';
+ /**
+ * @var string
+ */
+ private $headerTitleFormat = ' %s >';
+ /**
+ * @var string
+ */
+ private $footerTitleFormat = ' %s >';
+ /**
+ * @var string
+ */
+ private $cellHeaderFormat = '%s';
+ /**
+ * @var string
+ */
+ private $cellRowFormat = '%s';
+ /**
+ * @var string
+ */
+ private $cellRowContentFormat = ' %s ';
+ /**
+ * @var string
+ */
+ private $borderFormat = '%s';
+ /**
+ * @var int
+ */
+ private $padType = \STR_PAD_RIGHT;
+ /**
+ * Sets padding character, used for cell padding.
+ *
+ * @return $this
+ */
+ public function setPaddingChar(string $paddingChar)
+ {
+ if (!$paddingChar) {
+ throw new LogicException('The padding char must not be empty.');
+ }
+ $this->paddingChar = $paddingChar;
+ return $this;
+ }
+ /**
+ * Gets padding character, used for cell padding.
+ */
+ public function getPaddingChar() : string
+ {
+ return $this->paddingChar;
+ }
+ /**
+ * Sets horizontal border characters.
+ *
+ *
+ * ╔═══════════════╤══════════════════════════╤══════════════════╗
+ * 1 ISBN 2 Title │ Author ║
+ * ╠═══════════════╪══════════════════════════╪══════════════════╣
+ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║
+ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║
+ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║
+ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║
+ * ╚═══════════════╧══════════════════════════╧══════════════════╝
+ *
+ *
+ * @return $this
+ */
+ public function setHorizontalBorderChars(string $outside, string $inside = null)
+ {
+ $this->horizontalOutsideBorderChar = $outside;
+ $this->horizontalInsideBorderChar = $inside ?? $outside;
+ return $this;
+ }
+ /**
+ * Sets vertical border characters.
+ *
+ *
+ * ╔═══════════════╤══════════════════════════╤══════════════════╗
+ * ║ ISBN │ Title │ Author ║
+ * ╠═══════1═══════╪══════════════════════════╪══════════════════╣
+ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║
+ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║
+ * ╟───────2───────┼──────────────────────────┼──────────────────╢
+ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║
+ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║
+ * ╚═══════════════╧══════════════════════════╧══════════════════╝
+ *
+ *
+ * @return $this
+ */
+ public function setVerticalBorderChars(string $outside, string $inside = null)
+ {
+ $this->verticalOutsideBorderChar = $outside;
+ $this->verticalInsideBorderChar = $inside ?? $outside;
+ return $this;
+ }
+ /**
+ * Gets border characters.
+ *
+ * @internal
+ */
+ public function getBorderChars() : array
+ {
+ return [$this->horizontalOutsideBorderChar, $this->verticalOutsideBorderChar, $this->horizontalInsideBorderChar, $this->verticalInsideBorderChar];
+ }
+ /**
+ * Sets crossing characters.
+ *
+ * Example:
+ *
+ * 1═══════════════2══════════════════════════2══════════════════3
+ * ║ ISBN │ Title │ Author ║
+ * 8'══════════════0'═════════════════════════0'═════════════════4'
+ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║
+ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║
+ * 8───────────────0──────────────────────────0──────────────────4
+ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║
+ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║
+ * 7═══════════════6══════════════════════════6══════════════════5
+ *
+ *
+ * @param string $cross Crossing char (see #0 of example)
+ * @param string $topLeft Top left char (see #1 of example)
+ * @param string $topMid Top mid char (see #2 of example)
+ * @param string $topRight Top right char (see #3 of example)
+ * @param string $midRight Mid right char (see #4 of example)
+ * @param string $bottomRight Bottom right char (see #5 of example)
+ * @param string $bottomMid Bottom mid char (see #6 of example)
+ * @param string $bottomLeft Bottom left char (see #7 of example)
+ * @param string $midLeft Mid left char (see #8 of example)
+ * @param string|null $topLeftBottom Top left bottom char (see #8' of example), equals to $midLeft if null
+ * @param string|null $topMidBottom Top mid bottom char (see #0' of example), equals to $cross if null
+ * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null
+ *
+ * @return $this
+ */
+ public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null)
+ {
+ $this->crossingChar = $cross;
+ $this->crossingTopLeftChar = $topLeft;
+ $this->crossingTopMidChar = $topMid;
+ $this->crossingTopRightChar = $topRight;
+ $this->crossingMidRightChar = $midRight;
+ $this->crossingBottomRightChar = $bottomRight;
+ $this->crossingBottomMidChar = $bottomMid;
+ $this->crossingBottomLeftChar = $bottomLeft;
+ $this->crossingMidLeftChar = $midLeft;
+ $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft;
+ $this->crossingTopMidBottomChar = $topMidBottom ?? $cross;
+ $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight;
+ return $this;
+ }
+ /**
+ * Sets default crossing character used for each cross.
+ *
+ * @see {@link setCrossingChars()} for setting each crossing individually.
+ */
+ public function setDefaultCrossingChar(string $char) : self
+ {
+ return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);
+ }
+ /**
+ * Gets crossing character.
+ */
+ public function getCrossingChar() : string
+ {
+ return $this->crossingChar;
+ }
+ /**
+ * Gets crossing characters.
+ *
+ * @internal
+ */
+ public function getCrossingChars() : array
+ {
+ return [$this->crossingChar, $this->crossingTopLeftChar, $this->crossingTopMidChar, $this->crossingTopRightChar, $this->crossingMidRightChar, $this->crossingBottomRightChar, $this->crossingBottomMidChar, $this->crossingBottomLeftChar, $this->crossingMidLeftChar, $this->crossingTopLeftBottomChar, $this->crossingTopMidBottomChar, $this->crossingTopRightBottomChar];
+ }
+ /**
+ * Sets header cell format.
+ *
+ * @return $this
+ */
+ public function setCellHeaderFormat(string $cellHeaderFormat)
+ {
+ $this->cellHeaderFormat = $cellHeaderFormat;
+ return $this;
+ }
+ /**
+ * Gets header cell format.
+ */
+ public function getCellHeaderFormat() : string
+ {
+ return $this->cellHeaderFormat;
+ }
+ /**
+ * Sets row cell format.
+ *
+ * @return $this
+ */
+ public function setCellRowFormat(string $cellRowFormat)
+ {
+ $this->cellRowFormat = $cellRowFormat;
+ return $this;
+ }
+ /**
+ * Gets row cell format.
+ */
+ public function getCellRowFormat() : string
+ {
+ return $this->cellRowFormat;
+ }
+ /**
+ * Sets row cell content format.
+ *
+ * @return $this
+ */
+ public function setCellRowContentFormat(string $cellRowContentFormat)
+ {
+ $this->cellRowContentFormat = $cellRowContentFormat;
+ return $this;
+ }
+ /**
+ * Gets row cell content format.
+ */
+ public function getCellRowContentFormat() : string
+ {
+ return $this->cellRowContentFormat;
+ }
+ /**
+ * Sets table border format.
+ *
+ * @return $this
+ */
+ public function setBorderFormat(string $borderFormat)
+ {
+ $this->borderFormat = $borderFormat;
+ return $this;
+ }
+ /**
+ * Gets table border format.
+ */
+ public function getBorderFormat() : string
+ {
+ return $this->borderFormat;
+ }
+ /**
+ * Sets cell padding type.
+ *
+ * @return $this
+ */
+ public function setPadType(int $padType)
+ {
+ if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], \true)) {
+ throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
+ }
+ $this->padType = $padType;
+ return $this;
+ }
+ /**
+ * Gets cell padding type.
+ */
+ public function getPadType() : int
+ {
+ return $this->padType;
+ }
+ public function getHeaderTitleFormat() : string
+ {
+ return $this->headerTitleFormat;
+ }
+ /**
+ * @return $this
+ */
+ public function setHeaderTitleFormat(string $format)
+ {
+ $this->headerTitleFormat = $format;
+ return $this;
+ }
+ public function getFooterTitleFormat() : string
+ {
+ return $this->footerTitleFormat;
+ }
+ /**
+ * @return $this
+ */
+ public function setFooterTitleFormat(string $format)
+ {
+ $this->footerTitleFormat = $format;
+ return $this;
+ }
+}
diff --git a/vendor/symfony/console/Input/ArgvInput.php b/vendor/symfony/console/Input/ArgvInput.php
new file mode 100644
index 0000000000..bd34103190
--- /dev/null
+++ b/vendor/symfony/console/Input/ArgvInput.php
@@ -0,0 +1,336 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Input;
+
+use EasyCI202401\Symfony\Component\Console\Exception\RuntimeException;
+/**
+ * ArgvInput represents an input coming from the CLI arguments.
+ *
+ * Usage:
+ *
+ * $input = new ArgvInput();
+ *
+ * By default, the `$_SERVER['argv']` array is used for the input values.
+ *
+ * This can be overridden by explicitly passing the input values in the constructor:
+ *
+ * $input = new ArgvInput($_SERVER['argv']);
+ *
+ * If you pass it yourself, don't forget that the first element of the array
+ * is the name of the running application.
+ *
+ * When passing an argument to the constructor, be sure that it respects
+ * the same rules as the argv one. It's almost always better to use the
+ * `StringInput` when you want to provide your own input.
+ *
+ * @author Fabien Potencier
+ *
+ * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
+ * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
+ */
+class ArgvInput extends Input
+{
+ /**
+ * @var mixed[]
+ */
+ private $tokens;
+ /**
+ * @var mixed[]
+ */
+ private $parsed;
+ public function __construct(array $argv = null, InputDefinition $definition = null)
+ {
+ $argv = $argv ?? $_SERVER['argv'] ?? [];
+ // strip the application name
+ \array_shift($argv);
+ $this->tokens = $argv;
+ parent::__construct($definition);
+ }
+ /**
+ * @return void
+ */
+ protected function setTokens(array $tokens)
+ {
+ $this->tokens = $tokens;
+ }
+ /**
+ * @return void
+ */
+ protected function parse()
+ {
+ $parseOptions = \true;
+ $this->parsed = $this->tokens;
+ while (null !== ($token = \array_shift($this->parsed))) {
+ $parseOptions = $this->parseToken($token, $parseOptions);
+ }
+ }
+ protected function parseToken(string $token, bool $parseOptions) : bool
+ {
+ if ($parseOptions && '' == $token) {
+ $this->parseArgument($token);
+ } elseif ($parseOptions && '--' == $token) {
+ return \false;
+ } elseif ($parseOptions && \strncmp($token, '--', \strlen('--')) === 0) {
+ $this->parseLongOption($token);
+ } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
+ $this->parseShortOption($token);
+ } else {
+ $this->parseArgument($token);
+ }
+ return $parseOptions;
+ }
+ /**
+ * Parses a short option.
+ */
+ private function parseShortOption(string $token) : void
+ {
+ $name = \substr($token, 1);
+ if (\strlen($name) > 1) {
+ if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
+ // an option with a value (with no space)
+ $this->addShortOption($name[0], \substr($name, 1));
+ } else {
+ $this->parseShortOptionSet($name);
+ }
+ } else {
+ $this->addShortOption($name, null);
+ }
+ }
+ /**
+ * Parses a short option set.
+ *
+ * @throws RuntimeException When option given doesn't exist
+ */
+ private function parseShortOptionSet(string $name) : void
+ {
+ $len = \strlen($name);
+ for ($i = 0; $i < $len; ++$i) {
+ if (!$this->definition->hasShortcut($name[$i])) {
+ $encoding = \mb_detect_encoding($name, null, \true);
+ throw new RuntimeException(\sprintf('The "-%s" option does not exist.', \false === $encoding ? $name[$i] : \mb_substr($name, $i, 1, $encoding)));
+ }
+ $option = $this->definition->getOptionForShortcut($name[$i]);
+ if ($option->acceptValue()) {
+ $this->addLongOption($option->getName(), $i === $len - 1 ? null : \substr($name, $i + 1));
+ break;
+ } else {
+ $this->addLongOption($option->getName(), null);
+ }
+ }
+ }
+ /**
+ * Parses a long option.
+ */
+ private function parseLongOption(string $token) : void
+ {
+ $name = \substr($token, 2);
+ if (\false !== ($pos = \strpos($name, '='))) {
+ if ('' === ($value = \substr($name, $pos + 1))) {
+ \array_unshift($this->parsed, $value);
+ }
+ $this->addLongOption(\substr($name, 0, $pos), $value);
+ } else {
+ $this->addLongOption($name, null);
+ }
+ }
+ /**
+ * Parses an argument.
+ *
+ * @throws RuntimeException When too many arguments are given
+ */
+ private function parseArgument(string $token) : void
+ {
+ $c = \count($this->arguments);
+ // if input is expecting another argument, add it
+ if ($this->definition->hasArgument($c)) {
+ $arg = $this->definition->getArgument($c);
+ $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;
+ // if last argument isArray(), append token to last argument
+ } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
+ $arg = $this->definition->getArgument($c - 1);
+ $this->arguments[$arg->getName()][] = $token;
+ // unexpected argument
+ } else {
+ $all = $this->definition->getArguments();
+ $symfonyCommandName = null;
+ \reset($all);
+ if (($inputArgument = $all[$key = \key($all)] ?? null) && 'command' === $inputArgument->getName()) {
+ $symfonyCommandName = $this->arguments['command'] ?? null;
+ unset($all[$key]);
+ }
+ if (\count($all)) {
+ if ($symfonyCommandName) {
+ $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, \implode('" "', \array_keys($all)));
+ } else {
+ $message = \sprintf('Too many arguments, expected arguments "%s".', \implode('" "', \array_keys($all)));
+ }
+ } elseif ($symfonyCommandName) {
+ $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token);
+ } else {
+ $message = \sprintf('No arguments expected, got "%s".', $token);
+ }
+ throw new RuntimeException($message);
+ }
+ }
+ /**
+ * Adds a short option value.
+ *
+ * @throws RuntimeException When option given doesn't exist
+ * @param mixed $value
+ */
+ private function addShortOption(string $shortcut, $value) : void
+ {
+ if (!$this->definition->hasShortcut($shortcut)) {
+ throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut));
+ }
+ $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
+ }
+ /**
+ * Adds a long option value.
+ *
+ * @throws RuntimeException When option given doesn't exist
+ * @param mixed $value
+ */
+ private function addLongOption(string $name, $value) : void
+ {
+ if (!$this->definition->hasOption($name)) {
+ if (!$this->definition->hasNegation($name)) {
+ throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name));
+ }
+ $optionName = $this->definition->negationToName($name);
+ if (null !== $value) {
+ throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name));
+ }
+ $this->options[$optionName] = \false;
+ return;
+ }
+ $option = $this->definition->getOption($name);
+ if (null !== $value && !$option->acceptValue()) {
+ throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name));
+ }
+ if (\in_array($value, ['', null], \true) && $option->acceptValue() && \count($this->parsed)) {
+ // if option accepts an optional or mandatory argument
+ // let's see if there is one provided
+ $next = \array_shift($this->parsed);
+ if (isset($next[0]) && '-' !== $next[0] || \in_array($next, ['', null], \true)) {
+ $value = $next;
+ } else {
+ \array_unshift($this->parsed, $next);
+ }
+ }
+ if (null === $value) {
+ if ($option->isValueRequired()) {
+ throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name));
+ }
+ if (!$option->isArray() && !$option->isValueOptional()) {
+ $value = \true;
+ }
+ }
+ if ($option->isArray()) {
+ $this->options[$name][] = $value;
+ } else {
+ $this->options[$name] = $value;
+ }
+ }
+ public function getFirstArgument() : ?string
+ {
+ $isOption = \false;
+ foreach ($this->tokens as $i => $token) {
+ if ($token && '-' === $token[0]) {
+ if (\strpos($token, '=') !== \false || !isset($this->tokens[$i + 1])) {
+ continue;
+ }
+ // If it's a long option, consider that everything after "--" is the option name.
+ // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator)
+ $name = '-' === $token[1] ? \substr($token, 2) : \substr($token, -1);
+ if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
+ // noop
+ } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
+ $isOption = \true;
+ }
+ continue;
+ }
+ if ($isOption) {
+ $isOption = \false;
+ continue;
+ }
+ return $token;
+ }
+ return null;
+ }
+ /**
+ * @param string|mixed[] $values
+ */
+ public function hasParameterOption($values, bool $onlyParams = \false) : bool
+ {
+ $values = (array) $values;
+ foreach ($this->tokens as $token) {
+ if ($onlyParams && '--' === $token) {
+ return \false;
+ }
+ foreach ($values as $value) {
+ // Options with values:
+ // For long options, test for '--option=' at beginning
+ // For short options, test for '-o' at beginning
+ $leading = \strncmp($value, '--', \strlen('--')) === 0 ? $value . '=' : $value;
+ if ($token === $value || '' !== $leading && \strncmp($token, $leading, \strlen($leading)) === 0) {
+ return \true;
+ }
+ }
+ }
+ return \false;
+ }
+ /**
+ * @param string|mixed[] $values
+ * @param string|bool|int|float|mixed[]|null $default
+ * @return mixed
+ */
+ public function getParameterOption($values, $default = \false, bool $onlyParams = \false)
+ {
+ $values = (array) $values;
+ $tokens = $this->tokens;
+ while (0 < \count($tokens)) {
+ $token = \array_shift($tokens);
+ if ($onlyParams && '--' === $token) {
+ return $default;
+ }
+ foreach ($values as $value) {
+ if ($token === $value) {
+ return \array_shift($tokens);
+ }
+ // Options with values:
+ // For long options, test for '--option=' at beginning
+ // For short options, test for '-o' at beginning
+ $leading = \strncmp($value, '--', \strlen('--')) === 0 ? $value . '=' : $value;
+ if ('' !== $leading && \strncmp($token, $leading, \strlen($leading)) === 0) {
+ return \substr($token, \strlen($leading));
+ }
+ }
+ }
+ return $default;
+ }
+ /**
+ * Returns a stringified representation of the args passed to the command.
+ */
+ public function __toString() : string
+ {
+ $tokens = \array_map(function ($token) {
+ if (\preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
+ return $match[1] . $this->escapeToken($match[2]);
+ }
+ if ($token && '-' !== $token[0]) {
+ return $this->escapeToken($token);
+ }
+ return $token;
+ }, $this->tokens);
+ return \implode(' ', $tokens);
+ }
+}
diff --git a/vendor/symfony/console/Input/ArrayInput.php b/vendor/symfony/console/Input/ArrayInput.php
new file mode 100644
index 0000000000..9e37dab656
--- /dev/null
+++ b/vendor/symfony/console/Input/ArrayInput.php
@@ -0,0 +1,181 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Input;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidOptionException;
+/**
+ * ArrayInput represents an input provided as an array.
+ *
+ * Usage:
+ *
+ * $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']);
+ *
+ * @author Fabien Potencier
+ */
+class ArrayInput extends Input
+{
+ /**
+ * @var mixed[]
+ */
+ private $parameters;
+ public function __construct(array $parameters, InputDefinition $definition = null)
+ {
+ $this->parameters = $parameters;
+ parent::__construct($definition);
+ }
+ public function getFirstArgument() : ?string
+ {
+ foreach ($this->parameters as $param => $value) {
+ if ($param && \is_string($param) && '-' === $param[0]) {
+ continue;
+ }
+ return $value;
+ }
+ return null;
+ }
+ /**
+ * @param string|mixed[] $values
+ */
+ public function hasParameterOption($values, bool $onlyParams = \false) : bool
+ {
+ $values = (array) $values;
+ foreach ($this->parameters as $k => $v) {
+ if (!\is_int($k)) {
+ $v = $k;
+ }
+ if ($onlyParams && '--' === $v) {
+ return \false;
+ }
+ if (\in_array($v, $values)) {
+ return \true;
+ }
+ }
+ return \false;
+ }
+ /**
+ * @param string|mixed[] $values
+ * @param string|bool|int|float|mixed[]|null $default
+ * @return mixed
+ */
+ public function getParameterOption($values, $default = \false, bool $onlyParams = \false)
+ {
+ $values = (array) $values;
+ foreach ($this->parameters as $k => $v) {
+ if ($onlyParams && ('--' === $k || \is_int($k) && '--' === $v)) {
+ return $default;
+ }
+ if (\is_int($k)) {
+ if (\in_array($v, $values)) {
+ return \true;
+ }
+ } elseif (\in_array($k, $values)) {
+ return $v;
+ }
+ }
+ return $default;
+ }
+ /**
+ * Returns a stringified representation of the args passed to the command.
+ */
+ public function __toString() : string
+ {
+ $params = [];
+ foreach ($this->parameters as $param => $val) {
+ if ($param && \is_string($param) && '-' === $param[0]) {
+ $glue = '-' === $param[1] ? '=' : ' ';
+ if (\is_array($val)) {
+ foreach ($val as $v) {
+ $params[] = $param . ('' != $v ? $glue . $this->escapeToken($v) : '');
+ }
+ } else {
+ $params[] = $param . ('' != $val ? $glue . $this->escapeToken($val) : '');
+ }
+ } else {
+ $params[] = \is_array($val) ? \implode(' ', \array_map(\Closure::fromCallable([$this, 'escapeToken']), $val)) : $this->escapeToken($val);
+ }
+ }
+ return \implode(' ', $params);
+ }
+ /**
+ * @return void
+ */
+ protected function parse()
+ {
+ foreach ($this->parameters as $key => $value) {
+ if ('--' === $key) {
+ return;
+ }
+ if (\strncmp($key, '--', \strlen('--')) === 0) {
+ $this->addLongOption(\substr($key, 2), $value);
+ } elseif (\strncmp($key, '-', \strlen('-')) === 0) {
+ $this->addShortOption(\substr($key, 1), $value);
+ } else {
+ $this->addArgument($key, $value);
+ }
+ }
+ }
+ /**
+ * Adds a short option value.
+ *
+ * @throws InvalidOptionException When option given doesn't exist
+ * @param mixed $value
+ */
+ private function addShortOption(string $shortcut, $value) : void
+ {
+ if (!$this->definition->hasShortcut($shortcut)) {
+ throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut));
+ }
+ $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
+ }
+ /**
+ * Adds a long option value.
+ *
+ * @throws InvalidOptionException When option given doesn't exist
+ * @throws InvalidOptionException When a required value is missing
+ * @param mixed $value
+ */
+ private function addLongOption(string $name, $value) : void
+ {
+ if (!$this->definition->hasOption($name)) {
+ if (!$this->definition->hasNegation($name)) {
+ throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name));
+ }
+ $optionName = $this->definition->negationToName($name);
+ $this->options[$optionName] = \false;
+ return;
+ }
+ $option = $this->definition->getOption($name);
+ if (null === $value) {
+ if ($option->isValueRequired()) {
+ throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name));
+ }
+ if (!$option->isValueOptional()) {
+ $value = \true;
+ }
+ }
+ $this->options[$name] = $value;
+ }
+ /**
+ * Adds an argument value.
+ *
+ * @throws InvalidArgumentException When argument given doesn't exist
+ * @param string|int $name
+ * @param mixed $value
+ */
+ private function addArgument($name, $value) : void
+ {
+ if (!$this->definition->hasArgument($name)) {
+ throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name));
+ }
+ $this->arguments[$name] = $value;
+ }
+}
diff --git a/vendor/symfony/console/Input/Input.php b/vendor/symfony/console/Input/Input.php
new file mode 100644
index 0000000000..5f96fa6770
--- /dev/null
+++ b/vendor/symfony/console/Input/Input.php
@@ -0,0 +1,174 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace EasyCI202401\Symfony\Component\Console\Input;
+
+use EasyCI202401\Symfony\Component\Console\Exception\InvalidArgumentException;
+use EasyCI202401\Symfony\Component\Console\Exception\RuntimeException;
+/**
+ * Input is the base class for all concrete Input classes.
+ *
+ * Three concrete classes are provided by default:
+ *
+ * * `ArgvInput`: The input comes from the CLI arguments (argv)
+ * * `StringInput`: The input is provided as a string
+ * * `ArrayInput`: The input is provided as an array
+ *
+ * @author Fabien Potencier