Current File : //proc/thread-self/root/usr/share/phpmyadmin/vendor/twig/twig/src/Extension/CoreExtension.php
<?php

/*
 * This file is part of Twig.
 *
 * (c) Fabien Potencier
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Twig\Extension {
use Twig\ExpressionParser;
use Twig\Node\Expression\Binary\AddBinary;
use Twig\Node\Expression\Binary\AndBinary;
use Twig\Node\Expression\Binary\BitwiseAndBinary;
use Twig\Node\Expression\Binary\BitwiseOrBinary;
use Twig\Node\Expression\Binary\BitwiseXorBinary;
use Twig\Node\Expression\Binary\ConcatBinary;
use Twig\Node\Expression\Binary\DivBinary;
use Twig\Node\Expression\Binary\EndsWithBinary;
use Twig\Node\Expression\Binary\EqualBinary;
use Twig\Node\Expression\Binary\FloorDivBinary;
use Twig\Node\Expression\Binary\GreaterBinary;
use Twig\Node\Expression\Binary\GreaterEqualBinary;
use Twig\Node\Expression\Binary\HasEveryBinary;
use Twig\Node\Expression\Binary\HasSomeBinary;
use Twig\Node\Expression\Binary\InBinary;
use Twig\Node\Expression\Binary\LessBinary;
use Twig\Node\Expression\Binary\LessEqualBinary;
use Twig\Node\Expression\Binary\MatchesBinary;
use Twig\Node\Expression\Binary\ModBinary;
use Twig\Node\Expression\Binary\MulBinary;
use Twig\Node\Expression\Binary\NotEqualBinary;
use Twig\Node\Expression\Binary\NotInBinary;
use Twig\Node\Expression\Binary\OrBinary;
use Twig\Node\Expression\Binary\PowerBinary;
use Twig\Node\Expression\Binary\RangeBinary;
use Twig\Node\Expression\Binary\SpaceshipBinary;
use Twig\Node\Expression\Binary\StartsWithBinary;
use Twig\Node\Expression\Binary\SubBinary;
use Twig\Node\Expression\Filter\DefaultFilter;
use Twig\Node\Expression\NullCoalesceExpression;
use Twig\Node\Expression\Test\ConstantTest;
use Twig\Node\Expression\Test\DefinedTest;
use Twig\Node\Expression\Test\DivisiblebyTest;
use Twig\Node\Expression\Test\EvenTest;
use Twig\Node\Expression\Test\NullTest;
use Twig\Node\Expression\Test\OddTest;
use Twig\Node\Expression\Test\SameasTest;
use Twig\Node\Expression\Unary\NegUnary;
use Twig\Node\Expression\Unary\NotUnary;
use Twig\Node\Expression\Unary\PosUnary;
use Twig\NodeVisitor\MacroAutoImportNodeVisitor;
use Twig\TokenParser\ApplyTokenParser;
use Twig\TokenParser\BlockTokenParser;
use Twig\TokenParser\DeprecatedTokenParser;
use Twig\TokenParser\DoTokenParser;
use Twig\TokenParser\EmbedTokenParser;
use Twig\TokenParser\ExtendsTokenParser;
use Twig\TokenParser\FlushTokenParser;
use Twig\TokenParser\ForTokenParser;
use Twig\TokenParser\FromTokenParser;
use Twig\TokenParser\IfTokenParser;
use Twig\TokenParser\ImportTokenParser;
use Twig\TokenParser\IncludeTokenParser;
use Twig\TokenParser\MacroTokenParser;
use Twig\TokenParser\SetTokenParser;
use Twig\TokenParser\UseTokenParser;
use Twig\TokenParser\WithTokenParser;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;

final class CoreExtension extends AbstractExtension
{
    private $dateFormats = ['F j, Y H:i', '%d days'];
    private $numberFormat = [0, '.', ','];
    private $timezone = null;

    /**
     * Sets the default format to be used by the date filter.
     *
     * @param string $format             The default date format string
     * @param string $dateIntervalFormat The default date interval format string
     */
    public function setDateFormat($format = null, $dateIntervalFormat = null)
    {
        if (null !== $format) {
            $this->dateFormats[0] = $format;
        }

        if (null !== $dateIntervalFormat) {
            $this->dateFormats[1] = $dateIntervalFormat;
        }
    }

    /**
     * Gets the default format to be used by the date filter.
     *
     * @return array The default date format string and the default date interval format string
     */
    public function getDateFormat()
    {
        return $this->dateFormats;
    }

    /**
     * Sets the default timezone to be used by the date filter.
     *
     * @param \DateTimeZone|string $timezone The default timezone string or a \DateTimeZone object
     */
    public function setTimezone($timezone)
    {
        $this->timezone = $timezone instanceof \DateTimeZone ? $timezone : new \DateTimeZone($timezone);
    }

    /**
     * Gets the default timezone to be used by the date filter.
     *
     * @return \DateTimeZone The default timezone currently in use
     */
    public function getTimezone()
    {
        if (null === $this->timezone) {
            $this->timezone = new \DateTimeZone(date_default_timezone_get());
        }

        return $this->timezone;
    }

    /**
     * Sets the default format to be used by the number_format filter.
     *
     * @param int    $decimal      the number of decimal places to use
     * @param string $decimalPoint the character(s) to use for the decimal point
     * @param string $thousandSep  the character(s) to use for the thousands separator
     */
    public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
    {
        $this->numberFormat = [$decimal, $decimalPoint, $thousandSep];
    }

    /**
     * Get the default format used by the number_format filter.
     *
     * @return array The arguments for number_format()
     */
    public function getNumberFormat()
    {
        return $this->numberFormat;
    }

    public function getTokenParsers(): array
    {
        return [
            new ApplyTokenParser(),
            new ForTokenParser(),
            new IfTokenParser(),
            new ExtendsTokenParser(),
            new IncludeTokenParser(),
            new BlockTokenParser(),
            new UseTokenParser(),
            new MacroTokenParser(),
            new ImportTokenParser(),
            new FromTokenParser(),
            new SetTokenParser(),
            new FlushTokenParser(),
            new DoTokenParser(),
            new EmbedTokenParser(),
            new WithTokenParser(),
            new DeprecatedTokenParser(),
        ];
    }

    public function getFilters(): array
    {
        return [
            // formatting filters
            new TwigFilter('date', 'twig_date_format_filter', ['needs_environment' => true]),
            new TwigFilter('date_modify', 'twig_date_modify_filter', ['needs_environment' => true]),
            new TwigFilter('format', 'twig_sprintf'),
            new TwigFilter('replace', 'twig_replace_filter'),
            new TwigFilter('number_format', 'twig_number_format_filter', ['needs_environment' => true]),
            new TwigFilter('abs', 'abs'),
            new TwigFilter('round', 'twig_round'),

            // encoding
            new TwigFilter('url_encode', 'twig_urlencode_filter'),
            new TwigFilter('json_encode', 'json_encode'),
            new TwigFilter('convert_encoding', 'twig_convert_encoding'),

            // string filters
            new TwigFilter('title', 'twig_title_string_filter', ['needs_environment' => true]),
            new TwigFilter('capitalize', 'twig_capitalize_string_filter', ['needs_environment' => true]),
            new TwigFilter('upper', 'twig_upper_filter', ['needs_environment' => true]),
            new TwigFilter('lower', 'twig_lower_filter', ['needs_environment' => true]),
            new TwigFilter('striptags', 'twig_striptags'),
            new TwigFilter('trim', 'twig_trim_filter'),
            new TwigFilter('nl2br', 'twig_nl2br', ['pre_escape' => 'html', 'is_safe' => ['html']]),
            new TwigFilter('spaceless', 'twig_spaceless', ['is_safe' => ['html']]),

            // array helpers
            new TwigFilter('join', 'twig_join_filter'),
            new TwigFilter('split', 'twig_split_filter', ['needs_environment' => true]),
            new TwigFilter('sort', 'twig_sort_filter', ['needs_environment' => true]),
            new TwigFilter('merge', 'twig_array_merge'),
            new TwigFilter('batch', 'twig_array_batch'),
            new TwigFilter('column', 'twig_array_column'),
            new TwigFilter('filter', 'twig_array_filter', ['needs_environment' => true]),
            new TwigFilter('map', 'twig_array_map', ['needs_environment' => true]),
            new TwigFilter('reduce', 'twig_array_reduce', ['needs_environment' => true]),

            // string/array filters
            new TwigFilter('reverse', 'twig_reverse_filter', ['needs_environment' => true]),
            new TwigFilter('length', 'twig_length_filter', ['needs_environment' => true]),
            new TwigFilter('slice', 'twig_slice', ['needs_environment' => true]),
            new TwigFilter('first', 'twig_first', ['needs_environment' => true]),
            new TwigFilter('last', 'twig_last', ['needs_environment' => true]),

            // iteration and runtime
            new TwigFilter('default', '_twig_default_filter', ['node_class' => DefaultFilter::class]),
            new TwigFilter('keys', 'twig_get_array_keys_filter'),
        ];
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('max', 'max'),
            new TwigFunction('min', 'min'),
            new TwigFunction('range', 'range'),
            new TwigFunction('constant', 'twig_constant'),
            new TwigFunction('cycle', 'twig_cycle'),
            new TwigFunction('random', 'twig_random', ['needs_environment' => true]),
            new TwigFunction('date', 'twig_date_converter', ['needs_environment' => true]),
            new TwigFunction('include', 'twig_include', ['needs_environment' => true, 'needs_context' => true, 'is_safe' => ['all']]),
            new TwigFunction('source', 'twig_source', ['needs_environment' => true, 'is_safe' => ['all']]),
        ];
    }

    public function getTests(): array
    {
        return [
            new TwigTest('even', null, ['node_class' => EvenTest::class]),
            new TwigTest('odd', null, ['node_class' => OddTest::class]),
            new TwigTest('defined', null, ['node_class' => DefinedTest::class]),
            new TwigTest('same as', null, ['node_class' => SameasTest::class, 'one_mandatory_argument' => true]),
            new TwigTest('none', null, ['node_class' => NullTest::class]),
            new TwigTest('null', null, ['node_class' => NullTest::class]),
            new TwigTest('divisible by', null, ['node_class' => DivisiblebyTest::class, 'one_mandatory_argument' => true]),
            new TwigTest('constant', null, ['node_class' => ConstantTest::class]),
            new TwigTest('empty', 'twig_test_empty'),
            new TwigTest('iterable', 'twig_test_iterable'),
        ];
    }

    public function getNodeVisitors(): array
    {
        return [new MacroAutoImportNodeVisitor()];
    }

    public function getOperators(): array
    {
        return [
            [
                'not' => ['precedence' => 50, 'class' => NotUnary::class],
                '-' => ['precedence' => 500, 'class' => NegUnary::class],
                '+' => ['precedence' => 500, 'class' => PosUnary::class],
            ],
            [
                'or' => ['precedence' => 10, 'class' => OrBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'and' => ['precedence' => 15, 'class' => AndBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'b-or' => ['precedence' => 16, 'class' => BitwiseOrBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'b-xor' => ['precedence' => 17, 'class' => BitwiseXorBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'b-and' => ['precedence' => 18, 'class' => BitwiseAndBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '==' => ['precedence' => 20, 'class' => EqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '!=' => ['precedence' => 20, 'class' => NotEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '<=>' => ['precedence' => 20, 'class' => SpaceshipBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '<' => ['precedence' => 20, 'class' => LessBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '>' => ['precedence' => 20, 'class' => GreaterBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '>=' => ['precedence' => 20, 'class' => GreaterEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '<=' => ['precedence' => 20, 'class' => LessEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'not in' => ['precedence' => 20, 'class' => NotInBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'in' => ['precedence' => 20, 'class' => InBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'matches' => ['precedence' => 20, 'class' => MatchesBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'starts with' => ['precedence' => 20, 'class' => StartsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'ends with' => ['precedence' => 20, 'class' => EndsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'has some' => ['precedence' => 20, 'class' => HasSomeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'has every' => ['precedence' => 20, 'class' => HasEveryBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '..' => ['precedence' => 25, 'class' => RangeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '+' => ['precedence' => 30, 'class' => AddBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '-' => ['precedence' => 30, 'class' => SubBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '~' => ['precedence' => 40, 'class' => ConcatBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '*' => ['precedence' => 60, 'class' => MulBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '/' => ['precedence' => 60, 'class' => DivBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '//' => ['precedence' => 60, 'class' => FloorDivBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '%' => ['precedence' => 60, 'class' => ModBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'is' => ['precedence' => 100, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                'is not' => ['precedence' => 100, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                '**' => ['precedence' => 200, 'class' => PowerBinary::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT],
                '??' => ['precedence' => 300, 'class' => NullCoalesceExpression::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT],
            ],
        ];
    }
}
}

namespace {
    use Twig\Environment;
    use Twig\Error\LoaderError;
    use Twig\Error\RuntimeError;
    use Twig\Extension\CoreExtension;
    use Twig\Extension\SandboxExtension;
    use Twig\Markup;
    use Twig\Source;
    use Twig\Template;
    use Twig\TemplateWrapper;

/**
 * Cycles over a value.
 *
 * @param \ArrayAccess|array $values
 * @param int                $position The cycle position
 *
 * @return string The next value in the cycle
 */
function twig_cycle($values, $position)
{
    if (!\is_array($values) && !$values instanceof \ArrayAccess) {
        return $values;
    }

    return $values[$position % \count($values)];
}

/**
 * Returns a random value depending on the supplied parameter type:
 * - a random item from a \Traversable or array
 * - a random character from a string
 * - a random integer between 0 and the integer parameter.
 *
 * @param \Traversable|array|int|float|string $values The values to pick a random item from
 * @param int|null                            $max    Maximum value used when $values is an int
 *
 * @throws RuntimeError when $values is an empty array (does not apply to an empty string which is returned as is)
 *
 * @return mixed A random value from the given sequence
 */
function twig_random(Environment $env, $values = null, $max = null)
{
    if (null === $values) {
        return null === $max ? mt_rand() : mt_rand(0, (int) $max);
    }

    if (\is_int($values) || \is_float($values)) {
        if (null === $max) {
            if ($values < 0) {
                $max = 0;
                $min = $values;
            } else {
                $max = $values;
                $min = 0;
            }
        } else {
            $min = $values;
            $max = $max;
        }

        return mt_rand((int) $min, (int) $max);
    }

    if (\is_string($values)) {
        if ('' === $values) {
            return '';
        }

        $charset = $env->getCharset();

        if ('UTF-8' !== $charset) {
            $values = twig_convert_encoding($values, 'UTF-8', $charset);
        }

        // unicode version of str_split()
        // split at all positions, but not after the start and not before the end
        $values = preg_split('/(?<!^)(?!$)/u', $values);

        if ('UTF-8' !== $charset) {
            foreach ($values as $i => $value) {
                $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
            }
        }
    }

    if (!twig_test_iterable($values)) {
        return $values;
    }

    $values = twig_to_array($values);

    if (0 === \count($values)) {
        throw new RuntimeError('The random function cannot pick from an empty array.');
    }

    return $values[array_rand($values, 1)];
}

/**
 * Converts a date to the given format.
 *
 *   {{ post.published_at|date("m/d/Y") }}
 *
 * @param \DateTimeInterface|\DateInterval|string $date     A date
 * @param string|null                             $format   The target format, null to use the default
 * @param \DateTimeZone|string|false|null         $timezone The target timezone, null to use the default, false to leave unchanged
 *
 * @return string The formatted date
 */
function twig_date_format_filter(Environment $env, $date, $format = null, $timezone = null)
{
    if (null === $format) {
        $formats = $env->getExtension(CoreExtension::class)->getDateFormat();
        $format = $date instanceof \DateInterval ? $formats[1] : $formats[0];
    }

    if ($date instanceof \DateInterval) {
        return $date->format($format);
    }

    return twig_date_converter($env, $date, $timezone)->format($format);
}

/**
 * Returns a new date object modified.
 *
 *   {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
 *
 * @param \DateTimeInterface|string $date     A date
 * @param string                    $modifier A modifier string
 *
 * @return \DateTimeInterface
 */
function twig_date_modify_filter(Environment $env, $date, $modifier)
{
    $date = twig_date_converter($env, $date, false);

    return $date->modify($modifier);
}

/**
 * Returns a formatted string.
 *
 * @param string|null $format
 * @param ...$values
 *
 * @return string
 */
function twig_sprintf($format, ...$values)
{
    return sprintf($format ?? '', ...$values);
}

/**
 * Converts an input to a \DateTime instance.
 *
 *    {% if date(user.created_at) < date('+2days') %}
 *      {# do something #}
 *    {% endif %}
 *
 * @param \DateTimeInterface|string|null  $date     A date or null to use the current time
 * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
 *
 * @return \DateTimeInterface
 */
function twig_date_converter(Environment $env, $date = null, $timezone = null)
{
    // determine the timezone
    if (false !== $timezone) {
        if (null === $timezone) {
            $timezone = $env->getExtension(CoreExtension::class)->getTimezone();
        } elseif (!$timezone instanceof \DateTimeZone) {
            $timezone = new \DateTimeZone($timezone);
        }
    }

    // immutable dates
    if ($date instanceof \DateTimeImmutable) {
        return false !== $timezone ? $date->setTimezone($timezone) : $date;
    }

    if ($date instanceof \DateTimeInterface) {
        $date = clone $date;
        if (false !== $timezone) {
            $date->setTimezone($timezone);
        }

        return $date;
    }

    if (null === $date || 'now' === $date) {
        if (null === $date) {
            $date = 'now';
        }

        return new \DateTime($date, false !== $timezone ? $timezone : $env->getExtension(CoreExtension::class)->getTimezone());
    }

    $asString = (string) $date;
    if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
        $date = new \DateTime('@'.$date);
    } else {
        $date = new \DateTime($date, $env->getExtension(CoreExtension::class)->getTimezone());
    }

    if (false !== $timezone) {
        $date->setTimezone($timezone);
    }

    return $date;
}

/**
 * Replaces strings within a string.
 *
 * @param string|null        $str  String to replace in
 * @param array|\Traversable $from Replace values
 *
 * @return string
 */
function twig_replace_filter($str, $from)
{
    if (!twig_test_iterable($from)) {
        throw new RuntimeError(sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from)));
    }

    return strtr($str ?? '', twig_to_array($from));
}

/**
 * Rounds a number.
 *
 * @param int|float|string|null $value     The value to round
 * @param int|float             $precision The rounding precision
 * @param string                $method    The method to use for rounding
 *
 * @return int|float The rounded number
 */
function twig_round($value, $precision = 0, $method = 'common')
{
    $value = (float) $value;

    if ('common' === $method) {
        return round($value, $precision);
    }

    if ('ceil' !== $method && 'floor' !== $method) {
        throw new RuntimeError('The round filter only supports the "common", "ceil", and "floor" methods.');
    }

    return $method($value * 10 ** $precision) / 10 ** $precision;
}

/**
 * Number format filter.
 *
 * All of the formatting options can be left null, in that case the defaults will
 * be used. Supplying any of the parameters will override the defaults set in the
 * environment object.
 *
 * @param mixed  $number       A float/int/string of the number to format
 * @param int    $decimal      the number of decimal points to display
 * @param string $decimalPoint the character(s) to use for the decimal point
 * @param string $thousandSep  the character(s) to use for the thousands separator
 *
 * @return string The formatted number
 */
function twig_number_format_filter(Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
{
    $defaults = $env->getExtension(CoreExtension::class)->getNumberFormat();
    if (null === $decimal) {
        $decimal = $defaults[0];
    }

    if (null === $decimalPoint) {
        $decimalPoint = $defaults[1];
    }

    if (null === $thousandSep) {
        $thousandSep = $defaults[2];
    }

    return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
}

/**
 * URL encodes (RFC 3986) a string as a path segment or an array as a query string.
 *
 * @param string|array|null $url A URL or an array of query parameters
 *
 * @return string The URL encoded value
 */
function twig_urlencode_filter($url)
{
    if (\is_array($url)) {
        return http_build_query($url, '', '&', \PHP_QUERY_RFC3986);
    }

    return rawurlencode($url ?? '');
}

/**
 * Merges an array with another one.
 *
 *  {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
 *
 *  {% set items = items|merge({ 'peugeot': 'car' }) %}
 *
 *  {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
 *
 * @param array|\Traversable $arr1 An array
 * @param array|\Traversable $arr2 An array
 *
 * @return array The merged array
 */
function twig_array_merge($arr1, $arr2)
{
    if (!twig_test_iterable($arr1)) {
        throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($arr1)));
    }

    if (!twig_test_iterable($arr2)) {
        throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as second argument.', \gettype($arr2)));
    }

    return array_merge(twig_to_array($arr1), twig_to_array($arr2));
}

/**
 * Slices a variable.
 *
 * @param mixed $item         A variable
 * @param int   $start        Start of the slice
 * @param int   $length       Size of the slice
 * @param bool  $preserveKeys Whether to preserve key or not (when the input is an array)
 *
 * @return mixed The sliced variable
 */
function twig_slice(Environment $env, $item, $start, $length = null, $preserveKeys = false)
{
    if ($item instanceof \Traversable) {
        while ($item instanceof \IteratorAggregate) {
            $item = $item->getIterator();
        }

        if ($start >= 0 && $length >= 0 && $item instanceof \Iterator) {
            try {
                return iterator_to_array(new \LimitIterator($item, $start, null === $length ? -1 : $length), $preserveKeys);
            } catch (\OutOfBoundsException $e) {
                return [];
            }
        }

        $item = iterator_to_array($item, $preserveKeys);
    }

    if (\is_array($item)) {
        return \array_slice($item, $start, $length, $preserveKeys);
    }

    return (string) mb_substr((string) $item, $start, $length, $env->getCharset());
}

/**
 * Returns the first element of the item.
 *
 * @param mixed $item A variable
 *
 * @return mixed The first element of the item
 */
function twig_first(Environment $env, $item)
{
    $elements = twig_slice($env, $item, 0, 1, false);

    return \is_string($elements) ? $elements : current($elements);
}

/**
 * Returns the last element of the item.
 *
 * @param mixed $item A variable
 *
 * @return mixed The last element of the item
 */
function twig_last(Environment $env, $item)
{
    $elements = twig_slice($env, $item, -1, 1, false);

    return \is_string($elements) ? $elements : current($elements);
}

/**
 * Joins the values to a string.
 *
 * The separators between elements are empty strings per default, you can define them with the optional parameters.
 *
 *  {{ [1, 2, 3]|join(', ', ' and ') }}
 *  {# returns 1, 2 and 3 #}
 *
 *  {{ [1, 2, 3]|join('|') }}
 *  {# returns 1|2|3 #}
 *
 *  {{ [1, 2, 3]|join }}
 *  {# returns 123 #}
 *
 * @param array       $value An array
 * @param string      $glue  The separator
 * @param string|null $and   The separator for the last pair
 *
 * @return string The concatenated string
 */
function twig_join_filter($value, $glue = '', $and = null)
{
    if (!twig_test_iterable($value)) {
        $value = (array) $value;
    }

    $value = twig_to_array($value, false);

    if (0 === \count($value)) {
        return '';
    }

    if (null === $and || $and === $glue) {
        return implode($glue, $value);
    }

    if (1 === \count($value)) {
        return $value[0];
    }

    return implode($glue, \array_slice($value, 0, -1)).$and.$value[\count($value) - 1];
}

/**
 * Splits the string into an array.
 *
 *  {{ "one,two,three"|split(',') }}
 *  {# returns [one, two, three] #}
 *
 *  {{ "one,two,three,four,five"|split(',', 3) }}
 *  {# returns [one, two, "three,four,five"] #}
 *
 *  {{ "123"|split('') }}
 *  {# returns [1, 2, 3] #}
 *
 *  {{ "aabbcc"|split('', 2) }}
 *  {# returns [aa, bb, cc] #}
 *
 * @param string|null $value     A string
 * @param string      $delimiter The delimiter
 * @param int         $limit     The limit
 *
 * @return array The split string as an array
 */
function twig_split_filter(Environment $env, $value, $delimiter, $limit = null)
{
    $value = $value ?? '';

    if (\strlen($delimiter) > 0) {
        return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
    }

    if ($limit <= 1) {
        return preg_split('/(?<!^)(?!$)/u', $value);
    }

    $length = mb_strlen($value, $env->getCharset());
    if ($length < $limit) {
        return [$value];
    }

    $r = [];
    for ($i = 0; $i < $length; $i += $limit) {
        $r[] = mb_substr($value, $i, $limit, $env->getCharset());
    }

    return $r;
}

// The '_default' filter is used internally to avoid using the ternary operator
// which costs a lot for big contexts (before PHP 5.4). So, on average,
// a function call is cheaper.
/**
 * @internal
 */
function _twig_default_filter($value, $default = '')
{
    if (twig_test_empty($value)) {
        return $default;
    }

    return $value;
}

/**
 * Returns the keys for the given array.
 *
 * It is useful when you want to iterate over the keys of an array:
 *
 *  {% for key in array|keys %}
 *      {# ... #}
 *  {% endfor %}
 *
 * @param array $array An array
 *
 * @return array The keys
 */
function twig_get_array_keys_filter($array)
{
    if ($array instanceof \Traversable) {
        while ($array instanceof \IteratorAggregate) {
            $array = $array->getIterator();
        }

        $keys = [];
        if ($array instanceof \Iterator) {
            $array->rewind();
            while ($array->valid()) {
                $keys[] = $array->key();
                $array->next();
            }

            return $keys;
        }

        foreach ($array as $key => $item) {
            $keys[] = $key;
        }

        return $keys;
    }

    if (!\is_array($array)) {
        return [];
    }

    return array_keys($array);
}

/**
 * Reverses a variable.
 *
 * @param array|\Traversable|string|null $item         An array, a \Traversable instance, or a string
 * @param bool                           $preserveKeys Whether to preserve key or not
 *
 * @return mixed The reversed input
 */
function twig_reverse_filter(Environment $env, $item, $preserveKeys = false)
{
    if ($item instanceof \Traversable) {
        return array_reverse(iterator_to_array($item), $preserveKeys);
    }

    if (\is_array($item)) {
        return array_reverse($item, $preserveKeys);
    }

    $string = (string) $item;

    $charset = $env->getCharset();

    if ('UTF-8' !== $charset) {
        $string = twig_convert_encoding($string, 'UTF-8', $charset);
    }

    preg_match_all('/./us', $string, $matches);

    $string = implode('', array_reverse($matches[0]));

    if ('UTF-8' !== $charset) {
        $string = twig_convert_encoding($string, $charset, 'UTF-8');
    }

    return $string;
}

/**
 * Sorts an array.
 *
 * @param array|\Traversable $array
 *
 * @return array
 */
function twig_sort_filter(Environment $env, $array, $arrow = null)
{
    if ($array instanceof \Traversable) {
        $array = iterator_to_array($array);
    } elseif (!\is_array($array)) {
        throw new RuntimeError(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', \gettype($array)));
    }

    if (null !== $arrow) {
        twig_check_arrow_in_sandbox($env, $arrow, 'sort', 'filter');

        uasort($array, $arrow);
    } else {
        asort($array);
    }

    return $array;
}

/**
 * @internal
 */
function twig_in_filter($value, $compare)
{
    if ($value instanceof Markup) {
        $value = (string) $value;
    }
    if ($compare instanceof Markup) {
        $compare = (string) $compare;
    }

    if (\is_string($compare)) {
        if (\is_string($value) || \is_int($value) || \is_float($value)) {
            return '' === $value || false !== strpos($compare, (string) $value);
        }

        return false;
    }

    if (!is_iterable($compare)) {
        return false;
    }

    if (\is_object($value) || \is_resource($value)) {
        if (!\is_array($compare)) {
            foreach ($compare as $item) {
                if ($item === $value) {
                    return true;
                }
            }

            return false;
        }

        return \in_array($value, $compare, true);
    }

    foreach ($compare as $item) {
        if (0 === twig_compare($value, $item)) {
            return true;
        }
    }

    return false;
}

/**
 * Compares two values using a more strict version of the PHP non-strict comparison operator.
 *
 * @see https://wiki.php.net/rfc/string_to_number_comparison
 * @see https://wiki.php.net/rfc/trailing_whitespace_numerics
 *
 * @internal
 */
function twig_compare($a, $b)
{
    // int <=> string
    if (\is_int($a) && \is_string($b)) {
        $bTrim = trim($b, " \t\n\r\v\f");
        if (!is_numeric($bTrim)) {
            return (string) $a <=> $b;
        }
        if ((int) $bTrim == $bTrim) {
            return $a <=> (int) $bTrim;
        } else {
            return (float) $a <=> (float) $bTrim;
        }
    }
    if (\is_string($a) && \is_int($b)) {
        $aTrim = trim($a, " \t\n\r\v\f");
        if (!is_numeric($aTrim)) {
            return $a <=> (string) $b;
        }
        if ((int) $aTrim == $aTrim) {
            return (int) $aTrim <=> $b;
        } else {
            return (float) $aTrim <=> (float) $b;
        }
    }

    // float <=> string
    if (\is_float($a) && \is_string($b)) {
        if (is_nan($a)) {
            return 1;
        }
        $bTrim = trim($b, " \t\n\r\v\f");
        if (!is_numeric($bTrim)) {
            return (string) $a <=> $b;
        }

        return $a <=> (float) $bTrim;
    }
    if (\is_string($a) && \is_float($b)) {
        if (is_nan($b)) {
            return 1;
        }
        $aTrim = trim($a, " \t\n\r\v\f");
        if (!is_numeric($aTrim)) {
            return $a <=> (string) $b;
        }

        return (float) $aTrim <=> $b;
    }

    // fallback to <=>
    return $a <=> $b;
}

/**
 * @param string $pattern
 * @param string $subject
 *
 * @return int
 *
 * @throws RuntimeError When an invalid pattern is used
 */
function twig_matches(string $regexp, string $str)
{
    set_error_handler(function ($t, $m) use ($regexp) {
        throw new RuntimeError(sprintf('Regexp "%s" passed to "matches" is not valid', $regexp).substr($m, 12));
    });
    try {
        return preg_match($regexp, $str);
    } finally {
        restore_error_handler();
    }
}

/**
 * Returns a trimmed string.
 *
 * @param string|null $string
 * @param string|null $characterMask
 * @param string      $side
 *
 * @return string
 *
 * @throws RuntimeError When an invalid trimming side is used (not a string or not 'left', 'right', or 'both')
 */
function twig_trim_filter($string, $characterMask = null, $side = 'both')
{
    if (null === $characterMask) {
        $characterMask = " \t\n\r\0\x0B";
    }

    switch ($side) {
        case 'both':
            return trim($string ?? '', $characterMask);
        case 'left':
            return ltrim($string ?? '', $characterMask);
        case 'right':
            return rtrim($string ?? '', $characterMask);
        default:
            throw new RuntimeError('Trimming side must be "left", "right" or "both".');
    }
}

/**
 * Inserts HTML line breaks before all newlines in a string.
 *
 * @param string|null $string
 *
 * @return string
 */
function twig_nl2br($string)
{
    return nl2br($string ?? '');
}

/**
 * Removes whitespaces between HTML tags.
 *
 * @param string|null $string
 *
 * @return string
 */
function twig_spaceless($content)
{
    return trim(preg_replace('/>\s+</', '><', $content ?? ''));
}

/**
 * @param string|null $string
 * @param string      $to
 * @param string      $from
 *
 * @return string
 */
function twig_convert_encoding($string, $to, $from)
{
    if (!\function_exists('iconv')) {
        throw new RuntimeError('Unable to convert encoding: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
    }

    return iconv($from, $to, $string ?? '');
}

/**
 * Returns the length of a variable.
 *
 * @param mixed $thing A variable
 *
 * @return int The length of the value
 */
function twig_length_filter(Environment $env, $thing)
{
    if (null === $thing) {
        return 0;
    }

    if (is_scalar($thing)) {
        return mb_strlen($thing, $env->getCharset());
    }

    if ($thing instanceof \Countable || \is_array($thing) || $thing instanceof \SimpleXMLElement) {
        return \count($thing);
    }

    if ($thing instanceof \Traversable) {
        return iterator_count($thing);
    }

    if (method_exists($thing, '__toString') && !$thing instanceof \Countable) {
        return mb_strlen((string) $thing, $env->getCharset());
    }

    return 1;
}

/**
 * Converts a string to uppercase.
 *
 * @param string|null $string A string
 *
 * @return string The uppercased string
 */
function twig_upper_filter(Environment $env, $string)
{
    return mb_strtoupper($string ?? '', $env->getCharset());
}

/**
 * Converts a string to lowercase.
 *
 * @param string|null $string A string
 *
 * @return string The lowercased string
 */
function twig_lower_filter(Environment $env, $string)
{
    return mb_strtolower($string ?? '', $env->getCharset());
}

/**
 * Strips HTML and PHP tags from a string.
 *
 * @param string|null $string
 * @param string[]|string|null $string
 *
 * @return string
 */
function twig_striptags($string, $allowable_tags = null)
{
    return strip_tags($string ?? '', $allowable_tags);
}

/**
 * Returns a titlecased string.
 *
 * @param string|null $string A string
 *
 * @return string The titlecased string
 */
function twig_title_string_filter(Environment $env, $string)
{
    if (null !== $charset = $env->getCharset()) {
        return mb_convert_case($string ?? '', \MB_CASE_TITLE, $charset);
    }

    return ucwords(strtolower($string ?? ''));
}

/**
 * Returns a capitalized string.
 *
 * @param string|null $string A string
 *
 * @return string The capitalized string
 */
function twig_capitalize_string_filter(Environment $env, $string)
{
    $charset = $env->getCharset();

    return mb_strtoupper(mb_substr($string ?? '', 0, 1, $charset), $charset).mb_strtolower(mb_substr($string ?? '', 1, null, $charset), $charset);
}

/**
 * @internal
 */
function twig_call_macro(Template $template, string $method, array $args, int $lineno, array $context, Source $source)
{
    if (!method_exists($template, $method)) {
        $parent = $template;
        while ($parent = $parent->getParent($context)) {
            if (method_exists($parent, $method)) {
                return $parent->$method(...$args);
            }
        }

        throw new RuntimeError(sprintf('Macro "%s" is not defined in template "%s".', substr($method, \strlen('macro_')), $template->getTemplateName()), $lineno, $source);
    }

    return $template->$method(...$args);
}

/**
 * @internal
 */
function twig_ensure_traversable($seq)
{
    if ($seq instanceof \Traversable || \is_array($seq)) {
        return $seq;
    }

    return [];
}

/**
 * @internal
 */
function twig_to_array($seq, $preserveKeys = true)
{
    if ($seq instanceof \Traversable) {
        return iterator_to_array($seq, $preserveKeys);
    }

    if (!\is_array($seq)) {
        return $seq;
    }

    return $preserveKeys ? $seq : array_values($seq);
}

/**
 * Checks if a variable is empty.
 *
 *    {# evaluates to true if the foo variable is null, false, or the empty string #}
 *    {% if foo is empty %}
 *        {# ... #}
 *    {% endif %}
 *
 * @param mixed $value A variable
 *
 * @return bool true if the value is empty, false otherwise
 */
function twig_test_empty($value)
{
    if ($value instanceof \Countable) {
        return 0 === \count($value);
    }

    if ($value instanceof \Traversable) {
        return !iterator_count($value);
    }

    if (\is_object($value) && method_exists($value, '__toString')) {
        return '' === (string) $value;
    }

    return '' === $value || false === $value || null === $value || [] === $value;
}

/**
 * Checks if a variable is traversable.
 *
 *    {# evaluates to true if the foo variable is an array or a traversable object #}
 *    {% if foo is iterable %}
 *        {# ... #}
 *    {% endif %}
 *
 * @param mixed $value A variable
 *
 * @return bool true if the value is traversable
 */
function twig_test_iterable($value)
{
    return $value instanceof \Traversable || \is_array($value);
}

/**
 * Renders a template.
 *
 * @param array        $context
 * @param string|array $template      The template to render or an array of templates to try consecutively
 * @param array        $variables     The variables to pass to the template
 * @param bool         $withContext
 * @param bool         $ignoreMissing Whether to ignore missing templates or not
 * @param bool         $sandboxed     Whether to sandbox the template or not
 *
 * @return string The rendered template
 */
function twig_include(Environment $env, $context, $template, $variables = [], $withContext = true, $ignoreMissing = false, $sandboxed = false)
{
    $alreadySandboxed = false;
    $sandbox = null;
    if ($withContext) {
        $variables = array_merge($context, $variables);
    }

    if ($isSandboxed = $sandboxed && $env->hasExtension(SandboxExtension::class)) {
        $sandbox = $env->getExtension(SandboxExtension::class);
        if (!$alreadySandboxed = $sandbox->isSandboxed()) {
            $sandbox->enableSandbox();
        }

        foreach ((\is_array($template) ? $template : [$template]) as $name) {
            // if a Template instance is passed, it might have been instantiated outside of a sandbox, check security
            if ($name instanceof TemplateWrapper || $name instanceof Template) {
                $name->unwrap()->checkSecurity();
            }
        }
    }

    try {
        $loaded = null;
        try {
            $loaded = $env->resolveTemplate($template);
        } catch (LoaderError $e) {
            if (!$ignoreMissing) {
                throw $e;
            }
        }

        return $loaded ? $loaded->render($variables) : '';
    } finally {
        if ($isSandboxed && !$alreadySandboxed) {
            $sandbox->disableSandbox();
        }
    }
}

/**
 * Returns a template content without rendering it.
 *
 * @param string $name          The template name
 * @param bool   $ignoreMissing Whether to ignore missing templates or not
 *
 * @return string The template source
 */
function twig_source(Environment $env, $name, $ignoreMissing = false)
{
    $loader = $env->getLoader();
    try {
        return $loader->getSourceContext($name)->getCode();
    } catch (LoaderError $e) {
        if (!$ignoreMissing) {
            throw $e;
        }
    }
}

/**
 * Provides the ability to get constants from instances as well as class/global constants.
 *
 * @param string      $constant The name of the constant
 * @param object|null $object   The object to get the constant from
 *
 * @return string
 */
function twig_constant($constant, $object = null)
{
    if (null !== $object) {
        if ('class' === $constant) {
            return \get_class($object);
        }

        $constant = \get_class($object).'::'.$constant;
    }

    if (!\defined($constant)) {
        throw new RuntimeError(sprintf('Constant "%s" is undefined.', $constant));
    }

    return \constant($constant);
}

/**
 * Checks if a constant exists.
 *
 * @param string      $constant The name of the constant
 * @param object|null $object   The object to get the constant from
 *
 * @return bool
 */
function twig_constant_is_defined($constant, $object = null)
{
    if (null !== $object) {
        if ('class' === $constant) {
            return true;
        }

        $constant = \get_class($object).'::'.$constant;
    }

    return \defined($constant);
}

/**
 * Batches item.
 *
 * @param array $items An array of items
 * @param int   $size  The size of the batch
 * @param mixed $fill  A value used to fill missing items
 *
 * @return array
 */
function twig_array_batch($items, $size, $fill = null, $preserveKeys = true)
{
    if (!twig_test_iterable($items)) {
        throw new RuntimeError(sprintf('The "batch" filter expects an array or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items)));
    }

    $size = ceil($size);

    $result = array_chunk(twig_to_array($items, $preserveKeys), $size, $preserveKeys);

    if (null !== $fill && $result) {
        $last = \count($result) - 1;
        if ($fillCount = $size - \count($result[$last])) {
            for ($i = 0; $i < $fillCount; ++$i) {
                $result[$last][] = $fill;
            }
        }
    }

    return $result;
}

/**
 * Returns the attribute value for a given array/object.
 *
 * @param mixed  $object            The object or array from where to get the item
 * @param mixed  $item              The item to get from the array or object
 * @param array  $arguments         An array of arguments to pass if the item is an object method
 * @param string $type              The type of attribute (@see \Twig\Template constants)
 * @param bool   $isDefinedTest     Whether this is only a defined check
 * @param bool   $ignoreStrictCheck Whether to ignore the strict attribute check or not
 * @param int    $lineno            The template line where the attribute was called
 *
 * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
 *
 * @throws RuntimeError if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
 *
 * @internal
 */
function twig_get_attribute(Environment $env, Source $source, $object, $item, array $arguments = [], $type = /* Template::ANY_CALL */ 'any', $isDefinedTest = false, $ignoreStrictCheck = false, $sandboxed = false, int $lineno = -1)
{
    // array
    if (/* Template::METHOD_CALL */ 'method' !== $type) {
        $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item;

        if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, (array) $object)))
            || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
        ) {
            if ($isDefinedTest) {
                return true;
            }

            return $object[$arrayItem];
        }

        if (/* Template::ARRAY_CALL */ 'array' === $type || !\is_object($object)) {
            if ($isDefinedTest) {
                return false;
            }

            if ($ignoreStrictCheck || !$env->isStrictVariables()) {
                return;
            }

            if ($object instanceof ArrayAccess) {
                $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object));
            } elseif (\is_object($object)) {
                $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object));
            } elseif (\is_array($object)) {
                if (empty($object)) {
                    $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem);
                } else {
                    $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object)));
                }
            } elseif (/* Template::ARRAY_CALL */ 'array' === $type) {
                if (null === $object) {
                    $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item);
                } else {
                    $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
                }
            } elseif (null === $object) {
                $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item);
            } else {
                $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
            }

            throw new RuntimeError($message, $lineno, $source);
        }
    }

    if (!\is_object($object)) {
        if ($isDefinedTest) {
            return false;
        }

        if ($ignoreStrictCheck || !$env->isStrictVariables()) {
            return;
        }

        if (null === $object) {
            $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item);
        } elseif (\is_array($object)) {
            $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item);
        } else {
            $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
        }

        throw new RuntimeError($message, $lineno, $source);
    }

    if ($object instanceof Template) {
        throw new RuntimeError('Accessing \Twig\Template attributes is forbidden.', $lineno, $source);
    }

    // object property
    if (/* Template::METHOD_CALL */ 'method' !== $type) {
        if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) {
            if ($isDefinedTest) {
                return true;
            }

            if ($sandboxed) {
                $env->getExtension(SandboxExtension::class)->checkPropertyAllowed($object, $item, $lineno, $source);
            }

            return $object->$item;
        }
    }

    static $cache = [];

    $class = \get_class($object);

    // object method
    // precedence: getXxx() > isXxx() > hasXxx()
    if (!isset($cache[$class])) {
        $methods = get_class_methods($object);
        sort($methods);
        $lcMethods = array_map(function ($value) { return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); }, $methods);
        $classCache = [];
        foreach ($methods as $i => $method) {
            $classCache[$method] = $method;
            $classCache[$lcName = $lcMethods[$i]] = $method;

            if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) {
                $name = substr($method, 3);
                $lcName = substr($lcName, 3);
            } elseif ('i' === $lcName[0] && 0 === strpos($lcName, 'is')) {
                $name = substr($method, 2);
                $lcName = substr($lcName, 2);
            } elseif ('h' === $lcName[0] && 0 === strpos($lcName, 'has')) {
                $name = substr($method, 3);
                $lcName = substr($lcName, 3);
                if (\in_array('is'.$lcName, $lcMethods)) {
                    continue;
                }
            } else {
                continue;
            }

            // skip get() and is() methods (in which case, $name is empty)
            if ($name) {
                if (!isset($classCache[$name])) {
                    $classCache[$name] = $method;
                }

                if (!isset($classCache[$lcName])) {
                    $classCache[$lcName] = $method;
                }
            }
        }
        $cache[$class] = $classCache;
    }

    $call = false;
    if (isset($cache[$class][$item])) {
        $method = $cache[$class][$item];
    } elseif (isset($cache[$class][$lcItem = strtr($item, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')])) {
        $method = $cache[$class][$lcItem];
    } elseif (isset($cache[$class]['__call'])) {
        $method = $item;
        $call = true;
    } else {
        if ($isDefinedTest) {
            return false;
        }

        if ($ignoreStrictCheck || !$env->isStrictVariables()) {
            return;
        }

        throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()"/"has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source);
    }

    if ($isDefinedTest) {
        return true;
    }

    if ($sandboxed) {
        $env->getExtension(SandboxExtension::class)->checkMethodAllowed($object, $method, $lineno, $source);
    }

    // Some objects throw exceptions when they have __call, and the method we try
    // to call is not supported. If ignoreStrictCheck is true, we should return null.
    try {
        $ret = $object->$method(...$arguments);
    } catch (\BadMethodCallException $e) {
        if ($call && ($ignoreStrictCheck || !$env->isStrictVariables())) {
            return;
        }
        throw $e;
    }

    return $ret;
}

/**
 * Returns the values from a single column in the input array.
 *
 * <pre>
 *  {% set items = [{ 'fruit' : 'apple'}, {'fruit' : 'orange' }] %}
 *
 *  {% set fruits = items|column('fruit') %}
 *
 *  {# fruits now contains ['apple', 'orange'] #}
 * </pre>
 *
 * @param array|Traversable $array An array
 * @param mixed             $name  The column name
 * @param mixed             $index The column to use as the index/keys for the returned array
 *
 * @return array The array of values
 */
function twig_array_column($array, $name, $index = null): array
{
    if ($array instanceof Traversable) {
        $array = iterator_to_array($array);
    } elseif (!\is_array($array)) {
        throw new RuntimeError(sprintf('The column filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array)));
    }

    return array_column($array, $name, $index);
}

function twig_array_filter(Environment $env, $array, $arrow)
{
    if (!twig_test_iterable($array)) {
        throw new RuntimeError(sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
    }

    twig_check_arrow_in_sandbox($env, $arrow, 'filter', 'filter');

    if (\is_array($array)) {
        return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
    }

    // the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator
    return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow);
}

function twig_array_map(Environment $env, $array, $arrow)
{
    twig_check_arrow_in_sandbox($env, $arrow, 'map', 'filter');

    $r = [];
    foreach ($array as $k => $v) {
        $r[$k] = $arrow($v, $k);
    }

    return $r;
}

function twig_array_reduce(Environment $env, $array, $arrow, $initial = null)
{
    twig_check_arrow_in_sandbox($env, $arrow, 'reduce', 'filter');

    if (!\is_array($array)) {
        if (!$array instanceof \Traversable) {
            throw new RuntimeError(sprintf('The "reduce" filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array)));
        }

        $array = iterator_to_array($array);
    }

    return array_reduce($array, $arrow, $initial);
}

function twig_array_some(Environment $env, $array, $arrow)
{
    twig_check_arrow_in_sandbox($env, $arrow, 'some', 'filter');

    foreach ($array as $k => $v) {
        if ($arrow($v, $k)) {
            return true;
        }
    }

    return false;
}

function twig_array_every(Environment $env, $array, $arrow)
{
    twig_check_arrow_in_sandbox($env, $arrow, 'every', 'filter');

    foreach ($array as $k => $v) {
        if (!$arrow($v, $k)) {
            return false;
        }
    }

    return true;
}

function twig_check_arrow_in_sandbox(Environment $env, $arrow, $thing, $type)
{
    if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) {
        throw new RuntimeError(sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type));
    }
}
}
¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!