mirror of
https://gitlab.com/signalytic/client-external/streamline/streamline-emr.git
synced 2026-09-12 11:11:31 +00:00
updated streamline-setup v2
This commit is contained in:
+5
-19
@@ -31,26 +31,12 @@ class CachingIterator extends \CachingIterator implements \Countable
|
||||
private int $counter = 0;
|
||||
|
||||
|
||||
public function __construct($iterator)
|
||||
public function __construct(iterable|\stdClass $iterable)
|
||||
{
|
||||
if (is_array($iterator) || $iterator instanceof \stdClass) {
|
||||
$iterator = new \ArrayIterator($iterator);
|
||||
|
||||
} elseif ($iterator instanceof \IteratorAggregate) {
|
||||
do {
|
||||
$iterator = $iterator->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, get_debug_type($iterator)));
|
||||
}
|
||||
|
||||
parent::__construct($iterator, 0);
|
||||
$iterable = $iterable instanceof \stdClass
|
||||
? new \ArrayIterator($iterable)
|
||||
: Nette\Utils\Iterables::toIterator($iterable);
|
||||
parent::__construct($iterable, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,9 +10,8 @@ declare(strict_types=1);
|
||||
namespace Nette\Iterators;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Applies the callback to the elements of the inner iterator.
|
||||
* @deprecated use Nette\Utils\Iterables::map()
|
||||
*/
|
||||
class Mapper extends \IteratorIterator
|
||||
{
|
||||
|
||||
+59
-28
@@ -122,10 +122,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns the first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
||||
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template T
|
||||
* @param array<T> $array
|
||||
* @return ?T
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param ?callable(V, K, array<K, V>): bool $predicate
|
||||
* @return ?V
|
||||
*/
|
||||
public static function first(array $array, ?callable $predicate = null, ?callable $else = null): mixed
|
||||
{
|
||||
@@ -138,10 +139,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns the last item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
||||
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template T
|
||||
* @param array<T> $array
|
||||
* @return ?T
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param ?callable(V, K, array<K, V>): bool $predicate
|
||||
* @return ?V
|
||||
*/
|
||||
public static function last(array $array, ?callable $predicate = null, ?callable $else = null): mixed
|
||||
{
|
||||
@@ -154,7 +156,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns the key of first item (matching the specified predicate if given) or null if there is no such item.
|
||||
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param ?callable(V, K, array<K, V>): bool $predicate
|
||||
* @return ?K
|
||||
*/
|
||||
public static function firstKey(array $array, ?callable $predicate = null): int|string|null
|
||||
{
|
||||
@@ -172,7 +178,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns the key of last item (matching the specified predicate if given) or null if there is no such item.
|
||||
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param ?callable(V, K, array<K, V>): bool $predicate
|
||||
* @return ?K
|
||||
*/
|
||||
public static function lastKey(array $array, ?callable $predicate = null): int|string|null
|
||||
{
|
||||
@@ -368,12 +378,11 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether at least one element in the array passes the test implemented by the provided function,
|
||||
* which has the signature `function ($value, $key, array $array): bool`.
|
||||
* @template K
|
||||
* Tests whether at least one element in the array passes the test implemented by the provided function.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param iterable<K, V> $array
|
||||
* @param callable(V, K, ($array is array ? array<K, V> : iterable<K, V>)): bool $predicate
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): bool $predicate
|
||||
*/
|
||||
public static function some(iterable $array, callable $predicate): bool
|
||||
{
|
||||
@@ -388,12 +397,11 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
* @template K
|
||||
* Tests whether all elements in the array pass the test implemented by the provided function.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param iterable<K, V> $array
|
||||
* @param callable(V, K, ($array is array ? array<K, V> : iterable<K, V>)): bool $predicate
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): bool $predicate
|
||||
*/
|
||||
public static function every(iterable $array, callable $predicate): bool
|
||||
{
|
||||
@@ -409,11 +417,10 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns a new array containing all key-value pairs matching the given $predicate.
|
||||
* The callback has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template K of array-key
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): bool $predicate
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): bool $predicate
|
||||
* @return array<K, V>
|
||||
*/
|
||||
public static function filter(array $array, callable $predicate): array
|
||||
@@ -430,12 +437,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns an array containing the original keys and results of applying the given transform function to each element.
|
||||
* The function has signature `function ($value, $key, array $array): mixed`.
|
||||
* @template K of array-key
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @template R
|
||||
* @param iterable<K, V> $array
|
||||
* @param callable(V, K, ($array is array ? array<K, V> : iterable<K, V>)): R $transformer
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): R $transformer
|
||||
* @return array<K, R>
|
||||
*/
|
||||
public static function map(iterable $array, callable $transformer): array
|
||||
@@ -449,6 +455,31 @@ class Arrays
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array containing new keys and values generated by applying the given transform function to each element.
|
||||
* If the function returns null, the element is skipped.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @template ResK of int|string
|
||||
* @template ResV
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): ?array{ResK, ResV} $transformer
|
||||
* @return array<ResK, ResV>
|
||||
*/
|
||||
public static function mapWithKeys(array $array, callable $transformer): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($array as $k => $v) {
|
||||
$pair = $transformer($v, $k, $array);
|
||||
if ($pair) {
|
||||
$res[$pair[0]] = $pair[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invokes all callbacks and returns array of results.
|
||||
* @param callable[] $callbacks
|
||||
|
||||
@@ -94,7 +94,7 @@ final class Callback
|
||||
}
|
||||
|
||||
if (is_string($callable) && str_contains($callable, '::')) {
|
||||
return new ReflectionMethod($callable);
|
||||
return new ReflectionMethod(...explode('::', $callable, 2));
|
||||
} elseif (is_array($callable)) {
|
||||
return new ReflectionMethod($callable[0], $callable[1]);
|
||||
} elseif (is_object($callable) && !$callable instanceof \Closure) {
|
||||
|
||||
+14
-12
@@ -163,10 +163,7 @@ class Image
|
||||
*/
|
||||
public static function fromFile(string $file, ?int &$type = null): static
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
|
||||
self::ensureExtension();
|
||||
$type = self::detectTypeFromFile($file);
|
||||
if (!$type) {
|
||||
throw new UnknownImageFileException(is_file($file) ? "Unknown type of file '$file'." : "File '$file' not found.");
|
||||
@@ -183,10 +180,7 @@ class Image
|
||||
*/
|
||||
public static function fromString(string $s, ?int &$type = null): static
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
|
||||
self::ensureExtension();
|
||||
$type = self::detectTypeFromString($s);
|
||||
if (!$type) {
|
||||
throw new UnknownImageFileException('Unknown type of image.');
|
||||
@@ -221,10 +215,7 @@ class Image
|
||||
*/
|
||||
public static function fromBlank(int $width, int $height, ImageColor|array|null $color = null): static
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
|
||||
self::ensureExtension();
|
||||
if ($width < 1 || $height < 1) {
|
||||
throw new Nette\InvalidArgumentException('Image width and height must be greater than zero.');
|
||||
}
|
||||
@@ -308,6 +299,7 @@ class Image
|
||||
*/
|
||||
public static function isTypeSupported(int $type): bool
|
||||
{
|
||||
self::ensureExtension();
|
||||
return (bool) (imagetypes() & match ($type) {
|
||||
ImageType::JPEG => IMG_JPG,
|
||||
ImageType::PNG => IMG_PNG,
|
||||
@@ -323,6 +315,7 @@ class Image
|
||||
/** @return ImageType[] */
|
||||
public static function getSupportedTypes(): array
|
||||
{
|
||||
self::ensureExtension();
|
||||
$flag = imagetypes();
|
||||
return array_filter([
|
||||
$flag & IMG_GIF ? ImageType::GIF : null,
|
||||
@@ -640,6 +633,7 @@ class Image
|
||||
array $options = [],
|
||||
): array
|
||||
{
|
||||
self::ensureExtension();
|
||||
$box = imagettfbbox($size, $angle, $fontFile, $text, $options);
|
||||
return [
|
||||
'left' => $minX = min([$box[0], $box[2], $box[4], $box[6]]),
|
||||
@@ -826,4 +820,12 @@ class Image
|
||||
$color = $color instanceof ImageColor ? $color->toRGBA() : array_values($color);
|
||||
return imagecolorallocatealpha($this->image, ...$color) ?: imagecolorresolvealpha($this->image, ...$color);
|
||||
}
|
||||
|
||||
|
||||
private static function ensureExtension(): void
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,10 +49,11 @@ final class Iterables
|
||||
|
||||
/**
|
||||
* Returns the first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
||||
* The $predicate has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* @template T
|
||||
* @param iterable<T> $iterable
|
||||
* @return ?T
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param ?callable(V, K, iterable<K, V>): bool $predicate
|
||||
* @return ?V
|
||||
*/
|
||||
public static function first(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed
|
||||
{
|
||||
@@ -67,10 +68,11 @@ final class Iterables
|
||||
|
||||
/**
|
||||
* Returns the key of first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
||||
* The $predicate has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* @template T
|
||||
* @param iterable<T, mixed> $iterable
|
||||
* @return ?T
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param ?callable(V, K, iterable<K, V>): bool $predicate
|
||||
* @return ?K
|
||||
*/
|
||||
public static function firstKey(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed
|
||||
{
|
||||
@@ -84,11 +86,10 @@ final class Iterables
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether at least one element in the iterator passes the test implemented by the
|
||||
* provided callback with signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* Tests whether at least one element in the iterator passes the test implemented by the provided function.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): bool $predicate
|
||||
*/
|
||||
public static function some(iterable $iterable, callable $predicate): bool
|
||||
@@ -103,11 +104,10 @@ final class Iterables
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether all elements in the iterator pass the test implemented by the provided function,
|
||||
* which has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* Tests whether all elements in the iterator pass the test implemented by the provided function.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): bool $predicate
|
||||
*/
|
||||
public static function every(iterable $iterable, callable $predicate): bool
|
||||
@@ -123,11 +123,10 @@ final class Iterables
|
||||
|
||||
/**
|
||||
* Iterator that filters elements according to a given $predicate. Maintains original keys.
|
||||
* The callback has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): bool $predicate
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): bool $predicate
|
||||
* @return \Generator<K, V>
|
||||
*/
|
||||
public static function filter(iterable $iterable, callable $predicate): \Generator
|
||||
@@ -142,12 +141,11 @@ final class Iterables
|
||||
|
||||
/**
|
||||
* Iterator that transforms values by calling $transformer. Maintains original keys.
|
||||
* The callback has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* @template K
|
||||
* @template V
|
||||
* @template R
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): R $transformer
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): R $transformer
|
||||
* @return \Generator<K, R>
|
||||
*/
|
||||
public static function map(iterable $iterable, callable $transformer): \Generator
|
||||
@@ -156,4 +154,85 @@ final class Iterables
|
||||
yield $k => $transformer($v, $k, $iterable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iterator that transforms keys and values by calling $transformer. If it returns null, the element is skipped.
|
||||
* @template K
|
||||
* @template V
|
||||
* @template ResV
|
||||
* @template ResK
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): ?array{ResV, ResK} $transformer
|
||||
* @return \Generator<ResV, ResK>
|
||||
*/
|
||||
public static function mapWithKeys(iterable $iterable, callable $transformer): \Generator
|
||||
{
|
||||
foreach ($iterable as $k => $v) {
|
||||
$pair = $transformer($v, $k, $iterable);
|
||||
if ($pair) {
|
||||
yield $pair[0] => $pair[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wraps around iterator and caches its keys and values during iteration.
|
||||
* This allows the data to be re-iterated multiple times.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @return \IteratorAggregate<K, V>
|
||||
*/
|
||||
public static function memoize(iterable $iterable): iterable
|
||||
{
|
||||
return new class (self::toIterator($iterable)) implements \IteratorAggregate {
|
||||
public function __construct(
|
||||
private \Iterator $iterator,
|
||||
private array $cache = [],
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
public function getIterator(): \Generator
|
||||
{
|
||||
if (!$this->cache) {
|
||||
$this->iterator->rewind();
|
||||
}
|
||||
$i = 0;
|
||||
while (true) {
|
||||
if (isset($this->cache[$i])) {
|
||||
[$k, $v] = $this->cache[$i];
|
||||
} elseif ($this->iterator->valid()) {
|
||||
$k = $this->iterator->key();
|
||||
$v = $this->iterator->current();
|
||||
$this->iterator->next();
|
||||
$this->cache[$i] = [$k, $v];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
yield $k => $v;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates an iterator from anything that is iterable.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @return \Iterator<K, V>
|
||||
*/
|
||||
public static function toIterator(iterable $iterable): \Iterator
|
||||
{
|
||||
return match (true) {
|
||||
$iterable instanceof \Iterator => $iterable,
|
||||
$iterable instanceof \IteratorAggregate => self::toIterator($iterable->getIterator()),
|
||||
is_array($iterable) => new \ArrayIterator($iterable),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ final class Reflection
|
||||
|
||||
$hash = [$method->getFileName(), $method->getStartLine(), $method->getEndLine()];
|
||||
if (($alias = $decl->getTraitAliases()[$method->name] ?? null)
|
||||
&& ($m = new \ReflectionMethod($alias))
|
||||
&& ($m = new \ReflectionMethod(...explode('::', $alias, 2)))
|
||||
&& $hash === [$m->getFileName(), $m->getStartLine(), $m->getEndLine()]
|
||||
) {
|
||||
return self::getMethodDeclaringMethod($m);
|
||||
@@ -125,7 +125,7 @@ final class Reflection
|
||||
public static function areCommentsAvailable(): bool
|
||||
{
|
||||
static $res;
|
||||
return $res ?? $res = (bool) (new \ReflectionMethod(__METHOD__))->getDocComment();
|
||||
return $res ?? $res = (bool) (new \ReflectionMethod(self::class, __FUNCTION__))->getDocComment();
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,9 @@ final class Reflection
|
||||
} elseif ($ref instanceof \ReflectionMethod) {
|
||||
return $ref->getDeclaringClass()->name . '::' . $ref->name . '()';
|
||||
} elseif ($ref instanceof \ReflectionFunction) {
|
||||
return $ref->name . '()';
|
||||
return PHP_VERSION_ID >= 80200 && $ref->isAnonymous()
|
||||
? '{closure}()'
|
||||
: $ref->name . '()';
|
||||
} elseif ($ref instanceof \ReflectionProperty) {
|
||||
return self::getPropertyDeclaringClass($ref)->name . '::$' . $ref->name;
|
||||
} elseif ($ref instanceof \ReflectionParameter) {
|
||||
|
||||
@@ -589,6 +589,7 @@ class Strings
|
||||
/**
|
||||
* Searches the string for all occurrences matching the regular expression and
|
||||
* returns an array of arrays containing the found expression and each subexpression.
|
||||
* @return ($lazy is true ? \Generator<int, array> : array[])
|
||||
*/
|
||||
public static function matchAll(
|
||||
string $subject,
|
||||
@@ -599,21 +600,41 @@ class Strings
|
||||
bool $unmatchedAsNull = false,
|
||||
bool $patternOrder = false,
|
||||
bool $utf8 = false,
|
||||
): array
|
||||
bool $lazy = false,
|
||||
): array|\Generator
|
||||
{
|
||||
$flags = is_int($captureOffset) // back compatibility
|
||||
? $captureOffset
|
||||
: ($captureOffset ? PREG_OFFSET_CAPTURE : 0) | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0) | ($patternOrder ? PREG_PATTERN_ORDER : 0);
|
||||
|
||||
if ($utf8) {
|
||||
$offset = strlen(self::substring($subject, 0, $offset));
|
||||
$pattern .= 'u';
|
||||
}
|
||||
|
||||
if ($lazy) {
|
||||
$flags = PREG_OFFSET_CAPTURE | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0);
|
||||
return (function () use ($utf8, $captureOffset, $flags, $subject, $pattern, $offset) {
|
||||
$counter = 0;
|
||||
while (
|
||||
$offset <= strlen($subject) - ($counter ? 1 : 0)
|
||||
&& self::pcre('preg_match', [$pattern, $subject, &$m, $flags, $offset])
|
||||
) {
|
||||
$offset = $m[0][1] + max(1, strlen($m[0][0]));
|
||||
if (!$captureOffset) {
|
||||
$m = array_map(fn($item) => $item[0], $m);
|
||||
} elseif ($utf8) {
|
||||
$m = self::bytesToChars($subject, [$m])[0];
|
||||
}
|
||||
yield $counter++ => $m;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
if ($offset > strlen($subject)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$flags = is_int($captureOffset) // back compatibility
|
||||
? $captureOffset
|
||||
: ($captureOffset ? PREG_OFFSET_CAPTURE : 0) | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0) | ($patternOrder ? PREG_PATTERN_ORDER : 0);
|
||||
|
||||
self::pcre('preg_match_all', [
|
||||
$pattern, $subject, &$m,
|
||||
($flags & PREG_PATTERN_ORDER) ? $flags : ($flags | PREG_SET_ORDER),
|
||||
@@ -622,7 +643,6 @@ class Strings
|
||||
return $utf8 && $captureOffset
|
||||
? self::bytesToChars($subject, $m)
|
||||
: $m;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user