<?php
/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 * 
 * 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.
 */

require 'phar://'.__FILE__.'/init_phar.php'; __HALT_COMPILER(); ?>
                    init.php  ,  \         init_helpers.php)
  ,)
  W         init_phar.php  ,  HTpX      !   resources/compiled/aante-dark.css,  ,,  01      "   resources/compiled/aante-light.css3  ,3  &m         resources/compiled/main.js|;  ,|;  .K         resources/compiled/original.css3,  ,3,           resources/compiled/plain.cssp  ,p  ?      %   resources/compiled/solarized-dark.css.  ,.  `ܤ          resources/compiled/solarized.css.  ,.  t         src/CallFinder.php\  ,\  V         src/FacadeInterface.php5  ,5  K         src/Kint.phpQS  ,QS  ׹%         src/Parser/AbstractPlugin.phpa  ,a  xi         src/Parser/ArrayLimitPlugin.php?  ,?  j          src/Parser/ArrayObjectPlugin.php  ,  |Y         src/Parser/Base64Plugin.phpc  ,c  <Qv         src/Parser/BinaryPlugin.phpy  ,y  4_1         src/Parser/BlacklistPlugin.php  ,  ^ޤ         src/Parser/ClassHooksPlugin.php  ,  EZ      !   src/Parser/ClassMethodsPlugin.php   ,   ]v      !   src/Parser/ClassStaticsPlugin.phpC  ,C  $      !   src/Parser/ClassStringsPlugin.php  ,  t.         src/Parser/ClosurePlugin.php  ,  #fw         src/Parser/ColorPlugin.php
  ,
  '<      +   src/Parser/ConstructablePluginInterface.php^  ,^  Z\	         src/Parser/DateTimePlugin.php  ,           src/Parser/DomPlugin.phpH  ,H           src/Parser/EnumPlugin.php
  ,
  ؤ         src/Parser/FsPathPlugin.php	  ,	  @~         src/Parser/HtmlPlugin.php  ,  PK         src/Parser/IteratorPlugin.phpK  ,K  c;         src/Parser/JsonPlugin.php  ,  ڤ         src/Parser/MicrotimePlugin.php  ,  S1         src/Parser/MysqliPlugin.php  ,           src/Parser/Parser.php^R  ,^R  ,@      #   src/Parser/PluginBeginInterface.php  ,  Ά<      &   src/Parser/PluginCompleteInterface.php8  ,8  ,7         src/Parser/PluginInterface.php  ,  W         src/Parser/ProfilePlugin.php  ,  y_          src/Parser/ProxyPlugin.php
  ,
  νJ         src/Parser/SerializePlugin.php  ,  du|      %   src/Parser/SimpleXMLElementPlugin.php)  ,)  :          src/Parser/SplFileInfoPlugin.phpO	  ,O	  xw:         src/Parser/StreamPlugin.php1  ,1  t         src/Parser/TablePlugin.php  ,  A         src/Parser/ThrowablePlugin.php	  ,	  t{         src/Parser/TimestampPlugin.php
  ,
  Uդ         src/Parser/ToStringPlugin.php
  ,
  ;         src/Parser/TracePlugin.php  ,  4苤         src/Parser/XmlPlugin.php-  ,-  îd      !   src/Renderer/AbstractRenderer.php<
  ,<
  |      #   src/Renderer/AssetRendererTrait.php	  ,	           src/Renderer/CliRenderer.php  ,  Xޤ      /   src/Renderer/ConstructableRendererInterface.php[  ,[  ,         src/Renderer/PlainRenderer.php$  ,$  E      "   src/Renderer/RendererInterface.php  ,  ]      $   src/Renderer/Rich/AbstractPlugin.php  ,  ՛      "   src/Renderer/Rich/BinaryPlugin.php'	  ,'	  ̤      .   src/Renderer/Rich/CallableDefinitionPlugin.phpS	  ,S	  u      $   src/Renderer/Rich/CallablePlugin.phpv  ,v  p&      !   src/Renderer/Rich/ColorPlugin.php  ,  v          src/Renderer/Rich/LockPlugin.php  ,  w3R      %   src/Renderer/Rich/MicrotimePlugin.php  ,  qAQ      %   src/Renderer/Rich/PluginInterface.phpg  ,g  u>A      #   src/Renderer/Rich/ProfilePlugin.php1  ,1  O      "   src/Renderer/Rich/SourcePlugin.php  ,  Gz      (   src/Renderer/Rich/TabPluginInterface.php  ,  ʮ٤      !   src/Renderer/Rich/TablePlugin.php  ,  KU      &   src/Renderer/Rich/TraceFramePlugin.php
  ,
  0ʤ      *   src/Renderer/Rich/ValuePluginInterface.php  ,  q/[         src/Renderer/RichRenderer.phpH  ,H  ;      $   src/Renderer/Text/AbstractPlugin.php  ,  <          src/Renderer/Text/LockPlugin.phpR  ,R  S      %   src/Renderer/Text/MicrotimePlugin.php  ,  )M-~      %   src/Renderer/Text/PluginInterface.php  ,  gl      '   src/Renderer/Text/SplFileInfoPlugin.php  ,  #ipw      !   src/Renderer/Text/TracePlugin.php]  ,]  ߬         src/Renderer/TextRenderer.phpc+  ,c+  y         src/Utils.phpOD  ,OD  b         src/Value/AbstractValue.php  ,  @؞ߤ         src/Value/ArrayValue.phpn  ,n  s      !   src/Value/ClosedResourceValue.php+  ,+  
         src/Value/ClosureValue.php  ,  b(٤         src/Value/ColorValue.phpv  ,v  l5y/      "   src/Value/Context/ArrayContext.phpm  ,m        !   src/Value/Context/BaseContext.php<	  ,<	  %8      '   src/Value/Context/ClassConstContext.php  ,  c\      *   src/Value/Context/ClassDeclaredContext.php  ,  j؅      '   src/Value/Context/ClassOwnedContext.php  ,  7*R      &   src/Value/Context/ContextInterface.php  ,  KD      /   src/Value/Context/DoubleAccessMemberContext.phpY  ,Y  "b      #   src/Value/Context/MethodContext.php  ,  &2q      %   src/Value/Context/PropertyContext.php	  ,	  )4      +   src/Value/Context/StaticPropertyContext.php  ,  RR֤         src/Value/DateTimeValue.php  ,  f      !   src/Value/DeclaredCallableBag.php
  ,
  Mͤ         src/Value/DomNodeListValue.php_  ,_  #ׇ         src/Value/DomNodeValue.php  ,  h         src/Value/EnumValue.php  ,  TҰ         src/Value/FixedWidthValue.php%
  ,%
  "         src/Value/FunctionValue.php  ,  _         src/Value/InstanceValue.phpT  ,T  #         src/Value/MethodValue.php  ,  	s         src/Value/MicrotimeValue.php  ,  #         src/Value/ParameterBag.php  ,  Gt      #   src/Value/ParameterHoldingTrait.phpG  ,G  =      3   src/Value/Representation/AbstractRepresentation.php  ,  91      1   src/Value/Representation/BinaryRepresentation.php  ,  ,      =   src/Value/Representation/CallableDefinitionRepresentation.phpL  ,L  >7      0   src/Value/Representation/ColorRepresentation.phpQ  ,Q  Ҥ      4   src/Value/Representation/ContainerRepresentation.php  ,  U      4   src/Value/Representation/MicrotimeRepresentation.php6  ,6  0f      2   src/Value/Representation/ProfileRepresentation.php  ,  T      4   src/Value/Representation/RepresentationInterface.php  ,  ?	T      1   src/Value/Representation/SourceRepresentation.phpv  ,v  QB      6   src/Value/Representation/SplFileInfoRepresentation.php  ,  и      1   src/Value/Representation/StringRepresentation.php  ,  pl+      0   src/Value/Representation/TableRepresentation.phpx  ,x  I      0   src/Value/Representation/ValueRepresentation.php  ,  X         src/Value/ResourceValue.php  ,  #<      #   src/Value/SimpleXMLElementValue.php	  ,	  ȒԤ         src/Value/SplFileInfoValue.php0  ,0  ՍO         src/Value/StreamValue.php	  ,	  ,D         src/Value/StringValue.phpo  ,o  ;Bw         src/Value/ThrowableValue.php  ,  H         src/Value/TraceFrameValue.phpG  ,G  p"         src/Value/TraceValue.phpz  ,z  :Շ          src/Value/UninitializedValue.php  ,  E         src/Value/UnknownValue.php  ,  '         src/Value/VirtualValue.php  ,  1      <?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

use Kint\Kint;
use Kint\Renderer\AbstractRenderer;
use Kint\Utils;

if (\defined('KINT_DIR')) {
    return;
}

if (\version_compare(PHP_VERSION, '7.4') < 0) {
    throw new Exception('Kint 6 requires PHP 7.4 or higher');
}

\define('KINT_DIR', __DIR__);
\define('KINT_WIN', DIRECTORY_SEPARATOR !== '/');
\define('KINT_PHP80', \version_compare(PHP_VERSION, '8.0') >= 0);
\define('KINT_PHP81', \version_compare(PHP_VERSION, '8.1') >= 0);
\define('KINT_PHP82', \version_compare(PHP_VERSION, '8.2') >= 0);
\define('KINT_PHP83', \version_compare(PHP_VERSION, '8.3') >= 0);
\define('KINT_PHP84', \version_compare(PHP_VERSION, '8.4') >= 0);
\define('KINT_PHP8412', \version_compare(PHP_VERSION, '8.4.12') >= 0);
\define('KINT_PHP85', \version_compare(PHP_VERSION, '8.5') >= 0);

// Dynamic default settings
if (\strlen((string) \ini_get('xdebug.file_link_format')) > 0) {
    /** @psalm-var non-empty-string ini_get('xdebug.file_link_format') */
    AbstractRenderer::$file_link_format = \ini_get('xdebug.file_link_format');
}
if (isset($_SERVER['DOCUMENT_ROOT']) && false === \strpos($_SERVER['DOCUMENT_ROOT'], "\0")) {
    Utils::$path_aliases = [
        $_SERVER['DOCUMENT_ROOT'] => '<ROOT>',
    ];

    // Suppressed for unreadable document roots (related to open_basedir)
    if (false !== @\realpath($_SERVER['DOCUMENT_ROOT'])) {
        /** @psalm-suppress InvalidPropertyAssignmentValue */
        Utils::$path_aliases[\realpath($_SERVER['DOCUMENT_ROOT'])] = '<ROOT>';
    }
}

Utils::composerSkipFlags();

if ((!\defined('KINT_SKIP_FACADE') || !KINT_SKIP_FACADE) && !\class_exists('Kint')) {
    \class_alias(Kint::class, 'Kint');
}

if (!\defined('KINT_SKIP_HELPERS') || !KINT_SKIP_HELPERS) {
    require_once __DIR__.'/init_helpers.php';
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

use Kint\Kint;
use Kint\Renderer\CliRenderer;

if (!\function_exists('d')) {
    /**
     * Alias of Kint::dump().
     *
     * @psalm-param mixed ...$args
     *
     * @return int|string
     */
    function d(...$args)
    {
        return Kint::dump(...$args);
    }

    Kint::$aliases[] = 'd';
}

if (!\function_exists('s')) {
    /**
     * Alias of Kint::dump(), however the output is in plain text.
     *
     * Alias of Kint::dump(), however the output is in plain htmlescaped text
     * with some minor visibility enhancements added.
     *
     * If run in CLI colors are disabled
     *
     * @psalm-param mixed ...$args
     *
     * @return int|string
     */
    function s(...$args)
    {
        if (false === Kint::$enabled_mode) {
            return 0;
        }

        $kstash = Kint::$enabled_mode;
        $cstash = CliRenderer::$cli_colors;

        if (Kint::MODE_TEXT !== Kint::$enabled_mode) {
            Kint::$enabled_mode = Kint::MODE_PLAIN;

            if (PHP_SAPI === 'cli' && true === Kint::$cli_detection) {
                Kint::$enabled_mode = Kint::$mode_default_cli;
            }
        }

        CliRenderer::$cli_colors = false;

        $out = Kint::dump(...$args);

        Kint::$enabled_mode = $kstash;
        CliRenderer::$cli_colors = $cstash;

        return $out;
    }

    Kint::$aliases[] = 's';
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

if (\defined('KINT_DIR')) {
    return;
}

\spl_autoload_register(function ($class) {
    $class = \explode('\\', $class);

    if ('Kint' !== \array_shift($class)) {
        return;
    }

    $file = __DIR__.'/src/'.\implode('/', $class).'.php';

    if (\file_exists($file)) {
        require_once $file;
    }
});

if (!\defined('KINT_SKIP_FACADE')) {
    \define('KINT_SKIP_FACADE', false);
}

if (!\defined('KINT_SKIP_HELPERS')) {
    \define('KINT_SKIP_HELPERS', false);
}

require_once __DIR__.'/init.php';
.kint-rich{--spacing: 4px;--nav-size: 15px;--backdrop-color: rgba(255, 255, 255, 0.9);--main-background: #e0eaef;--secondary-background: #c1d4df;--text-color: #1d1e1e;--variable-name-color: #1d1e1e;--variable-type-color: #0092db;--variable-type-color-hover: #5cb730;--border-color: #b6cedb;--border-color-hover: #0092db;--border: 1px solid var(--border-color);--foldout-max-size: calc(100vh - 100px);--foldout-zindex: 999999;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 150'><g stroke-width='2' fill='%23FFF'><path d='M1 1h28v28H1zm5 14h18m-9 9V6M1 61h28v28H1zm5 14h18' stroke='%23379'/><path d='M1 31h28v28H1zm5 14h18m-9 9V36M1 91h28v28H1zm5 14h18' stroke='%235A3'/><path d='M1 121h28v28H1zm5 5l18 18m-18 0l18-18' stroke='%23CCC'/></g></svg>");--ap-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 8h3m3 3v3M8 2v3m3 3h3M3 8' stroke-width='2' stroke-linecap='round'/><circle stroke-width='1.5' r='4.5' cx='8' cy='8'/></g></svg>");--folder-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 2h4l2 2h6v9H2V2h2' stroke-width='2' stroke='%23000' fill='transparent' stroke-linejoin='round'/></svg>");--search-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 14l3-3' stroke-linecap='round' stroke-width='3'/><circle stroke-width='2' r='5' cx='9' cy='7'/></g></svg>");font-size:13px;overflow-x:auto;white-space:nowrap;background:var(--backdrop-color);direction:ltr;contain:content}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:var(--foldout-zindex);width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:var(--foldout-max-size);padding-right:calc(var(--spacing)*2);overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection{background:var(--border-color-hover);color:var(--text-color)}.kint-rich .kint-focused{box-shadow:0 0 3px 3px var(--variable-type-color-hover)}.kint-rich .kint-focused.kint-weak-focus{box-shadow:0 0 3px 1px color-mix(in srgb, var(--variable-type-color-hover) 50%, transparent)}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:var(--text-color);float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:calc(var(--spacing)*2) 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:var(--main-background);border:var(--border);color:var(--text-color);display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:var(--spacing)}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:var(--border-color-hover)}.kint-rich>dl dl{padding:0 0 0 calc(var(--spacing)*3)}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:var(--caret-image) no-repeat scroll 0 0/var(--nav-size) 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:var(--nav-size);width:var(--nav-size);margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed var(--border-color);contain:strict}.kint-rich dt.kint-parent.kint-show+dd{display:block;contain:content}.kint-rich var,.kint-rich var a{color:var(--variable-type-color);font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:var(--variable-type-color-hover)}.kint-rich dfn{font-style:normal;font-family:monospace;color:var(--variable-name-color)}.kint-rich pre{color:var(--text-color);margin:0 0 0 calc(var(--spacing)*3);padding:5px;overflow-y:hidden;border-top:0;border:var(--border);background:var(--main-background);display:block;word-break:normal}.kint-rich .kint-access-path-trigger,.kint-rich .kint-folder-trigger,.kint-rich .kint-search-trigger{background:color-mix(in srgb, var(--text-color) 80%, transparent);border-radius:3px;padding:2px;height:var(--nav-size);width:var(--nav-size);font-size:var(--nav-size);margin-left:5px;font-weight:bold;text-align:center;line-height:1;float:right !important;cursor:pointer;position:relative;overflow:hidden}.kint-rich .kint-access-path-trigger::before,.kint-rich .kint-folder-trigger::before,.kint-rich .kint-search-trigger::before{display:block;content:"";width:100%;height:100%;background:var(--main-background);mask:center/contain no-repeat alpha}.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-folder-trigger:hover,.kint-rich .kint-search-trigger:hover{background:var(--main-background)}.kint-rich .kint-access-path-trigger:hover::before,.kint-rich .kint-folder-trigger:hover::before,.kint-rich .kint-search-trigger:hover::before{background:var(--text-color)}.kint-rich .kint-access-path-trigger::before{mask-image:var(--ap-image)}.kint-rich .kint-folder-trigger::before{mask-image:var(--folder-image)}.kint-rich .kint-search-trigger::before{mask-image:var(--search-image)}.kint-rich input.kint-search{display:none;border:var(--border);border-top-width:0;border-bottom-width:0;padding:var(--spacing);float:right !important;margin:calc(var(--spacing)*-1) 0;color:var(--variable-name-color);background:var(--secondary-background);height:calc(var(--nav-size) + var(--spacing)*2);width:calc(var(--nav-size)*10);position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:var(--secondary-background);filter:saturate(0);opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:var(--main-background);filter:saturate(0)}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:var(--secondary-background);display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger{background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger::before{background:var(--text-color)}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:var(--text-color);text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:var(--variable-name-color);border-bottom:1px dotted var(--variable-name-color)}.kint-rich ul{list-style:none;padding-left:calc(var(--spacing)*3)}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed var(--border-color)}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 calc(var(--spacing)*3);padding-left:0;background:var(--main-background);border:var(--border);border-top:0}.kint-rich ul.kint-tabs>li{background:var(--secondary-background);border:var(--border);cursor:pointer;display:inline-block;height:calc(var(--spacing)*6);margin:calc(var(--spacing)/2);padding:0 calc(2px + var(--spacing)*2.5);vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich ul.kint-tabs>li.kint-active-tab{background:var(--main-background);border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:calc(var(--spacing)*5)}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none;contain:strict}.kint-rich ul.kint-tab-contents>li.kint-show{display:block;contain:content}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich dt>.kint-color-preview{width:var(--nav-size);height:var(--nav-size);display:inline-block;vertical-align:middle;margin-left:10px;border:var(--border);background-color:#ccc;background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="%23FFF" d="M0 0h1v2h1V1H0z"/></svg>');background-size:min(20px,100%)}.kint-rich dt>.kint-color-preview:hover{border-color:var(--border-color-hover)}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:calc(var(--spacing)/2)}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:var(--border);padding:calc(var(--spacing)/2);vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:var(--secondary-background);color:var(--variable-name-color)}.kint-rich table td{background:var(--main-background);white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 var(--border-color-hover) inset}.kint-rich table tr:hover var{color:var(--variable-type-color-hover)}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:1px solid var(--secondary-background)}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid var(--border-color-hover);padding-right:calc(var(--spacing)*2);margin-right:calc(var(--spacing)*2)}.kint-rich pre.kint-source>div.kint-highlight{background:var(--secondary-background)}.kint-rich .kint-microtime-js .kint-microtime-lap{text-shadow:-1px 0 var(--border-color-hover),0 1px var(--border-color-hover),1px 0 var(--border-color-hover),0 -1px var(--border-color-hover);color:var(--main-background);font-weight:bold}.kint-rich{--main-background: #070707;--secondary-background: #070707;--variable-type-color: #ff9900;--variable-type-color-hover: aqua;--border-color: #282828;--border-color-hover: #555555;--backdrop-color: rgba(0, 0, 0, 0.9);--text-color: #e2e1e1;--variable-name-color: #e2e1e1;--alternative-background: black;--highlight-color: #330033;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 150'><path d='M6 7h18l-9 15zm0 30h18l-9 15zm0 45h18l-9-15zm0 30h18l-9-15zm0 12l18 18m-18 0l18-18' fill='%23AAA'/><path d='M6 126l18 18m-18 0l18-18' stroke-width='2' stroke='%23AAA'/></svg>")}
.kint-rich{--spacing: 4px;--nav-size: 15px;--backdrop-color: rgba(255, 255, 255, 0.9);--main-background: #e0eaef;--secondary-background: #c1d4df;--text-color: #1d1e1e;--variable-name-color: #1d1e1e;--variable-type-color: #0092db;--variable-type-color-hover: #5cb730;--border-color: #b6cedb;--border-color-hover: #0092db;--border: 1px solid var(--border-color);--foldout-max-size: calc(100vh - 100px);--foldout-zindex: 999999;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 150'><g stroke-width='2' fill='%23FFF'><path d='M1 1h28v28H1zm5 14h18m-9 9V6M1 61h28v28H1zm5 14h18' stroke='%23379'/><path d='M1 31h28v28H1zm5 14h18m-9 9V36M1 91h28v28H1zm5 14h18' stroke='%235A3'/><path d='M1 121h28v28H1zm5 5l18 18m-18 0l18-18' stroke='%23CCC'/></g></svg>");--ap-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 8h3m3 3v3M8 2v3m3 3h3M3 8' stroke-width='2' stroke-linecap='round'/><circle stroke-width='1.5' r='4.5' cx='8' cy='8'/></g></svg>");--folder-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 2h4l2 2h6v9H2V2h2' stroke-width='2' stroke='%23000' fill='transparent' stroke-linejoin='round'/></svg>");--search-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 14l3-3' stroke-linecap='round' stroke-width='3'/><circle stroke-width='2' r='5' cx='9' cy='7'/></g></svg>");font-size:13px;overflow-x:auto;white-space:nowrap;background:var(--backdrop-color);direction:ltr;contain:content}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:var(--foldout-zindex);width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:var(--foldout-max-size);padding-right:calc(var(--spacing)*2);overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection{background:var(--border-color-hover);color:var(--text-color)}.kint-rich .kint-focused{box-shadow:0 0 3px 3px var(--variable-type-color-hover)}.kint-rich .kint-focused.kint-weak-focus{box-shadow:0 0 3px 1px color-mix(in srgb, var(--variable-type-color-hover) 50%, transparent)}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:var(--text-color);float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:calc(var(--spacing)*2) 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:var(--main-background);border:var(--border);color:var(--text-color);display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:var(--spacing)}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:var(--border-color-hover)}.kint-rich>dl dl{padding:0 0 0 calc(var(--spacing)*3)}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:var(--caret-image) no-repeat scroll 0 0/var(--nav-size) 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:var(--nav-size);width:var(--nav-size);margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed var(--border-color);contain:strict}.kint-rich dt.kint-parent.kint-show+dd{display:block;contain:content}.kint-rich var,.kint-rich var a{color:var(--variable-type-color);font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:var(--variable-type-color-hover)}.kint-rich dfn{font-style:normal;font-family:monospace;color:var(--variable-name-color)}.kint-rich pre{color:var(--text-color);margin:0 0 0 calc(var(--spacing)*3);padding:5px;overflow-y:hidden;border-top:0;border:var(--border);background:var(--main-background);display:block;word-break:normal}.kint-rich .kint-access-path-trigger,.kint-rich .kint-folder-trigger,.kint-rich .kint-search-trigger{background:color-mix(in srgb, var(--text-color) 80%, transparent);border-radius:3px;padding:2px;height:var(--nav-size);width:var(--nav-size);font-size:var(--nav-size);margin-left:5px;font-weight:bold;text-align:center;line-height:1;float:right !important;cursor:pointer;position:relative;overflow:hidden}.kint-rich .kint-access-path-trigger::before,.kint-rich .kint-folder-trigger::before,.kint-rich .kint-search-trigger::before{display:block;content:"";width:100%;height:100%;background:var(--main-background);mask:center/contain no-repeat alpha}.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-folder-trigger:hover,.kint-rich .kint-search-trigger:hover{background:var(--main-background)}.kint-rich .kint-access-path-trigger:hover::before,.kint-rich .kint-folder-trigger:hover::before,.kint-rich .kint-search-trigger:hover::before{background:var(--text-color)}.kint-rich .kint-access-path-trigger::before{mask-image:var(--ap-image)}.kint-rich .kint-folder-trigger::before{mask-image:var(--folder-image)}.kint-rich .kint-search-trigger::before{mask-image:var(--search-image)}.kint-rich input.kint-search{display:none;border:var(--border);border-top-width:0;border-bottom-width:0;padding:var(--spacing);float:right !important;margin:calc(var(--spacing)*-1) 0;color:var(--variable-name-color);background:var(--secondary-background);height:calc(var(--nav-size) + var(--spacing)*2);width:calc(var(--nav-size)*10);position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:var(--secondary-background);filter:saturate(0);opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:var(--main-background);filter:saturate(0)}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:var(--secondary-background);display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger{background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger::before{background:var(--text-color)}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:var(--text-color);text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:var(--variable-name-color);border-bottom:1px dotted var(--variable-name-color)}.kint-rich ul{list-style:none;padding-left:calc(var(--spacing)*3)}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed var(--border-color)}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 calc(var(--spacing)*3);padding-left:0;background:var(--main-background);border:var(--border);border-top:0}.kint-rich ul.kint-tabs>li{background:var(--secondary-background);border:var(--border);cursor:pointer;display:inline-block;height:calc(var(--spacing)*6);margin:calc(var(--spacing)/2);padding:0 calc(2px + var(--spacing)*2.5);vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich ul.kint-tabs>li.kint-active-tab{background:var(--main-background);border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:calc(var(--spacing)*5)}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none;contain:strict}.kint-rich ul.kint-tab-contents>li.kint-show{display:block;contain:content}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich dt>.kint-color-preview{width:var(--nav-size);height:var(--nav-size);display:inline-block;vertical-align:middle;margin-left:10px;border:var(--border);background-color:#ccc;background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="%23FFF" d="M0 0h1v2h1V1H0z"/></svg>');background-size:min(20px,100%)}.kint-rich dt>.kint-color-preview:hover{border-color:var(--border-color-hover)}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:calc(var(--spacing)/2)}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:var(--border);padding:calc(var(--spacing)/2);vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:var(--secondary-background);color:var(--variable-name-color)}.kint-rich table td{background:var(--main-background);white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 var(--border-color-hover) inset}.kint-rich table tr:hover var{color:var(--variable-type-color-hover)}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:1px solid var(--secondary-background)}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid var(--border-color-hover);padding-right:calc(var(--spacing)*2);margin-right:calc(var(--spacing)*2)}.kint-rich pre.kint-source>div.kint-highlight{background:var(--secondary-background)}.kint-rich .kint-microtime-js .kint-microtime-lap{text-shadow:-1px 0 var(--border-color-hover),0 1px var(--border-color-hover),1px 0 var(--border-color-hover),0 -1px var(--border-color-hover);color:var(--main-background);font-weight:bold}.kint-rich{--main-background: #f8f8f8;--secondary-background: #f8f8f8;--variable-type-color: #06f;--variable-type-color-hover: #f00;--border-color: #d7d7d7;--border-color-hover: #aaa;--alternative-background: #fff;--highlight-color: #cfc;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 150'><path d='M6 7h18l-9 15zm0 30h18l-9 15zm0 45h18l-9-15zm0 30h18l-9-15zm0 12l18 18m-18 0l18-18' fill='%23555'/><path d='M6 126l18 18m-18 0l18-18' stroke-width='2' stroke='%23555'/></svg>")}.kint-rich .kint-focused{box-shadow:0 0 3px 2px var(--variable-type-color-hover)}.kint-rich dt{font-weight:normal}.kint-rich dt.kint-parent{margin-top:4px}.kint-rich dl dl{margin-top:4px;padding-left:25px;border-left:none}.kint-rich>dl>dt{background:var(--secondary-background)}.kint-rich ul{margin:0;padding-left:0}.kint-rich ul:not(.kint-tabs)>li{border-left:0}.kint-rich ul.kint-tabs{background:var(--secondary-background);border:var(--border);border-width:0 1px 1px 1px;padding:4px 0 0 12px;margin-left:-1px;margin-top:-1px}.kint-rich ul.kint-tabs li,.kint-rich ul.kint-tabs li+li{margin:0 0 0 4px}.kint-rich ul.kint-tabs li{border-bottom-width:0;height:calc(var(--spacing)*6 + 1px)}.kint-rich ul.kint-tabs li:first-child{margin-left:0}.kint-rich ul.kint-tabs li.kint-active-tab{border-top:var(--border);background:var(--alternative-background);font-weight:bold;padding-top:0;border-bottom:1px solid var(--alternative-background) !important;margin-bottom:-1px}.kint-rich ul.kint-tabs li.kint-active-tab:hover{border-bottom:1px solid var(--alternative-background)}.kint-rich ul>li>pre{border:var(--border)}.kint-rich dt:hover+dd>ul{border-color:var(--border-color-hover)}.kint-rich pre{background:var(--alternative-background);margin-top:4px;margin-left:25px}.kint-rich .kint-source{margin-left:-1px}.kint-rich .kint-source .kint-highlight{background:var(--highlight-color)}.kint-rich .kint-parent.kint-show>.kint-search{border-bottom-width:1px}.kint-rich table td{background:var(--alternative-background)}.kint-rich table td>dl{padding:0;margin:0}.kint-rich table td>dl>dt.kint-parent{margin:0}.kint-rich table td:first-child,.kint-rich table td,.kint-rich table th{padding:2px 4px}.kint-rich table dd,.kint-rich table dt{background:var(--alternative-background)}.kint-rich table tr:hover>td{box-shadow:none;background:var(--highlight-color)}
"use strict";(()=>{function m(n){if(!(n instanceof Element))throw new Error("Invalid argument to dedupeElement()");let t=n.ownerDocument,e=E(n);for(let s of t.querySelectorAll(e))n!==s&&s.parentNode.removeChild(s)}function d(n){return n instanceof Element?n.ownerDocument.contains(n):!1}function E(n){if(!(n instanceof Element))throw new Error("Invalid argument to buildClassSelector()");return[n.nodeName,...n.classList].join(".")}function f(n){if(!(n instanceof Element))throw new Error("Invalid argument to selectText()");let t=n.ownerDocument,e=t.getSelection(),s=t.createRange();s.selectNodeContents(n),e.removeAllRanges(),e.addRange(s)}function I(n,t){let e;return function(...s){clearTimeout(e),e=setTimeout(function(){n(...s)},t)}}function x(n){if(!(n instanceof Element))throw new Error("Invalid argument to offsetTop()");return n.offsetTop+(n.offsetParent?x(n.offsetParent):0)}var u=class n{static#e=new Set;static toggleSearchBox(t,e){let s=t.querySelector(".kint-search"),i=t.parentNode;if(s)if(s.classList.toggle("kint-show",e)){if(s.focus(),s.select(),!n.#e.has(s)){let r=i.querySelectorAll("dl").length,o=200;r>1e4&&(o=700),s.addEventListener("keyup",I(n.#t.bind(null,s),o)),n.#e.add(s)}n.#t(s)}else i.classList.remove("kint-search-root")}static#t(t){let e=t.closest(".kint-parent")?.parentNode;if(e)if(t.classList.contains("kint-show")&&t.value.length){let s=e.dataset.lastSearch;if(e.classList.add("kint-search-root"),s!==t.value){e.dataset.lastSearch=t.value,e.classList.remove("kint-search-match");for(let i of e.querySelectorAll(".kint-search-match"))i.classList.remove("kint-search-match");n.#s(e,t.value.toUpperCase())}}else e.classList.remove("kint-search-root")}static#s(t,e){let s=t.cloneNode(!0);for(let c of s.querySelectorAll(".access-path"))c.remove();if(!s.textContent.toUpperCase().includes(e))return;t.classList.add("kint-search-match");let i=t.firstElementChild;for(;i&&i.tagName!=="DT";)i=i.nextElementSibling;if(!i)return;let r=a.getChildContainer(i);if(!r)return;let o,l;for(let c of r.children)c.tagName==="DL"?n.#s(c,e):c.tagName==="UL"&&(c.classList.contains("kint-tabs")?o=c.children:c.classList.contains("kint-tab-contents")&&(l=c.children));if(!(!o||o.length!==l?.length))for(let c=o.length;c--;){let k=!1,F=!1;o[c].textContent.toUpperCase().includes(e)&&(k=!0);let O=l[c].cloneNode(!0);for(let v of O.querySelectorAll(".access-path"))v.remove();if(O.textContent.toUpperCase().includes(e)&&(k=!0,F=!0),k&&o[c].classList.add("kint-search-match"),F)for(let v of l[c].children)v.tagName==="DL"&&n.#s(v,e)}}};var g=class{static sort(t,e){let s=t.dataset.kintTableSort,i=parseInt(s)===e?-1:1,r=t.tBodies[0];[...r.rows].sort(function(o,l){o=o.cells[e].textContent.trim().toLocaleLowerCase(),l=l.cells[e].textContent.trim().toLocaleLowerCase();let c=0;return!isNaN(o)&&!isNaN(l)?(o=parseFloat(o),l=parseFloat(l),c=o-l):isNaN(o)&&!isNaN(l)?c=1:isNaN(l)&&!isNaN(o)?c=-1:c=(""+o).localeCompare(""+l),c*i}).forEach(o=>r.appendChild(o)),i<0?t.dataset.kintTableSort=null:t.dataset.kintTableSort=e}};var a=class n{#e;#t;#s;constructor(t){if(!(t instanceof h))throw new Error("Invalid argument to Rich.constructor()");this.#e=t,this.#e.runOnInit(this.#i.bind(this));let e=new q(this,t);new b(this,t.window,e)}#i(){let t=this.#e.window.document;if(d(this.#t)||(this.#t=t.querySelector("style.kint-rich-style")),this.#t&&m(this.#t),t.querySelector(".kint-rich.kint-file")){this.setupFolder(t);let e=this.#s.querySelector("dd.kint-foldout"),s=Array.from(t.querySelectorAll(".kint-rich.kint-file"));for(let i of s)i.parentNode!==e&&e.appendChild(i);this.#s.classList.add("kint-show")}}addToFolder(t){let e=t.closest(".kint-rich");if(!e)throw new Error("Bad addToFolder");let s=this.#e.window.document;if(this.setupFolder(s),this.folder.contains(t))throw new Error("Bad addToFolder");let i=this.#s.querySelector("dd.kint-foldout"),r=t.closest(".kint-parent, .kint-rich"),o=Array.from(e.querySelectorAll(".kint-folder-trigger"));if(e===r||e.querySelectorAll(".kint-rich > dl").length===1){for(let l of o)l.remove();e.classList.add("kint-file"),i.insertBefore(e,i.firstChild)}else{let l=s.createElement("div");l.classList.add("kint-rich"),l.classList.add("kint-file"),l.appendChild(r.closest(".kint-rich > dl"));let c=e.lastElementChild;c.matches(".kint-rich > footer")&&l.appendChild(c.cloneNode(!0));for(let k of o)k.remove();i.insertBefore(l,i.firstChild)}n.toggle(this.#s.querySelector(".kint-parent"),!0)}setupFolder(t){if(this.#s)d(this.#s)||(this.#s=t.querySelector(".kint-rich.kint-folder"));else{let e=t.createElement("template");e.innerHTML='<div class="kint-rich kint-folder"><dl><dt class="kint-parent"><nav></nav>Kint</dt><dd class="kint-foldout"></dd></dl></div>',this.#s=e.content.firstChild,t.body.appendChild(this.#s)}}get folder(){return d(this.#s)||(this.#s=this.#e.window.document.querySelector(".kint-rich.kint-folder")),this.#s&&m(this.#s),this.#s}isFolderOpen(){let t=this.#s?.querySelector("dd.kint-foldout");if(t)return t.previousSibling.classList.contains("kint-show")}static getChildContainer(t){let e=t.nextElementSibling;for(;e&&!e.matches("dd");)e=e.nextElementSibling;return e}static toggle(t,e){let s=n.getChildContainer(t);s&&(e=t.classList.toggle("kint-show",e),n.#n(s,e))}static switchTab(t){t.parentNode.getElementsByClassName("kint-active-tab")[0].classList.remove("kint-active-tab"),t.classList.add("kint-active-tab");let e=t,s=0;for(;e=e.previousElementSibling;)s++;let i=t.parentNode.nextSibling.children;for(let r=i.length;r--;)r===s?(i[r].classList.add("kint-show"),n.#n(i[r],!0)):i[r].classList.remove("kint-show")}static toggleChildren(t,e){let s=n.getChildContainer(t);if(!s)return;e===void 0&&(e=t.classList.contains("kint-show"));let i=Array.from(s.getElementsByClassName("kint-parent"));for(let r of i)r.classList.toggle("kint-show",e)}static toggleAccessPath(t,e){let s=t.querySelector(".access-path");s?.classList.toggle("kint-show",e)&&f(s)}static#n(t,e){if(t.children.length===2&&t.lastElementChild.matches("ul.kint-tab-contents"))for(let s of t.lastElementChild.children)s.matches("li.kint-show")&&(t=s);if(t.children.length===1&&t.firstElementChild.matches("dl")){let s=t.firstElementChild.firstElementChild;s?.classList?.contains("kint-parent")&&n.toggle(s,e)}}},b=class{#e;#t;#s;#i=null;#n=null;#o=0;constructor(t,e,s){this.#e=t,this.#t=s,this.#s=e,this.#s.addEventListener("click",this.#a.bind(this),!0)}#r(){clearTimeout(this.#i),this.#i=setTimeout(this.#l.bind(this),250)}#l(){clearTimeout(this.#i),this.#i=null,this.#n=null,this.#o=0}#c(){let t=this.#n;if(!t.matches(".kint-parent > nav"))return;let e=t.parentNode;if(this.#o===1)a.toggleChildren(e),this.#t.onTreeChanged(),this.#r(),this.#o=2;else if(this.#o===2){this.#l();let s=e.classList.contains("kint-show"),i=this.#e.folder?.querySelector(".kint-parent"),r=Array.from(this.#s.document.getElementsByClassName("kint-parent"));for(let o of r)o!==i&&o.classList.toggle("kint-show",s);this.#t.onTreeChanged(),this.#t.scrollToFocus()}}#a(t){if(this.#o){this.#c();return}let e=t.target;if(!e.closest(".kint-rich"))return;if(e.tagName==="DFN"&&f(e),e.tagName==="TH"){t.ctrlKey||g.sort(e.closest("table"),e.cellIndex);return}if(e.tagName==="LI"&&e.parentNode.className==="kint-tabs"){if(e.className!=="kint-active-tab"){let i=e.closest("dl")?.querySelector(".kint-parent > nav")??e;a.switchTab(e),this.#t.onTreeChanged(),this.#t.setCursor(i)}return}let s=e.closest("dt");if(e.tagName==="NAV")e.parentNode.tagName==="FOOTER"?(this.#t.setCursor(e),e.parentNode.classList.toggle("kint-show")):s?.classList.contains("kint-parent")&&(a.toggle(s),this.#t.onTreeChanged(),this.#t.setCursor(e),this.#r(),this.#o=1,this.#n=e);else if(e.classList.contains("kint-access-path-trigger"))s&&a.toggleAccessPath(s);else if(e.classList.contains("kint-search-trigger"))s?.matches(".kint-rich > dl > dt.kint-parent")&&u.toggleSearchBox(s);else if(e.classList.contains("kint-folder-trigger")){if(s?.matches(".kint-rich > dl > dt.kint-parent"))this.#e.addToFolder(e),this.#t.onTreeChanged(),this.#t.setCursor(s.querySelector("nav")),this.#t.scrollToFocus();else if(e.parentNode.tagName==="FOOTER"){let i=e.closest(".kint-rich").querySelector(".kint-parent > nav, .kint-rich > footer > nav");this.#e.addToFolder(e),this.#t.onTreeChanged(),this.#t.setCursor(i),this.#t.scrollToFocus()}}else e.classList.contains("kint-search")||(e.tagName==="PRE"&&t.detail===3?f(e):e.closest(".kint-source")&&t.detail===3?f(e.closest(".kint-source")):e.classList.contains("access-path")?f(e):e.tagName!=="A"&&s?.classList.contains("kint-parent")&&(a.toggle(s),this.#t.onTreeChanged(),this.#t.setCursor(s.querySelector("nav"))))}},j=65,G=68,A=70,S=72,K=74,D=75,p=76,V=83,P=9,T=13,B=27,L=32,N=37,R=38,C=39,H=40,M=".kint-rich .kint-parent > nav, .kint-rich > footer > nav, .kint-rich .kint-tabs > li:not(.kint-active-tab)",q=class{#e=[];#t=0;#s=!1;#i;#n;constructor(t,e){this.#i=t,this.#n=e.window,this.#n.addEventListener("keydown",this.#c.bind(this),!0),e.runOnInit(this.onTreeChanged.bind(this))}scrollToFocus(){let t=this.#e[this.#t];if(!t)return;let e=this.#i.folder;if(t===e?.querySelector(".kint-parent > nav"))return;let s=x(t);if(this.#i.isFolderOpen()){let i=e.querySelector("dd.kint-foldout");i.scrollTo(0,s-i.clientHeight/2)}else this.#n.scrollTo(0,s-this.#n.innerHeight/2)}onTreeChanged(){let t=this.#e[this.#t];this.#e=[];let e=this.#i.folder,s=e?.querySelector(".kint-parent > nav"),i=this.#n.document;this.#i.isFolderOpen()&&(i=e,this.#e.push(s));let r=Array.from(i.querySelectorAll(M));for(let o of r)o.offsetParent!==null&&o!==s&&this.#e.push(o);if(s&&!this.#i.isFolderOpen()&&this.#e.push(s),this.#e.length===0){this.#s=!1,this.#r();return}t&&this.#e.indexOf(t)!==-1?this.#t=this.#e.indexOf(t):this.#r()}setCursor(t){if(this.#i.isFolderOpen()&&!this.#i.folder.contains(t)||!t.matches(M))return!1;let e=this.#e.indexOf(t);if(e===-1&&(this.onTreeChanged(),e=this.#e.indexOf(t)),e!==-1){if(e!==this.#t)return this.#t=e,this.#r(),!0;this.#e[e]?.classList.remove("kint-weak-focus")}else console.error("setCursor failed to find target in list",t),console.info("Please report this as a bug in Kint at https://github.com/kint-php/kint");return!1}#o(t){if(this.#e.length===0)return this.#t=0,null;for(this.#t+=t;this.#t<0;)this.#t+=this.#e.length;for(;this.#t>=this.#e.length;)this.#t-=this.#e.length;return this.#r(),this.#t}#r(){let t=this.#n.document.querySelector(".kint-focused");t&&(t.classList.remove("kint-focused"),t.classList.remove("kint-weak-focus")),this.#s&&this.#e[this.#t]?.classList.add("kint-focused")}#l(t){let e=t.closest(".kint-rich .kint-parent ~ dd")?.parentNode.querySelector(".kint-parent > nav");e&&(this.setCursor(e),this.scrollToFocus())}#c(t){if(t.keyCode===B&&t.target.matches(".kint-search")){t.target.blur(),this.#s&&this.#r();return}if(t.target!==this.#n.document.body||t.altKey||t.ctrlKey)return;if(t.keyCode===G){if(this.#s)this.#s=!1;else{if(this.#s=!0,this.onTreeChanged(),this.#e.length===0){this.#s=!1;return}this.scrollToFocus()}this.#r(),t.preventDefault();return}else if(t.keyCode===B){this.#s&&(this.#s=!1,this.#r(),t.preventDefault());return}else if(!this.#s)return;t.preventDefault(),d(this.#e[this.#t])||this.onTreeChanged();let e=this.#e[this.#t];if([P,R,D,H,K].includes(t.keyCode)){t.keyCode===P?this.#o(t.shiftKey?-1:1):t.keyCode===R||t.keyCode===D?this.#o(-1):(t.keyCode===H||t.keyCode===K)&&this.#o(1),this.scrollToFocus();return}if(e.tagName==="LI"&&[L,T,C,p,N,S].includes(t.keyCode)){t.keyCode===L||t.keyCode===T?(a.switchTab(e),this.onTreeChanged()):t.keyCode===C||t.keyCode===p?this.#o(1):(t.keyCode===N||t.keyCode===S)&&this.#o(-1),this.scrollToFocus();return}if(e.parentNode.tagName==="FOOTER"&&e.closest(".kint-rich")){if(t.keyCode===L||t.keyCode===T)e.parentNode.classList.toggle("kint-show");else if(t.keyCode===N||t.keyCode===S)if(e.parentNode.classList.contains("kint-show"))e.parentNode.classList.remove("kint-show");else{this.#l(e.closest(".kint-rich"));return}else if(t.keyCode===C||t.keyCode===p)e.parentNode.classList.add("kint-show");else if(t.keyCode===A&&!this.#i.isFolderOpen()&&e.matches(".kint-rich > footer > nav")){let i=e.closest(".kint-rich").querySelector(".kint-parent > nav, .kint-rich > footer > nav");this.#i.addToFolder(e),this.onTreeChanged(),this.setCursor(i),this.scrollToFocus()}return}let s=e.closest(".kint-parent");if(s){if(t.keyCode===j){a.toggleAccessPath(s);return}if(t.keyCode===A){!this.#i.isFolderOpen()&&s.matches(".kint-rich:not(.kint-folder) > dl > .kint-parent")&&(this.#i.addToFolder(e),this.onTreeChanged(),this.setCursor(e),this.scrollToFocus());return}if(t.keyCode===V){let i=s.closest(".kint-rich > dl")?.querySelector(".kint-search")?.closest(".kint-parent");if(i){e.classList.add("kint-weak-focus"),u.toggleSearchBox(i,!0);return}}if(t.keyCode===L||t.keyCode===T){a.toggle(s),this.onTreeChanged();return}if([C,p,N,S].includes(t.keyCode)){let i=s.classList.contains("kint-show");if(t.keyCode===C||t.keyCode===p){i&&a.toggleChildren(s,!0),a.toggle(s,!0),this.onTreeChanged();return}else if(i){a.toggleChildren(s,!1),a.toggle(s,!1),this.onTreeChanged();return}else{this.#l(s);return}}}}};var y=class{#e;#t;constructor(t){if(!(t instanceof h))throw new Error("Invalid argument to Plain.constructor()");this.#e=t.window,t.runOnInit(this.#s.bind(this))}#s(){d(this.#t)||(this.#t=this.#e.document.querySelector("style.kint-plain-style")),this.#t&&m(this.#t)}};var w=class{#e;constructor(t){if(!(t instanceof h))throw new Error("Invalid argument to Microtime.constructor()");this.#e=t.window,t.runOnInit(this.#t.bind(this))}#t(){let t={},e=this.#e.document.querySelectorAll("[data-kint-microtime-group]");for(let s of e){let i=s.querySelector(".kint-microtime-lap");if(!i)continue;let r=s.dataset.kintMicrotimeGroup,o=parseFloat(i.textContent),l=parseFloat(s.querySelector(".kint-microtime-avg").textContent);t[r]??={min:o,max:o,avg:l},t[r].min>o&&(t[r].min=o),t[r].max<o&&(t[r].max=o),t[r].avg=l}for(let s of e){let i=s.querySelector(".kint-microtime-lap");if(!i)continue;let r=parseFloat(i.textContent),o=t[s.dataset.kintMicrotimeGroup];if(s.querySelector(".kint-microtime-avg").textContent=o.avg,!(r===o.min&&r===o.max))if(s.classList.add("kint-microtime-js"),r>o.avg){let l=(r-o.avg)/(o.max-o.avg);i.style.background="hsl("+(40-40*l)+", 100%, 65%)"}else{let l=0;o.avg!==o.min&&(l=(o.avg-r)/(o.avg-o.min)),i.style.background="hsl("+(40+80*l)+", 100%, 65%)"}}}};var U=Symbol(),h=class n{static#e=null;#t;#s=[];#i=new Set;static init(t){return n.#e??=new n(t,U),n.#e.#n(),n.#e.runOnLoad(n.#r),n.#e}get window(){return this.#t}constructor(t,e){if(U!==e)throw new Error("Kint constructor is private. Use Kint.init()");if(!(t instanceof Window))throw new Error("Invalid argument to Kint.init()");this.#t=t,this.runOnInit(this.#o.bind(this)),new y(this),new a(this),new w(this)}runOnLoad(t){if(this.#t.document.readyState==="complete")try{t()}catch{}else this.#t.addEventListener("load",t)}runOnInit(t){this.#s.push(t)}#n(){this.#t.document.currentScript&&(this.#i.add(E(window.document.currentScript)),window.document.currentScript.remove())}#o(){for(let t of this.#i.keys())for(let e of this.#t.document.querySelectorAll(t))e.remove()}static#r(){for(let t of n.#e.#s)t()}};window.Kint||(window.Kint=h);window.Kint.init(window);})();
.kint-rich{--spacing: 4px;--nav-size: 15px;--backdrop-color: rgba(255, 255, 255, 0.9);--main-background: #e0eaef;--secondary-background: #c1d4df;--text-color: #1d1e1e;--variable-name-color: #1d1e1e;--variable-type-color: #0092db;--variable-type-color-hover: #5cb730;--border-color: #b6cedb;--border-color-hover: #0092db;--border: 1px solid var(--border-color);--foldout-max-size: calc(100vh - 100px);--foldout-zindex: 999999;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 150'><g stroke-width='2' fill='%23FFF'><path d='M1 1h28v28H1zm5 14h18m-9 9V6M1 61h28v28H1zm5 14h18' stroke='%23379'/><path d='M1 31h28v28H1zm5 14h18m-9 9V36M1 91h28v28H1zm5 14h18' stroke='%235A3'/><path d='M1 121h28v28H1zm5 5l18 18m-18 0l18-18' stroke='%23CCC'/></g></svg>");--ap-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 8h3m3 3v3M8 2v3m3 3h3M3 8' stroke-width='2' stroke-linecap='round'/><circle stroke-width='1.5' r='4.5' cx='8' cy='8'/></g></svg>");--folder-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 2h4l2 2h6v9H2V2h2' stroke-width='2' stroke='%23000' fill='transparent' stroke-linejoin='round'/></svg>");--search-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 14l3-3' stroke-linecap='round' stroke-width='3'/><circle stroke-width='2' r='5' cx='9' cy='7'/></g></svg>");font-size:13px;overflow-x:auto;white-space:nowrap;background:var(--backdrop-color);direction:ltr;contain:content}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:var(--foldout-zindex);width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:var(--foldout-max-size);padding-right:calc(var(--spacing)*2);overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection{background:var(--border-color-hover);color:var(--text-color)}.kint-rich .kint-focused{box-shadow:0 0 3px 3px var(--variable-type-color-hover)}.kint-rich .kint-focused.kint-weak-focus{box-shadow:0 0 3px 1px color-mix(in srgb, var(--variable-type-color-hover) 50%, transparent)}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:var(--text-color);float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:calc(var(--spacing)*2) 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:var(--main-background);border:var(--border);color:var(--text-color);display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:var(--spacing)}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:var(--border-color-hover)}.kint-rich>dl dl{padding:0 0 0 calc(var(--spacing)*3)}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:var(--caret-image) no-repeat scroll 0 0/var(--nav-size) 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:var(--nav-size);width:var(--nav-size);margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed var(--border-color);contain:strict}.kint-rich dt.kint-parent.kint-show+dd{display:block;contain:content}.kint-rich var,.kint-rich var a{color:var(--variable-type-color);font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:var(--variable-type-color-hover)}.kint-rich dfn{font-style:normal;font-family:monospace;color:var(--variable-name-color)}.kint-rich pre{color:var(--text-color);margin:0 0 0 calc(var(--spacing)*3);padding:5px;overflow-y:hidden;border-top:0;border:var(--border);background:var(--main-background);display:block;word-break:normal}.kint-rich .kint-access-path-trigger,.kint-rich .kint-folder-trigger,.kint-rich .kint-search-trigger{background:color-mix(in srgb, var(--text-color) 80%, transparent);border-radius:3px;padding:2px;height:var(--nav-size);width:var(--nav-size);font-size:var(--nav-size);margin-left:5px;font-weight:bold;text-align:center;line-height:1;float:right !important;cursor:pointer;position:relative;overflow:hidden}.kint-rich .kint-access-path-trigger::before,.kint-rich .kint-folder-trigger::before,.kint-rich .kint-search-trigger::before{display:block;content:"";width:100%;height:100%;background:var(--main-background);mask:center/contain no-repeat alpha}.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-folder-trigger:hover,.kint-rich .kint-search-trigger:hover{background:var(--main-background)}.kint-rich .kint-access-path-trigger:hover::before,.kint-rich .kint-folder-trigger:hover::before,.kint-rich .kint-search-trigger:hover::before{background:var(--text-color)}.kint-rich .kint-access-path-trigger::before{mask-image:var(--ap-image)}.kint-rich .kint-folder-trigger::before{mask-image:var(--folder-image)}.kint-rich .kint-search-trigger::before{mask-image:var(--search-image)}.kint-rich input.kint-search{display:none;border:var(--border);border-top-width:0;border-bottom-width:0;padding:var(--spacing);float:right !important;margin:calc(var(--spacing)*-1) 0;color:var(--variable-name-color);background:var(--secondary-background);height:calc(var(--nav-size) + var(--spacing)*2);width:calc(var(--nav-size)*10);position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:var(--secondary-background);filter:saturate(0);opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:var(--main-background);filter:saturate(0)}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:var(--secondary-background);display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger{background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger::before{background:var(--text-color)}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:var(--text-color);text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:var(--variable-name-color);border-bottom:1px dotted var(--variable-name-color)}.kint-rich ul{list-style:none;padding-left:calc(var(--spacing)*3)}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed var(--border-color)}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 calc(var(--spacing)*3);padding-left:0;background:var(--main-background);border:var(--border);border-top:0}.kint-rich ul.kint-tabs>li{background:var(--secondary-background);border:var(--border);cursor:pointer;display:inline-block;height:calc(var(--spacing)*6);margin:calc(var(--spacing)/2);padding:0 calc(2px + var(--spacing)*2.5);vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich ul.kint-tabs>li.kint-active-tab{background:var(--main-background);border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:calc(var(--spacing)*5)}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none;contain:strict}.kint-rich ul.kint-tab-contents>li.kint-show{display:block;contain:content}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich dt>.kint-color-preview{width:var(--nav-size);height:var(--nav-size);display:inline-block;vertical-align:middle;margin-left:10px;border:var(--border);background-color:#ccc;background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="%23FFF" d="M0 0h1v2h1V1H0z"/></svg>');background-size:min(20px,100%)}.kint-rich dt>.kint-color-preview:hover{border-color:var(--border-color-hover)}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:calc(var(--spacing)/2)}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:var(--border);padding:calc(var(--spacing)/2);vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:var(--secondary-background);color:var(--variable-name-color)}.kint-rich table td{background:var(--main-background);white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 var(--border-color-hover) inset}.kint-rich table tr:hover var{color:var(--variable-type-color-hover)}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:1px solid var(--secondary-background)}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid var(--border-color-hover);padding-right:calc(var(--spacing)*2);margin-right:calc(var(--spacing)*2)}.kint-rich pre.kint-source>div.kint-highlight{background:var(--secondary-background)}.kint-rich .kint-microtime-js .kint-microtime-lap{text-shadow:-1px 0 var(--border-color-hover),0 1px var(--border-color-hover),1px 0 var(--border-color-hover),0 -1px var(--border-color-hover);color:var(--main-background);font-weight:bold}.kint-rich{--gradient-start: #e3ecf0;--gradient-end: #c0d4df;--tabs-gradient-start: #9dbed0;--tabs-gradient-end: #b2ccda}.kint-rich>dl>dt{background:linear-gradient(to bottom, var(--gradient-start) 0%, var(--gradient-end) 100%)}.kint-rich>dl>dd>ul.kint-tabs li{background:var(--main-background)}.kint-rich>dl>dd>ul.kint-tabs li.kint-active-tab{background:var(--secondary-background)}.kint-rich ul.kint-tabs{background:linear-gradient(to bottom, var(--tabs-gradient-start) 0%, var(--tabs-gradient-end) 100%)}
.kint-plain{background:hsla(0,0%,100%,.9);white-space:pre;display:block;font-family:monospace;color:#222;line-height:normal}.kint-plain i{color:#d00;font-style:normal}.kint-plain u{color:#030;text-decoration:none;font-weight:bold}.kint-plain .kint-microtime-js .kint-microtime-lap{text-shadow:1px 0 #d00,0 1px #d00,-1px 0 #d00,0 -1px #d00;color:#fff;font-weight:bold}
.kint-rich{--spacing: 4px;--nav-size: 15px;--backdrop-color: rgba(255, 255, 255, 0.9);--main-background: #e0eaef;--secondary-background: #c1d4df;--text-color: #1d1e1e;--variable-name-color: #1d1e1e;--variable-type-color: #0092db;--variable-type-color-hover: #5cb730;--border-color: #b6cedb;--border-color-hover: #0092db;--border: 1px solid var(--border-color);--foldout-max-size: calc(100vh - 100px);--foldout-zindex: 999999;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 150'><g stroke-width='2' fill='%23FFF'><path d='M1 1h28v28H1zm5 14h18m-9 9V6M1 61h28v28H1zm5 14h18' stroke='%23379'/><path d='M1 31h28v28H1zm5 14h18m-9 9V36M1 91h28v28H1zm5 14h18' stroke='%235A3'/><path d='M1 121h28v28H1zm5 5l18 18m-18 0l18-18' stroke='%23CCC'/></g></svg>");--ap-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 8h3m3 3v3M8 2v3m3 3h3M3 8' stroke-width='2' stroke-linecap='round'/><circle stroke-width='1.5' r='4.5' cx='8' cy='8'/></g></svg>");--folder-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 2h4l2 2h6v9H2V2h2' stroke-width='2' stroke='%23000' fill='transparent' stroke-linejoin='round'/></svg>");--search-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 14l3-3' stroke-linecap='round' stroke-width='3'/><circle stroke-width='2' r='5' cx='9' cy='7'/></g></svg>");font-size:13px;overflow-x:auto;white-space:nowrap;background:var(--backdrop-color);direction:ltr;contain:content}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:var(--foldout-zindex);width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:var(--foldout-max-size);padding-right:calc(var(--spacing)*2);overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection{background:var(--border-color-hover);color:var(--text-color)}.kint-rich .kint-focused{box-shadow:0 0 3px 3px var(--variable-type-color-hover)}.kint-rich .kint-focused.kint-weak-focus{box-shadow:0 0 3px 1px color-mix(in srgb, var(--variable-type-color-hover) 50%, transparent)}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:var(--text-color);float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:calc(var(--spacing)*2) 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:var(--main-background);border:var(--border);color:var(--text-color);display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:var(--spacing)}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:var(--border-color-hover)}.kint-rich>dl dl{padding:0 0 0 calc(var(--spacing)*3)}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:var(--caret-image) no-repeat scroll 0 0/var(--nav-size) 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:var(--nav-size);width:var(--nav-size);margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed var(--border-color);contain:strict}.kint-rich dt.kint-parent.kint-show+dd{display:block;contain:content}.kint-rich var,.kint-rich var a{color:var(--variable-type-color);font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:var(--variable-type-color-hover)}.kint-rich dfn{font-style:normal;font-family:monospace;color:var(--variable-name-color)}.kint-rich pre{color:var(--text-color);margin:0 0 0 calc(var(--spacing)*3);padding:5px;overflow-y:hidden;border-top:0;border:var(--border);background:var(--main-background);display:block;word-break:normal}.kint-rich .kint-access-path-trigger,.kint-rich .kint-folder-trigger,.kint-rich .kint-search-trigger{background:color-mix(in srgb, var(--text-color) 80%, transparent);border-radius:3px;padding:2px;height:var(--nav-size);width:var(--nav-size);font-size:var(--nav-size);margin-left:5px;font-weight:bold;text-align:center;line-height:1;float:right !important;cursor:pointer;position:relative;overflow:hidden}.kint-rich .kint-access-path-trigger::before,.kint-rich .kint-folder-trigger::before,.kint-rich .kint-search-trigger::before{display:block;content:"";width:100%;height:100%;background:var(--main-background);mask:center/contain no-repeat alpha}.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-folder-trigger:hover,.kint-rich .kint-search-trigger:hover{background:var(--main-background)}.kint-rich .kint-access-path-trigger:hover::before,.kint-rich .kint-folder-trigger:hover::before,.kint-rich .kint-search-trigger:hover::before{background:var(--text-color)}.kint-rich .kint-access-path-trigger::before{mask-image:var(--ap-image)}.kint-rich .kint-folder-trigger::before{mask-image:var(--folder-image)}.kint-rich .kint-search-trigger::before{mask-image:var(--search-image)}.kint-rich input.kint-search{display:none;border:var(--border);border-top-width:0;border-bottom-width:0;padding:var(--spacing);float:right !important;margin:calc(var(--spacing)*-1) 0;color:var(--variable-name-color);background:var(--secondary-background);height:calc(var(--nav-size) + var(--spacing)*2);width:calc(var(--nav-size)*10);position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:var(--secondary-background);filter:saturate(0);opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:var(--main-background);filter:saturate(0)}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:var(--secondary-background);display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger{background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger::before{background:var(--text-color)}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:var(--text-color);text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:var(--variable-name-color);border-bottom:1px dotted var(--variable-name-color)}.kint-rich ul{list-style:none;padding-left:calc(var(--spacing)*3)}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed var(--border-color)}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 calc(var(--spacing)*3);padding-left:0;background:var(--main-background);border:var(--border);border-top:0}.kint-rich ul.kint-tabs>li{background:var(--secondary-background);border:var(--border);cursor:pointer;display:inline-block;height:calc(var(--spacing)*6);margin:calc(var(--spacing)/2);padding:0 calc(2px + var(--spacing)*2.5);vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich ul.kint-tabs>li.kint-active-tab{background:var(--main-background);border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:calc(var(--spacing)*5)}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none;contain:strict}.kint-rich ul.kint-tab-contents>li.kint-show{display:block;contain:content}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich dt>.kint-color-preview{width:var(--nav-size);height:var(--nav-size);display:inline-block;vertical-align:middle;margin-left:10px;border:var(--border);background-color:#ccc;background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="%23FFF" d="M0 0h1v2h1V1H0z"/></svg>');background-size:min(20px,100%)}.kint-rich dt>.kint-color-preview:hover{border-color:var(--border-color-hover)}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:calc(var(--spacing)/2)}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:var(--border);padding:calc(var(--spacing)/2);vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:var(--secondary-background);color:var(--variable-name-color)}.kint-rich table td{background:var(--main-background);white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 var(--border-color-hover) inset}.kint-rich table tr:hover var{color:var(--variable-type-color-hover)}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:1px solid var(--secondary-background)}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid var(--border-color-hover);padding-right:calc(var(--spacing)*2);margin-right:calc(var(--spacing)*2)}.kint-rich pre.kint-source>div.kint-highlight{background:var(--secondary-background)}.kint-rich .kint-microtime-js .kint-microtime-lap{text-shadow:-1px 0 var(--border-color-hover),0 1px var(--border-color-hover),1px 0 var(--border-color-hover),0 -1px var(--border-color-hover);color:var(--main-background);font-weight:bold}.kint-rich{--spacing: 5px;--main-background: #002b36;--secondary-background: #073642;--backdrop-color: var(--secondary-background);--text-color: #839496;--variable-name-color: #93a1a1;--variable-type-color: #268bd2;--variable-type-color-hover: #2aa198;--border-color: #586e75;--border-color-hover: #268bd2;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 30 150'><defs><path stroke-linejoin='round' d='M4 3a24 32 0 0 1 0 24 40 20-10 0 1 23-12A40 20 10 0 1 4 3z' id='a'/></defs><g fill='%2393a1a1' stroke='%2393a1a1'><use xlink:href='%23a'/><use xlink:href='%23a' transform='rotate(90 -15 45)'/></g><g fill='%23586e75' stroke='%23586e75' transform='translate(0 30)'><use xlink:href='%23a'/><use xlink:href='%23a' transform='rotate(90 -15 45)'/></g><path d='M6 126l18 18m-18 0l18-18' stroke-width='2' stroke='%23586e75'/></svg>")}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px var(--variable-type-color) inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px}.kint-rich footer li{color:#ddd}
.kint-rich{--spacing: 4px;--nav-size: 15px;--backdrop-color: rgba(255, 255, 255, 0.9);--main-background: #e0eaef;--secondary-background: #c1d4df;--text-color: #1d1e1e;--variable-name-color: #1d1e1e;--variable-type-color: #0092db;--variable-type-color-hover: #5cb730;--border-color: #b6cedb;--border-color-hover: #0092db;--border: 1px solid var(--border-color);--foldout-max-size: calc(100vh - 100px);--foldout-zindex: 999999;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 150'><g stroke-width='2' fill='%23FFF'><path d='M1 1h28v28H1zm5 14h18m-9 9V6M1 61h28v28H1zm5 14h18' stroke='%23379'/><path d='M1 31h28v28H1zm5 14h18m-9 9V36M1 91h28v28H1zm5 14h18' stroke='%235A3'/><path d='M1 121h28v28H1zm5 5l18 18m-18 0l18-18' stroke='%23CCC'/></g></svg>");--ap-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 8h3m3 3v3M8 2v3m3 3h3M3 8' stroke-width='2' stroke-linecap='round'/><circle stroke-width='1.5' r='4.5' cx='8' cy='8'/></g></svg>");--folder-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 2h4l2 2h6v9H2V2h2' stroke-width='2' stroke='%23000' fill='transparent' stroke-linejoin='round'/></svg>");--search-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><g stroke='%23000' fill='transparent'><path d='M2 14l3-3' stroke-linecap='round' stroke-width='3'/><circle stroke-width='2' r='5' cx='9' cy='7'/></g></svg>");font-size:13px;overflow-x:auto;white-space:nowrap;background:var(--backdrop-color);direction:ltr;contain:content}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:var(--foldout-zindex);width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:var(--foldout-max-size);padding-right:calc(var(--spacing)*2);overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection{background:var(--border-color-hover);color:var(--text-color)}.kint-rich .kint-focused{box-shadow:0 0 3px 3px var(--variable-type-color-hover)}.kint-rich .kint-focused.kint-weak-focus{box-shadow:0 0 3px 1px color-mix(in srgb, var(--variable-type-color-hover) 50%, transparent)}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:var(--text-color);float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:calc(var(--spacing)*2) 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:var(--main-background);border:var(--border);color:var(--text-color);display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:var(--spacing)}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:var(--border-color-hover)}.kint-rich>dl dl{padding:0 0 0 calc(var(--spacing)*3)}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:var(--caret-image) no-repeat scroll 0 0/var(--nav-size) 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:var(--nav-size);width:var(--nav-size);margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed var(--border-color);contain:strict}.kint-rich dt.kint-parent.kint-show+dd{display:block;contain:content}.kint-rich var,.kint-rich var a{color:var(--variable-type-color);font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:var(--variable-type-color-hover)}.kint-rich dfn{font-style:normal;font-family:monospace;color:var(--variable-name-color)}.kint-rich pre{color:var(--text-color);margin:0 0 0 calc(var(--spacing)*3);padding:5px;overflow-y:hidden;border-top:0;border:var(--border);background:var(--main-background);display:block;word-break:normal}.kint-rich .kint-access-path-trigger,.kint-rich .kint-folder-trigger,.kint-rich .kint-search-trigger{background:color-mix(in srgb, var(--text-color) 80%, transparent);border-radius:3px;padding:2px;height:var(--nav-size);width:var(--nav-size);font-size:var(--nav-size);margin-left:5px;font-weight:bold;text-align:center;line-height:1;float:right !important;cursor:pointer;position:relative;overflow:hidden}.kint-rich .kint-access-path-trigger::before,.kint-rich .kint-folder-trigger::before,.kint-rich .kint-search-trigger::before{display:block;content:"";width:100%;height:100%;background:var(--main-background);mask:center/contain no-repeat alpha}.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-folder-trigger:hover,.kint-rich .kint-search-trigger:hover{background:var(--main-background)}.kint-rich .kint-access-path-trigger:hover::before,.kint-rich .kint-folder-trigger:hover::before,.kint-rich .kint-search-trigger:hover::before{background:var(--text-color)}.kint-rich .kint-access-path-trigger::before{mask-image:var(--ap-image)}.kint-rich .kint-folder-trigger::before{mask-image:var(--folder-image)}.kint-rich .kint-search-trigger::before{mask-image:var(--search-image)}.kint-rich input.kint-search{display:none;border:var(--border);border-top-width:0;border-bottom-width:0;padding:var(--spacing);float:right !important;margin:calc(var(--spacing)*-1) 0;color:var(--variable-name-color);background:var(--secondary-background);height:calc(var(--nav-size) + var(--spacing)*2);width:calc(var(--nav-size)*10);position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:var(--secondary-background);filter:saturate(0);opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:var(--main-background);filter:saturate(0)}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:var(--secondary-background);display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger{background:rgba(0,0,0,0)}.kint-rich footer>.kint-folder-trigger::before{background:var(--text-color)}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:var(--text-color);text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:var(--variable-name-color);border-bottom:1px dotted var(--variable-name-color)}.kint-rich ul{list-style:none;padding-left:calc(var(--spacing)*3)}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed var(--border-color)}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 calc(var(--spacing)*3);padding-left:0;background:var(--main-background);border:var(--border);border-top:0}.kint-rich ul.kint-tabs>li{background:var(--secondary-background);border:var(--border);cursor:pointer;display:inline-block;height:calc(var(--spacing)*6);margin:calc(var(--spacing)/2);padding:0 calc(2px + var(--spacing)*2.5);vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich ul.kint-tabs>li.kint-active-tab{background:var(--main-background);border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:calc(var(--spacing)*5)}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none;contain:strict}.kint-rich ul.kint-tab-contents>li.kint-show{display:block;contain:content}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:var(--border-color-hover);color:var(--variable-type-color-hover)}.kint-rich dt>.kint-color-preview{width:var(--nav-size);height:var(--nav-size);display:inline-block;vertical-align:middle;margin-left:10px;border:var(--border);background-color:#ccc;background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="%23FFF" d="M0 0h1v2h1V1H0z"/></svg>');background-size:min(20px,100%)}.kint-rich dt>.kint-color-preview:hover{border-color:var(--border-color-hover)}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:calc(var(--spacing)/2)}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:var(--border);padding:calc(var(--spacing)/2);vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:var(--secondary-background);color:var(--variable-name-color)}.kint-rich table td{background:var(--main-background);white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 var(--border-color-hover) inset}.kint-rich table tr:hover var{color:var(--variable-type-color-hover)}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:1px solid var(--secondary-background)}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid var(--border-color-hover);padding-right:calc(var(--spacing)*2);margin-right:calc(var(--spacing)*2)}.kint-rich pre.kint-source>div.kint-highlight{background:var(--secondary-background)}.kint-rich .kint-microtime-js .kint-microtime-lap{text-shadow:-1px 0 var(--border-color-hover),0 1px var(--border-color-hover),1px 0 var(--border-color-hover),0 -1px var(--border-color-hover);color:var(--main-background);font-weight:bold}.kint-rich{--spacing: 5px;--main-background: #fdf6e3;--secondary-background: #eee8d5;--text-color: #657b83;--variable-name-color: #586e75;--variable-type-color: #268bd2;--variable-type-color-hover: #2aa198;--border-color: #93a1a1;--border-color-hover: #268bd2;--caret-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 30 150'><defs><path stroke-linejoin='round' d='M4 3a24 32 0 0 1 0 24 40 20-10 0 1 23-12A40 20 10 0 1 4 3z' id='a'/></defs><g fill='%2393a1a1' stroke='%2393a1a1'><use xlink:href='%23a'/><use xlink:href='%23a' transform='rotate(90 -15 45)'/></g><g fill='%23586e75' stroke='%23586e75' transform='translate(0 30)'><use xlink:href='%23a'/><use xlink:href='%23a' transform='rotate(90 -15 45)'/></g><path d='M6 126l18 18m-18 0l18-18' stroke-width='2' stroke='%23586e75'/></svg>")}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px var(--variable-type-color) inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint;

/**
 * @psalm-type PhpTokenArray = array{int, string, int}
 * @psalm-type PhpToken = string|PhpTokenArray
 * @psalm-type CallParameter = array{
 *   name: string,
 *   path: string,
 *   expression: bool,
 *   literal: bool,
 *   new_without_parens: bool,
 * }
 */
class CallFinder
{
    private static array $ignore = [
        T_CLOSE_TAG => true,
        T_COMMENT => true,
        T_DOC_COMMENT => true,
        T_INLINE_HTML => true,
        T_OPEN_TAG => true,
        T_OPEN_TAG_WITH_ECHO => true,
        T_WHITESPACE => true,
    ];

    /**
     * Things we need to do specially for operator tokens:
     * - Refuse to strip spaces around them
     * - Wrap the access path in parentheses if there
     *   are any of these in the final short parameter.
     */
    private static array $operator = [
        T_AND_EQUAL => true,
        T_BOOLEAN_AND => true,
        T_BOOLEAN_OR => true,
        T_ARRAY_CAST => true,
        T_BOOL_CAST => true,
        T_CLONE => true,
        T_CONCAT_EQUAL => true,
        T_DEC => true,
        T_DIV_EQUAL => true,
        T_DOUBLE_CAST => true,
        T_FUNCTION => true,
        T_INC => true,
        T_INCLUDE => true,
        T_INCLUDE_ONCE => true,
        T_INSTANCEOF => true,
        T_INT_CAST => true,
        T_IS_EQUAL => true,
        T_IS_GREATER_OR_EQUAL => true,
        T_IS_IDENTICAL => true,
        T_IS_NOT_EQUAL => true,
        T_IS_NOT_IDENTICAL => true,
        T_IS_SMALLER_OR_EQUAL => true,
        T_LOGICAL_AND => true,
        T_LOGICAL_OR => true,
        T_LOGICAL_XOR => true,
        T_MINUS_EQUAL => true,
        T_MOD_EQUAL => true,
        T_MUL_EQUAL => true,
        T_OBJECT_CAST => true,
        T_OR_EQUAL => true,
        T_PLUS_EQUAL => true,
        T_REQUIRE => true,
        T_REQUIRE_ONCE => true,
        T_SL => true,
        T_SL_EQUAL => true,
        T_SR => true,
        T_SR_EQUAL => true,
        T_STRING_CAST => true,
        T_UNSET_CAST => true,
        T_XOR_EQUAL => true,
        T_POW => true,
        T_POW_EQUAL => true,
        T_SPACESHIP => true,
        T_DOUBLE_ARROW => true,
        T_FN => true,
        T_COALESCE_EQUAL => true,
        '!' => true,
        '%' => true,
        '&' => true,
        '*' => true,
        '+' => true,
        '-' => true,
        '.' => true,
        '/' => true,
        ':' => true,
        '<' => true,
        '=' => true,
        '>' => true,
        '?' => true,
        '^' => true,
        '|' => true,
        '~' => true,
    ];

    private static array $preserve_spaces = [
        T_CLASS => true,
        T_NEW => true,
    ];

    private static array $strip = [
        '(' => true,
        ')' => true,
        '[' => true,
        ']' => true,
        '{' => true,
        '}' => true,
        T_OBJECT_OPERATOR => true,
        T_DOUBLE_COLON => true,
        T_NS_SEPARATOR => true,
    ];

    private static array $classcalls = [
        T_DOUBLE_COLON => true,
        T_OBJECT_OPERATOR => true,
    ];

    private static array $namespace = [
        T_STRING => true,
    ];

    /**
     * @psalm-param callable-string|(callable-array&list{class-string, non-empty-string}) $function
     *
     * @return array List of matching calls on the relevant line
     *
     * @psalm-return list<array{parameters: list<CallParameter>, modifiers: list<PhpToken>}>
     */
    public static function getFunctionCalls(string $source, int $line, $function): array
    {
        static $up = [
            '(' => true,
            '[' => true,
            '{' => true,
            T_CURLY_OPEN => true,
            T_DOLLAR_OPEN_CURLY_BRACES => true,
        ];
        static $down = [
            ')' => true,
            ']' => true,
            '}' => true,
        ];
        static $modifiers = [
            '!' => true,
            '@' => true,
            '~' => true,
            '+' => true,
            '-' => true,
        ];
        static $identifier = [
            T_DOUBLE_COLON => true,
            T_STRING => true,
            T_NS_SEPARATOR => true,
        ];

        if (KINT_PHP80) {
            $up[T_ATTRIBUTE] = true;
            self::$operator[T_MATCH] = true;
            self::$strip[T_NULLSAFE_OBJECT_OPERATOR] = true;
            self::$classcalls[T_NULLSAFE_OBJECT_OPERATOR] = true;
            self::$namespace[T_NAME_FULLY_QUALIFIED] = true;
            self::$namespace[T_NAME_QUALIFIED] = true;
            self::$namespace[T_NAME_RELATIVE] = true;
            $identifier[T_NAME_FULLY_QUALIFIED] = true;
            $identifier[T_NAME_QUALIFIED] = true;
            $identifier[T_NAME_RELATIVE] = true;
        }

        if (!KINT_PHP84) {
            self::$operator[T_NEW] = true; // @codeCoverageIgnore
        }

        if (KINT_PHP85) {
            /** @psalm-suppress UndefinedConstant */
            self::$operator[T_PIPE] = true;
        }

        /** @psalm-var list<PhpToken> */
        $tokens = \token_get_all($source);
        $function_calls = [];

        // Performance optimization preventing backwards loops
        /** @psalm-var array<PhpToken|null> */
        $prev_tokens = [null, null, null];

        if (\is_array($function)) {
            $class = \explode('\\', $function[0]);
            $class = \strtolower(\end($class));
            $function = \strtolower($function[1]);
        } else {
            $class = null;
            $function = \strtolower($function);
        }

        // Loop through tokens
        foreach ($tokens as $index => $token) {
            if (!\is_array($token)) {
                continue;
            }

            if ($token[2] > $line) {
                break;
            }

            // Store the last real tokens for later
            if (isset(self::$ignore[$token[0]])) {
                continue;
            }

            $prev_tokens = [$prev_tokens[1], $prev_tokens[2], $token];

            // The logic for 7.3 through 8.1 is far more complicated.
            // This should speed things up without making a lot more work for us
            if (KINT_PHP82 && $line !== $token[2]) {
                continue;
            }

            // Check if it's the right type to be the function we're looking for
            if (!isset(self::$namespace[$token[0]])) {
                continue;
            }

            $ns = \explode('\\', \strtolower($token[1]));

            if (\end($ns) !== $function) {
                continue;
            }

            // Check if it's a function call
            $nextReal = self::realTokenIndex($tokens, $index);
            if ('(' !== ($tokens[$nextReal] ?? null)) {
                continue;
            }

            // Check if it matches the signature
            if (null === $class) {
                if (null !== $prev_tokens[1] && isset(self::$classcalls[$prev_tokens[1][0]])) {
                    continue;
                }
            } else {
                if (null === $prev_tokens[1] || T_DOUBLE_COLON !== $prev_tokens[1][0]) {
                    continue;
                }

                if (null === $prev_tokens[0] || !isset(self::$namespace[$prev_tokens[0][0]])) {
                    continue;
                }

                // All self::$namespace tokens are T_ constants
                /**
                 * @psalm-var PhpTokenArray $prev_tokens[0]
                 * Psalm bug #746 (wontfix)
                 */
                $ns = \explode('\\', \strtolower($prev_tokens[0][1]));

                if (\end($ns) !== $class) {
                    continue;
                }
            }

            $last_line = $token[2];
            $depth = 1; // The depth respective to the function call
            $offset = $nextReal + 1; // The start of the function call
            $instring = false; // Whether we're in a string or not
            $realtokens = false; // Whether the current scope contains anything meaningful or not
            $paramrealtokens = false; // Whether the current parameter contains anything meaningful
            $params = []; // All our collected parameters
            $shortparam = []; // The short version of the parameter
            $param_start = $offset; // The distance to the start of the parameter
            $quote = null; // Buffer to store quote type for shortparam
            $in_ternary = false;

            // Loop through the following tokens until the function call ends
            while (isset($tokens[$offset])) {
                $token = $tokens[$offset];

                if (\is_array($token)) {
                    $last_line = $token[2];
                }

                if (!isset(self::$ignore[$token[0]]) && !isset($down[$token[0]])) {
                    $paramrealtokens = $realtokens = true;
                }

                // If it's a token that makes us to up a level, increase the depth
                if (isset($up[$token[0]])) {
                    if (1 === $depth) {
                        $shortparam[] = $token;
                        $realtokens = false;
                    }

                    ++$depth;
                } elseif (isset($down[$token[0]])) {
                    --$depth;

                    // If this brings us down to the parameter level, and we've had
                    // real tokens since going up, fill the $shortparam with an ellipsis
                    if (1 === $depth) {
                        if ($realtokens) {
                            $shortparam[] = '...';
                        }
                        $shortparam[] = $token;
                    }
                } elseif ('"' === $token || 'b"' === $token) {
                    // Strings use the same symbol for up and down, but we can
                    // only ever be inside one string, so just use a bool for that
                    if ($instring) {
                        --$depth;
                        if (1 === $depth) {
                            $shortparam[] = '...';
                        }
                    } else {
                        ++$depth;
                    }

                    $instring = !$instring;

                    $shortparam[] = $token;
                } elseif (T_START_HEREDOC === $token[0]) {
                    if (1 === $depth) {
                        $quote = \ltrim($token[1], " \t<")[0];
                        if ("'" !== $quote) {
                            $quote = '"';
                        }
                        $shortparam[] = [T_START_HEREDOC, $quote];
                        $instring = true;
                    }

                    ++$depth;
                } elseif (T_END_HEREDOC === $token[0]) {
                    --$depth;

                    if (1 === $depth) {
                        if ($realtokens) {
                            $shortparam[] = '...';
                        }
                        $shortparam[] = [T_END_HEREDOC, $quote];
                    }
                } elseif (1 === $depth) {
                    if (',' === $token[0]) {
                        $params[] = [
                            'full' => \array_slice($tokens, $param_start, $offset - $param_start),
                            'short' => $shortparam,
                        ];
                        $shortparam = [];
                        $paramrealtokens = false;
                        $in_ternary = false;
                        $param_start = $offset + 1;
                    } elseif (T_CONSTANT_ENCAPSED_STRING === $token[0]) {
                        $quote = $token[1][0];
                        if ('b' === $quote) {
                            $quote = $token[1][1];
                            if (\strlen($token[1]) > 3) {
                                $token[1] = 'b'.$quote.'...'.$quote;
                            }
                        } else {
                            if (\strlen($token[1]) > 2) {
                                $token[1] = $quote.'...'.$quote;
                            }
                        }
                        $shortparam[] = $token;
                    } else {
                        // We can't tell the order of named parameters or if they're splatting
                        // without parsing the called function and that's too much work for this
                        // edge case so we'll just skip parameters altogether.
                        if ('?' === $token) {
                            $in_ternary = true;
                        } elseif (!$in_ternary && ':' === $token) {
                            $params = [];
                            break;
                        }
                        $shortparam[] = $token;
                    }
                }

                // Depth has dropped to 0 (So we've hit the closing paren)
                if ($depth <= 0) {
                    if ($paramrealtokens) {
                        $params[] = [
                            'full' => \array_slice($tokens, $param_start, $offset - $param_start),
                            'short' => $shortparam,
                        ];
                    }

                    break;
                }

                ++$offset;
            }

            // If we're not passed (or at) the line at the end
            // of the function call, we're too early so skip it
            // Only applies to < 8.2 since we check line explicitly above that
            if (!KINT_PHP82 && $last_line < $line) {
                continue; // @codeCoverageIgnore
            }

            $formatted_parameters = [];

            // Format the final output parameters
            foreach ($params as $param) {
                $name = self::tokensFormatted($param['short']);
                $path = self::tokensToString(self::tokensTrim($param['full']));
                $expression = false;
                $literal = false;
                $new_without_parens = false;

                foreach ($name as $name_index => $token) {
                    if (KINT_PHP85 && T_CLONE === $token[0]) {
                        $nextReal = self::realTokenIndex($name, $name_index + 1);

                        if (null !== $nextReal && '(' === $name[$nextReal]) {
                            continue;
                        }
                    }

                    if (self::tokenIsOperator($token)) {
                        $expression = true;
                        break;
                    }
                }

                if (!$expression && T_START_HEREDOC === $name[0][0]) {
                    $expression = true;
                    $literal = true;
                }

                // As of 8.4 new is only an expression when parentheses are
                // omitted. In that case we can cheat and add them ourselves.
                //
                // > PHP interprets the first expression after new as a class name
                // per https://wiki.php.net/rfc/new_without_parentheses
                if (KINT_PHP84 && !$expression && T_NEW === $name[0][0]) {
                    $had_name_token = false;
                    $new_without_parens = true;

                    foreach ($name as $token) {
                        if (T_NEW === $token[0]) {
                            continue;
                        }

                        if (isset(self::$ignore[$token[0]])) {
                            continue;
                        }

                        if (T_CLASS === $token[0]) {
                            $new_without_parens = false;
                            break;
                        }

                        if ('(' === $token && $had_name_token) {
                            $new_without_parens = false;
                            break;
                        }

                        $had_name_token = true;
                    }
                }

                if (!$expression && 1 === \count($name)) {
                    switch ($name[0][0]) {
                        case T_CONSTANT_ENCAPSED_STRING:
                        case T_LNUMBER:
                        case T_DNUMBER:
                            $literal = true;
                            break;
                        case T_STRING:
                            switch (\strtolower($name[0][1])) {
                                case 'null':
                                case 'true':
                                case 'false':
                                    $literal = true;
                            }
                    }

                    $name = self::tokensToString($name);
                } else {
                    $name = self::tokensToString($name);

                    if (!$expression) {
                        switch (\strtolower($name)) {
                            case 'array()':
                            case '[]':
                                $literal = true;
                                break;
                        }
                    }
                }

                $formatted_parameters[] = [
                    'name' => $name,
                    'path' => $path,
                    'expression' => $expression,
                    'literal' => $literal,
                    'new_without_parens' => $new_without_parens,
                ];
            }

            // Skip first-class callables
            if (KINT_PHP81 && 1 === \count($formatted_parameters) && '...' === \reset($formatted_parameters)['path']) {
                continue;
            }

            // Get the modifiers
            --$index;

            while (isset($tokens[$index])) {
                if (!isset(self::$ignore[$tokens[$index][0]]) && !isset($identifier[$tokens[$index][0]])) {
                    break;
                }

                --$index;
            }

            $mods = [];

            while (isset($tokens[$index])) {
                if (isset(self::$ignore[$tokens[$index][0]])) {
                    --$index;
                    continue;
                }

                if (isset($modifiers[$tokens[$index][0]])) {
                    $mods[] = $tokens[$index];
                    --$index;
                    continue;
                }

                break;
            }

            $function_calls[] = [
                'parameters' => $formatted_parameters,
                'modifiers' => $mods,
            ];
        }

        return $function_calls;
    }

    private static function realTokenIndex(array $tokens, int $index): ?int
    {
        ++$index;

        while (isset($tokens[$index])) {
            if (!isset(self::$ignore[$tokens[$index][0]])) {
                return $index;
            }

            ++$index;
        }

        return null;
    }

    /**
     * We need a separate method to check if tokens are operators because we
     * occasionally add "..." to short parameter versions. If we simply check
     * for `$token[0]` then "..." will incorrectly match the "." operator.
     *
     * @psalm-param PhpToken $token The token to check
     */
    private static function tokenIsOperator($token): bool
    {
        return '...' !== $token && isset(self::$operator[$token[0]]);
    }

    /**
     * @psalm-param PhpToken $token The token to check
     */
    private static function tokenPreserveWhitespace($token): bool
    {
        return self::tokenIsOperator($token) || isset(self::$preserve_spaces[$token[0]]);
    }

    private static function tokensToString(array $tokens): string
    {
        $out = '';

        foreach ($tokens as $token) {
            if (\is_string($token)) {
                $out .= $token;
            } else {
                $out .= $token[1];
            }
        }

        return $out;
    }

    private static function tokensTrim(array $tokens): array
    {
        foreach ($tokens as $index => $token) {
            if (isset(self::$ignore[$token[0]])) {
                unset($tokens[$index]);
            } else {
                break;
            }
        }

        $tokens = \array_reverse($tokens);

        foreach ($tokens as $index => $token) {
            if (isset(self::$ignore[$token[0]])) {
                unset($tokens[$index]);
            } else {
                break;
            }
        }

        return \array_reverse($tokens);
    }

    /** @psalm-return list<PhpToken> */
    private static function tokensFormatted(array $tokens): array
    {
        $tokens = self::tokensTrim($tokens);

        $space = false;
        $attribute = false;
        // Keep space between "strip" symbols for different behavior for matches or closures
        // Normally we want to strip spaces between strip tokens: $x{...}[...]
        // However with closures and matches we don't: function (...) {...}
        $ignorestrip = false;
        $output = [];
        $last = null;

        if (T_FUNCTION === $tokens[0][0] ||
            T_FN === $tokens[0][0] ||
            (KINT_PHP80 && T_MATCH === $tokens[0][0])
        ) {
            $ignorestrip = true;
        }

        foreach ($tokens as $index => $token) {
            if (isset(self::$ignore[$token[0]])) {
                if ($space) {
                    continue;
                }

                $next = self::realTokenIndex($tokens, $index);
                if (null === $next) {
                    // This should be impossible, since we always call tokensTrim first
                    break; // @codeCoverageIgnore
                }
                $next = $tokens[$next];

                /**
                 * @psalm-var PhpToken $last
                 * Since we call tokensTrim we know we can't be here without a $last
                 */
                if ($attribute && ']' === $last[0]) {
                    $attribute = false;
                } elseif (!$ignorestrip && isset(self::$strip[$last[0]]) && !self::tokenPreserveWhitespace($next)) {
                    continue;
                }

                if (!$ignorestrip && isset(self::$strip[$next[0]]) && !self::tokenPreserveWhitespace($last)) {
                    continue;
                }

                $token[1] = ' ';
                $space = true;
            } else {
                if (KINT_PHP80 && null !== $last && T_ATTRIBUTE === $last[0]) {
                    $attribute = true;
                }

                $space = false;
                $last = $token;
            }

            $output[] = $token;
        }

        return $output;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint;

use Kint\Parser\Parser;
use Kint\Renderer\RendererInterface;
use Kint\Value\Context\ContextInterface;

interface FacadeInterface
{
    public function __construct(Parser $p, RendererInterface $r);

    public function setStatesFromStatics(array $statics): void;

    public function setStatesFromCallInfo(array $info): void;

    /**
     * Renders a list of vars including the pre and post renders.
     *
     * @param array              $vars Data to dump
     * @param ContextInterface[] $base The base contexts
     */
    public function dumpAll(array $vars, array $base): string;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint;

use InvalidArgumentException;
use Kint\Parser\ConstructablePluginInterface;
use Kint\Parser\Parser;
use Kint\Parser\PluginInterface;
use Kint\Renderer\ConstructableRendererInterface;
use Kint\Renderer\RendererInterface;
use Kint\Renderer\TextRenderer;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\ContextInterface;
use Kint\Value\TraceFrameValue;
use Kint\Value\UninitializedValue;

/**
 * @psalm-consistent-constructor
 * Psalm bug #8523
 *
 * @psalm-import-type CallParameter from CallFinder
 * @psalm-import-type TraceFrame from TraceFrameValue
 *
 * @psalm-type KintMode = array-key|bool
 * @psalm-type KintCallInfo = array{
 *   params: ?list<CallParameter>,
 *   modifiers: array,
 *   callee: ?callable,
 *   caller: ?callable,
 *   trace: TraceFrame[],
 * }
 *
 * @psalm-api
 */
class Kint implements FacadeInterface
{
    public const MODE_RICH = 'r';
    public const MODE_TEXT = 't';
    public const MODE_CLI = 'c';
    public const MODE_PLAIN = 'p';

    /**
     * @var mixed Kint mode
     *
     * false: Disabled
     * true: Enabled, default mode selection
     * other: Manual mode selection
     *
     * @psalm-var KintMode
     */
    public static $enabled_mode = true;

    /**
     * Default mode.
     *
     * @psalm-var KintMode
     */
    public static $mode_default = self::MODE_RICH;

    /**
     * Default mode in CLI with cli_detection on.
     *
     * @psalm-var KintMode
     */
    public static $mode_default_cli = self::MODE_CLI;

    /**
     * @var bool enable detection when Kint is command line.
     *
     * Formats output with whitespace only; does not HTML-escape it
     */
    public static bool $cli_detection = true;

    /**
     * @var bool Return output instead of echoing
     */
    public static bool $return = false;

    /**
     * @var int depth limit for array/object traversal. 0 for no limit
     */
    public static int $depth_limit = 7;

    /**
     * @var bool expand all trees by default for rich view
     */
    public static bool $expanded = false;

    /**
     * @var bool whether to display where kint was called from
     */
    public static bool $display_called_from = true;

    /**
     * @var array Kint aliases. Add debug functions in Kint wrappers here to fix modifiers and backtraces
     */
    public static array $aliases = [
        [self::class, 'dump'],
        [self::class, 'trace'],
        [self::class, 'dumpAll'],
    ];

    /**
     * @psalm-var array<RendererInterface|class-string<ConstructableRendererInterface>>
     *
     * Array of modes to renderer class names
     */
    public static array $renderers = [
        self::MODE_RICH => Renderer\RichRenderer::class,
        self::MODE_PLAIN => Renderer\PlainRenderer::class,
        self::MODE_TEXT => TextRenderer::class,
        self::MODE_CLI => Renderer\CliRenderer::class,
    ];

    /**
     * @psalm-var array<PluginInterface|class-string<ConstructablePluginInterface>>
     */
    public static array $plugins = [
        \Kint\Parser\ArrayLimitPlugin::class,
        \Kint\Parser\ArrayObjectPlugin::class,
        \Kint\Parser\Base64Plugin::class,
        \Kint\Parser\BinaryPlugin::class,
        \Kint\Parser\BlacklistPlugin::class,
        \Kint\Parser\ClassHooksPlugin::class,
        \Kint\Parser\ClassMethodsPlugin::class,
        \Kint\Parser\ClassStaticsPlugin::class,
        \Kint\Parser\ClassStringsPlugin::class,
        \Kint\Parser\ClosurePlugin::class,
        \Kint\Parser\ColorPlugin::class,
        \Kint\Parser\DateTimePlugin::class,
        \Kint\Parser\DomPlugin::class,
        \Kint\Parser\EnumPlugin::class,
        \Kint\Parser\FsPathPlugin::class,
        \Kint\Parser\HtmlPlugin::class,
        \Kint\Parser\IteratorPlugin::class,
        \Kint\Parser\JsonPlugin::class,
        \Kint\Parser\MicrotimePlugin::class,
        \Kint\Parser\MysqliPlugin::class,
        // \Kint\Parser\SerializePlugin::class,
        \Kint\Parser\SimpleXMLElementPlugin::class,
        \Kint\Parser\SplFileInfoPlugin::class,
        \Kint\Parser\StreamPlugin::class,
        \Kint\Parser\TablePlugin::class,
        \Kint\Parser\ThrowablePlugin::class,
        \Kint\Parser\TimestampPlugin::class,
        \Kint\Parser\ToStringPlugin::class,
        \Kint\Parser\TracePlugin::class,
        \Kint\Parser\XmlPlugin::class,
    ];

    protected Parser $parser;
    protected RendererInterface $renderer;

    public function __construct(Parser $p, RendererInterface $r)
    {
        $this->parser = $p;
        $this->renderer = $r;
    }

    public function setParser(Parser $p): void
    {
        $this->parser = $p;
    }

    public function getParser(): Parser
    {
        return $this->parser;
    }

    public function setRenderer(RendererInterface $r): void
    {
        $this->renderer = $r;
    }

    public function getRenderer(): RendererInterface
    {
        return $this->renderer;
    }

    public function setStatesFromStatics(array $statics): void
    {
        $this->renderer->setStatics($statics);

        $this->parser->setDepthLimit($statics['depth_limit'] ?? 0);
        $this->parser->clearPlugins();

        if (!isset($statics['plugins'])) {
            return;
        }

        $plugins = [];

        foreach ($statics['plugins'] as $plugin) {
            if ($plugin instanceof PluginInterface) {
                $plugins[] = $plugin;
            } elseif (\is_string($plugin) && \is_a($plugin, ConstructablePluginInterface::class, true)) {
                $plugins[] = new $plugin($this->parser);
            }
        }

        $plugins = $this->renderer->filterParserPlugins($plugins);

        foreach ($plugins as $plugin) {
            try {
                $this->parser->addPlugin($plugin);
            } catch (InvalidArgumentException $e) {
                \trigger_error(
                    'Plugin '.Utils::errorSanitizeString(\get_class($plugin)).' could not be added to a Kint parser: '.Utils::errorSanitizeString($e->getMessage()),
                    E_USER_WARNING
                );
            }
        }
    }

    public function setStatesFromCallInfo(array $info): void
    {
        $this->renderer->setCallInfo($info);

        if (isset($info['modifiers']) && \is_array($info['modifiers']) && \in_array('+', $info['modifiers'], true)) {
            $this->parser->setDepthLimit(0);
        }

        $this->parser->setCallerClass($info['caller']['class'] ?? null);
    }

    public function dumpAll(array $vars, array $base): string
    {
        if (\array_keys($vars) !== \array_keys($base)) {
            throw new InvalidArgumentException('Kint::dumpAll requires arrays of identical size and keys as arguments');
        }

        if ([] === $vars) {
            return $this->dumpNothing();
        }

        $output = $this->renderer->preRender();

        foreach ($vars as $key => $_) {
            if (!$base[$key] instanceof ContextInterface) {
                throw new InvalidArgumentException('Kint::dumpAll requires all elements of the second argument to be ContextInterface instances');
            }
            $output .= $this->dumpVar($vars[$key], $base[$key]);
        }

        $output .= $this->renderer->postRender();

        return $output;
    }

    protected function dumpNothing(): string
    {
        $output = $this->renderer->preRender();
        $output .= $this->renderer->render(new UninitializedValue(new BaseContext('No argument')));
        $output .= $this->renderer->postRender();

        return $output;
    }

    /**
     * Dumps and renders a var.
     *
     * @param mixed &$var Data to dump
     */
    protected function dumpVar(&$var, ContextInterface $c): string
    {
        return $this->renderer->render(
            $this->parser->parse($var, $c)
        );
    }

    /**
     * Gets all static settings at once.
     *
     * @return array Current static settings
     */
    public static function getStatics(): array
    {
        return [
            'aliases' => static::$aliases,
            'cli_detection' => static::$cli_detection,
            'depth_limit' => static::$depth_limit,
            'display_called_from' => static::$display_called_from,
            'enabled_mode' => static::$enabled_mode,
            'expanded' => static::$expanded,
            'mode_default' => static::$mode_default,
            'mode_default_cli' => static::$mode_default_cli,
            'plugins' => static::$plugins,
            'renderers' => static::$renderers,
            'return' => static::$return,
        ];
    }

    /**
     * Creates a Kint instance based on static settings.
     *
     * @param array $statics array of statics as returned by getStatics
     */
    public static function createFromStatics(array $statics): ?FacadeInterface
    {
        $mode = false;

        if (isset($statics['enabled_mode'])) {
            $mode = $statics['enabled_mode'];

            if (true === $mode && isset($statics['mode_default'])) {
                $mode = $statics['mode_default'];

                if (PHP_SAPI === 'cli' && !empty($statics['cli_detection']) && isset($statics['mode_default_cli'])) {
                    $mode = $statics['mode_default_cli'];
                }
            }
        }

        if (false === $mode) {
            return null;
        }

        $renderer = null;
        if (isset($statics['renderers'][$mode])) {
            if ($statics['renderers'][$mode] instanceof RendererInterface) {
                $renderer = $statics['renderers'][$mode];
            }

            if (\is_a($statics['renderers'][$mode], ConstructableRendererInterface::class, true)) {
                $renderer = new $statics['renderers'][$mode]();
            }
        }

        $renderer ??= new TextRenderer();

        return new static(new Parser(), $renderer);
    }

    /**
     * Creates base contexts given parameter info.
     *
     * @psalm-param list<CallParameter> $params
     *
     * @return BaseContext[] Base contexts for the arguments
     */
    public static function getBasesFromParamInfo(array $params, int $argc): array
    {
        $bases = [];

        for ($i = 0; $i < $argc; ++$i) {
            $param = $params[$i] ?? null;

            if (!empty($param['literal'])) {
                $name = 'literal';
            } else {
                $name = $param['name'] ?? '$'.$i;
            }

            if (isset($param['path'])) {
                $access_path = $param['path'];

                if ($param['expression']) {
                    $access_path = '('.$access_path.')';
                } elseif ($param['new_without_parens']) {
                    $access_path .= '()';
                }
            } else {
                $access_path = '$'.$i;
            }

            $base = new BaseContext($name);
            $base->access_path = $access_path;
            $bases[] = $base;
        }

        return $bases;
    }

    /**
     * Gets call info from the backtrace, alias, and argument count.
     *
     * Aliases must be normalized beforehand (Utils::normalizeAliases)
     *
     * @param array   $aliases Call aliases as found in Kint::$aliases
     * @param array[] $trace   Backtrace
     * @param array   $args    Arguments
     *
     * @psalm-param list<non-empty-array> $trace
     *
     * @return KintCallInfo Call info
     */
    public static function getCallInfo(array $aliases, array $trace, array $args): array
    {
        $found = false;
        $callee = null;
        $caller = null;
        $miniTrace = [];

        foreach ($trace as $frame) {
            if (Utils::traceFrameIsListed($frame, $aliases)) {
                $found = true;
                $miniTrace = [];
            }

            if (!Utils::traceFrameIsListed($frame, ['spl_autoload_call'])) {
                $miniTrace[] = $frame;
            }
        }

        if ($found) {
            $callee = \reset($miniTrace) ?: null;
            $caller = \next($miniTrace) ?: null;
        }

        foreach ($miniTrace as $index => $frame) {
            if ((0 === $index && $callee === $frame) || isset($frame['file'], $frame['line'])) {
                unset($frame['object'], $frame['args']);
                $miniTrace[$index] = $frame;
            } else {
                unset($miniTrace[$index]);
            }
        }

        $miniTrace = \array_values($miniTrace);

        $call = static::getSingleCall($callee ?: [], $args);

        $ret = [
            'params' => null,
            'modifiers' => [],
            'callee' => $callee,
            'caller' => $caller,
            'trace' => $miniTrace,
        ];

        if (null !== $call) {
            $ret['params'] = $call['parameters'];
            $ret['modifiers'] = $call['modifiers'];
        }

        return $ret;
    }

    /**
     * Dumps a backtrace.
     *
     * Functionally equivalent to Kint::dump(1) or Kint::dump(debug_backtrace(true))
     *
     * @return int|string
     */
    public static function trace()
    {
        if (false === static::$enabled_mode) {
            return 0;
        }

        static::$aliases = Utils::normalizeAliases(static::$aliases);

        $call_info = static::getCallInfo(static::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), []);

        $statics = static::getStatics();

        if (\in_array('~', $call_info['modifiers'], true)) {
            $statics['enabled_mode'] = static::MODE_TEXT;
        }

        $kintstance = static::createFromStatics($statics);
        if (!$kintstance) {
            return 0;
        }

        if (\in_array('-', $call_info['modifiers'], true)) {
            while (\ob_get_level()) {
                \ob_end_clean();
            }
        }

        $kintstance->setStatesFromStatics($statics);
        $kintstance->setStatesFromCallInfo($call_info);

        $trimmed_trace = [];
        $trace = \debug_backtrace();

        foreach ($trace as $frame) {
            if (Utils::traceFrameIsListed($frame, static::$aliases)) {
                $trimmed_trace = [];
            }

            $trimmed_trace[] = $frame;
        }

        \array_shift($trimmed_trace);

        $base = new BaseContext('Kint\\Kint::trace()');
        $base->access_path = 'debug_backtrace()';
        $output = $kintstance->dumpAll([$trimmed_trace], [$base]);

        if (static::$return || \in_array('@', $call_info['modifiers'], true)) {
            return $output;
        }

        echo $output;

        if (\in_array('-', $call_info['modifiers'], true)) {
            \flush(); // @codeCoverageIgnore
        }

        return 0;
    }

    /**
     * Dumps some data.
     *
     * Functionally equivalent to Kint::dump(1) or Kint::dump(debug_backtrace())
     *
     * @psalm-param mixed ...$args
     *
     * @return int|string
     */
    public static function dump(...$args)
    {
        if (false === static::$enabled_mode) {
            return 0;
        }

        static::$aliases = Utils::normalizeAliases(static::$aliases);

        $call_info = static::getCallInfo(static::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), $args);

        $statics = static::getStatics();

        if (\in_array('~', $call_info['modifiers'], true)) {
            $statics['enabled_mode'] = static::MODE_TEXT;
        }

        $kintstance = static::createFromStatics($statics);
        if (!$kintstance) {
            return 0;
        }

        if (\in_array('-', $call_info['modifiers'], true)) {
            while (\ob_get_level()) {
                \ob_end_clean();
            }
        }

        $kintstance->setStatesFromStatics($statics);
        $kintstance->setStatesFromCallInfo($call_info);

        $bases = static::getBasesFromParamInfo($call_info['params'] ?? [], \count($args));
        $output = $kintstance->dumpAll(\array_values($args), $bases);

        if (static::$return || \in_array('@', $call_info['modifiers'], true)) {
            return $output;
        }

        echo $output;

        if (\in_array('-', $call_info['modifiers'], true)) {
            \flush(); // @codeCoverageIgnore
        }

        return 0;
    }

    /**
     * Returns specific function call info from a stack trace frame, or null if no match could be found.
     *
     * @param array $frame The stack trace frame in question
     * @param array $args  The arguments
     *
     * @return ?array params and modifiers, or null if a specific call could not be determined
     */
    protected static function getSingleCall(array $frame, array $args): ?array
    {
        if (
            !isset($frame['file'], $frame['line'], $frame['function']) ||
            !\is_readable($frame['file']) ||
            false === ($source = \file_get_contents($frame['file']))
        ) {
            return null;
        }

        if (empty($frame['class'])) {
            $callfunc = $frame['function'];
        } else {
            $callfunc = [$frame['class'], $frame['function']];
        }

        $calls = CallFinder::getFunctionCalls($source, $frame['line'], $callfunc);

        $argc = \count($args);

        $return = null;

        foreach ($calls as $call) {
            $is_unpack = false;

            // Handle argument unpacking as a last resort
            foreach ($call['parameters'] as $i => &$param) {
                if (0 === \strpos($param['name'], '...')) {
                    $is_unpack = true;

                    // If we're on the last param
                    if ($i < $argc && $i === \count($call['parameters']) - 1) {
                        unset($call['parameters'][$i]);

                        if (Utils::isAssoc($args)) {
                            // Associated unpacked arrays can be accessed by key
                            $keys = \array_slice(\array_keys($args), $i);

                            foreach ($keys as $key) {
                                $call['parameters'][] = [
                                    'name' => ((string) \substr($param['name'], 3)).'['.\var_export($key, true).']',
                                    'path' => ((string) \substr($param['path'], 3)).'['.\var_export($key, true).']',
                                    'expression' => false,
                                    'literal' => false,
                                    'new_without_parens' => false,
                                ];
                            }
                        } else {
                            // Numeric unpacked arrays have their order blown away like a pass
                            // through array_values so we can't access them directly at all
                            for ($j = 0; $j + $i < $argc; ++$j) {
                                $call['parameters'][] = [
                                    'name' => 'array_values('.((string) \substr($param['name'], 3)).')['.$j.']',
                                    'path' => 'array_values('.((string) \substr($param['path'], 3)).')['.$j.']',
                                    'expression' => false,
                                    'literal' => false,
                                    'new_without_parens' => false,
                                ];
                            }
                        }

                        $call['parameters'] = \array_values($call['parameters']);
                    } else {
                        $call['parameters'] = \array_slice($call['parameters'], 0, $i);
                    }

                    break;
                }

                if ($i >= $argc) {
                    continue 2;
                }
            }

            if ($is_unpack || \count($call['parameters']) === $argc) {
                if (null === $return) {
                    $return = $call;
                } else {
                    // If we have multiple calls on the same line with the same amount of arguments,
                    // we can't be sure which it is so just return null and let them figure it out
                    return null;
                }
            }
        }

        return $return;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

abstract class AbstractPlugin implements ConstructablePluginInterface
{
    private Parser $parser;

    public function __construct(Parser $parser)
    {
        $this->parser = $parser;
    }

    public function setParser(Parser $p): void
    {
        $this->parser = $p;
    }

    protected function getParser(): Parser
    {
        return $this->parser;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use InvalidArgumentException;
use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\ArrayValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\ContextInterface;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\ProfileRepresentation;
use Kint\Value\Representation\ValueRepresentation;

class ArrayLimitPlugin extends AbstractPlugin implements PluginBeginInterface
{
    /**
     * Maximum size of arrays before limiting.
     */
    public static int $trigger = 1000;

    /**
     * Maximum amount of items to show in a limited array.
     */
    public static int $limit = 50;

    /**
     * Don't limit arrays with string keys.
     */
    public static bool $numeric_only = true;

    public function __construct(Parser $p)
    {
        if (self::$limit < 0) {
            throw new InvalidArgumentException('ArrayLimitPlugin::$limit can not be lower than 0');
        }

        if (self::$limit >= self::$trigger) {
            throw new InvalidArgumentException('ArrayLimitPlugin::$limit can not be lower than ArrayLimitPlugin::$trigger');
        }

        parent::__construct($p);
    }

    public function getTypes(): array
    {
        return ['array'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_BEGIN;
    }

    public function parseBegin(&$var, ContextInterface $c): ?AbstractValue
    {
        $parser = $this->getParser();
        $pdepth = $parser->getDepthLimit();

        if (!$pdepth) {
            return null;
        }

        $cdepth = $c->getDepth();

        if ($cdepth >= $pdepth - 1) {
            return null;
        }

        if (\count($var) < self::$trigger) {
            return null;
        }

        if (self::$numeric_only && Utils::isAssoc($var)) {
            return null;
        }

        $slice = \array_slice($var, 0, self::$limit, true);
        $array = $parser->parse($slice, $c);

        if (!$array instanceof ArrayValue) {
            return null;
        }

        $base = new BaseContext($c->getName());
        $base->depth = $pdepth - 1;
        $base->access_path = $c->getAccessPath();

        $slice = \array_slice($var, self::$limit, null, true);
        $slice = $parser->parse($slice, $base);

        if (!$slice instanceof ArrayValue) {
            return null;
        }

        foreach ($slice->getContents() as $child) {
            $this->replaceDepthLimit($child, $cdepth + 1);
        }

        $out = new ArrayValue($c, \count($var), \array_merge($array->getContents(), $slice->getContents()));
        $out->flags = $array->flags;

        // Explicitly copy over profile plugin
        $arrayp = $array->getRepresentation('profiling');
        $slicep = $slice->getRepresentation('profiling');
        if ($arrayp instanceof ProfileRepresentation && $slicep instanceof ProfileRepresentation) {
            $out->addRepresentation(new ProfileRepresentation($arrayp->complexity + $slicep->complexity));
        }

        // Add contents. Check is in case some bad plugin empties both $slice and $array
        if ($contents = $out->getContents()) {
            $out->addRepresentation(new ContainerRepresentation('Contents', $contents, null, true));
        }

        return $out;
    }

    protected function replaceDepthLimit(AbstractValue $v, int $depth): void
    {
        $c = $v->getContext();

        if ($c instanceof BaseContext) {
            $c->depth = $depth;
        }

        $pdepth = $this->getParser()->getDepthLimit();

        if (($v->flags & AbstractValue::FLAG_DEPTH_LIMIT) && $pdepth && $depth < $pdepth) {
            $v->flags = $v->flags & ~AbstractValue::FLAG_DEPTH_LIMIT | AbstractValue::FLAG_ARRAY_LIMIT;
        }

        $reps = $v->getRepresentations();

        foreach ($reps as $rep) {
            if ($rep instanceof ContainerRepresentation) {
                foreach ($rep->getContents() as $child) {
                    $this->replaceDepthLimit($child, $depth + 1);
                }
            } elseif ($rep instanceof ValueRepresentation) {
                $this->replaceDepthLimit($rep->getValue(), $depth + 1);
            }
        }
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use ArrayObject;
use Kint\Value\AbstractValue;
use Kint\Value\Context\ContextInterface;

class ArrayObjectPlugin extends AbstractPlugin implements PluginBeginInterface
{
    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_BEGIN;
    }

    public function parseBegin(&$var, ContextInterface $c): ?AbstractValue
    {
        if (!$var instanceof ArrayObject) {
            return null;
        }

        $flags = $var->getFlags();

        if (ArrayObject::STD_PROP_LIST === $flags) {
            return null;
        }

        $parser = $this->getParser();

        $var->setFlags(ArrayObject::STD_PROP_LIST);

        $v = $parser->parse($var, $c);

        $var->setFlags($flags);

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Representation\ValueRepresentation;
use Kint\Value\StringValue;

class Base64Plugin extends AbstractPlugin implements PluginCompleteInterface
{
    /**
     * The minimum length before a string will be considered for base64 decoding.
     */
    public static int $min_length_hard = 16;

    /**
     * The minimum length before the base64 decoding will take precedence.
     */
    public static int $min_length_soft = 50;

    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (\strlen($var) < self::$min_length_hard || \strlen($var) % 4) {
            return $v;
        }

        if (\preg_match('/^[A-Fa-f0-9]+$/', $var)) {
            return $v;
        }

        if (!\preg_match('/^[A-Za-z0-9+\\/=]+$/', $var)) {
            return $v;
        }

        $data = \base64_decode($var, true);

        if (false === $data) {
            return $v;
        }

        $c = $v->getContext();

        $base = new BaseContext('base64_decode('.$c->getName().')');
        $base->depth = $c->getDepth() + 1;

        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = 'base64_decode('.$ap.')';
        }

        $data = $this->getParser()->parse($data, $base);
        $data->flags |= AbstractValue::FLAG_GENERATED;

        if (!$data instanceof StringValue || false === $data->getEncoding()) {
            return $v;
        }

        $r = new ValueRepresentation('Base64', $data);

        if (\strlen($var) > self::$min_length_soft) {
            $v->addRepresentation($r, 0);
        } else {
            $v->addRepresentation($r);
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Representation\BinaryRepresentation;
use Kint\Value\StringValue;

class BinaryPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if ($v instanceof StringValue && false === $v->getEncoding()) {
            $v->addRepresentation(new BinaryRepresentation($v->getValue(), true), 0);
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\ContextInterface;
use Kint\Value\InstanceValue;
use Psr\Container\ContainerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;

class BlacklistPlugin extends AbstractPlugin implements PluginBeginInterface
{
    /**
     * List of classes and interfaces to blacklist.
     *
     * @var class-string[]
     */
    public static array $blacklist = [];

    /**
     * List of classes and interfaces to blacklist except when dumped directly.
     *
     * @var class-string[]
     */
    public static array $shallow_blacklist = [
        ContainerInterface::class,
        EventDispatcherInterface::class,
    ];

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_BEGIN;
    }

    public function parseBegin(&$var, ContextInterface $c): ?AbstractValue
    {
        foreach (self::$blacklist as $class) {
            if ($var instanceof $class) {
                return $this->blacklistValue($var, $c);
            }
        }

        if ($c->getDepth() <= 0) {
            return null;
        }

        foreach (self::$shallow_blacklist as $class) {
            if ($var instanceof $class) {
                return $this->blacklistValue($var, $c);
            }
        }

        return null;
    }

    /**
     * @param object &$var
     */
    protected function blacklistValue(&$var, ContextInterface $c): InstanceValue
    {
        $object = new InstanceValue($c, \get_class($var), \spl_object_hash($var), \spl_object_id($var));
        $object->flags |= AbstractValue::FLAG_BLACKLIST;

        return $object;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\MethodContext;
use Kint\Value\Context\PropertyContext;
use Kint\Value\DeclaredCallableBag;
use Kint\Value\InstanceValue;
use Kint\Value\MethodValue;
use Kint\Value\Representation\ContainerRepresentation;
use ReflectionProperty;

class ClassHooksPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public static bool $verbose = false;

    /** @psalm-var array<class-string, array<string, MethodValue[]>> */
    private array $cache = [];
    /** @psalm-var array<class-string, array<string, MethodValue[]>> */
    private array $cache_verbose = [];

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        if (!KINT_PHP84) {
            return Parser::TRIGGER_NONE; // @codeCoverageIgnore
        }

        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$v instanceof InstanceValue) {
            return $v;
        }

        $props = $v->getRepresentation('properties');

        if (!$props instanceof ContainerRepresentation) {
            return $v;
        }

        foreach ($props->getContents() as $prop) {
            $c = $prop->getContext();

            if (!$c instanceof PropertyContext || PropertyContext::HOOK_NONE === $c->hooks) {
                continue;
            }

            $cname = $c->getName();
            $cowner = $c->owner_class;

            if (!isset($this->cache_verbose[$cowner][$cname])) {
                $ref = new ReflectionProperty($cowner, $cname);
                $hooks = $ref->getHooks();

                foreach ($hooks as $hook) {
                    if (!self::$verbose && false === $hook->getDocComment()) {
                        continue;
                    }

                    $m = new MethodValue(
                        new MethodContext($hook),
                        new DeclaredCallableBag($hook)
                    );

                    $this->cache_verbose[$cowner][$cname][] = $m;

                    if (false !== $hook->getDocComment()) {
                        $this->cache[$cowner][$cname][] = $m;
                    }
                }

                $this->cache[$cowner][$cname] ??= [];

                if (self::$verbose) {
                    $this->cache_verbose[$cowner][$cname] ??= [];
                }
            }

            $cache = self::$verbose ? $this->cache_verbose : $this->cache;
            $cache = $cache[$cowner][$cname] ?? [];

            if (\count($cache)) {
                $prop->addRepresentation(new ContainerRepresentation('Hooks', $cache, 'propertyhooks'));
            }
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\MethodContext;
use Kint\Value\DeclaredCallableBag;
use Kint\Value\InstanceValue;
use Kint\Value\MethodValue;
use Kint\Value\Representation\ContainerRepresentation;
use ReflectionClass;
use ReflectionMethod;

class ClassMethodsPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public static bool $show_access_path = true;

    /**
     * Whether to go out of the way to show constructor paths
     * when the instance isn't accessible.
     *
     * Disabling this improves performance.
     */
    public static bool $show_constructor_path = false;

    /** @psalm-var array<class-string, MethodValue[]> */
    private array $instance_cache = [];

    /** @psalm-var array<class-string, MethodValue[]> */
    private array $static_cache = [];

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    /**
     * @psalm-template T of AbstractValue
     *
     * @psalm-param mixed $var
     * @psalm-param T $v
     *
     * @psalm-return T
     */
    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$v instanceof InstanceValue) {
            return $v;
        }

        $class = $v->getClassName();
        $scope = $this->getParser()->getCallerClass();

        if ($contents = $this->getCachedMethods($class)) {
            if (self::$show_access_path) {
                if (null !== $v->getContext()->getAccessPath()) {
                    // If we have an access path we can generate them for the children
                    foreach ($contents as $key => $val) {
                        if ($val->getContext()->isAccessible($scope)) {
                            $val = clone $val;
                            $val->getContext()->setAccessPathFromParent($v);
                            $contents[$key] = $val;
                        }
                    }
                } elseif (self::$show_constructor_path && isset($contents['__construct'])) {
                    // __construct is the only exception: The only non-static method
                    // that can be called without access to the parent instance.
                    // Technically I guess it really is a static method but so long
                    // as PHP continues to refer to it as a normal one so will we.
                    $val = $contents['__construct'];
                    if ($val->getContext()->isAccessible($scope)) {
                        $val = clone $val;
                        $val->getContext()->setAccessPathFromParent($v);
                        $contents['__construct'] = $val;
                    }
                }
            }

            $v->addRepresentation(new ContainerRepresentation('Methods', $contents));
        }

        if ($contents = $this->getCachedStaticMethods($class)) {
            $v->addRepresentation(new ContainerRepresentation('Static methods', $contents));
        }

        return $v;
    }

    /**
     * @psalm-param class-string $class
     *
     * @psalm-return MethodValue[]
     */
    private function getCachedMethods(string $class): array
    {
        if (!isset($this->instance_cache[$class])) {
            $methods = [];

            $r = new ReflectionClass($class);

            $parent_methods = [];
            if ($parent = \get_parent_class($class)) {
                $parent_methods = $this->getCachedMethods($parent);
            }

            foreach ($r->getMethods() as $mr) {
                if ($mr->isStatic()) {
                    continue;
                }

                $canon_name = \strtolower($mr->name);
                if ($mr->isPrivate() && '__construct' !== $canon_name) {
                    $canon_name = \strtolower($mr->getDeclaringClass()->name).'::'.$canon_name;
                }

                if ($mr->getDeclaringClass()->name === $class) {
                    $method = new MethodValue(new MethodContext($mr), new DeclaredCallableBag($mr));
                    $methods[$canon_name] = $method;
                    unset($parent_methods[$canon_name]);
                } elseif (isset($parent_methods[$canon_name])) {
                    $method = $parent_methods[$canon_name];
                    unset($parent_methods[$canon_name]);

                    if (!$method->getContext()->inherited) {
                        $method = clone $method;
                        $method->getContext()->inherited = true;
                    }

                    $methods[$canon_name] = $method;
                } elseif ($mr->getDeclaringClass()->isInterface()) {
                    $c = new MethodContext($mr);
                    $c->inherited = true;
                    $methods[$canon_name] = new MethodValue($c, new DeclaredCallableBag($mr));
                }
            }

            foreach ($parent_methods as $name => $method) {
                if (!$method->getContext()->inherited) {
                    $method = clone $method;
                    $method->getContext()->inherited = true;
                }

                if ('__construct' === $name) {
                    $methods['__construct'] = $method;
                } else {
                    $methods[] = $method;
                }
            }

            $this->instance_cache[$class] = $methods;
        }

        return $this->instance_cache[$class];
    }

    /**
     * @psalm-param class-string $class
     *
     * @psalm-return MethodValue[]
     */
    private function getCachedStaticMethods(string $class): array
    {
        if (!isset($this->static_cache[$class])) {
            $methods = [];

            $r = new ReflectionClass($class);

            $parent_methods = [];
            if ($parent = \get_parent_class($class)) {
                $parent_methods = $this->getCachedStaticMethods($parent);
            }

            foreach ($r->getMethods(ReflectionMethod::IS_STATIC) as $mr) {
                $canon_name = \strtolower($mr->getDeclaringClass()->name.'::'.$mr->name);

                if ($mr->getDeclaringClass()->name === $class) {
                    $method = new MethodValue(new MethodContext($mr), new DeclaredCallableBag($mr));
                    $methods[$canon_name] = $method;
                } elseif (isset($parent_methods[$canon_name])) {
                    $methods[$canon_name] = $parent_methods[$canon_name];
                } elseif ($mr->getDeclaringClass()->isInterface()) {
                    $c = new MethodContext($mr);
                    $c->inherited = true;
                    $methods[$canon_name] = new MethodValue($c, new DeclaredCallableBag($mr));
                }

                unset($parent_methods[$canon_name]);
            }

            $this->static_cache[$class] = $methods + $parent_methods;
        }

        return $this->static_cache[$class];
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\ClassConstContext;
use Kint\Value\Context\ClassDeclaredContext;
use Kint\Value\Context\StaticPropertyContext;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\UninitializedValue;
use ReflectionClass;
use ReflectionClassConstant;
use ReflectionProperty;
use UnitEnum;

class ClassStaticsPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    /** @psalm-var array<class-string, array<1|0, array<AbstractValue>>> */
    private array $cache = [];

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    /**
     * @psalm-template T of AbstractValue
     *
     * @psalm-param mixed $var
     * @psalm-param T $v
     *
     * @psalm-return T
     */
    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$v instanceof InstanceValue) {
            return $v;
        }

        $deep = 0 === $this->getParser()->getDepthLimit();

        $r = new ReflectionClass($v->getClassName());

        if ($statics = $this->getStatics($r, $v->getContext()->getDepth() + 1)) {
            $v->addRepresentation(new ContainerRepresentation('Static properties', \array_values($statics), 'statics'));
        }

        if ($consts = $this->getCachedConstants($r, $deep)) {
            $v->addRepresentation(new ContainerRepresentation('Class constants', \array_values($consts), 'constants'));
        }

        return $v;
    }

    /** @psalm-return array<AbstractValue> */
    private function getStatics(ReflectionClass $r, int $depth): array
    {
        $cdepth = $depth ?: 1;
        $class = $r->getName();
        $parent = $r->getParentClass();

        $parent_statics = $parent ? $this->getStatics($parent, $depth) : [];
        $statics = [];

        foreach ($r->getProperties(ReflectionProperty::IS_STATIC) as $pr) {
            $canon_name = \strtolower($pr->getDeclaringClass()->name.'::'.$pr->name);

            if ($pr->getDeclaringClass()->name === $class) {
                $statics[$canon_name] = $this->buildStaticValue($pr, $cdepth);
            } elseif (isset($parent_statics[$canon_name])) {
                $statics[$canon_name] = $parent_statics[$canon_name];
                unset($parent_statics[$canon_name]);
            } else {
                // This should never happen since abstract static properties can't exist
                $statics[$canon_name] = $this->buildStaticValue($pr, $cdepth); // @codeCoverageIgnore
            }
        }

        foreach ($parent_statics as $canon_name => $value) {
            $statics[$canon_name] = $value;
        }

        return $statics;
    }

    private function buildStaticValue(ReflectionProperty $pr, int $depth): AbstractValue
    {
        $context = new StaticPropertyContext(
            $pr->name,
            $pr->getDeclaringClass()->name,
            ClassDeclaredContext::ACCESS_PUBLIC
        );
        $context->depth = $depth;
        $context->final = KINT_PHP84 && $pr->isFinal();

        if ($pr->isProtected()) {
            $context->access = ClassDeclaredContext::ACCESS_PROTECTED;
        } elseif ($pr->isPrivate()) {
            $context->access = ClassDeclaredContext::ACCESS_PRIVATE;
        }

        $parser = $this->getParser();

        if ($context->isAccessible($parser->getCallerClass())) {
            $context->access_path = '\\'.$context->owner_class.'::$'.$context->name;
        }

        if (KINT_PHP81 === false) {
            $pr->setAccessible(true);
        }

        /**
         * @psalm-suppress TooFewArguments
         * Appears to have been fixed in master.
         */
        if (!$pr->isInitialized()) {
            $context->access_path = null;

            return new UninitializedValue($context);
        }

        $val = $pr->getValue();

        $out = $this->getParser()->parse($val, $context);
        $context->access_path = null;

        return $out;
    }

    /** @psalm-return array<AbstractValue> */
    private function getCachedConstants(ReflectionClass $r, bool $deep): array
    {
        $parser = $this->getParser();
        $cdepth = $parser->getDepthLimit() ?: 1;
        $deepkey = (int) $deep;
        $class = $r->getName();

        // Separate cache for dumping with/without depth limit
        // This means we can do immediate depth limit on normal dumps
        if (!isset($this->cache[$class][$deepkey])) {
            $consts = [];

            $parent_consts = [];
            if ($parent = $r->getParentClass()) {
                $parent_consts = $this->getCachedConstants($parent, $deep);
            }
            foreach ($r->getConstants() as $name => $val) {
                $cr = new ReflectionClassConstant($class, $name);

                // Skip enum constants
                if ($cr->class === $class && \is_a($class, UnitEnum::class, true)) {
                    continue;
                }

                $canon_name = \strtolower($cr->getDeclaringClass()->name.'::'.$name);

                if ($cr->getDeclaringClass()->name === $class) {
                    $context = $this->buildConstContext($cr);
                    $context->depth = $cdepth;

                    $consts[$canon_name] = $parser->parse($val, $context);
                    $context->access_path = null;
                } elseif (isset($parent_consts[$canon_name])) {
                    $consts[$canon_name] = $parent_consts[$canon_name];
                } else {
                    $context = $this->buildConstContext($cr);
                    $context->depth = $cdepth;

                    $consts[$canon_name] = $parser->parse($val, $context);
                    $context->access_path = null;
                }

                unset($parent_consts[$canon_name]);
            }

            $this->cache[$class][$deepkey] = $consts + $parent_consts;
        }

        return $this->cache[$class][$deepkey];
    }

    private function buildConstContext(ReflectionClassConstant $cr): ClassConstContext
    {
        $context = new ClassConstContext(
            $cr->name,
            $cr->getDeclaringClass()->name,
            ClassDeclaredContext::ACCESS_PUBLIC
        );
        $context->final = KINT_PHP81 && $cr->isFinal();

        if ($cr->isProtected()) {
            $context->access = ClassDeclaredContext::ACCESS_PROTECTED;
        } elseif ($cr->isPrivate()) {
            $context->access = ClassDeclaredContext::ACCESS_PRIVATE;
        } else {
            $context->access_path = '\\'.$context->owner_class.'::'.$context->name;
        }

        return $context;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\InstanceValue;
use ReflectionClass;

class ClassStringsPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public static array $blacklist = [];

    protected ClassMethodsPlugin $methods_plugin;
    protected ClassStaticsPlugin $statics_plugin;

    public function __construct(Parser $parser)
    {
        parent::__construct($parser);

        $this->methods_plugin = new ClassMethodsPlugin($parser);
        $this->statics_plugin = new ClassStaticsPlugin($parser);
    }

    public function setParser(Parser $p): void
    {
        parent::setParser($p);

        $this->methods_plugin->setParser($p);
        $this->statics_plugin->setParser($p);
    }

    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        $c = $v->getContext();

        if ($c->getDepth() > 0) {
            return $v;
        }

        if (!\class_exists($var, true)) {
            return $v;
        }

        if (\in_array($var, self::$blacklist, true)) {
            return $v;
        }

        $r = new ReflectionClass($var);

        $fakeC = new BaseContext($c->getName());
        $fakeC->access_path = null;
        $fakeV = new InstanceValue($fakeC, $r->getName(), 'badhash', -1);
        $fakeVar = null;

        $fakeV = $this->methods_plugin->parseComplete($fakeVar, $fakeV, Parser::TRIGGER_SUCCESS);
        $fakeV = $this->statics_plugin->parseComplete($fakeVar, $fakeV, Parser::TRIGGER_SUCCESS);

        foreach (['methods', 'static_methods', 'statics', 'constants'] as $rep) {
            if ($rep = $fakeV->getRepresentation($rep)) {
                $v->addRepresentation($rep);
            }
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Closure;
use Kint\Value\AbstractValue;
use Kint\Value\ClosureValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Representation\ContainerRepresentation;
use ReflectionFunction;
use ReflectionReference;

class ClosurePlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$var instanceof Closure) {
            return $v;
        }

        $c = $v->getContext();

        $object = new ClosureValue($c, $var);
        $object->flags = $v->flags;
        $object->appendRepresentations($v->getRepresentations());

        $object->removeRepresentation('properties');

        $closure = new ReflectionFunction($var);

        $statics = [];

        if ($v = $closure->getClosureThis()) {
            $statics = ['this' => $v];
        }

        $statics = $statics + $closure->getStaticVariables();

        $cdepth = $c->getDepth();

        if (\count($statics)) {
            $statics_parsed = [];

            $parser = $this->getParser();

            foreach ($statics as $name => $_) {
                $base = new BaseContext('$'.$name);
                $base->depth = $cdepth + 1;
                $base->reference = null !== ReflectionReference::fromArrayElement($statics, $name);
                $statics_parsed[$name] = $parser->parse($statics[$name], $base);
            }

            $object->addRepresentation(new ContainerRepresentation('Uses', $statics_parsed), 0);
        }

        return $object;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use InvalidArgumentException;
use Kint\Value\AbstractValue;
use Kint\Value\ColorValue;
use Kint\Value\Representation\ColorRepresentation;
use Kint\Value\StringValue;

class ColorPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (\strlen($var) > 32) {
            return $v;
        }

        if (!$v instanceof StringValue) {
            return $v;
        }

        $trimmed = \strtolower(\trim($var));

        if (!isset(ColorRepresentation::$color_map[$trimmed]) && !\preg_match('/^(?:(?:rgb|hsl)a?[^\\)]{6,}\\)|#[0-9a-f]{3,8})$/', $trimmed)) {
            return $v;
        }

        try {
            $rep = new ColorRepresentation($var);
        } catch (InvalidArgumentException $e) {
            return $v;
        }

        $out = new ColorValue($v->getContext(), $v->getValue(), $v->getEncoding());
        $out->flags = $v->flags;
        $out->appendRepresentations($v->getRepresentations());
        $out->removeRepresentation('contents');
        $out->addRepresentation($rep, 0);

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

interface ConstructablePluginInterface extends PluginInterface
{
    public function __construct(Parser $p);
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use DateTimeInterface;
use Error;
use Kint\Value\AbstractValue;
use Kint\Value\DateTimeValue;
use Kint\Value\InstanceValue;

class DateTimePlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$var instanceof DateTimeInterface || !$v instanceof InstanceValue) {
            return $v;
        }

        try {
            $dtv = new DateTimeValue($v->getContext(), $var);
        } catch (Error $e) {
            // Only happens if someone makes a DateTimeInterface with a private __clone
            return $v;
        }

        $dtv->setChildren($v->getChildren());
        $dtv->flags = $v->flags;
        $dtv->appendRepresentations($v->getRepresentations());

        return $dtv;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Dom\Attr;
use Dom\CharacterData;
use Dom\Document;
use Dom\DocumentType;
use Dom\Element;
use Dom\HTMLElement;
use Dom\NamedNodeMap;
use Dom\Node;
use Dom\NodeList;
use DOMAttr;
use DOMCharacterData;
use DOMDocumentType;
use DOMElement;
use DOMNamedNodeMap;
use DOMNode;
use DOMNodeList;
use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\ClassDeclaredContext;
use Kint\Value\Context\ContextInterface;
use Kint\Value\Context\PropertyContext;
use Kint\Value\DomNodeListValue;
use Kint\Value\DomNodeValue;
use Kint\Value\FixedWidthValue;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\StringValue;
use LogicException;
use ReflectionClass;

class DomPlugin extends AbstractPlugin implements PluginBeginInterface
{
    /**
     * Reflection doesn't show readonly status.
     *
     * In order to ensure this is stable enough we're only going to provide
     * properties for element and node. If subclasses like attr or document
     * have their own fields then tough shit we're not showing them.
     *
     * @psalm-var non-empty-array<string, bool> Property names to readable status
     */
    public const NODE_PROPS = [
        'nodeType' => true,
        'nodeName' => true,
        'baseURI' => true,
        'isConnected' => true,
        'ownerDocument' => true,
        'parentNode' => true,
        'parentElement' => true,
        'childNodes' => true,
        'firstChild' => true,
        'lastChild' => true,
        'previousSibling' => true,
        'nextSibling' => true,
        'nodeValue' => true,
        'textContent' => false,
    ];

    /**
     * @psalm-var non-empty-array<string, bool> Property names to readable status
     */
    public const ELEMENT_PROPS = [
        'namespaceURI' => true,
        'prefix' => true,
        'localName' => true,
        'tagName' => true,
        'id' => false,
        'className' => false,
        'classList' => true,
        'attributes' => true,
        'firstElementChild' => true,
        'lastElementChild' => true,
        'childElementCount' => true,
        'previousElementSibling' => true,
        'nextElementSibling' => true,
        'innerHTML' => false,
        'outerHTML' => true,
        'substitutedNodeValue' => false,
        'children' => true,
    ];

    /**
     * @psalm-var non-empty-array<string, bool> Property names to readable status
     */
    public const DOMNODE_PROPS = [
        'nodeName' => true,
        'nodeValue' => false,
        'nodeType' => true,
        'parentNode' => true,
        'parentElement' => true,
        'childNodes' => true,
        'firstChild' => true,
        'lastChild' => true,
        'previousSibling' => true,
        'nextSibling' => true,
        'attributes' => true,
        'isConnected' => true,
        'ownerDocument' => true,
        'namespaceURI' => true,
        'prefix' => false,
        'localName' => true,
        'baseURI' => true,
        'textContent' => false,
    ];

    /**
     * @psalm-var non-empty-array<string, bool> Property names to readable status
     */
    public const DOMELEMENT_PROPS = [
        'tagName' => true,
        'className' => false,
        'id' => false,
        'schemaTypeInfo' => true,
        'firstElementChild' => true,
        'lastElementChild' => true,
        'childElementCount' => true,
        'previousElementSibling' => true,
        'nextElementSibling' => true,
    ];

    public const DOM_VERSIONS = [
        'parentElement' => KINT_PHP83,
        'isConnected' => KINT_PHP83,
        'className' => KINT_PHP83,
        'id' => KINT_PHP83,
        'firstElementChild' => KINT_PHP80,
        'lastElementChild' => KINT_PHP80,
        'childElementCount' => KINT_PHP80,
        'previousElementSibling' => KINT_PHP80,
        'nextElementSibling' => KINT_PHP80,
    ];

    /**
     * List of properties to skip parsing.
     *
     * The properties of a Dom\Node can do a *lot* of damage to debuggers. The
     * Dom\Node contains not one, not two, but 13 different ways to recurse into itself:
     * * parentNode
     * * firstChild
     * * lastChild
     * * previousSibling
     * * nextSibling
     * * parentElement
     * * firstElementChild
     * * lastElementChild
     * * previousElementSibling
     * * nextElementSibling
     * * childNodes
     * * attributes
     * * ownerDocument
     *
     * All of this combined: the tiny SVGs used as the caret in Kint were already
     * enough to make parsing and rendering take over a second, and send memory
     * usage over 128 megs, back in the old DOM API. So we blacklist every field
     * we don't strictly need and hope that that's good enough.
     *
     * In retrospect -- this is probably why print_r does the same
     *
     * @psalm-var array<string, true>
     */
    public static array $blacklist = [
        'parentNode' => true,
        'firstChild' => true,
        'lastChild' => true,
        'previousSibling' => true,
        'nextSibling' => true,
        'firstElementChild' => true,
        'lastElementChild' => true,
        'parentElement' => true,
        'previousElementSibling' => true,
        'nextElementSibling' => true,
        'ownerDocument' => true,
    ];

    /**
     * Show all properties and methods.
     */
    public static bool $verbose = false;

    /** @psalm-var array<class-string, array<string, bool>> cache of properties for getKnownProperties */
    protected static array $property_cache = [];

    protected ClassMethodsPlugin $methods_plugin;
    protected ClassStaticsPlugin $statics_plugin;

    public function __construct(Parser $parser)
    {
        parent::__construct($parser);

        $this->methods_plugin = new ClassMethodsPlugin($parser);
        $this->statics_plugin = new ClassStaticsPlugin($parser);
    }

    public function setParser(Parser $p): void
    {
        parent::setParser($p);

        $this->methods_plugin->setParser($p);
        $this->statics_plugin->setParser($p);
    }

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_BEGIN;
    }

    public function parseBegin(&$var, ContextInterface $c): ?AbstractValue
    {
        // Attributes and chardata (Which is parent of comments and text
        // nodes) don't need children or attributes of their own
        if ($var instanceof Attr || $var instanceof CharacterData || $var instanceof DOMAttr || $var instanceof DOMCharacterData) {
            return $this->parseText($var, $c);
        }

        if ($var instanceof NamedNodeMap || $var instanceof NodeList || $var instanceof DOMNamedNodeMap || $var instanceof DOMNodeList) {
            return $this->parseList($var, $c);
        }

        if ($var instanceof Node || $var instanceof DOMNode) {
            return $this->parseNode($var, $c);
        }

        return null;
    }

    /** @psalm-param Node|DOMNode $var */
    private function parseProperty(object $var, string $prop, ContextInterface $c): AbstractValue
    {
        // Suppress deprecation message
        if (@!isset($var->{$prop})) {
            return new FixedWidthValue($c, null);
        }

        $parser = $this->getParser();
        // Suppress deprecation message
        @$value = $var->{$prop};

        if (\is_scalar($value)) {
            return $parser->parse($value, $c);
        }

        if (isset(self::$blacklist[$prop])) {
            $b = new InstanceValue($c, \get_class($value), \spl_object_hash($value), \spl_object_id($value));
            $b->flags |= AbstractValue::FLAG_GENERATED | AbstractValue::FLAG_BLACKLIST;

            return $b;
        }

        // Everything we can handle in parseBegin
        if ($value instanceof Attr || $value instanceof CharacterData || $value instanceof DOMAttr || $value instanceof DOMCharacterData || $value instanceof NamedNodeMap || $value instanceof NodeList || $value instanceof DOMNamedNodeMap || $value instanceof DOMNodeList || $value instanceof Node || $value instanceof DOMNode) {
            $out = $this->parseBegin($value, $c);
        }

        if (!isset($out)) {
            // Shouldn't ever happen
            $out = $parser->parse($value, $c); // @codeCoverageIgnore
        }

        $out->flags |= AbstractValue::FLAG_GENERATED;

        return $out;
    }

    /** @psalm-param Attr|CharacterData|DOMAttr|DOMCharacterData $var */
    private function parseText(object $var, ContextInterface $c): AbstractValue
    {
        if ($c instanceof BaseContext && null !== $c->access_path) {
            $c->access_path .= '->nodeValue';
        }

        return $this->parseProperty($var, 'nodeValue', $c);
    }

    /** @psalm-param NamedNodeMap|NodeList|DOMNamedNodeMap|DOMNodeList $var */
    private function parseList(object $var, ContextInterface $c): InstanceValue
    {
        if ($var instanceof NodeList || $var instanceof DOMNodeList) {
            $v = new DomNodeListValue($c, $var);
        } else {
            $v = new InstanceValue($c, \get_class($var), \spl_object_hash($var), \spl_object_id($var));
        }

        $parser = $this->getParser();
        $pdepth = $parser->getDepthLimit();

        // Depth limit
        // Use empty iterator representation since we need it to point out depth limits
        if (($var instanceof NodeList || $var instanceof DOMNodeList) && $pdepth && $c->getDepth() >= $pdepth) {
            $v->flags |= AbstractValue::FLAG_DEPTH_LIMIT;

            return $v;
        }

        if (self::$verbose) {
            $v = $this->methods_plugin->parseComplete($var, $v, Parser::TRIGGER_SUCCESS);
            $v = $this->statics_plugin->parseComplete($var, $v, Parser::TRIGGER_SUCCESS);
        }

        if (0 === $var->length) {
            $v->setChildren([]);

            return $v;
        }

        $cdepth = $c->getDepth();
        $ap = $c->getAccessPath();
        $contents = [];

        foreach ($var as $key => $item) {
            $base_obj = new BaseContext($item->nodeName);
            $base_obj->depth = $cdepth + 1;

            if ($var instanceof NamedNodeMap || $var instanceof DOMNamedNodeMap) {
                if (null !== $ap) {
                    $base_obj->access_path = $ap.'['.\var_export($item->nodeName, true).']';
                }
            } else { // NodeList
                if (null !== $ap) {
                    $base_obj->access_path = $ap.'['.\var_export($key, true).']';
                }
            }

            if ($item instanceof HTMLElement) {
                $base_obj->name = $item->localName;
            }

            $item = $parser->parse($item, $base_obj);
            $item->flags |= AbstractValue::FLAG_GENERATED;

            $contents[] = $item;
        }

        $v->setChildren($contents);

        if ($contents) {
            $v->addRepresentation(new ContainerRepresentation('Iterator', $contents), 0);
        }

        return $v;
    }

    /** @psalm-param Node|DOMNode $var */
    private function parseNode(object $var, ContextInterface $c): DomNodeValue
    {
        $class = \get_class($var);
        $pdepth = $this->getParser()->getDepthLimit();

        if ($pdepth && $c->getDepth() >= $pdepth) {
            $v = new DomNodeValue($c, $var);
            $v->flags |= AbstractValue::FLAG_DEPTH_LIMIT;

            return $v;
        }

        if (($var instanceof DocumentType || $var instanceof DOMDocumentType) && $c instanceof BaseContext && $c->name === $var->nodeName) {
            $c->name = '!DOCTYPE '.$c->name;
        }

        $cdepth = $c->getDepth();
        $ap = $c->getAccessPath();

        $properties = [];
        $children = [];
        $attributes = [];

        foreach (self::getKnownProperties($var) as $prop => $readonly) {
            $prop_c = new PropertyContext($prop, $class, ClassDeclaredContext::ACCESS_PUBLIC);
            $prop_c->depth = $cdepth + 1;
            $prop_c->readonly = KINT_PHP81 && $readonly;

            if (null !== $ap) {
                $prop_c->access_path = $ap.'->'.$prop;
            }

            $properties[] = $prop_obj = $this->parseProperty($var, $prop, $prop_c);

            if ('childNodes' === $prop) {
                if (!$prop_obj instanceof DomNodeListValue) {
                    throw new LogicException('childNodes property parsed incorrectly'); // @codeCoverageIgnore
                }
                $children = self::getChildren($prop_obj);
            } elseif ('attributes' === $prop) {
                $attributes = $prop_obj->getRepresentation('iterator');
                $attributes = $attributes instanceof ContainerRepresentation ? $attributes->getContents() : [];
            } elseif ('classList' === $prop) {
                if ($iter = $prop_obj->getRepresentation('iterator')) {
                    $prop_obj->removeRepresentation($iter);
                    $prop_obj->addRepresentation($iter, 0);
                }
            }
        }

        $v = new DomNodeValue($c, $var);
        // If we're in text mode, we can see children through the childNodes property
        $v->setChildren($properties);

        if ($children) {
            $v->addRepresentation(new ContainerRepresentation('Children', $children, null, true));
        }

        if ($attributes) {
            $v->addRepresentation(new ContainerRepresentation('Attributes', $attributes));
        }

        if (self::$verbose) {
            $v->addRepresentation(new ContainerRepresentation('Properties', $properties));

            $v = $this->methods_plugin->parseComplete($var, $v, Parser::TRIGGER_SUCCESS);
            $v = $this->statics_plugin->parseComplete($var, $v, Parser::TRIGGER_SUCCESS);
        }

        return $v;
    }

    /**
     * @psalm-param Node|DOMNode $var
     *
     * @psalm-return non-empty-array<string, bool>
     */
    public static function getKnownProperties(object $var): array
    {
        if (KINT_PHP81) {
            $r = new ReflectionClass($var);
            $classname = $r->getName();

            if (!isset(self::$property_cache[$classname])) {
                self::$property_cache[$classname] = [];

                foreach ($r->getProperties() as $prop) {
                    if ($prop->isStatic()) {
                        continue;
                    }

                    $declaring = $prop->getDeclaringClass()->getName();
                    $name = $prop->name;

                    if (\in_array($declaring, [Node::class, Element::class], true)) {
                        $readonly = self::NODE_PROPS[$name] ?? self::ELEMENT_PROPS[$name];
                    } elseif (\in_array($declaring, [DOMNode::class, DOMElement::class], true)) {
                        $readonly = self::DOMNODE_PROPS[$name] ?? self::DOMELEMENT_PROPS[$name];
                    } else {
                        continue;
                    }

                    self::$property_cache[$classname][$prop->name] = $readonly;
                }

                if ($var instanceof Document) {
                    self::$property_cache[$classname]['textContent'] = true;
                }

                if ($var instanceof Attr || $var instanceof CharacterData) {
                    self::$property_cache[$classname]['nodeValue'] = false;
                }
            }

            $known_properties = self::$property_cache[$classname];
        } else {
            $known_properties = self::DOMNODE_PROPS;
            if ($var instanceof DOMElement) {
                $known_properties += self::DOMELEMENT_PROPS;
            }

            foreach (self::DOM_VERSIONS as $key => $val) {
                if (false === $val) {
                    unset($known_properties[$key]); // @codeCoverageIgnore
                }
            }
        }

        /** @psalm-var non-empty-array $known_properties */
        if (!self::$verbose) {
            $known_properties = \array_intersect_key($known_properties, [
                'nodeValue' => null,
                'childNodes' => null,
                'attributes' => null,
            ]);
        }

        return $known_properties;
    }

    /** @psalm-return list<AbstractValue> */
    private static function getChildren(DomNodeListValue $property): array
    {
        if (0 === $property->getLength()) {
            return [];
        }

        if ($property->flags & AbstractValue::FLAG_DEPTH_LIMIT) {
            return [$property];
        }

        $list_items = $property->getChildren();

        if (null === $list_items) {
            // This is here for psalm but all DomNodeListValue should
            // either be depth_limit or have array children
            return []; // @codeCoverageIgnore
        }

        $children = [];

        foreach ($list_items as $node) {
            // Remove text nodes if theyre empty
            if ($node instanceof StringValue && '#text' === $node->getContext()->getName()) {
                /**
                 * @psalm-suppress InvalidArgument
                 * Psalm bug #11055
                 */
                if (\ctype_space($node->getValue()) || '' === $node->getValue()) {
                    continue;
                }
            }

            $children[] = $node;
        }

        return $children;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\EnumValue;
use Kint\Value\Representation\ContainerRepresentation;
use UnitEnum;

class EnumPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    private array $cache = [];

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        if (!KINT_PHP81) {
            return Parser::TRIGGER_NONE;
        }

        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$var instanceof UnitEnum) {
            return $v;
        }

        $c = $v->getContext();
        $class = \get_class($var);

        if (!isset($this->cache[$class])) {
            $contents = [];

            foreach ($var->cases() as $case) {
                $base = new BaseContext($case->name);
                $base->access_path = '\\'.$class.'::'.$case->name;
                $base->depth = $c->getDepth() + 1;
                $contents[] = new EnumValue($base, $case);
            }

            /** @psalm-var non-empty-array<EnumValue> $contents */
            $this->cache[$class] = new ContainerRepresentation('Enum values', $contents, 'enum');
        }

        $object = new EnumValue($c, $var);
        $object->flags = $v->flags;
        $object->appendRepresentations($v->getRepresentations());
        $object->addRepresentation($this->cache[$class], 0);

        return $object;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Representation\SplFileInfoRepresentation;
use SplFileInfo;
use TypeError;

class FsPathPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public static array $blacklist = ['/', '.'];

    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (\strlen($var) > 2048) {
            return $v;
        }

        if (!\preg_match('/[\\/\\'.DIRECTORY_SEPARATOR.']/', $var)) {
            return $v;
        }

        if (\preg_match('/[?<>"*|]/', $var)) {
            return $v;
        }

        try {
            if (!@\file_exists($var)) {
                return $v;
            }
        } catch (TypeError $e) {// @codeCoverageIgnore
            // Only possible in PHP 7
            return $v; // @codeCoverageIgnore
        }

        if (\in_array($var, self::$blacklist, true)) {
            return $v;
        }

        $v->addRepresentation(new SplFileInfoRepresentation(new SplFileInfo($var)), 0);

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Dom\HTMLDocument;
use DOMException;
use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\ValueRepresentation;

class HtmlPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        if (!KINT_PHP84) {
            return Parser::TRIGGER_NONE; // @codeCoverageIgnore
        }

        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if ('<!doctype html>' !== \strtolower((string) \substr($var, 0, 15))) {
            return $v;
        }

        try {
            $html = HTMLDocument::createFromString($var, LIBXML_NOERROR);
        } catch (DOMException $e) { // @codeCoverageIgnore
            return $v; // @codeCoverageIgnore
        }

        $c = $v->getContext();

        $base = new BaseContext('childNodes');
        $base->depth = $c->getDepth();

        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = '\\Dom\\HTMLDocument::createFromString('.$ap.')->childNodes';
        }

        $out = $this->getParser()->parse($html->childNodes, $base);
        $iter = $out->getRepresentation('iterator');

        if ($out->flags & AbstractValue::FLAG_DEPTH_LIMIT) {
            $out->flags |= AbstractValue::FLAG_GENERATED;
            $v->addRepresentation(new ValueRepresentation('HTML', $out), 0);
        } elseif ($iter instanceof ContainerRepresentation) {
            $v->addRepresentation(new ContainerRepresentation('HTML', $iter->getContents()), 0);
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Dom\NamedNodeMap;
use Dom\NodeList;
use DOMNamedNodeMap;
use DOMNodeList;
use Kint\Value\AbstractValue;
use Kint\Value\ArrayValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\ValueRepresentation;
use Kint\Value\UninitializedValue;
use mysqli_result;
use PDOStatement;
use SimpleXMLElement;
use SplFileObject;
use Throwable;
use Traversable;

class IteratorPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    /**
     * List of classes and interfaces to blacklist.
     *
     * Certain classes (Such as PDOStatement) irreversibly lose information
     * when traversed. Others are just huge. Either way, put them in here
     * and you won't have to worry about them being parsed.
     *
     * @psalm-var class-string[]
     */
    public static array $blacklist = [
        NamedNodeMap::class,
        NodeList::class,
        DOMNamedNodeMap::class,
        DOMNodeList::class,
        mysqli_result::class,
        PDOStatement::class,
        SimpleXMLElement::class,
        SplFileObject::class,
    ];

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$var instanceof Traversable || !$v instanceof InstanceValue || $v->getRepresentation('iterator')) {
            return $v;
        }

        $c = $v->getContext();

        foreach (self::$blacklist as $class) {
            if ($var instanceof $class) {
                $base = new BaseContext($class.' Iterator Contents');
                $base->depth = $c->getDepth() + 1;
                if (null !== ($ap = $c->getAccessPath())) {
                    $base->access_path = 'iterator_to_array('.$ap.', false)';
                }

                $b = new UninitializedValue($base);
                $b->flags |= AbstractValue::FLAG_BLACKLIST;

                $v->addRepresentation(new ValueRepresentation('Iterator', $b));

                return $v;
            }
        }

        try {
            $data = \iterator_to_array($var, false);
        } catch (Throwable $t) {
            return $v;
        }

        if (!\count($data)) {
            return $v;
        }

        $base = new BaseContext('Iterator Contents');
        $base->depth = $c->getDepth();
        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = 'iterator_to_array('.$ap.', false)';
        }

        $iter_val = $this->getParser()->parse($data, $base);

        // Since we didn't get TRIGGER_DEPTH_LIMIT and set the iterator to the
        // same depth we can assume at least 1 level deep will exist
        if ($iter_val instanceof ArrayValue && $iterator_items = $iter_val->getContents()) {
            $r = new ContainerRepresentation('Iterator', $iterator_items);
            $iterator_items = \array_values($iterator_items);
        } else {
            $r = new ValueRepresentation('Iterator', $iter_val);
            $iterator_items = [$iter_val];
        }

        if ((bool) $v->getChildren()) {
            $v->addRepresentation($r);
        } else {
            $v->setChildren($iterator_items);
            $v->addRepresentation($r, 0);
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use JsonException;
use Kint\Value\AbstractValue;
use Kint\Value\ArrayValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\ValueRepresentation;

class JsonPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!isset($var[0]) || ('{' !== $var[0] && '[' !== $var[0])) {
            return $v;
        }

        try {
            $json = \json_decode($var, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException $e) {
            return $v;
        }

        $json = (array) $json;

        $c = $v->getContext();

        $base = new BaseContext('JSON Decode');
        $base->depth = $c->getDepth();

        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = 'json_decode('.$ap.', true)';
        }

        $json = $this->getParser()->parse($json, $base);

        if ($json instanceof ArrayValue && (~$json->flags & AbstractValue::FLAG_DEPTH_LIMIT) && $contents = $json->getContents()) {
            foreach ($contents as $value) {
                $value->flags |= AbstractValue::FLAG_GENERATED;
            }
            $v->addRepresentation(new ContainerRepresentation('Json', $contents), 0);
        } else {
            $json->flags |= AbstractValue::FLAG_GENERATED;
            $v->addRepresentation(new ValueRepresentation('Json', $json), 0);
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\MicrotimeValue;
use Kint\Value\Representation\MicrotimeRepresentation;

class MicrotimePlugin extends AbstractPlugin implements PluginCompleteInterface
{
    private static ?array $last = null;
    private static ?float $start = null;
    private static int $times = 0;
    private static ?string $group = null;

    public function getTypes(): array
    {
        return ['string', 'double'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        $c = $v->getContext();

        if ($c->getDepth() > 0) {
            return $v;
        }

        if (\is_string($var)) {
            if ('microtime()' !== $c->getName() || !\preg_match('/^0\\.[0-9]{8} [0-9]{10}$/', $var)) {
                return $v;
            }

            $usec = (int) \substr($var, 2, 6);
            $sec = (int) \substr($var, 11, 10);
        } else {
            if ('microtime(...)' !== $c->getName()) {
                return $v;
            }

            $sec = (int) \floor($var);
            $usec = $var - $sec;
            $usec = (int) \floor($usec * 1000000);
        }

        $time = $sec + ($usec / 1000000);

        if (null !== self::$last) {
            $last_time = self::$last[0] + (self::$last[1] / 1000000);
            $lap = $time - $last_time;
            ++self::$times;
        } else {
            $lap = null;
            self::$start = $time;
        }

        self::$last = [$sec, $usec];

        if (null !== $lap) {
            $total = $time - self::$start;
            $r = new MicrotimeRepresentation($sec, $usec, self::getGroup(), $lap, $total, self::$times);
        } else {
            $r = new MicrotimeRepresentation($sec, $usec, self::getGroup());
        }

        $out = new MicrotimeValue($v);
        $out->removeRepresentation('contents');
        $out->addRepresentation($r);

        return $out;
    }

    /** @psalm-api */
    public static function clean(): void
    {
        self::$last = null;
        self::$start = null;
        self::$times = 0;
        self::newGroup();
    }

    private static function getGroup(): string
    {
        if (null === self::$group) {
            return self::newGroup();
        }

        return self::$group;
    }

    private static function newGroup(): string
    {
        return self::$group = \bin2hex(\random_bytes(4));
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\PropertyContext;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\ContainerRepresentation;
use mysqli;
use Throwable;

/**
 * Adds support for mysqli object parsing.
 *
 * Due to the way mysqli is implemented in PHP, this will cause
 * warnings on certain mysqli objects if screaming is enabled.
 */
class MysqliPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    // These 'properties' are actually globals
    public const ALWAYS_READABLE = [
        'client_version' => true,
        'connect_errno' => true,
        'connect_error' => true,
    ];

    // These are readable on empty mysqli objects, but not on failed connections
    public const EMPTY_READABLE = [
        'client_info' => true,
        'errno' => true,
        'error' => true,
    ];

    // These are only readable on connected mysqli objects
    public const CONNECTED_READABLE = [
        'affected_rows' => true,
        'error_list' => true,
        'field_count' => true,
        'host_info' => true,
        'info' => true,
        'insert_id' => true,
        'server_info' => true,
        'server_version' => true,
        'sqlstate' => true,
        'protocol_version' => true,
        'thread_id' => true,
        'warning_count' => true,
    ];

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_COMPLETE;
    }

    /**
     * Before 8.1: Properties were nulls when cast to array
     * After 8.1: Properties are readonly and uninitialized when cast to array (Aka missing).
     */
    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$var instanceof mysqli || !$v instanceof InstanceValue) {
            return $v;
        }

        $props = $v->getRepresentation('properties');

        if (!$props instanceof ContainerRepresentation) {
            return $v;
        }

        /**
         * @psalm-var ?string $var->sqlstate
         * @psalm-var ?string $var->client_info
         * Psalm bug #4502
         */
        try {
            $connected = \is_string(@$var->sqlstate);
        } catch (Throwable $t) {
            $connected = false;
        }

        try {
            $empty = !$connected && \is_string(@$var->client_info);
        } catch (Throwable $t) { // @codeCoverageIgnore
            // Only possible in PHP 8.0. Before 8.0 there's no exception,
            // after 8.1 there are no failed connection objects
            $empty = false; // @codeCoverageIgnore
        }

        $parser = $this->getParser();

        $new_contents = [];

        foreach ($props->getContents() as $key => $obj) {
            $new_contents[$key] = $obj;

            $c = $obj->getContext();

            if (!$c instanceof PropertyContext) {
                continue;
            }

            if (isset(self::CONNECTED_READABLE[$c->getName()])) {
                $c->readonly = KINT_PHP81;
                if (!$connected) {
                    // No failed connections after PHP 8.1
                    continue; // @codeCoverageIgnore
                }
            } elseif (isset(self::EMPTY_READABLE[$c->getName()])) {
                $c->readonly = KINT_PHP81;
                // No failed connections after PHP 8.1
                if (!$connected && !$empty) { // @codeCoverageIgnore
                    continue; // @codeCoverageIgnore
                }
            } elseif (!isset(self::ALWAYS_READABLE[$c->getName()])) {
                continue; // @codeCoverageIgnore
            }

            $c->readonly = KINT_PHP81;

            // Only handle unparsed properties
            if ((KINT_PHP81 ? 'uninitialized' : 'null') !== $obj->getType()) {
                continue;
            }

            $param = $var->{$c->getName()};

            // If it really was a null
            if (!KINT_PHP81 && null === $param) {
                continue; // @codeCoverageIgnore
            }

            $new_contents[$key] = $parser->parse($param, $c);
        }

        $new_contents = \array_values($new_contents);

        $v->setChildren($new_contents);

        if ($new_contents) {
            $v->replaceRepresentation(new ContainerRepresentation('Properties', $new_contents));
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use DomainException;
use InvalidArgumentException;
use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\ArrayValue;
use Kint\Value\ClosedResourceValue;
use Kint\Value\Context\ArrayContext;
use Kint\Value\Context\ClassDeclaredContext;
use Kint\Value\Context\ClassOwnedContext;
use Kint\Value\Context\ContextInterface;
use Kint\Value\Context\PropertyContext;
use Kint\Value\FixedWidthValue;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\StringRepresentation;
use Kint\Value\ResourceValue;
use Kint\Value\StringValue;
use Kint\Value\UninitializedValue;
use Kint\Value\UnknownValue;
use Kint\Value\VirtualValue;
use ReflectionClass;
use ReflectionObject;
use ReflectionProperty;
use ReflectionReference;
use Throwable;

/**
 * @psalm-type ParserTrigger int-mask-of<Parser::TRIGGER_*>
 */
class Parser
{
    /**
     * Plugin triggers.
     *
     * These are constants indicating trigger points for plugins
     *
     * BEGIN: Before normal parsing
     * SUCCESS: After successful parsing
     * RECURSION: After parsing cancelled by recursion
     * DEPTH_LIMIT: After parsing cancelled by depth limit
     * COMPLETE: SUCCESS | RECURSION | DEPTH_LIMIT
     *
     * While a plugin's getTriggers may return any of these only one should
     * be given to the plugin when PluginInterface::parse is called
     */
    public const TRIGGER_NONE = 0;
    public const TRIGGER_BEGIN = 1 << 0;
    public const TRIGGER_SUCCESS = 1 << 1;
    public const TRIGGER_RECURSION = 1 << 2;
    public const TRIGGER_DEPTH_LIMIT = 1 << 3;
    public const TRIGGER_COMPLETE = self::TRIGGER_SUCCESS | self::TRIGGER_RECURSION | self::TRIGGER_DEPTH_LIMIT;

    /** @psalm-var ?class-string */
    protected ?string $caller_class;
    protected int $depth_limit = 0;
    protected array $array_ref_stack = [];
    protected array $object_hashes = [];
    protected array $plugins = [];

    /**
     * @param int     $depth_limit Maximum depth to parse data
     * @param ?string $caller      Caller class name
     *
     * @psalm-param ?class-string $caller
     */
    public function __construct(int $depth_limit = 0, ?string $caller = null)
    {
        $this->depth_limit = $depth_limit;
        $this->caller_class = $caller;
    }

    /**
     * Set the caller class.
     *
     * @psalm-param ?class-string $caller
     */
    public function setCallerClass(?string $caller = null): void
    {
        $this->noRecurseCall();

        $this->caller_class = $caller;
    }

    /** @psalm-return ?class-string */
    public function getCallerClass(): ?string
    {
        return $this->caller_class;
    }

    /**
     * Set the depth limit.
     *
     * @param int $depth_limit Maximum depth to parse data, 0 for none
     */
    public function setDepthLimit(int $depth_limit = 0): void
    {
        $this->noRecurseCall();

        $this->depth_limit = $depth_limit;
    }

    public function getDepthLimit(): int
    {
        return $this->depth_limit;
    }

    /**
     * Parses a variable into a Kint object structure.
     *
     * @param mixed &$var The input variable
     */
    public function parse(&$var, ContextInterface $c): AbstractValue
    {
        $type = \strtolower(\gettype($var));

        if ($v = $this->applyPluginsBegin($var, $c, $type)) {
            return $v;
        }

        switch ($type) {
            case 'array':
                return $this->parseArray($var, $c);
            case 'boolean':
            case 'double':
            case 'integer':
            case 'null':
                return $this->parseFixedWidth($var, $c);
            case 'object':
                return $this->parseObject($var, $c);
            case 'resource':
                return $this->parseResource($var, $c);
            case 'string':
                return $this->parseString($var, $c);
            case 'resource (closed)':
                return $this->parseResourceClosed($var, $c);

            case 'unknown type': // @codeCoverageIgnore
            default:
                // These should never happen. Unknown is resource (closed) from old
                // PHP versions and there shouldn't be any other types.
                return $this->parseUnknown($var, $c); // @codeCoverageIgnore
        }
    }

    public function addPlugin(PluginInterface $p): void
    {
        try {
            $this->noRecurseCall();
        } catch (DomainException $e) { // @codeCoverageIgnore
            \trigger_error('Calling Kint\\Parser::addPlugin from inside a parse is deprecated', E_USER_DEPRECATED); // @codeCoverageIgnore
        }

        if (!$types = $p->getTypes()) {
            return;
        }

        if (!$triggers = $p->getTriggers()) {
            return;
        }

        if ($triggers & self::TRIGGER_BEGIN && !$p instanceof PluginBeginInterface) {
            throw new InvalidArgumentException('Parsers triggered on begin must implement PluginBeginInterface');
        }

        if ($triggers & self::TRIGGER_COMPLETE && !$p instanceof PluginCompleteInterface) {
            throw new InvalidArgumentException('Parsers triggered on completion must implement PluginCompleteInterface');
        }

        $p->setParser($this);

        foreach ($types as $type) {
            $this->plugins[$type] ??= [
                self::TRIGGER_BEGIN => [],
                self::TRIGGER_SUCCESS => [],
                self::TRIGGER_RECURSION => [],
                self::TRIGGER_DEPTH_LIMIT => [],
            ];

            foreach ($this->plugins[$type] as $trigger => &$pool) {
                if ($triggers & $trigger) {
                    $pool[] = $p;
                }
            }
        }
    }

    public function clearPlugins(): void
    {
        try {
            $this->noRecurseCall();
        } catch (DomainException $e) { // @codeCoverageIgnore
            \trigger_error('Calling Kint\\Parser::clearPlugins from inside a parse is deprecated', E_USER_DEPRECATED); // @codeCoverageIgnore
        }

        $this->plugins = [];
    }

    protected function noRecurseCall(): void
    {
        $bt = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS);

        \reset($bt);
        /** @psalm-var array{class: class-string, function: string, ...} $caller_frame */
        $caller_frame = \next($bt);

        foreach ($bt as $frame) {
            if (isset($frame['object']) && $frame['object'] === $this && 'parse' === $frame['function']) {
                throw new DomainException($caller_frame['class'].'::'.$caller_frame['function'].' cannot be called from inside a parse');
            }
        }
    }

    /**
     * @psalm-param null|bool|float|int &$var
     */
    private function parseFixedWidth(&$var, ContextInterface $c): AbstractValue
    {
        $v = new FixedWidthValue($c, $var);

        return $this->applyPluginsComplete($var, $v, self::TRIGGER_SUCCESS);
    }

    private function parseString(string &$var, ContextInterface $c): AbstractValue
    {
        $string = new StringValue($c, $var, Utils::detectEncoding($var));

        if (false !== $string->getEncoding() && \strlen($var)) {
            $string->addRepresentation(new StringRepresentation('Contents', $var, null, true));
        }

        return $this->applyPluginsComplete($var, $string, self::TRIGGER_SUCCESS);
    }

    private function parseArray(array &$var, ContextInterface $c): AbstractValue
    {
        $size = \count($var);
        $contents = [];
        $parentRef = ReflectionReference::fromArrayElement([&$var], 0)->getId();

        if (isset($this->array_ref_stack[$parentRef])) {
            $array = new ArrayValue($c, $size, $contents);
            $array->flags |= AbstractValue::FLAG_RECURSION;

            return $this->applyPluginsComplete($var, $array, self::TRIGGER_RECURSION);
        }

        try {
            $this->array_ref_stack[$parentRef] = true;

            $cdepth = $c->getDepth();
            $ap = $c->getAccessPath();

            if ($size > 0 && $this->depth_limit && $cdepth >= $this->depth_limit) {
                $array = new ArrayValue($c, $size, $contents);
                $array->flags |= AbstractValue::FLAG_DEPTH_LIMIT;

                return $this->applyPluginsComplete($var, $array, self::TRIGGER_DEPTH_LIMIT);
            }

            foreach ($var as $key => $_) {
                $child = new ArrayContext($key);
                $child->depth = $cdepth + 1;
                $child->reference = null !== ReflectionReference::fromArrayElement($var, $key);

                if (null !== $ap) {
                    $child->access_path = $ap.'['.\var_export($key, true).']';
                }

                $contents[$key] = $this->parse($var[$key], $child);
            }

            $array = new ArrayValue($c, $size, $contents);

            if ($contents) {
                $array->addRepresentation(new ContainerRepresentation('Contents', $contents, null, true));
            }

            return $this->applyPluginsComplete($var, $array, self::TRIGGER_SUCCESS);
        } finally {
            unset($this->array_ref_stack[$parentRef]);
        }
    }

    /**
     * @psalm-return ReflectionProperty[]
     */
    private function getPropsOrdered(ReflectionClass $r): array
    {
        if ($parent = $r->getParentClass()) {
            $props = self::getPropsOrdered($parent);
        } else {
            $props = [];
        }

        foreach ($r->getProperties() as $prop) {
            if ($prop->isStatic()) {
                continue;
            }

            if ($prop->isPrivate()) {
                $props[] = $prop;
            } else {
                $props[$prop->name] = $prop;
            }
        }

        return $props;
    }

    /**
     * @codeCoverageIgnore
     *
     * @psalm-return ReflectionProperty[]
     */
    private function getPropsOrderedOld(ReflectionClass $r): array
    {
        $props = [];

        foreach ($r->getProperties() as $prop) {
            if ($prop->isStatic()) {
                continue;
            }

            $props[] = $prop;
        }

        while ($r = $r->getParentClass()) {
            foreach ($r->getProperties(ReflectionProperty::IS_PRIVATE) as $prop) {
                if ($prop->isStatic()) {
                    continue;
                }

                $props[] = $prop;
            }
        }

        return $props;
    }

    private function parseObject(object &$var, ContextInterface $c): AbstractValue
    {
        $hash = \spl_object_hash($var);
        $classname = \get_class($var);

        if (isset($this->object_hashes[$hash])) {
            $object = new InstanceValue($c, $classname, $hash, \spl_object_id($var));
            $object->flags |= AbstractValue::FLAG_RECURSION;

            return $this->applyPluginsComplete($var, $object, self::TRIGGER_RECURSION);
        }

        try {
            $this->object_hashes[$hash] = true;

            $cdepth = $c->getDepth();
            $ap = $c->getAccessPath();

            if ($this->depth_limit && $cdepth >= $this->depth_limit) {
                $object = new InstanceValue($c, $classname, $hash, \spl_object_id($var));
                $object->flags |= AbstractValue::FLAG_DEPTH_LIMIT;

                return $this->applyPluginsComplete($var, $object, self::TRIGGER_DEPTH_LIMIT);
            }

            if (KINT_PHP81) {
                $props = $this->getPropsOrdered(new ReflectionObject($var));
            } else {
                $props = $this->getPropsOrderedOld(new ReflectionObject($var)); // @codeCoverageIgnore
            }

            $values = (array) $var;
            $properties = [];

            foreach ($props as $rprop) {
                if (KINT_PHP81 === false) {
                    $rprop->setAccessible(true);
                }

                $name = $rprop->getName();

                // Casting object to array:
                // private properties show in the form "\0$owner_class_name\0$property_name";
                // protected properties show in the form "\0*\0$property_name";
                // public properties show in the form "$property_name";
                // http://www.php.net/manual/en/language.types.array.php#language.types.array.casting
                $key = $name;
                if ($rprop->isProtected()) {
                    $key = "\0*\0".$name;
                } elseif ($rprop->isPrivate()) {
                    $key = "\0".$rprop->getDeclaringClass()->getName()."\0".$name;
                }
                $initialized = \array_key_exists($key, $values);
                if ($key === (string) (int) $key) {
                    $key = (int) $key;
                }

                if ($rprop->isDefault()) {
                    $child = new PropertyContext(
                        $name,
                        $rprop->getDeclaringClass()->getName(),
                        ClassDeclaredContext::ACCESS_PUBLIC
                    );

                    $child->readonly = KINT_PHP81 && $rprop->isReadOnly();

                    if ($rprop->isProtected()) {
                        $child->access = ClassDeclaredContext::ACCESS_PROTECTED;
                    } elseif ($rprop->isPrivate()) {
                        $child->access = ClassDeclaredContext::ACCESS_PRIVATE;
                    }

                    if (KINT_PHP84) {
                        if ($rprop->isProtectedSet()) {
                            $child->access_set = ClassDeclaredContext::ACCESS_PROTECTED;
                        } elseif ($rprop->isPrivateSet()) {
                            $child->access_set = ClassDeclaredContext::ACCESS_PRIVATE;
                        }

                        $hooks = $rprop->getHooks();
                        if (isset($hooks['get'])) {
                            $child->hooks |= PropertyContext::HOOK_GET;
                            if ($hooks['get']->returnsReference()) {
                                $child->hooks |= PropertyContext::HOOK_GET_REF;
                            }
                        }
                        if (isset($hooks['set'])) {
                            $child->hooks |= PropertyContext::HOOK_SET;

                            $child->hook_set_type = (string) $rprop->getSettableType();
                            if ($child->hook_set_type !== (string) $rprop->getType()) {
                                $child->hooks |= PropertyContext::HOOK_SET_TYPE;
                            } elseif ('' === $child->hook_set_type) {
                                $child->hook_set_type = null;
                            }
                        }
                    }

                    if (KINT_PHP8412) {
                        $proto_prop = $rprop;
                        while (($parent_class = $proto_prop->getDeclaringClass()->getParentClass()) &&
                            $parent_class->hasProperty($name) &&
                            ($parent_prop = $parent_class->getProperty($name)) &&
                            !$parent_prop->isPrivate()) {
                            $proto_prop = $parent_prop;
                        }

                        $proto_class = $proto_prop->getDeclaringClass()->getName();
                        if ($proto_class !== $child->owner_class) {
                            $child->proto_class = $proto_prop->getDeclaringClass()->getName();
                        }
                    }
                } else {
                    $child = new ClassOwnedContext($name, $rprop->getDeclaringClass()->getName());
                }

                $child->reference = $initialized && null !== ReflectionReference::fromArrayElement($values, $key);
                $child->depth = $cdepth + 1;

                if (null !== $ap && $child->isAccessible($this->caller_class)) {
                    /** @psalm-var string $child->name */
                    if (Utils::isValidPhpName($child->name)) {
                        $child->access_path = $ap.'->'.$child->name;
                    } else {
                        $child->access_path = $ap.'->{'.\var_export($child->name, true).'}';
                    }
                }

                if (KINT_PHP84 && $rprop->isVirtual()) {
                    $properties[] = new VirtualValue($child);
                } elseif (!$initialized) {
                    $properties[] = new UninitializedValue($child);
                } else {
                    $properties[] = $this->parse($values[$key], $child);
                }
            }

            $object = new InstanceValue($c, $classname, $hash, \spl_object_id($var));
            if ($props) {
                $object->setChildren($properties);
            }

            if ($properties) {
                $object->addRepresentation(new ContainerRepresentation('Properties', $properties));
            }

            return $this->applyPluginsComplete($var, $object, self::TRIGGER_SUCCESS);
        } finally {
            unset($this->object_hashes[$hash]);
        }
    }

    /**
     * @psalm-param resource $var
     */
    private function parseResource(&$var, ContextInterface $c): AbstractValue
    {
        $resource = new ResourceValue($c, \get_resource_type($var));

        $resource = $this->applyPluginsComplete($var, $resource, self::TRIGGER_SUCCESS);

        return $resource;
    }

    /**
     * @psalm-param mixed $var
     */
    private function parseResourceClosed(&$var, ContextInterface $c): AbstractValue
    {
        $v = new ClosedResourceValue($c);

        $v = $this->applyPluginsComplete($var, $v, self::TRIGGER_SUCCESS);

        return $v;
    }

    /**
     * Catch-all for any unexpectedgettype.
     *
     * This should never happen.
     *
     * @codeCoverageIgnore
     *
     * @psalm-param mixed $var
     */
    private function parseUnknown(&$var, ContextInterface $c): AbstractValue
    {
        $v = new UnknownValue($c);

        $v = $this->applyPluginsComplete($var, $v, self::TRIGGER_SUCCESS);

        return $v;
    }

    /**
     * Applies plugins for a yet-unparsed value.
     *
     * @param mixed &$var The input variable
     */
    private function applyPluginsBegin(&$var, ContextInterface $c, string $type): ?AbstractValue
    {
        $plugins = $this->plugins[$type][self::TRIGGER_BEGIN] ?? [];

        foreach ($plugins as $plugin) {
            try {
                if ($v = $plugin->parseBegin($var, $c)) {
                    return $v;
                }
            } catch (Throwable $e) {
                \trigger_error(
                    Utils::errorSanitizeString(\get_class($e)).' was thrown in '.$e->getFile().' on line '.$e->getLine().' while executing '.Utils::errorSanitizeString(\get_class($plugin)).'->parseBegin. Error message: '.Utils::errorSanitizeString($e->getMessage()),
                    E_USER_WARNING
                );
            }
        }

        return null;
    }

    /**
     * Applies plugins for a parsed AbstractValue.
     *
     * @param mixed &$var The input variable
     */
    private function applyPluginsComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        $plugins = $this->plugins[$v->getType()][$trigger] ?? [];

        foreach ($plugins as $plugin) {
            try {
                $v = $plugin->parseComplete($var, $v, $trigger);
            } catch (Throwable $e) {
                \trigger_error(
                    Utils::errorSanitizeString(\get_class($e)).' was thrown in '.$e->getFile().' on line '.$e->getLine().' while executing '.Utils::errorSanitizeString(\get_class($plugin)).'->parseComplete. Error message: '.Utils::errorSanitizeString($e->getMessage()),
                    E_USER_WARNING
                );
            }
        }

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\ContextInterface;

interface PluginBeginInterface extends PluginInterface
{
    /**
     * @psalm-param mixed &$var
     */
    public function parseBegin(&$var, ContextInterface $c): ?AbstractValue;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;

/**
 * @psalm-import-type ParserTrigger from Parser
 */
interface PluginCompleteInterface extends PluginInterface
{
    /**
     * @psalm-param mixed &$var
     * @psalm-param ParserTrigger $trigger
     */
    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

/**
 * @psalm-import-type ParserTrigger from Parser
 */
interface PluginInterface
{
    public function setParser(Parser $p): void;

    public function getTypes(): array;

    /**
     * @psalm-return ParserTrigger
     */
    public function getTriggers(): int;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\ContextInterface;
use Kint\Value\FixedWidthValue;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\ProfileRepresentation;

/** @psalm-api */
class ProfilePlugin extends AbstractPlugin implements PluginBeginInterface, PluginCompleteInterface
{
    protected array $instance_counts = [];
    protected array $instance_complexity = [];
    protected array $instance_count_stack = [];
    protected array $class_complexity = [];
    protected array $class_count_stack = [];

    public function getTypes(): array
    {
        return ['string', 'object', 'array', 'integer', 'double', 'resource'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_BEGIN | Parser::TRIGGER_COMPLETE;
    }

    public function parseBegin(&$var, ContextInterface $c): ?AbstractValue
    {
        if (0 === $c->getDepth()) {
            $this->instance_counts = [];
            $this->instance_complexity = [];
            $this->instance_count_stack = [];
            $this->class_complexity = [];
            $this->class_count_stack = [];
        }

        if (\is_object($var)) {
            $hash = \spl_object_hash($var);
            $this->instance_counts[$hash] ??= 0;
            $this->instance_complexity[$hash] ??= 0;
            $this->instance_count_stack[$hash] ??= 0;

            if (0 === $this->instance_count_stack[$hash]) {
                /**
                 * @psalm-suppress PossiblyFalseIterator
                 * Psalm bug #11392
                 */
                foreach (\class_parents($var) as $class) {
                    $this->class_count_stack[$class] ??= 0;
                    ++$this->class_count_stack[$class];
                }

                /**
                 * @psalm-suppress PossiblyFalseIterator
                 * Psalm bug #11392
                 */
                foreach (\class_implements($var) as $iface) {
                    $this->class_count_stack[$iface] ??= 0;
                    ++$this->class_count_stack[$iface];
                }
            }

            ++$this->instance_count_stack[$hash];
        }

        return null;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if ($v instanceof InstanceValue) {
            --$this->instance_count_stack[$v->getSplObjectHash()];

            if (0 === $this->instance_count_stack[$v->getSplObjectHash()]) {
                /**
                 * @psalm-suppress PossiblyFalseIterator
                 * Psalm bug #11392
                 */
                foreach (\class_parents($var) as $class) {
                    --$this->class_count_stack[$class];
                }

                /**
                 * @psalm-suppress PossiblyFalseIterator
                 * Psalm bug #11392
                 */
                foreach (\class_implements($var) as $iface) {
                    --$this->class_count_stack[$iface];
                }
            }
        }

        // Don't check subs if we're in recursion or array limit
        if (~$trigger & Parser::TRIGGER_SUCCESS) {
            return $v;
        }

        $sub_complexity = 1;

        foreach ($v->getRepresentations() as $rep) {
            if ($rep instanceof ContainerRepresentation) {
                foreach ($rep->getContents() as $value) {
                    $profile = $value->getRepresentation('profiling');
                    $sub_complexity += $profile instanceof ProfileRepresentation ? $profile->complexity : 1;
                }
            } else {
                ++$sub_complexity;
            }
        }

        if ($v instanceof InstanceValue) {
            ++$this->instance_counts[$v->getSplObjectHash()];
            if (0 === $this->instance_count_stack[$v->getSplObjectHash()]) {
                $this->instance_complexity[$v->getSplObjectHash()] += $sub_complexity;

                $this->class_complexity[$v->getClassName()] ??= 0;
                $this->class_complexity[$v->getClassName()] += $sub_complexity;

                /**
                 * @psalm-suppress PossiblyFalseIterator
                 * Psalm bug #11392
                 */
                foreach (\class_parents($var) as $class) {
                    $this->class_complexity[$class] ??= 0;
                    if (0 === $this->class_count_stack[$class]) {
                        $this->class_complexity[$class] += $sub_complexity;
                    }
                }

                /**
                 * @psalm-suppress PossiblyFalseIterator
                 * Psalm bug #11392
                 */
                foreach (\class_implements($var) as $iface) {
                    $this->class_complexity[$iface] ??= 0;
                    if (0 === $this->class_count_stack[$iface]) {
                        $this->class_complexity[$iface] += $sub_complexity;
                    }
                }
            }
        }

        if (0 === $v->getContext()->getDepth()) {
            $contents = [];

            \arsort($this->class_complexity);

            foreach ($this->class_complexity as $name => $complexity) {
                $contents[] = new FixedWidthValue(new BaseContext($name), $complexity);
            }

            if ($contents) {
                $v->addRepresentation(new ContainerRepresentation('Class complexity', $contents), 0);
            }
        }

        $rep = new ProfileRepresentation($sub_complexity);
        /** @psalm-suppress UnsupportedReferenceUsage */
        if ($v instanceof InstanceValue) {
            $rep->instance_counts = &$this->instance_counts[$v->getSplObjectHash()];
            $rep->instance_complexity = &$this->instance_complexity[$v->getSplObjectHash()];
        }

        $v->addRepresentation($rep, 0);

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\ContextInterface;

/**
 * @psalm-import-type ParserTrigger from Parser
 *
 * @psalm-api
 */
class ProxyPlugin implements PluginBeginInterface, PluginCompleteInterface
{
    protected array $types;
    /** @psalm-var ParserTrigger */
    protected int $triggers;
    /** @psalm-var callable */
    protected $callback;
    private ?Parser $parser = null;

    /**
     * @psalm-param ParserTrigger $triggers
     * @psalm-param callable $callback
     */
    public function __construct(array $types, int $triggers, $callback)
    {
        $this->types = $types;
        $this->triggers = $triggers;
        $this->callback = $callback;
    }

    public function setParser(Parser $p): void
    {
        $this->parser = $p;
    }

    public function getTypes(): array
    {
        return $this->types;
    }

    public function getTriggers(): int
    {
        return $this->triggers;
    }

    public function parseBegin(&$var, ContextInterface $c): ?AbstractValue
    {
        return \call_user_func_array($this->callback, [
            &$var,
            $c,
            Parser::TRIGGER_BEGIN,
            $this->parser,
        ]);
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        return \call_user_func_array($this->callback, [
            &$var,
            $v,
            $trigger,
            $this->parser,
        ]);
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Representation\ValueRepresentation;
use Kint\Value\UninitializedValue;

/** @psalm-api */
class SerializePlugin extends AbstractPlugin implements PluginCompleteInterface
{
    /**
     * Disables automatic unserialization on arrays and objects.
     *
     * As the PHP manual notes:
     *
     * > Unserialization can result in code being loaded and executed due to
     * > object instantiation and autoloading, and a malicious user may be able
     * > to exploit this.
     *
     * The natural way to stop that from happening is to just refuse to unserialize
     * stuff by default. Which is what we're doing for anything that's not scalar.
     */
    public static bool $safe_mode = true;

    /**
     * @psalm-var bool|class-string[]
     */
    public static $allowed_classes = false;

    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        $trimmed = \rtrim($var);

        if ('N;' !== $trimmed && !\preg_match('/^(?:[COabis]:\\d+[:;]|d:\\d+(?:\\.\\d+);)/', $trimmed)) {
            return $v;
        }

        $options = ['allowed_classes' => self::$allowed_classes];

        $c = $v->getContext();

        $base = new BaseContext('unserialize('.$c->getName().')');
        $base->depth = $c->getDepth() + 1;

        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = 'unserialize('.$ap;
            if (true === self::$allowed_classes) {
                $base->access_path .= ')';
            } else {
                $base->access_path .= ', '.\var_export($options, true).')';
            }
        }

        if (self::$safe_mode && \in_array($trimmed[0], ['C', 'O', 'a'], true)) {
            $data = new UninitializedValue($base);
            $data->flags |= AbstractValue::FLAG_BLACKLIST;
        } else {
            // Suppress warnings on unserializeable variable
            $data = @\unserialize($trimmed, $options);

            if (false === $data && 'b:0;' !== \substr($trimmed, 0, 4)) {
                return $v;
            }

            $data = $this->getParser()->parse($data, $base);
        }

        $data->flags |= AbstractValue::FLAG_GENERATED;

        $v->addRepresentation(new ValueRepresentation('Serialized', $data), 0);

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\Context\ArrayContext;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\ClassOwnedContext;
use Kint\Value\Context\ContextInterface;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\ValueRepresentation;
use Kint\Value\SimpleXMLElementValue;
use SimpleXMLElement;

class SimpleXMLElementPlugin extends AbstractPlugin implements PluginBeginInterface
{
    /**
     * Show all properties and methods.
     */
    public static bool $verbose = false;

    protected ClassMethodsPlugin $methods_plugin;

    public function __construct(Parser $parser)
    {
        parent::__construct($parser);

        $this->methods_plugin = new ClassMethodsPlugin($parser);
    }

    public function setParser(Parser $p): void
    {
        parent::setParser($p);

        $this->methods_plugin->setParser($p);
    }

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        // SimpleXMLElement is a weirdo. No recursion (Or rather everything is
        // recursion) and depth limit will have to be handled manually anyway.
        return Parser::TRIGGER_BEGIN;
    }

    public function parseBegin(&$var, ContextInterface $c): ?AbstractValue
    {
        if (!$var instanceof SimpleXMLElement) {
            return null;
        }

        return $this->parseElement($var, $c);
    }

    protected function parseElement(SimpleXMLElement &$var, ContextInterface $c): SimpleXMLElementValue
    {
        $parser = $this->getParser();
        $pdepth = $parser->getDepthLimit();
        $cdepth = $c->getDepth();

        $depthlimit = $pdepth && $cdepth >= $pdepth;
        $has_children = self::hasChildElements($var);

        if ($depthlimit && $has_children) {
            $x = new SimpleXMLElementValue($c, $var, [], null);
            $x->flags |= AbstractValue::FLAG_DEPTH_LIMIT;

            return $x;
        }

        $children = $this->getChildren($c, $var);
        $attributes = $this->getAttributes($c, $var);
        $toString = (string) $var;
        $string_body = !$has_children && \strlen($toString);

        $x = new SimpleXMLElementValue($c, $var, $children, \strlen($toString) ? $toString : null);

        if (self::$verbose) {
            $x = $this->methods_plugin->parseComplete($var, $x, Parser::TRIGGER_SUCCESS);
        }

        if ($attributes) {
            $x->addRepresentation(new ContainerRepresentation('Attributes', $attributes), 0);
        }

        if ($string_body) {
            $base = new BaseContext('(string) '.$c->getName());
            $base->depth = $cdepth + 1;
            if (null !== ($ap = $c->getAccessPath())) {
                $base->access_path = '(string) '.$ap;
            }

            $toString = $parser->parse($toString, $base);

            $x->addRepresentation(new ValueRepresentation('toString', $toString, null, true), 0);
        }

        if ($children) {
            $x->addRepresentation(new ContainerRepresentation('Children', $children), 0);
        }

        return $x;
    }

    /** @psalm-return list<AbstractValue> */
    protected function getAttributes(ContextInterface $c, SimpleXMLElement $var): array
    {
        $parser = $this->getParser();
        $namespaces = \array_merge(['' => null], $var->getDocNamespaces());

        $cdepth = $c->getDepth();
        $ap = $c->getAccessPath();

        $contents = [];

        foreach ($namespaces as $nsAlias => $_) {
            if ((bool) $nsAttribs = $var->attributes($nsAlias, true)) {
                foreach ($nsAttribs as $name => $attrib) {
                    $obj = new ArrayContext($name);
                    $obj->depth = $cdepth + 1;

                    if (null !== $ap) {
                        $obj->access_path = '(string) '.$ap;
                        if ('' !== $nsAlias) {
                            $obj->access_path .= '->attributes('.\var_export($nsAlias, true).', true)';
                        }
                        $obj->access_path .= '['.\var_export($name, true).']';
                    }

                    if ('' !== $nsAlias) {
                        $obj->name = $nsAlias.':'.$obj->name;
                    }

                    $string = (string) $attrib;
                    $attribute = $parser->parse($string, $obj);

                    $contents[] = $attribute;
                }
            }
        }

        return $contents;
    }

    /**
     * Alright kids, let's learn about SimpleXMLElement::children!
     * children can take a namespace url or alias and provide a list of
     * child nodes. This is great since just accessing the members through
     * properties doesn't work on SimpleXMLElement when they have a
     * namespace at all!
     *
     * Unfortunately SimpleXML decided to go the retarded route of
     * categorizing elements by their tag name rather than by their local
     * name (to put it in Dom terms) so if you have something like this:
     *
     * <root xmlns:localhost="http://localhost/">
     *   <tag />
     *   <tag xmlns="http://localhost/" />
     *   <localhost:tag />
     * </root>
     *
     * * children(null) will get the first 2 results
     * * children('', true) will get the first 2 results
     * * children('http://localhost/') will get the last 2 results
     * * children('localhost', true) will get the last result
     *
     * So let's just give up and stick to aliases because fuck that mess!
     *
     * @psalm-return list<SimpleXMLElementValue>
     */
    protected function getChildren(ContextInterface $c, SimpleXMLElement $var): array
    {
        $namespaces = \array_merge(['' => null], $var->getDocNamespaces());

        $cdepth = $c->getDepth();
        $ap = $c->getAccessPath();

        $contents = [];

        foreach ($namespaces as $nsAlias => $_) {
            $nsChildren = $var->children($nsAlias, true);
            if (!(bool) $nsChildren) {
                continue;
            }

            $nsap = [];

            foreach ($nsChildren as $name => $child) {
                $base = new ClassOwnedContext((string) $name, SimpleXMLElement::class);
                $base->depth = $cdepth + 1;

                if ('' !== $nsAlias) {
                    $base->name = $nsAlias.':'.$name;
                }

                if (null !== $ap) {
                    if ('' === $nsAlias) {
                        $base->access_path = $ap.'->';
                    } else {
                        $base->access_path = $ap.'->children('.\var_export($nsAlias, true).', true)->';
                    }

                    if (Utils::isValidPhpName((string) $name)) {
                        $base->access_path .= (string) $name;
                    } else {
                        $base->access_path .= '{'.\var_export((string) $name, true).'}';
                    }

                    if (isset($nsap[$base->access_path])) {
                        ++$nsap[$base->access_path];
                        $base->access_path .= '['.$nsap[$base->access_path].']';
                    } else {
                        $nsap[$base->access_path] = 0;
                    }
                }

                $v = $this->parseElement($child, $base);
                $v->flags |= AbstractValue::FLAG_GENERATED;
                $contents[] = $v;
            }
        }

        return $contents;
    }

    /**
     * More SimpleXMLElement bullshit.
     *
     * If we want to know if the element contains text we can cast to string.
     * Except if it contains text mixed with elements simplexml for some stupid
     * reason decides to concatenate the text from between those elements
     * rather than all the text in the hierarchy...
     *
     * So we have NO way of getting text nodes between elements, but we can
     * still tell if we have elements right? If we have elements we assume it's
     * not a string and call it a day!
     *
     * Well if you cast the element to an array attributes will be on it so
     * you'd have to remove that key, and if it's a string it'll also have the
     * 0 index used for the string contents too...
     *
     * Wait, can we use the 0 index to tell if it's a string? Nope! CDATA
     * doesn't show up AT ALL when casting to anything but string, and we'll
     * still get those concatenated strings of mostly whitespace if we just do
     * (string) and check the length.
     *
     * Luckily, I found the only way to do this reliably is through children().
     * We still have to loop through all the namespaces and see if there's a
     * match but then we have the problem of the attributes showing up again...
     *
     * Or at least that's what var_dump says. And when we cast the result to
     * bool it's true too... But if we cast it to array then it's suddenly empty!
     *
     * Long story short the function below is the only way to reliably check if
     * a SimpleXMLElement has children
     */
    protected static function hasChildElements(SimpleXMLElement $var): bool
    {
        $namespaces = \array_merge(['' => null], $var->getDocNamespaces());

        foreach ($namespaces as $nsAlias => $_) {
            if ((array) $var->children($nsAlias, true)) {
                return true;
            }
        }

        return false;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\SplFileInfoRepresentation;
use Kint\Value\SplFileInfoValue;
use SplFileInfo;
use SplFileObject;

class SplFileInfoPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        // SplFileObject throws exceptions in normal use in places SplFileInfo doesn't
        if (!$var instanceof SplFileInfo || $var instanceof SplFileObject) {
            return $v;
        }

        if (!$v instanceof InstanceValue) {
            return $v;
        }

        $out = new SplFileInfoValue($v->getContext(), $var);
        $out->setChildren($v->getChildren());
        $out->flags = $v->flags;
        $out->addRepresentation(new SplFileInfoRepresentation(clone $var));
        $out->appendRepresentations($v->getRepresentations());

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\ArrayContext;
use Kint\Value\ResourceValue;
use Kint\Value\StreamValue;
use TypeError;

class StreamPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['resource'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$v instanceof ResourceValue) {
            return $v;
        }

        // Doublecheck that the resource is open before we get the metadata
        if (!\is_resource($var)) {
            return $v;
        }

        try {
            $meta = \stream_get_meta_data($var);
        } catch (TypeError $e) {
            return $v;
        }

        $c = $v->getContext();

        $parser = $this->getParser();
        $parsed_meta = [];
        foreach ($meta as $key => $val) {
            $base = new ArrayContext($key);
            $base->depth = $c->getDepth() + 1;

            if (null !== ($ap = $c->getAccessPath())) {
                $base->access_path = 'stream_get_meta_data('.$ap.')['.\var_export($key, true).']';
            }

            $val = $parser->parse($val, $base);
            $val->flags |= AbstractValue::FLAG_GENERATED;
            $parsed_meta[] = $val;
        }

        $stream = new StreamValue($c, $parsed_meta, $meta['uri'] ?? null);
        $stream->flags = $v->flags;
        $stream->appendRepresentations($v->getRepresentations());

        return $stream;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\ArrayValue;
use Kint\Value\Representation\TableRepresentation;

// Note: Interaction with ArrayLimitPlugin:
// Any array limited children will be shown in tables identically to
// non-array-limited children since the table only shows that it is an array
// and it's size anyway. Because ArrayLimitPlugin halts the parse on finding
// a limit all other plugins including this one are stopped, so you cannot get
// a tabular representation of an array that is longer than the limit.
class TablePlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public static int $max_width = 300;
    public static int $min_width = 2;

    public function getTypes(): array
    {
        return ['array'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$v instanceof ArrayValue) {
            return $v;
        }

        if (\count($var) < 2) {
            return $v;
        }

        // Ensure this is an array of arrays and that all child arrays have the
        // same keys. We don't care about their children - if there's another
        // "table" inside we'll just make another one down the value tab
        $keys = null;
        foreach ($var as $elem) {
            if (!\is_array($elem)) {
                return $v;
            }

            if (null === $keys) {
                if (\count($elem) < self::$min_width || \count($elem) > self::$max_width) {
                    return $v;
                }

                $keys = \array_keys($elem);
            } elseif (\array_keys($elem) !== $keys) {
                return $v;
            }
        }

        $children = $v->getContents();

        if (!$children) {
            return $v;
        }

        // Ensure none of the child arrays are recursion or depth limit. We
        // don't care if their children are since they are the table cells
        foreach ($children as $childarray) {
            if (!$childarray instanceof ArrayValue || empty($childarray->getContents())) {
                return $v;
            }
        }

        $v->addRepresentation(new TableRepresentation($children), 0);

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\InstanceValue;
use Kint\Value\Representation\SourceRepresentation;
use Kint\Value\ThrowableValue;
use RuntimeException;
use Throwable;

class ThrowablePlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$var instanceof Throwable || !$v instanceof InstanceValue) {
            return $v;
        }

        $throw = new ThrowableValue($v->getContext(), $var);
        $throw->setChildren($v->getChildren());
        $throw->flags = $v->flags;
        $throw->appendRepresentations($v->getRepresentations());

        try {
            $throw->addRepresentation(new SourceRepresentation($var->getFile(), $var->getLine(), null, true), 0);
        } catch (RuntimeException $e) {
        }

        return $throw;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use DateTimeImmutable;
use Kint\Value\AbstractValue;
use Kint\Value\FixedWidthValue;
use Kint\Value\Representation\StringRepresentation;
use Kint\Value\StringValue;

class TimestampPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public static array $blacklist = [
        2147483648,
        2147483647,
        1073741824,
        1073741823,
    ];

    public function getTypes(): array
    {
        return ['string', 'integer'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (\is_string($var) && !\ctype_digit($var)) {
            return $v;
        }

        if ($var < 0) {
            return $v;
        }

        if (\in_array($var, self::$blacklist, true)) {
            return $v;
        }

        $len = \strlen((string) $var);

        // Guess for anything between March 1973 and November 2286
        if ($len < 9 || $len > 10) {
            return $v;
        }

        if (!$v instanceof StringValue && !$v instanceof FixedWidthValue) {
            return $v;
        }

        if (!$dt = DateTimeImmutable::createFromFormat('U', (string) $var)) {
            return $v;
        }

        $v->removeRepresentation('contents');
        $v->addRepresentation(new StringRepresentation('Timestamp', $dt->format('c'), null, true));

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Representation\ValueRepresentation;
use ReflectionClass;
use SimpleXMLElement;
use SplFileInfo;
use Throwable;

class ToStringPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public static array $blacklist = [
        SimpleXMLElement::class,
        SplFileInfo::class,
    ];

    public function getTypes(): array
    {
        return ['object'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        $reflection = new ReflectionClass($var);
        if (!$reflection->hasMethod('__toString')) {
            return $v;
        }

        foreach (self::$blacklist as $class) {
            if ($var instanceof $class) {
                return $v;
            }
        }

        try {
            $string = (string) $var;
        } catch (Throwable $t) {
            return $v;
        }

        $c = $v->getContext();

        $base = new BaseContext($c->getName());
        $base->depth = $c->getDepth() + 1;
        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = '(string) '.$ap;
        }

        $string = $this->getParser()->parse($string, $base);

        $v->addRepresentation(new ValueRepresentation('toString', $string));

        return $v;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\ArrayValue;
use Kint\Value\Context\ArrayContext;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\SourceRepresentation;
use Kint\Value\Representation\ValueRepresentation;
use Kint\Value\TraceFrameValue;
use Kint\Value\TraceValue;
use RuntimeException;

/**
 * @psalm-import-type TraceFrame from TraceFrameValue
 */
class TracePlugin extends AbstractPlugin implements PluginCompleteInterface
{
    public static array $blacklist = ['spl_autoload_call'];
    public static array $path_blacklist = [];

    public function getTypes(): array
    {
        return ['array'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if (!$v instanceof ArrayValue) {
            return $v;
        }

        // Shallow copy so we don't have to worry about touching var
        $trace = $var;

        if (!Utils::isTrace($trace)) {
            return $v;
        }

        $pdepth = $this->getParser()->getDepthLimit();
        $c = $v->getContext();

        // We need at least 2 levels in order to get $trace[n]['args']
        if ($pdepth && $c->getDepth() + 2 >= $pdepth) {
            return $v;
        }

        $contents = $v->getContents();

        self::$blacklist = Utils::normalizeAliases(self::$blacklist);
        $path_blacklist = self::normalizePaths(self::$path_blacklist);

        $frames = [];

        foreach ($contents as $frame) {
            if (!$frame instanceof ArrayValue || !$frame->getContext() instanceof ArrayContext) {
                continue;
            }

            $index = $frame->getContext()->getName();

            if (!isset($trace[$index]['file']) || Utils::traceFrameIsListed($trace[$index], self::$blacklist)) {
                continue;
            }

            if (false !== ($realfile = \realpath($trace[$index]['file']))) {
                foreach ($path_blacklist as $path) {
                    if (0 === \strpos($realfile, $path)) {
                        continue 2;
                    }
                }
            }

            $frame = new TraceFrameValue($frame, $trace[$index]);

            if (null !== ($file = $frame->getFile()) && null !== ($line = $frame->getLine())) {
                try {
                    $frame->addRepresentation(new SourceRepresentation($file, $line));
                } catch (RuntimeException $e) {
                }
            }

            if ($args = $frame->getArgs()) {
                $frame->addRepresentation(new ContainerRepresentation('Arguments', $args));
            }

            if ($obj = $frame->getObject()) {
                $frame->addRepresentation(
                    new ValueRepresentation(
                        'Callee object ['.$obj->getClassName().']',
                        $obj,
                        'callee_object'
                    )
                );
            }

            $frames[$index] = $frame;
        }

        $traceobj = new TraceValue($c, \count($frames), $frames);

        if ($frames) {
            $traceobj->addRepresentation(new ContainerRepresentation('Contents', $frames, null, true));
        }

        return $traceobj;
    }

    protected static function normalizePaths(array $paths): array
    {
        $normalized = [];

        foreach ($paths as $path) {
            $realpath = \realpath($path);
            if (false !== $realpath && \is_dir($realpath)) {
                $realpath .= DIRECTORY_SEPARATOR;
            }

            $normalized[] = $realpath;
        }

        return $normalized;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Parser;

use Dom\Node;
use Dom\XMLDocument;
use DOMDocument;
use DOMException;
use DOMNode;
use InvalidArgumentException;
use Kint\Value\AbstractValue;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\ContextInterface;
use Kint\Value\Representation\ValueRepresentation;
use Throwable;

class XmlPlugin extends AbstractPlugin implements PluginCompleteInterface
{
    /**
     * Which method to parse the variable with.
     *
     * DOMDocument provides more information including the text between nodes,
     * however it's memory usage is very high and it takes longer to parse and
     * render. Plus it's a pain to work with. So SimpleXML is the default.
     *
     * @psalm-var 'SimpleXML'|'DOMDocument'|'XMLDocument'
     */
    public static string $parse_method = 'SimpleXML';

    public function getTypes(): array
    {
        return ['string'];
    }

    public function getTriggers(): int
    {
        return Parser::TRIGGER_SUCCESS;
    }

    public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue
    {
        if ('<?xml' !== \substr($var, 0, 5)) {
            return $v;
        }

        if (!\method_exists($this, 'xmlTo'.self::$parse_method)) {
            return $v;
        }

        $c = $v->getContext();

        $out = \call_user_func([$this, 'xmlTo'.self::$parse_method], $var, $c);

        if (null === $out) {
            return $v;
        }

        $out->flags |= AbstractValue::FLAG_GENERATED;

        $v->addRepresentation(new ValueRepresentation('XML', $out), 0);

        return $v;
    }

    /** @psalm-suppress PossiblyUnusedMethod */
    protected function xmlToSimpleXML(string $var, ContextInterface $c): ?AbstractValue
    {
        $errors = \libxml_use_internal_errors(true);
        try {
            $xml = \simplexml_load_string($var);
            if (!(bool) $xml) {
                throw new InvalidArgumentException('Bad XML parse in XmlPlugin::xmlToSimpleXML');
            }
        } catch (Throwable $t) {
            return null;
        } finally {
            \libxml_use_internal_errors($errors);
            \libxml_clear_errors();
        }

        $base = new BaseContext($xml->getName());
        $base->depth = $c->getDepth() + 1;
        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = 'simplexml_load_string('.$ap.')';
        }

        return $this->getParser()->parse($xml, $base);
    }

    /**
     * Get the DOMDocument info.
     *
     * If it errors loading then we wouldn't have gotten this far in the first place.
     *
     * @psalm-suppress PossiblyUnusedMethod
     *
     * @psalm-param non-empty-string $var
     */
    protected function xmlToDOMDocument(string $var, ContextInterface $c): ?AbstractValue
    {
        try {
            $xml = new DOMDocument();
            $check = $xml->loadXML($var, LIBXML_NOWARNING | LIBXML_NOERROR);

            if (false === $check) {
                throw new InvalidArgumentException('Bad XML parse in XmlPlugin::xmlToDOMDocument');
            }
        } catch (Throwable $t) {
            return null;
        }

        $xml = $xml->firstChild;

        /**
         * @psalm-var DOMNode $xml
         * Psalm bug #11120
         */
        $base = new BaseContext($xml->nodeName);
        $base->depth = $c->getDepth() + 1;
        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = '(function($s){$x = new \\DomDocument(); $x->loadXML($s); return $x;})('.$ap.')->firstChild';
        }

        return $this->getParser()->parse($xml, $base);
    }

    /** @psalm-suppress PossiblyUnusedMethod */
    protected function xmlToXMLDocument(string $var, ContextInterface $c): ?AbstractValue
    {
        if (!KINT_PHP84) {
            return null; // @codeCoverageIgnore
        }

        try {
            $xml = XMLDocument::createFromString($var, LIBXML_NOWARNING | LIBXML_NOERROR);
        } catch (DOMException $e) {
            return null;
        }

        $xml = $xml->firstChild;

        /**
         * @psalm-var Node $xml
         * Psalm bug #11120
         */
        $base = new BaseContext($xml->nodeName);
        $base->depth = $c->getDepth() + 1;
        if (null !== ($ap = $c->getAccessPath())) {
            $base->access_path = '\\Dom\\XMLDocument::createFromString('.$ap.')->firstChild';
        }

        return $this->getParser()->parse($xml, $base);
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer;

abstract class AbstractRenderer implements ConstructableRendererInterface
{
    public static ?string $js_nonce = null;
    public static ?string $css_nonce = null;

    /** @psalm-var ?non-empty-string */
    public static ?string $file_link_format = null;

    protected bool $show_trace = true;
    protected ?array $callee = null;
    protected array $trace = [];

    protected bool $render_spl_ids = true;

    public function __construct()
    {
    }

    public function shouldRenderObjectIds(): bool
    {
        return $this->render_spl_ids;
    }

    public function setCallInfo(array $info): void
    {
        $this->callee = $info['callee'] ?? null;
        $this->trace = $info['trace'] ?? [];
    }

    public function setStatics(array $statics): void
    {
        $this->show_trace = !empty($statics['display_called_from']);
    }

    public function filterParserPlugins(array $plugins): array
    {
        return $plugins;
    }

    public function preRender(): string
    {
        return '';
    }

    public function postRender(): string
    {
        return '';
    }

    public static function getFileLink(string $file, int $line): ?string
    {
        if (null === self::$file_link_format) {
            return null;
        }

        return \str_replace(['%f', '%l'], [$file, $line], self::$file_link_format);
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer;

trait AssetRendererTrait
{
    public static ?string $theme = null;

    /** @psalm-var array{js?:string, css?:array<path, string|false>} */
    private static array $assetCache = [];

    /** @psalm-api */
    public static function renderJs(): string
    {
        if (!isset(self::$assetCache['js'])) {
            self::$assetCache['js'] = \file_get_contents(KINT_DIR.'/resources/compiled/main.js');
        }

        return self::$assetCache['js'];
    }

    /** @psalm-api */
    public static function renderCss(): ?string
    {
        if (!isset(self::$theme)) {
            return null;
        }

        if (!isset(self::$assetCache['css'][self::$theme])) {
            if (\file_exists(KINT_DIR.'/resources/compiled/'.self::$theme)) {
                self::$assetCache['css'][self::$theme] = \file_get_contents(KINT_DIR.'/resources/compiled/'.self::$theme);
            } elseif (\file_exists(self::$theme)) {
                self::$assetCache['css'][self::$theme] = \file_get_contents(self::$theme);
            } else {
                self::$assetCache['css'][self::$theme] = false;
            }
        }

        if (false === self::$assetCache['css'][self::$theme]) {
            return null;
        }

        return self::$assetCache['css'][self::$theme];
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer;

use Kint\Value\AbstractValue;
use Throwable;

class CliRenderer extends TextRenderer
{
    /**
     * @var bool enable colors
     */
    public static bool $cli_colors = true;

    /**
     * Detects the terminal width on startup.
     */
    public static bool $detect_width = true;

    /**
     * The minimum width to detect terminal size as.
     *
     * Less than this is ignored and falls back to default width.
     */
    public static int $min_terminal_width = 40;

    /**
     * Forces utf8 output on windows.
     */
    public static bool $force_utf8 = false;

    /**
     * Which stream to check for VT100 support on windows.
     *
     * uses STDOUT by default if it's defined
     *
     * @psalm-var ?resource
     */
    public static $windows_stream = null;

    protected static ?int $terminal_width = null;

    protected bool $windows_output = false;

    protected bool $colors = false;

    public function __construct()
    {
        parent::__construct();

        if (!self::$force_utf8 && KINT_WIN) {
            if (!\function_exists('sapi_windows_vt100_support')) {
                $this->windows_output = true;
            } else {
                $stream = self::$windows_stream;

                if (!$stream && \defined('STDOUT')) {
                    $stream = STDOUT;
                }

                if (!$stream) {
                    $this->windows_output = true;
                } else {
                    $this->windows_output = !\sapi_windows_vt100_support($stream);
                }
            }
        }

        if (null === self::$terminal_width) {
            if (self::$detect_width) {
                try {
                    $tput = KINT_WIN ? \exec('tput cols 2>nul') : \exec('tput cols 2>/dev/null');
                    if ((bool) $tput) {
                        /**
                         * @psalm-suppress InvalidCast
                         * Psalm bug #11080
                         */
                        self::$terminal_width = (int) $tput;
                    }
                } catch (Throwable $t) {
                    self::$terminal_width = self::$default_width;
                }
            }

            if (!isset(self::$terminal_width) || self::$terminal_width < self::$min_terminal_width) {
                self::$terminal_width = self::$default_width;
            }
        }

        $this->colors = $this->windows_output ? false : self::$cli_colors;

        $this->header_width = self::$terminal_width;
    }

    public function colorValue(string $string): string
    {
        if (!$this->colors) {
            return $string;
        }

        return "\x1b[32m".\str_replace("\n", "\x1b[0m\n\x1b[32m", $string)."\x1b[0m";
    }

    public function colorType(string $string): string
    {
        if (!$this->colors) {
            return $string;
        }

        return "\x1b[35;1m".\str_replace("\n", "\x1b[0m\n\x1b[35;1m", $string)."\x1b[0m";
    }

    public function colorTitle(string $string): string
    {
        if (!$this->colors) {
            return $string;
        }

        return "\x1b[36m".\str_replace("\n", "\x1b[0m\n\x1b[36m", $string)."\x1b[0m";
    }

    public function renderTitle(AbstractValue $v): string
    {
        if ($this->windows_output) {
            return $this->utf8ToWindows(parent::renderTitle($v));
        }

        return parent::renderTitle($v);
    }

    public function preRender(): string
    {
        return PHP_EOL;
    }

    public function postRender(): string
    {
        if ($this->windows_output) {
            return $this->utf8ToWindows(parent::postRender());
        }

        return parent::postRender();
    }

    public function escape(string $string, $encoding = false): string
    {
        return \str_replace("\x1b", '\\x1b', $string);
    }

    protected function utf8ToWindows(string $string): string
    {
        return \str_replace(
            ['┌', '═', '┐', '│', '└', '─', '┘'],
            [' ', '=', ' ', '|', ' ', '-', ' '],
            $string
        );
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer;

interface ConstructableRendererInterface extends RendererInterface
{
    public function __construct();
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer;

use Kint\Utils;
use Kint\Value\AbstractValue;

class PlainRenderer extends TextRenderer
{
    use AssetRendererTrait;

    public static array $pre_render_sources = [
        'script' => [
            [self::class, 'renderJs'],
        ],
        'style' => [
            [self::class, 'renderCss'],
        ],
        'raw' => [],
    ];

    /**
     * Output htmlentities instead of utf8.
     */
    public static bool $disable_utf8 = false;

    public static bool $needs_pre_render = true;

    public static bool $always_pre_render = false;

    protected bool $force_pre_render = false;

    public function __construct()
    {
        parent::__construct();
        self::$theme ??= 'plain.css';
        $this->setForcePreRender(self::$always_pre_render);
    }

    public function setCallInfo(array $info): void
    {
        parent::setCallInfo($info);

        if (\in_array('@', $info['modifiers'], true)) {
            $this->setForcePreRender(true);
        }
    }

    public function setStatics(array $statics): void
    {
        parent::setStatics($statics);

        if (!empty($statics['return'])) {
            $this->setForcePreRender(true);
        }
    }

    public function setForcePreRender(bool $force_pre_render): void
    {
        $this->force_pre_render = $force_pre_render;
    }

    public function getForcePreRender(): bool
    {
        return $this->force_pre_render;
    }

    public function shouldPreRender(): bool
    {
        return $this->getForcePreRender() || self::$needs_pre_render;
    }

    public function colorValue(string $string): string
    {
        return '<i>'.$string.'</i>';
    }

    public function colorType(string $string): string
    {
        return '<b>'.$string.'</b>';
    }

    public function colorTitle(string $string): string
    {
        return '<u>'.$string.'</u>';
    }

    public function renderTitle(AbstractValue $v): string
    {
        if (self::$disable_utf8) {
            return $this->utf8ToHtmlentity(parent::renderTitle($v));
        }

        return parent::renderTitle($v);
    }

    public function preRender(): string
    {
        $output = '';

        if ($this->shouldPreRender()) {
            foreach (self::$pre_render_sources as $type => $values) {
                $contents = '';
                foreach ($values as $v) {
                    $contents .= \call_user_func($v, $this);
                }

                if (!\strlen($contents)) {
                    continue;
                }

                switch ($type) {
                    case 'script':
                        $output .= '<script class="kint-plain-script"';
                        if (null !== self::$js_nonce) {
                            $output .= ' nonce="'.\htmlspecialchars(self::$js_nonce).'"';
                        }
                        $output .= '>'.$contents.'</script>';
                        break;
                    case 'style':
                        $output .= '<style class="kint-plain-style"';
                        if (null !== self::$css_nonce) {
                            $output .= ' nonce="'.\htmlspecialchars(self::$css_nonce).'"';
                        }
                        $output .= '>'.$contents.'</style>';
                        break;
                    default:
                        $output .= $contents;
                }
            }

            // Don't pre-render on every dump
            if (!$this->getForcePreRender()) {
                self::$needs_pre_render = false;
            }
        }

        return $output.'<div class="kint-plain">';
    }

    public function postRender(): string
    {
        if (self::$disable_utf8) {
            return $this->utf8ToHtmlentity(parent::postRender()).'</div>';
        }

        return parent::postRender().'</div>';
    }

    public function ideLink(string $file, int $line): string
    {
        $path = $this->escape(Utils::shortenPath($file)).':'.$line;
        $ideLink = self::getFileLink($file, $line);

        if (null === $ideLink) {
            return $path;
        }

        return '<a href="'.$this->escape($ideLink).'">'.$path.'</a>';
    }

    public function escape(string $string, $encoding = false): string
    {
        if (false === $encoding) {
            $encoding = Utils::detectEncoding($string);
        }

        $original_encoding = $encoding;

        if (false === $encoding || 'ASCII' === $encoding) {
            $encoding = 'UTF-8';
        }

        $string = \htmlspecialchars($string, ENT_NOQUOTES, $encoding);

        // this call converts all non-ASCII characters into numeirc htmlentities
        if (\function_exists('mb_encode_numericentity') && 'ASCII' !== $original_encoding) {
            $string = \mb_encode_numericentity($string, [0x80, 0xFFFF, 0, 0xFFFF], $encoding);
        }

        return $string;
    }

    protected function utf8ToHtmlentity(string $string): string
    {
        return \str_replace(
            ['┌', '═', '┐', '│', '└', '─', '┘'],
            ['&#9484;', '&#9552;', '&#9488;', '&#9474;', '&#9492;', '&#9472;', '&#9496;'],
            $string
        );
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer;

use Kint\Value\AbstractValue;

interface RendererInterface
{
    public function render(AbstractValue $v): string;

    public function shouldRenderObjectIds(): bool;

    public function setCallInfo(array $info): void;

    public function setStatics(array $statics): void;

    public function filterParserPlugins(array $plugins): array;

    public function preRender(): string;

    public function postRender(): string;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Renderer\RichRenderer;
use Kint\Value\AbstractValue;
use Kint\Value\Context\ClassDeclaredContext;
use Kint\Value\Context\PropertyContext;
use Kint\Value\InstanceValue;

abstract class AbstractPlugin implements PluginInterface
{
    protected RichRenderer $renderer;

    public function __construct(RichRenderer $r)
    {
        $this->renderer = $r;
    }

    /**
     * @param string $content The replacement for the getValueShort contents
     */
    public function renderLockedHeader(AbstractValue $v, string $content): string
    {
        $header = '<dt class="kint-parent kint-locked">';

        $c = $v->getContext();

        if (RichRenderer::$access_paths && $c->getDepth() > 0 && null !== ($ap = $c->getAccessPath())) {
            $header .= '<span class="kint-access-path-trigger" title="Show access path">&rlarr;</span>';
        }

        $header .= '<nav></nav>';

        if ($c instanceof ClassDeclaredContext) {
            $header .= '<var>'.$c->getModifiers().'</var> ';
        }

        $header .= '<dfn>'.$this->renderer->escape($v->getDisplayName()).'</dfn> ';

        if ($c instanceof PropertyContext && null !== ($s = $c->getHooks())) {
            $header .= '<var>'.$this->renderer->escape($s).'</var> ';
        }

        if (null !== ($s = $c->getOperator())) {
            $header .= $this->renderer->escape($s, 'ASCII').' ';
        }

        $s = $v->getDisplayType();

        if (RichRenderer::$escape_types) {
            $s = $this->renderer->escape($s);
        }

        if ($c->isRef()) {
            $s = '&amp;'.$s;
        }

        $header .= '<var>'.$s.'</var>';

        if ($v instanceof InstanceValue && $this->renderer->shouldRenderObjectIds()) {
            $header .= '#'.$v->getSplObjectId();
        }

        $header .= ' ';

        if (null !== ($s = $v->getDisplaySize())) {
            if (RichRenderer::$escape_types) {
                $s = $this->renderer->escape($s);
            }
            $header .= '('.$s.') ';
        }

        $header .= $content;

        if (!empty($ap)) {
            $header .= '<div class="access-path">'.$this->renderer->escape($ap).'</div>';
        }

        return $header.'</dt>';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Value\AbstractValue;
use Kint\Value\Representation\BinaryRepresentation;
use Kint\Value\Representation\RepresentationInterface;

class BinaryPlugin extends AbstractPlugin implements TabPluginInterface
{
    /** @psalm-var positive-int */
    public static int $line_length = 0x10;
    /** @psalm-var positive-int */
    public static int $chunk_length = 0x2;

    public function renderTab(RepresentationInterface $r, AbstractValue $v): ?string
    {
        if (!$r instanceof BinaryRepresentation) {
            return null;
        }

        $out = '<pre>';

        $lines = \str_split($r->getValue(), self::$line_length);

        foreach ($lines as $index => $line) {
            $out .= ((string) \sprintf('%08X', $index * self::$line_length)).":\t";

            $chunks = \str_split(\str_pad(\bin2hex($line), 2 * self::$line_length, ' '), 2 * self::$chunk_length);

            $out .= \implode(' ', $chunks);
            $out .= "\t".\preg_replace('/[^\\x20-\\x7E]/', '.', $line)."\n";
        }

        $out .= '</pre>';

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\MethodValue;
use Kint\Value\Representation\CallableDefinitionRepresentation;
use Kint\Value\Representation\RepresentationInterface;

class CallableDefinitionPlugin extends AbstractPlugin implements TabPluginInterface
{
    public function renderTab(RepresentationInterface $r, AbstractValue $v): ?string
    {
        if (!$r instanceof CallableDefinitionRepresentation) {
            return null;
        }

        $docstring = [];

        if ($v instanceof MethodValue) {
            $c = $v->getContext();

            if ($c->inherited) {
                $docstring[] = 'Inherited from '.$this->renderer->escape($c->owner_class);
            }
        }

        $docstring[] = 'Defined in '.$this->renderer->escape(Utils::shortenPath($r->getFileName())).':'.$r->getLine();

        $docstring = '<small>'.\implode("\n", $docstring).'</small>';

        if (null !== ($trimmed = $r->getDocstringTrimmed())) {
            $docstring = $this->renderer->escape($trimmed)."\n\n".$docstring;
        }

        return '<pre>'.$docstring.'</pre>';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Renderer\RichRenderer;
use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\Context\MethodContext;
use Kint\Value\MethodValue;

class CallablePlugin extends AbstractPlugin implements ValuePluginInterface
{
    protected static array $method_cache = [];

    public function renderValue(AbstractValue $v): ?string
    {
        if (!$v instanceof MethodValue) {
            return null;
        }

        $c = $v->getContext();

        if (!$c instanceof MethodContext) {
            return null;
        }

        if (!isset(self::$method_cache[$c->owner_class][$c->name])) {
            $children = $this->renderer->renderChildren($v);

            $header = '<var>'.$c->getModifiers();

            if ($v->getCallableBag()->return_reference) {
                $header .= ' &amp;';
            }

            $header .= '</var> ';

            $function = $this->renderer->escape($v->getDisplayName());

            if (null !== ($url = $v->getPhpDocUrl())) {
                $function = '<a href="'.$url.'" target=_blank>'.$function.'</a>';
            }

            $header .= '<dfn>'.$function.'</dfn>';

            if (null !== ($rt = $v->getCallableBag()->returntype)) {
                $header .= ': <var>';
                $header .= $this->renderer->escape($rt).'</var>';
            } elseif (null !== ($ds = $v->getCallableBag()->docstring)) {
                if (\preg_match('/@return\\s+(.*)\\r?\\n/m', $ds, $matches)) {
                    if (\trim($matches[1])) {
                        $header .= ': <var>'.$this->renderer->escape(\trim($matches[1])).'</var>';
                    }
                }
            }

            if (null !== ($s = $v->getDisplayValue())) {
                if (RichRenderer::$strlen_max) {
                    $s = Utils::truncateString($s, RichRenderer::$strlen_max);
                }
                $header .= ' '.$this->renderer->escape($s);
            }

            self::$method_cache[$c->owner_class][$c->name] = [
                'header' => $header,
                'children' => $children,
            ];
        }

        $children = self::$method_cache[$c->owner_class][$c->name]['children'];

        $header = $this->renderer->renderHeaderWrapper(
            $c,
            (bool) \strlen($children),
            self::$method_cache[$c->owner_class][$c->name]['header']
        );

        return '<dl>'.$header.$children.'</dl>';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Value\AbstractValue;
use Kint\Value\Representation\ColorRepresentation;
use Kint\Value\Representation\RepresentationInterface;

class ColorPlugin extends AbstractPlugin implements TabPluginInterface, ValuePluginInterface
{
    public function renderValue(AbstractValue $v): ?string
    {
        $r = $v->getRepresentation('color');

        if (!$r instanceof ColorRepresentation) {
            return null;
        }

        $children = $this->renderer->renderChildren($v);

        $header = $this->renderer->renderHeader($v);
        $header .= '<div class="kint-color-preview"><div style="background:';
        $header .= $r->getColor(ColorRepresentation::COLOR_RGBA);
        $header .= '"></div></div>';

        $header = $this->renderer->renderHeaderWrapper($v->getContext(), (bool) \strlen($children), $header);

        return '<dl>'.$header.$children.'</dl>';
    }

    public function renderTab(RepresentationInterface $r, AbstractValue $v): ?string
    {
        if (!$r instanceof ColorRepresentation) {
            return null;
        }

        $out = '';

        if ($color = $r->getColor(ColorRepresentation::COLOR_NAME)) {
            $out .= '<dfn>'.$color."</dfn>\n";
        }
        if ($color = $r->getColor(ColorRepresentation::COLOR_HEX_3)) {
            $out .= '<dfn>'.$color."</dfn>\n";
        }
        if ($color = $r->getColor(ColorRepresentation::COLOR_HEX_6)) {
            $out .= '<dfn>'.$color."</dfn>\n";
        }

        if ($r->hasAlpha()) {
            if ($color = $r->getColor(ColorRepresentation::COLOR_HEX_4)) {
                $out .= '<dfn>'.$color."</dfn>\n";
            }
            if ($color = $r->getColor(ColorRepresentation::COLOR_HEX_8)) {
                $out .= '<dfn>'.$color."</dfn>\n";
            }
            if ($color = $r->getColor(ColorRepresentation::COLOR_RGBA)) {
                $out .= '<dfn>'.$color."</dfn>\n";
            }
            if ($color = $r->getColor(ColorRepresentation::COLOR_HSLA)) {
                $out .= '<dfn>'.$color."</dfn>\n";
            }
        } else {
            if ($color = $r->getColor(ColorRepresentation::COLOR_RGB)) {
                $out .= '<dfn>'.$color."</dfn>\n";
            }
            if ($color = $r->getColor(ColorRepresentation::COLOR_HSL)) {
                $out .= '<dfn>'.$color."</dfn>\n";
            }
        }

        if (!\strlen($out)) {
            return null;
        }

        return '<pre>'.$out.'</pre>';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Value\AbstractValue;

class LockPlugin extends AbstractPlugin implements ValuePluginInterface
{
    public function renderValue(AbstractValue $v): ?string
    {
        switch ($v->getHint()) {
            case 'blacklist':
                return '<dl>'.$this->renderLockedHeader($v, '<var>Blacklisted</var>').'</dl>';
            case 'recursion':
                return '<dl>'.$this->renderLockedHeader($v, '<var>Recursion</var>').'</dl>';
            case 'depth_limit':
                return '<dl>'.$this->renderLockedHeader($v, '<var>Depth Limit</var>').'</dl>';
            case 'array_limit':
                return '<dl>'.$this->renderLockedHeader($v, '<var>Array Limit</var>').'</dl>';
        }

        return null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\Representation\MicrotimeRepresentation;
use Kint\Value\Representation\RepresentationInterface;

class MicrotimePlugin extends AbstractPlugin implements TabPluginInterface
{
    public function renderTab(RepresentationInterface $r, AbstractValue $v): ?string
    {
        if (!$r instanceof MicrotimeRepresentation || !($dt = $r->getDateTime())) {
            return null;
        }

        $out = $dt->format('Y-m-d H:i:s.u');
        if (null !== ($lap = $r->getLapTime())) {
            $out .= '<br><b>SINCE LAST CALL:</b> <span class="kint-microtime-lap">'.\round($lap, 4).'</span>s.';
        }
        if (null !== ($total = $r->getTotalTime())) {
            $out .= '<br><b>SINCE START:</b> '.\round($total, 4).'s.';
        }
        if (null !== ($avg = $r->getAverageTime())) {
            $out .= '<br><b>AVERAGE DURATION:</b> <span class="kint-microtime-avg">'.\round($avg, 4).'</span>s.';
        }

        $bytes = Utils::getHumanReadableBytes($r->getMemoryUsage());
        $out .= '<br><b>MEMORY USAGE:</b> '.$r->getMemoryUsage().' bytes ('.\round($bytes['value'], 3).' '.$bytes['unit'].')';
        $bytes = Utils::getHumanReadableBytes($r->getMemoryUsageReal());
        $out .= ' (real '.\round($bytes['value'], 3).' '.$bytes['unit'].')';

        $bytes = Utils::getHumanReadableBytes($r->getMemoryPeakUsage());
        $out .= '<br><b>PEAK MEMORY USAGE:</b> '.$r->getMemoryPeakUsage().' bytes ('.\round($bytes['value'], 3).' '.$bytes['unit'].')';
        $bytes = Utils::getHumanReadableBytes($r->getMemoryPeakUsageReal());
        $out .= ' (real '.\round($bytes['value'], 3).' '.$bytes['unit'].')';

        return '<pre data-kint-microtime-group="'.$r->getGroup().'">'.$out.'</pre>';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Renderer\RichRenderer;

interface PluginInterface
{
    public function __construct(RichRenderer $r);
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Value\AbstractValue;
use Kint\Value\Representation\ProfileRepresentation;
use Kint\Value\Representation\RepresentationInterface;

class ProfilePlugin extends AbstractPlugin implements TabPluginInterface
{
    public function renderTab(RepresentationInterface $r, AbstractValue $v): ?string
    {
        if (!$r instanceof ProfileRepresentation) {
            return null;
        }

        $out = '<pre>';

        $out .= 'Complexity: '.$r->complexity.PHP_EOL;
        if (isset($r->instance_counts)) {
            $out .= 'Instance repetitions: '.\var_export($r->instance_counts, true).PHP_EOL;
        }
        if (isset($r->instance_complexity)) {
            $out .= 'Instance complexity: '.\var_export($r->instance_complexity, true).PHP_EOL;
        }

        $out .= '</pre>';

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Value\AbstractValue;
use Kint\Value\Representation\RepresentationInterface;
use Kint\Value\Representation\SourceRepresentation;

class SourcePlugin extends AbstractPlugin implements TabPluginInterface
{
    public function renderTab(RepresentationInterface $r, AbstractValue $v): ?string
    {
        if (!$r instanceof SourceRepresentation) {
            return null;
        }

        $source = $r->getSourceLines();

        // Trim empty lines from the start and end of the source
        foreach ($source as $linenum => $line) {
            if (\strlen(\trim($line)) || $linenum === $r->getLine()) {
                break;
            }

            unset($source[$linenum]);
        }

        foreach (\array_reverse($source, true) as $linenum => $line) {
            if (\strlen(\trim($line)) || $linenum === $r->getLine()) {
                break;
            }

            unset($source[$linenum]);
        }

        $output = '';

        foreach ($source as $linenum => $line) {
            if ($linenum === $r->getLine()) {
                $output .= '<div class="kint-highlight">'.$this->renderer->escape($line)."\n".'</div>';
            } else {
                $output .= '<div>'.$this->renderer->escape($line)."\n".'</div>';
            }
        }

        if ($output) {
            $data = '';
            if ($r->showFileName()) {
                $data = ' data-kint-filename="'.$this->renderer->escape($r->getFileName()).'"';
            }

            return '<div><pre class="kint-source"'.$data.' style="counter-reset: kint-l '.((int) \array_key_first($source) - 1).';">'.$output.'</pre></div><div></div>';
        }

        return null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Value\AbstractValue;
use Kint\Value\Representation\RepresentationInterface;

interface TabPluginInterface extends PluginInterface
{
    public function renderTab(RepresentationInterface $r, AbstractValue $v): ?string;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Renderer\RichRenderer;
use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\ArrayValue;
use Kint\Value\FixedWidthValue;
use Kint\Value\Representation\RepresentationInterface;
use Kint\Value\Representation\TableRepresentation;
use Kint\Value\StringValue;

class TablePlugin extends AbstractPlugin implements TabPluginInterface
{
    public static bool $respect_str_length = true;

    public function renderTab(RepresentationInterface $r, AbstractValue $v): ?string
    {
        if (!$r instanceof TableRepresentation) {
            return null;
        }

        $contents = $r->getContents();

        $firstrow = \reset($contents);

        if (!$firstrow instanceof ArrayValue) {
            return null;
        }

        $out = '<pre><table><thead><tr><th></th>';

        foreach ($firstrow->getContents() as $field) {
            $out .= '<th>'.$this->renderer->escape($field->getDisplayName()).'</th>';
        }

        $out .= '</tr></thead><tbody>';

        foreach ($contents as $row) {
            if (!$row instanceof ArrayValue) {
                return null;
            }

            $out .= '<tr><th>'.$this->renderer->escape($row->getDisplayName()).'</th>';

            foreach ($row->getContents() as $field) {
                $ref = $field->getContext()->isRef() ? '&amp;' : '';
                $type = $this->renderer->escape($field->getDisplayType());

                $out .= '<td title="'.$ref.$type;

                if (null !== ($size = $field->getDisplaySize())) {
                    $size = $this->renderer->escape($size);
                    $out .= ' ('.$size.')';
                }

                $out .= '">';

                if ($field instanceof FixedWidthValue) {
                    if (null === ($dv = $field->getDisplayValue())) {
                        $out .= '<var>'.$ref.'null</var>';
                    } elseif ('boolean' === $field->getType()) {
                        $out .= '<var>'.$ref.$dv.'</var>';
                    } else {
                        $out .= $dv;
                    }
                } elseif ($field instanceof StringValue) {
                    if (false !== $field->getEncoding()) {
                        $val = $field->getValueUtf8();

                        if (RichRenderer::$strlen_max && self::$respect_str_length) {
                            $val = Utils::truncateString($val, RichRenderer::$strlen_max, 'UTF-8');
                        }

                        $out .= $this->renderer->escape($val);
                    } else {
                        $out .= '<var>'.$ref.$type.'</var>';
                    }
                } elseif ($field instanceof ArrayValue) {
                    $out .= '<var>'.$ref.'array</var> ('.$field->getSize().')';
                } else {
                    $out .= '<var>'.$ref.$type.'</var>';
                    if (null !== $size) {
                        $out .= ' ('.$size.')';
                    }
                }

                if ($field->flags & AbstractValue::FLAG_BLACKLIST) {
                    $out .= ' <var>Blacklisted</var>';
                } elseif ($field->flags & AbstractValue::FLAG_RECURSION) {
                    $out .= ' <var>Recursion</var>';
                } elseif ($field->flags & AbstractValue::FLAG_DEPTH_LIMIT) {
                    $out .= ' <var>Depth Limit</var>';
                }

                $out .= '</td>';
            }

            $out .= '</tr>';
        }

        $out .= '</tbody></table></pre>';

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Value\AbstractValue;
use Kint\Value\MethodValue;
use Kint\Value\TraceFrameValue;

class TraceFramePlugin extends AbstractPlugin implements ValuePluginInterface
{
    public function renderValue(AbstractValue $v): ?string
    {
        if (!$v instanceof TraceFrameValue) {
            return null;
        }

        if (null !== ($file = $v->getFile()) && null !== ($line = $v->getLine())) {
            $header = '<var>'.$this->renderer->ideLink($file, $line).'</var> ';
        } else {
            $header = '<var>PHP internal call</var> ';
        }

        if ($callable = $v->getCallable()) {
            if ($callable instanceof MethodValue) {
                $function = $callable->getFullyQualifiedDisplayName();
            } else {
                $function = $callable->getDisplayName();
            }

            $function = $this->renderer->escape($function);

            if (null !== ($url = $callable->getPhpDocUrl())) {
                $function = '<a href="'.$url.'" target=_blank>'.$function.'</a>';
            }

            $header .= $function;
        }

        $children = $this->renderer->renderChildren($v);
        $header = $this->renderer->renderHeaderWrapper($v->getContext(), (bool) \strlen($children), $header);

        return '<dl>'.$header.$children.'</dl>';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Rich;

use Kint\Value\AbstractValue;

interface ValuePluginInterface extends PluginInterface
{
    public function renderValue(AbstractValue $v): ?string;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer;

use Kint\Renderer\Rich\TabPluginInterface;
use Kint\Renderer\Rich\ValuePluginInterface;
use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\Context\ClassDeclaredContext;
use Kint\Value\Context\ContextInterface;
use Kint\Value\Context\PropertyContext;
use Kint\Value\InstanceValue;
use Kint\Value\Representation;
use Kint\Value\Representation\ContainerRepresentation;
use Kint\Value\Representation\RepresentationInterface;
use Kint\Value\Representation\StringRepresentation;
use Kint\Value\Representation\ValueRepresentation;
use Kint\Value\StringValue;

/**
 * @psalm-import-type Encoding from StringValue
 */
class RichRenderer extends AbstractRenderer
{
    use AssetRendererTrait;

    /**
     * RichRenderer value plugins should implement ValuePluginInterface.
     *
     * @psalm-var class-string<ValuePluginInterface>[]
     */
    public static array $value_plugins = [
        'array_limit' => Rich\LockPlugin::class,
        'blacklist' => Rich\LockPlugin::class,
        'callable' => Rich\CallablePlugin::class,
        'color' => Rich\ColorPlugin::class,
        'depth_limit' => Rich\LockPlugin::class,
        'recursion' => Rich\LockPlugin::class,
        'trace_frame' => Rich\TraceFramePlugin::class,
    ];

    /**
     * RichRenderer tab plugins should implement TabPluginInterface.
     *
     * @psalm-var array<string, class-string<TabPluginInterface>>
     */
    public static array $tab_plugins = [
        'binary' => Rich\BinaryPlugin::class,
        'callable' => Rich\CallableDefinitionPlugin::class,
        'color' => Rich\ColorPlugin::class,
        'microtime' => Rich\MicrotimePlugin::class,
        'profiling' => Rich\ProfilePlugin::class,
        'source' => Rich\SourcePlugin::class,
        'table' => Rich\TablePlugin::class,
    ];

    public static array $pre_render_sources = [
        'script' => [
            [self::class, 'renderJs'],
        ],
        'style' => [
            [self::class, 'renderCss'],
        ],
        'raw' => [],
    ];

    /**
     * The maximum length of a string before it is truncated.
     *
     * Falsey to disable
     */
    public static int $strlen_max = 80;

    /**
     * Timestamp to print in footer in date() format.
     */
    public static ?string $timestamp = null;

    /**
     * Whether or not to render access paths.
     *
     * Access paths can become incredibly heavy with very deep and wide
     * structures. Given mostly public variables it will typically make
     * up one quarter of the output HTML size.
     *
     * If this is an unacceptably large amount and your browser is groaning
     * under the weight of the access paths - your first order of buisiness
     * should be to get a new browser. Failing that, use this to turn them off.
     */
    public static bool $access_paths = true;

    /**
     * Assume types and sizes don't need to be escaped.
     *
     * Turn this off if you use anything but ascii in your class names,
     * but it'll cause a slowdown of around 10%
     */
    public static bool $escape_types = false;

    /**
     * Move all dumps to a folder at the bottom of the body.
     */
    public static bool $folder = false;

    public static bool $needs_pre_render = true;
    public static bool $always_pre_render = false;

    protected array $plugin_objs = [];
    protected bool $expand = false;
    protected bool $force_pre_render = false;
    protected bool $use_folder = false;

    public function __construct()
    {
        parent::__construct();
        self::$theme ??= 'original.css';
        $this->use_folder = self::$folder;
        $this->force_pre_render = self::$always_pre_render;
    }

    public function setCallInfo(array $info): void
    {
        parent::setCallInfo($info);

        if (\in_array('!', $info['modifiers'], true)) {
            $this->expand = true;
            $this->use_folder = false;
        }

        if (\in_array('@', $info['modifiers'], true)) {
            $this->force_pre_render = true;
        }
    }

    public function setStatics(array $statics): void
    {
        parent::setStatics($statics);

        if (!empty($statics['expanded'])) {
            $this->expand = true;
        }

        if (!empty($statics['return'])) {
            $this->force_pre_render = true;
        }
    }

    public function shouldPreRender(): bool
    {
        return $this->force_pre_render || self::$needs_pre_render;
    }

    public function render(AbstractValue $v): string
    {
        $render_spl_ids_stash = $this->render_spl_ids;

        if ($this->render_spl_ids && $v->flags & AbstractValue::FLAG_GENERATED) {
            $this->render_spl_ids = false;
        }

        if ($plugin = $this->getValuePlugin($v)) {
            $output = $plugin->renderValue($v);
            if (null !== $output && \strlen($output)) {
                if (!$this->render_spl_ids && $render_spl_ids_stash) {
                    $this->render_spl_ids = true;
                }

                return $output;
            }
        }

        $children = $this->renderChildren($v);
        $header = $this->renderHeaderWrapper($v->getContext(), (bool) \strlen($children), $this->renderHeader($v));

        if (!$this->render_spl_ids && $render_spl_ids_stash) {
            $this->render_spl_ids = true;
        }

        return '<dl>'.$header.$children.'</dl>';
    }

    public function renderHeaderWrapper(ContextInterface $c, bool $has_children, string $contents): string
    {
        $out = '<dt';

        if ($has_children) {
            $out .= ' class="kint-parent';

            if ($this->expand) {
                $out .= ' kint-show';
            }

            $out .= '"';
        }

        $out .= '>';

        if (self::$access_paths && $c->getDepth() > 0 && null !== ($ap = $c->getAccessPath())) {
            $out .= '<span class="kint-access-path-trigger" title="Show access path"></span>';
        }

        if ($has_children) {
            if (0 === $c->getDepth()) {
                if (!$this->use_folder) {
                    $out .= '<span class="kint-folder-trigger" title="Move to folder"></span>';
                }
                $out .= '<span class="kint-search-trigger" title="Show search box"></span>';
                $out .= '<input type="text" class="kint-search" value="">';
            }

            $out .= '<nav></nav>';
        }

        $out .= $contents;

        if (!empty($ap)) {
            $out .= '<div class="access-path">'.$this->escape($ap).'</div>';
        }

        return $out.'</dt>';
    }

    public function renderHeader(AbstractValue $v): string
    {
        $c = $v->getContext();

        $output = '';

        if ($c instanceof ClassDeclaredContext) {
            $output .= '<var>'.$c->getModifiers().'</var> ';
        }

        $output .= '<dfn>'.$this->escape($v->getDisplayName()).'</dfn> ';

        if ($c instanceof PropertyContext && null !== ($s = $c->getHooks())) {
            $output .= '<var>'.$this->escape($s).'</var> ';
        }

        if (null !== ($s = $c->getOperator())) {
            $output .= $this->escape($s, 'ASCII').' ';
        }

        $s = $v->getDisplayType();
        if (self::$escape_types) {
            $s = $this->escape($s);
        }

        if ($c->isRef()) {
            $s = '&amp;'.$s;
        }

        $output .= '<var>'.$s.'</var>';

        if ($v instanceof InstanceValue && $this->shouldRenderObjectIds()) {
            $output .= '#'.$v->getSplObjectId();
        }

        $output .= ' ';

        if (null !== ($s = $v->getDisplaySize())) {
            if (self::$escape_types) {
                $s = $this->escape($s);
            }
            $output .= '('.$s.') ';
        }

        if (null !== ($s = $v->getDisplayValue())) {
            $s = (string) \preg_replace('/\\s+/', ' ', $s);

            if (self::$strlen_max) {
                $s = Utils::truncateString($s, self::$strlen_max);
            }

            $output .= $this->escape($s);
        }

        return \trim($output);
    }

    public function renderChildren(AbstractValue $v): string
    {
        $contents = [];
        $tabs = [];

        foreach ($v->getRepresentations() as $rep) {
            $result = $this->renderTab($v, $rep);
            if (\strlen($result)) {
                $contents[] = $result;
                $tabs[] = $rep;
            }
        }

        if (empty($tabs)) {
            return '';
        }

        $output = '<dd>';

        if (1 === \count($tabs) && $tabs[0]->labelIsImplicit()) {
            $output .= (string) \reset($contents);
        } else {
            $output .= '<ul class="kint-tabs">';

            foreach ($tabs as $i => $tab) {
                if (0 === $i) {
                    $output .= '<li class="kint-active-tab">';
                } else {
                    $output .= '<li>';
                }

                $output .= $this->escape($tab->getLabel()).'</li>';
            }

            $output .= '</ul><ul class="kint-tab-contents">';

            foreach ($contents as $i => $tab) {
                if (0 === $i) {
                    $output .= '<li class="kint-show">';
                } else {
                    $output .= '<li>';
                }

                $output .= $tab.'</li>';
            }

            $output .= '</ul>';
        }

        return $output.'</dd>';
    }

    public function preRender(): string
    {
        $output = '';

        if ($this->shouldPreRender()) {
            foreach (self::$pre_render_sources as $type => $values) {
                $contents = '';
                foreach ($values as $v) {
                    $contents .= \call_user_func($v, $this);
                }

                if (!\strlen($contents)) {
                    continue;
                }

                switch ($type) {
                    case 'script':
                        $output .= '<script class="kint-rich-script"';
                        if (null !== self::$js_nonce) {
                            $output .= ' nonce="'.\htmlspecialchars(self::$js_nonce).'"';
                        }
                        $output .= '>'.$contents.'</script>';
                        break;
                    case 'style':
                        $output .= '<style class="kint-rich-style"';
                        if (null !== self::$css_nonce) {
                            $output .= ' nonce="'.\htmlspecialchars(self::$css_nonce).'"';
                        }
                        $output .= '>'.$contents.'</style>';
                        break;
                    default:
                        $output .= $contents;
                }
            }

            // Don't pre-render on every dump
            if (!$this->force_pre_render) {
                self::$needs_pre_render = false;
            }
        }

        $output .= '<div class="kint-rich';

        if ($this->use_folder) {
            $output .= ' kint-file';
        }

        $output .= '">';

        return $output;
    }

    public function postRender(): string
    {
        if (!$this->show_trace) {
            return '</div>';
        }

        $output = '<footer';

        if ($this->expand) {
            $output .= ' class="kint-show"';
        }

        $output .= '>';

        if (!$this->use_folder) {
            $output .= '<span class="kint-folder-trigger" title="Move to folder">&mapstodown;</span>';
        }

        if (!empty($this->trace) && \count($this->trace) > 1) {
            $output .= '<nav></nav>';
        }

        $output .= $this->calledFrom();

        if (!empty($this->trace) && \count($this->trace) > 1) {
            $output .= '<ol>';
            foreach ($this->trace as $index => $step) {
                if (!$index) {
                    continue;
                }

                $output .= '<li>'.$this->ideLink($step['file'], $step['line']); // closing tag not required
                if (isset($step['function']) &&
                    !\in_array($step['function'], ['include', 'include_once', 'require', 'require_once'], true)
                ) {
                    $output .= ' [';
                    $output .= $step['class'] ?? '';
                    $output .= $step['type'] ?? '';
                    $output .= $step['function'].'()]';
                }
            }
            $output .= '</ol>';
        }

        $output .= '</footer></div>';

        return $output;
    }

    /**
     * @psalm-param Encoding $encoding
     */
    public function escape(string $string, $encoding = false): string
    {
        if (false === $encoding) {
            $encoding = Utils::detectEncoding($string);
        }

        $original_encoding = $encoding;

        if (false === $encoding || 'ASCII' === $encoding) {
            $encoding = 'UTF-8';
        }

        $string = \htmlspecialchars($string, ENT_NOQUOTES, $encoding);

        // this call converts all non-ASCII characters into numeirc htmlentities
        if (\function_exists('mb_encode_numericentity') && 'ASCII' !== $original_encoding) {
            $string = \mb_encode_numericentity($string, [0x80, 0xFFFF, 0, 0xFFFF], $encoding);
        }

        return $string;
    }

    public function ideLink(string $file, int $line): string
    {
        $path = $this->escape(Utils::shortenPath($file)).':'.$line;
        $ideLink = self::getFileLink($file, $line);

        if (null === $ideLink) {
            return $path;
        }

        return '<a href="'.$this->escape($ideLink).'">'.$path.'</a>';
    }

    protected function calledFrom(): string
    {
        $output = '';

        if (isset($this->callee['file'])) {
            $output .= ' '.$this->ideLink(
                $this->callee['file'],
                $this->callee['line']
            );
        }

        if (
            isset($this->callee['function']) &&
            (
                !empty($this->callee['class']) ||
                !\in_array(
                    $this->callee['function'],
                    ['include', 'include_once', 'require', 'require_once'],
                    true
                )
            )
        ) {
            $output .= ' [';
            $output .= $this->callee['class'] ?? '';
            $output .= $this->callee['type'] ?? '';
            $output .= $this->callee['function'].'()]';
        }

        if ('' !== $output) {
            $output = 'Called from'.$output;
        }

        if (null !== self::$timestamp) {
            $output .= ' '.\date(self::$timestamp);
        }

        return $output;
    }

    protected function renderTab(AbstractValue $v, RepresentationInterface $rep): string
    {
        if ($plugin = $this->getTabPlugin($rep)) {
            $output = $plugin->renderTab($rep, $v);
            if (null !== $output) {
                return $output;
            }
        }

        if ($rep instanceof ValueRepresentation) {
            return $this->render($rep->getValue());
        }

        if ($rep instanceof ContainerRepresentation) {
            $output = '';

            foreach ($rep->getContents() as $obj) {
                $output .= $this->render($obj);
            }

            return $output;
        }

        if ($rep instanceof StringRepresentation) {
            // If we're dealing with the content representation
            if ($v instanceof StringValue && $rep->getValue() === $v->getValue()) {
                // Only show the contents if:
                if (\preg_match('/(:?[\\r\\n\\t\\f\\v]| {2})/', $rep->getValue())) {
                    // We have unrepresentable whitespace (Without whitespace preservation)
                    $show_contents = true;
                } elseif (self::$strlen_max && Utils::strlen($v->getDisplayValue()) > self::$strlen_max) {
                    // We had to truncate getDisplayValue
                    $show_contents = true;
                } else {
                    $show_contents = false;
                }
            } else {
                $show_contents = true;
            }

            if ($show_contents) {
                return '<pre>'.$this->escape($rep->getValue())."\n</pre>";
            }
        }

        return '';
    }

    protected function getValuePlugin(AbstractValue $v): ?ValuePluginInterface
    {
        $hint = $v->getHint();

        if (null === $hint || !isset(self::$value_plugins[$hint])) {
            return null;
        }

        $plugin = self::$value_plugins[$hint];

        if (!\is_a($plugin, ValuePluginInterface::class, true)) {
            return null;
        }

        if (!isset($this->plugin_objs[$plugin])) {
            $this->plugin_objs[$plugin] = new $plugin($this);
        }

        return $this->plugin_objs[$plugin];
    }

    protected function getTabPlugin(RepresentationInterface $r): ?TabPluginInterface
    {
        $hint = $r->getHint();

        if (null === $hint || !isset(self::$tab_plugins[$hint])) {
            return null;
        }

        $plugin = self::$tab_plugins[$hint];

        if (!\is_a($plugin, TabPluginInterface::class, true)) {
            return null;
        }

        if (!isset($this->plugin_objs[$plugin])) {
            $this->plugin_objs[$plugin] = new $plugin($this);
        }

        return $this->plugin_objs[$plugin];
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Text;

use Kint\Renderer\TextRenderer;
use Kint\Value\AbstractValue;

abstract class AbstractPlugin implements PluginInterface
{
    protected TextRenderer $renderer;

    public function __construct(TextRenderer $r)
    {
        $this->renderer = $r;
    }

    public function renderLockedHeader(AbstractValue $v, ?string $content = null): string
    {
        $out = '';

        if (0 === $v->getContext()->getDepth()) {
            $out .= $this->renderer->colorTitle($this->renderer->renderTitle($v)).PHP_EOL;
        }

        $out .= $this->renderer->renderHeader($v);

        if (null !== $content) {
            $out .= ' '.$this->renderer->colorValue($content);
        }

        $out .= PHP_EOL;

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Text;

use Kint\Value\AbstractValue;

class LockPlugin extends AbstractPlugin
{
    public function render(AbstractValue $v): ?string
    {
        switch ($v->getHint()) {
            case 'blacklist':
                return $this->renderLockedHeader($v, 'BLACKLISTED');
            case 'recursion':
                return $this->renderLockedHeader($v, 'RECURSION');
            case 'depth_limit':
                return $this->renderLockedHeader($v, 'DEPTH LIMIT');
            case 'array_limit':
                return $this->renderLockedHeader($v, 'ARRAY LIMIT');
        }

        return null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Text;

use Kint\Renderer\PlainRenderer;
use Kint\Renderer\TextRenderer;
use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\Representation\MicrotimeRepresentation;

class MicrotimePlugin extends AbstractPlugin
{
    protected bool $useJs = false;

    public function __construct(TextRenderer $r)
    {
        parent::__construct($r);

        if ($this->renderer instanceof PlainRenderer) {
            $this->useJs = true;
        }
    }

    public function render(AbstractValue $v): ?string
    {
        $r = $v->getRepresentation('microtime');

        if (!$r instanceof MicrotimeRepresentation || !($dt = $r->getDateTime())) {
            return null;
        }

        $c = $v->getContext();

        $out = '';

        if (0 === $c->getDepth()) {
            $out .= $this->renderer->colorTitle($this->renderer->renderTitle($v)).PHP_EOL;
        }

        $out .= $this->renderer->renderHeader($v);
        $out .= $this->renderer->renderChildren($v).PHP_EOL;

        $indent = \str_repeat(' ', ($c->getDepth() + 1) * $this->renderer->indent_width);

        if ($this->useJs) {
            $out .= '<span data-kint-microtime-group="'.$r->getGroup().'">';
        }

        $out .= $indent.$this->renderer->colorType('TIME:').' ';
        $out .= $this->renderer->colorValue($dt->format('Y-m-d H:i:s.u')).PHP_EOL;

        if (null !== ($lap = $r->getLapTime())) {
            $out .= $indent.$this->renderer->colorType('SINCE LAST CALL:').' ';

            $lap = \round($lap, 4);

            if ($this->useJs) {
                $lap = '<span class="kint-microtime-lap">'.$lap.'</span>';
            }

            $out .= $this->renderer->colorValue($lap.'s').'.'.PHP_EOL;
        }
        if (null !== ($total = $r->getTotalTime())) {
            $out .= $indent.$this->renderer->colorType('SINCE START:').' ';
            $out .= $this->renderer->colorValue(\round($total, 4).'s').'.'.PHP_EOL;
        }
        if (null !== ($avg = $r->getAverageTime())) {
            $out .= $indent.$this->renderer->colorType('AVERAGE DURATION:').' ';

            $avg = \round($avg, 4);

            if ($this->useJs) {
                $avg = '<span class="kint-microtime-avg">'.$avg.'</span>';
            }

            $out .= $this->renderer->colorValue($avg.'s').'.'.PHP_EOL;
        }

        $bytes = Utils::getHumanReadableBytes($r->getMemoryUsage());
        $mem = $r->getMemoryUsage().' bytes ('.\round($bytes['value'], 3).' '.$bytes['unit'].')';
        $bytes = Utils::getHumanReadableBytes($r->getMemoryUsageReal());
        $mem .= ' (real '.\round($bytes['value'], 3).' '.$bytes['unit'].')';

        $out .= $indent.$this->renderer->colorType('MEMORY USAGE:').' ';
        $out .= $this->renderer->colorValue($mem).'.'.PHP_EOL;

        $bytes = Utils::getHumanReadableBytes($r->getMemoryPeakUsage());
        $mem = $r->getMemoryPeakUsage().' bytes ('.\round($bytes['value'], 3).' '.$bytes['unit'].')';
        $bytes = Utils::getHumanReadableBytes($r->getMemoryPeakUsageReal());
        $mem .= ' (real '.\round($bytes['value'], 3).' '.$bytes['unit'].')';

        $out .= $indent.$this->renderer->colorType('PEAK MEMORY USAGE:').' ';
        $out .= $this->renderer->colorValue($mem).'.'.PHP_EOL;

        if ($this->useJs) {
            $out .= '</span>';
        }

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Text;

use Kint\Renderer\TextRenderer;
use Kint\Value\AbstractValue;

interface PluginInterface
{
    public function __construct(TextRenderer $r);

    public function render(AbstractValue $v): ?string;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Text;

use Kint\Value\AbstractValue;
use Kint\Value\Representation\SplFileInfoRepresentation;

class SplFileInfoPlugin extends AbstractPlugin
{
    public function render(AbstractValue $v): ?string
    {
        $r = $v->getRepresentation('splfileinfo');

        if (!$r instanceof SplFileInfoRepresentation) {
            return null;
        }

        $out = '';

        $c = $v->getContext();

        if (0 === $c->getDepth()) {
            $out .= $this->renderer->colorTitle($this->renderer->renderTitle($v)).PHP_EOL;
        }

        $out .= $this->renderer->renderHeader($v);
        if (null !== $v->getDisplayValue()) {
            $out .= ' =>';
        }
        $out .= ' '.$this->renderer->colorValue($this->renderer->escape($r->getValue())).PHP_EOL;

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer\Text;

use Kint\Value\AbstractValue;
use Kint\Value\MethodValue;
use Kint\Value\Representation\SourceRepresentation;
use Kint\Value\TraceFrameValue;
use Kint\Value\TraceValue;

class TracePlugin extends AbstractPlugin
{
    public function render(AbstractValue $v): ?string
    {
        if (!$v instanceof TraceValue) {
            return null;
        }

        $c = $v->getContext();

        $out = '';

        if (0 === $c->getDepth()) {
            $out .= $this->renderer->colorTitle($this->renderer->renderTitle($v)).PHP_EOL;
        }

        $out .= $this->renderer->renderHeader($v).':'.PHP_EOL;

        $indent = \str_repeat(' ', ($c->getDepth() + 1) * $this->renderer->indent_width);

        $i = 1;
        foreach ($v->getContents() as $frame) {
            if (!$frame instanceof TraceFrameValue) {
                continue;
            }

            $framedesc = $indent.\str_pad($i.': ', 4, ' ');

            if (null !== ($file = $frame->getFile()) && null !== ($line = $frame->getLine())) {
                $framedesc .= $this->renderer->ideLink($file, $line).PHP_EOL;
            } else {
                $framedesc .= 'PHP internal call'.PHP_EOL;
            }

            if ($callable = $frame->getCallable()) {
                $framedesc .= $indent.'    ';

                if ($callable instanceof MethodValue) {
                    $framedesc .= $this->renderer->escape($callable->getContext()->owner_class.$callable->getContext()->getOperator());
                }

                $framedesc .= $this->renderer->escape($callable->getDisplayName());
            }

            $out .= $this->renderer->colorType($framedesc).PHP_EOL.PHP_EOL;

            $source = $frame->getRepresentation('source');

            if ($source instanceof SourceRepresentation) {
                $line_wanted = $source->getLine();
                $source = $source->getSourceLines();

                // Trim empty lines from the start and end of the source
                foreach ($source as $linenum => $line) {
                    if (\trim($line) || $linenum === $line_wanted) {
                        break;
                    }

                    unset($source[$linenum]);
                }

                foreach (\array_reverse($source, true) as $linenum => $line) {
                    if (\trim($line) || $linenum === $line_wanted) {
                        break;
                    }

                    unset($source[$linenum]);
                }

                foreach ($source as $lineno => $line) {
                    if ($lineno === $line_wanted) {
                        $out .= $indent.$this->renderer->colorValue($this->renderer->escape($line)).PHP_EOL;
                    } else {
                        $out .= $indent.$this->renderer->escape($line).PHP_EOL;
                    }
                }
            }

            ++$i;
        }

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Renderer;

use Kint\Parser;
use Kint\Parser\PluginInterface as ParserPluginInterface;
use Kint\Renderer\Text\PluginInterface;
use Kint\Utils;
use Kint\Value\AbstractValue;
use Kint\Value\ArrayValue;
use Kint\Value\Context\ArrayContext;
use Kint\Value\Context\ClassDeclaredContext;
use Kint\Value\Context\PropertyContext;
use Kint\Value\InstanceValue;
use Kint\Value\StringValue;

/**
 * @psalm-import-type Encoding from StringValue
 */
class TextRenderer extends AbstractRenderer
{
    /**
     * TextRenderer plugins should implement PluginInterface.
     *
     * @psalm-var class-string<PluginInterface>[]
     */
    public static array $plugins = [
        'array_limit' => Text\LockPlugin::class,
        'blacklist' => Text\LockPlugin::class,
        'depth_limit' => Text\LockPlugin::class,
        'splfileinfo' => Text\SplFileInfoPlugin::class,
        'microtime' => Text\MicrotimePlugin::class,
        'recursion' => Text\LockPlugin::class,
        'trace' => Text\TracePlugin::class,
    ];

    /**
     * Parser plugins must be instanceof one of these or
     * it will be removed for performance reasons.
     *
     * @psalm-var class-string<ParserPluginInterface>[]
     */
    public static array $parser_plugin_whitelist = [
        Parser\ArrayLimitPlugin::class,
        Parser\ArrayObjectPlugin::class,
        Parser\BlacklistPlugin::class,
        Parser\ClosurePlugin::class,
        Parser\DateTimePlugin::class,
        Parser\DomPlugin::class,
        Parser\EnumPlugin::class,
        Parser\IteratorPlugin::class,
        Parser\MicrotimePlugin::class,
        Parser\MysqliPlugin::class,
        Parser\SimpleXMLElementPlugin::class,
        Parser\SplFileInfoPlugin::class,
        Parser\StreamPlugin::class,
        Parser\TracePlugin::class,
    ];

    /**
     * The maximum length of a string before it is truncated.
     *
     * Falsey to disable
     */
    public static int $strlen_max = 0;

    /**
     * Timestamp to print in footer in date() format.
     */
    public static ?string $timestamp = null;

    /**
     * The default width of the terminal for headers.
     */
    public static int $default_width = 80;

    /**
     * Indentation width.
     */
    public static int $default_indent = 4;

    /**
     * Decorate the header and footer.
     */
    public static bool $decorations = true;

    public int $header_width = 80;
    public int $indent_width = 4;

    protected array $plugin_objs = [];

    public function __construct()
    {
        parent::__construct();
        $this->header_width = self::$default_width;
        $this->indent_width = self::$default_indent;
    }

    public function render(AbstractValue $v): string
    {
        $render_spl_ids_stash = $this->render_spl_ids;

        if ($this->render_spl_ids && ($v->flags & AbstractValue::FLAG_GENERATED)) {
            $this->render_spl_ids = false;
        }

        if ($plugin = $this->getPlugin($v)) {
            $output = $plugin->render($v);
            if (null !== $output && \strlen($output)) {
                if (!$this->render_spl_ids && $render_spl_ids_stash) {
                    $this->render_spl_ids = true;
                }

                return $output;
            }
        }

        $out = '';

        $c = $v->getContext();

        if (0 === $c->getDepth()) {
            $out .= $this->colorTitle($this->renderTitle($v)).PHP_EOL;
        }

        $out .= $header = $this->renderHeader($v);
        $out .= $this->renderChildren($v);

        if (\strlen($header)) {
            $out .= PHP_EOL;
        }

        if (!$this->render_spl_ids && $render_spl_ids_stash) {
            $this->render_spl_ids = true;
        }

        return $out;
    }

    public function boxText(string $text, int $width): string
    {
        $out = '┌'.\str_repeat('─', $width - 2).'┐'.PHP_EOL;

        if (\strlen($text)) {
            $text = Utils::truncateString($text, $width - 4);
            $text = \str_pad($text, $width - 4);

            $out .= '│ '.$this->escape($text).' │'.PHP_EOL;
        }

        $out .= '└'.\str_repeat('─', $width - 2).'┘';

        return $out;
    }

    public function renderTitle(AbstractValue $v): string
    {
        if (self::$decorations) {
            return $this->boxText($v->getDisplayName(), $this->header_width);
        }

        return Utils::truncateString($v->getDisplayName(), $this->header_width);
    }

    public function renderHeader(AbstractValue $v): string
    {
        $output = [];

        $c = $v->getContext();

        if ($c->getDepth() > 0) {
            if ($c instanceof ClassDeclaredContext) {
                $output[] = $this->colorType($c->getModifiers());
            }

            if ($c instanceof ArrayContext) {
                $output[] = $this->escape(\var_export($c->getName(), true));
            } else {
                $output[] = $this->escape((string) $c->getName());
            }

            if ($c instanceof PropertyContext && null !== ($s = $c->getHooks())) {
                $output[] = $this->colorType($this->escape($s));
            }

            if (null !== ($s = $c->getOperator())) {
                $output[] = $this->escape($s);
            }
        }

        $s = $v->getDisplayType();
        if ($c->isRef()) {
            $s = '&'.$s;
        }

        $s = $this->colorType($this->escape($s));

        if ($v instanceof InstanceValue && $this->shouldRenderObjectIds()) {
            $s .= '#'.$v->getSplObjectId();
        }

        $output[] = $s;

        if (null !== ($s = $v->getDisplaySize())) {
            $output[] = '('.$this->escape($s).')';
        }

        if (null !== ($s = $v->getDisplayValue())) {
            if (self::$strlen_max) {
                $s = Utils::truncateString($s, self::$strlen_max);
            }
            $output[] = $this->colorValue($this->escape($s));
        }

        return \str_repeat(' ', $c->getDepth() * $this->indent_width).\implode(' ', $output);
    }

    public function renderChildren(AbstractValue $v): string
    {
        $children = $v->getDisplayChildren();

        if (!$children) {
            if ($v instanceof ArrayValue) {
                return ' []';
            }

            return '';
        }

        if ($v instanceof ArrayValue) {
            $output = ' [';
        } elseif ($v instanceof InstanceValue) {
            $output = ' (';
        } else {
            $output = '';
        }

        $output .= PHP_EOL;
        foreach ($children as $child) {
            $output .= $this->render($child);
        }

        $indent = \str_repeat(' ', $v->getContext()->getDepth() * $this->indent_width);

        if ($v instanceof ArrayValue) {
            $output .= $indent.']';
        } elseif ($v instanceof InstanceValue) {
            $output .= $indent.')';
        }

        return $output;
    }

    public function colorValue(string $string): string
    {
        return $string;
    }

    public function colorType(string $string): string
    {
        return $string;
    }

    public function colorTitle(string $string): string
    {
        return $string;
    }

    public function postRender(): string
    {
        if (self::$decorations) {
            $output = \str_repeat('═', $this->header_width);
        } else {
            $output = '';
        }

        if (!$this->show_trace) {
            return $this->colorTitle($output);
        }

        if ($output) {
            $output .= PHP_EOL;
        }

        return $this->colorTitle($output.$this->calledFrom().PHP_EOL);
    }

    public function filterParserPlugins(array $plugins): array
    {
        $return = [];

        foreach ($plugins as $plugin) {
            foreach (self::$parser_plugin_whitelist as $whitelist) {
                if ($plugin instanceof $whitelist) {
                    $return[] = $plugin;
                    continue 2;
                }
            }
        }

        return $return;
    }

    public function ideLink(string $file, int $line): string
    {
        return $this->escape(Utils::shortenPath($file)).':'.$line;
    }

    /**
     * @psalm-param Encoding $encoding
     */
    public function escape(string $string, $encoding = false): string
    {
        return $string;
    }

    protected function calledFrom(): string
    {
        $output = '';

        if (isset($this->callee['file'])) {
            $output .= 'Called from '.$this->ideLink(
                $this->callee['file'],
                $this->callee['line']
            );
        }

        if (
            isset($this->callee['function']) &&
            (
                !empty($this->callee['class']) ||
                !\in_array(
                    $this->callee['function'],
                    ['include', 'include_once', 'require', 'require_once'],
                    true
                )
            )
        ) {
            $output .= ' [';
            $output .= $this->callee['class'] ?? '';
            $output .= $this->callee['type'] ?? '';
            $output .= $this->callee['function'].'()]';
        }

        if (null !== self::$timestamp) {
            if (\strlen($output)) {
                $output .= ' ';
            }
            $output .= \date(self::$timestamp);
        }

        return $output;
    }

    protected function getPlugin(AbstractValue $v): ?PluginInterface
    {
        $hint = $v->getHint();

        if (null === $hint || !isset(self::$plugins[$hint])) {
            return null;
        }

        $plugin = self::$plugins[$hint];

        if (!\is_a($plugin, PluginInterface::class, true)) {
            return null;
        }

        if (!isset($this->plugin_objs[$plugin])) {
            $this->plugin_objs[$plugin] = new $plugin($this);
        }

        return $this->plugin_objs[$plugin];
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint;

use Kint\Value\StringValue;
use Kint\Value\TraceFrameValue;
use ReflectionNamedType;
use ReflectionType;
use UnexpectedValueException;

/**
 * A collection of utility methods. Should all be static methods with no dependencies.
 *
 * @psalm-import-type Encoding from StringValue
 * @psalm-import-type TraceFrame from TraceFrameValue
 */
final class Utils
{
    public const BT_STRUCTURE = [
        'function' => 'string',
        'line' => 'integer',
        'file' => 'string',
        'class' => 'string',
        'object' => 'object',
        'type' => 'string',
        'args' => 'array',
    ];

    public const BYTE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB'];

    /**
     * @var array Character encodings to detect
     *
     * @see https://secure.php.net/function.mb-detect-order
     *
     * In practice, mb_detect_encoding can only successfully determine the
     * difference between the following common charsets at once without
     * breaking things for one of the other charsets:
     * - ASCII
     * - UTF-8
     * - SJIS
     * - EUC-JP
     *
     * The order of the charsets is significant. If you put UTF-8 before ASCII
     * it will never match ASCII, because UTF-8 is a superset of ASCII.
     * Similarly, SJIS and EUC-JP frequently match UTF-8 strings, so you should
     * check UTF-8 first. SJIS and EUC-JP seem to work either way, but SJIS is
     * more common so it should probably be first.
     *
     * While you're free to experiment with other charsets, remember to keep
     * this behavior in mind when setting up your char_encodings array.
     *
     * This depends on the mbstring extension
     */
    public static array $char_encodings = [
        'ASCII',
        'UTF-8',
    ];

    /**
     * @var array Legacy character encodings to detect
     *
     * @see https://secure.php.net/function.iconv
     *
     * Assuming the other encoding checks fail, this will perform a
     * simple iconv conversion to check for invalid bytes. If any are
     * found it will not match.
     *
     * This can be useful for ambiguous single byte encodings like
     * windows-125x and iso-8859-x which have practically undetectable
     * differences because they use every single byte available.
     *
     * This is *NOT* reliable and should not be trusted implicitly. Since it
     * works by triggering and suppressing conversion warnings, your error
     * handler may complain.
     *
     * As with char_encodings, the order of the charsets is significant.
     *
     * This depends on the iconv extension
     */
    public static array $legacy_encodings = [];

    /**
     * @var array Path aliases that will be displayed instead of the full path.
     *
     * Keys are paths, values are replacement strings
     *
     * Example for laravel:
     *
     * Utils::$path_aliases = [
     *     base_path() => '<BASE>',
     *     app_path() => '<APP>',
     *     base_path().'/vendor' => '<VENDOR>',
     * ];
     *
     * Defaults to [$_SERVER['DOCUMENT_ROOT'] => '<ROOT>']
     *
     * @psalm-var array<non-empty-string, string>
     */
    public static array $path_aliases = [];

    /**
     * @codeCoverageIgnore
     *
     * @psalm-suppress UnusedConstructor
     */
    private function __construct()
    {
    }

    /**
     * Turns a byte value into a human-readable representation.
     *
     * @param int $value Amount of bytes
     *
     * @return array Human readable value and unit
     *
     * @psalm-return array{value: float, unit: 'B'|'KB'|'MB'|'GB'|'TB'}
     *
     * @psalm-pure
     */
    public static function getHumanReadableBytes(int $value): array
    {
        $negative = $value < 0;
        $value = \abs($value);

        if ($value < 1024) {
            $i = 0;
            $value = \floor($value);
        } elseif ($value < 0xFFFCCCCCCCCCCCC >> 40) {
            $i = 1;
        } elseif ($value < 0xFFFCCCCCCCCCCCC >> 30) {
            $i = 2;
        } elseif ($value < 0xFFFCCCCCCCCCCCC >> 20) {
            $i = 3;
        } else {
            $i = 4;
        }

        if ($i) {
            $value = $value / \pow(1024, $i);
        }

        if ($negative) {
            $value *= -1;
        }

        return [
            'value' => \round($value, 1),
            'unit' => self::BYTE_UNITS[$i],
        ];
    }

    /** @psalm-pure */
    public static function isSequential(array $array): bool
    {
        return \array_keys($array) === \range(0, \count($array) - 1);
    }

    /** @psalm-pure */
    public static function isAssoc(array $array): bool
    {
        return (bool) \count(\array_filter(\array_keys($array), 'is_string'));
    }

    /**
     * @psalm-assert-if-true list<TraceFrame> $trace
     */
    public static function isTrace(array $trace): bool
    {
        if (!self::isSequential($trace)) {
            return false;
        }

        $file_found = false;

        foreach ($trace as $frame) {
            if (!\is_array($frame) || !isset($frame['function'])) {
                return false;
            }

            if (isset($frame['class']) && !\class_exists($frame['class'], false)) {
                return false;
            }

            foreach ($frame as $key => $val) {
                if (!isset(self::BT_STRUCTURE[$key])) {
                    return false;
                }

                if (\gettype($val) !== self::BT_STRUCTURE[$key]) {
                    return false;
                }

                if ('file' === $key) {
                    $file_found = true;
                }
            }
        }

        return $file_found;
    }

    /**
     * @psalm-param TraceFrame $frame
     *
     * @psalm-pure
     */
    public static function traceFrameIsListed(array $frame, array $matches): bool
    {
        if (isset($frame['class'])) {
            $called = [\strtolower($frame['class']), \strtolower($frame['function'])];
        } else {
            $called = \strtolower($frame['function']);
        }

        return \in_array($called, $matches, true);
    }

    /** @psalm-pure */
    public static function normalizeAliases(array $aliases): array
    {
        foreach ($aliases as $index => $alias) {
            if (\is_array($alias) && 2 === \count($alias)) {
                $alias = \array_values(\array_filter($alias, 'is_string'));

                if (2 === \count($alias) && self::isValidPhpName($alias[1]) && self::isValidPhpNamespace($alias[0])) {
                    $aliases[$index] = [
                        \strtolower(\ltrim($alias[0], '\\')),
                        \strtolower($alias[1]),
                    ];
                } else {
                    unset($aliases[$index]);
                    continue;
                }
            } elseif (\is_string($alias)) {
                if (self::isValidPhpNamespace($alias)) {
                    $alias = \explode('\\', \strtolower($alias));
                    $aliases[$index] = \end($alias);
                } else {
                    unset($aliases[$index]);
                    continue;
                }
            } else {
                unset($aliases[$index]);
            }
        }

        return \array_values($aliases);
    }

    /** @psalm-pure */
    public static function isValidPhpName(string $name): bool
    {
        return (bool) \preg_match('/^[a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*$/', $name);
    }

    /** @psalm-pure */
    public static function isValidPhpNamespace(string $ns): bool
    {
        $parts = \explode('\\', $ns);
        if ('' === \reset($parts)) {
            \array_shift($parts);
        }

        if (!\count($parts)) {
            return false;
        }

        foreach ($parts as $part) {
            if (!self::isValidPhpName($part)) {
                return false;
            }
        }

        return true;
    }

    /**
     * trigger_error before PHP 8.1 truncates the error message at nul
     * so we have to sanitize variable strings before using them.
     *
     * @psalm-pure
     */
    public static function errorSanitizeString(string $input): string
    {
        if (KINT_PHP82 || '' === $input) {
            return $input;
        }

        return (string) \strtok($input, "\0"); // @codeCoverageIgnore
    }

    /** @psalm-pure */
    public static function getTypeString(ReflectionType $type): string
    {
        // @codeCoverageIgnoreStart
        // ReflectionType::__toString was deprecated in 7.4 and undeprecated in 8
        // and toString doesn't correctly show the nullable ? in the type before 8
        if (!KINT_PHP80) {
            if (!$type instanceof ReflectionNamedType) {
                throw new UnexpectedValueException('ReflectionType on PHP 7 must be ReflectionNamedType');
            }

            $name = $type->getName();
            if ($type->allowsNull() && 'mixed' !== $name && false === \strpos($name, '|')) {
                $name = '?'.$name;
            }

            return $name;
        }
        // @codeCoverageIgnoreEnd

        return (string) $type;
    }

    /**
     * @psalm-param Encoding $encoding
     */
    public static function truncateString(string $input, int $length = PHP_INT_MAX, string $end = '...', $encoding = false): string
    {
        $endlength = self::strlen($end);

        if ($endlength >= $length) {
            $endlength = 0;
            $end = '';
        }

        if (self::strlen($input, $encoding) > $length) {
            return self::substr($input, 0, $length - $endlength, $encoding).$end;
        }

        return $input;
    }

    /**
     * @psalm-return Encoding
     */
    public static function detectEncoding(string $string)
    {
        if (\function_exists('mb_detect_encoding')) {
            $ret = \mb_detect_encoding($string, self::$char_encodings, true);
            if (false !== $ret) {
                return $ret;
            }
        }

        // Pretty much every character encoding uses first 32 bytes as control
        // characters. If it's not a multi-byte format it's safe to say matching
        // any control character besides tab, nl, and cr means it's binary.
        if (\preg_match('/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]/', $string)) {
            return false;
        }

        if (\function_exists('iconv')) {
            foreach (self::$legacy_encodings as $encoding) {
                // Iconv detection works by triggering
                // "Detected an illegal character in input string" notices
                // This notice does not become a TypeError with strict_types
                // so we don't have to wrap this in a try catch
                if (@\iconv($encoding, $encoding, $string) === $string) {
                    return $encoding;
                }
            }
        } elseif (!\function_exists('mb_detect_encoding')) { // @codeCoverageIgnore
            // If a user has neither mb_detect_encoding, nor iconv, nor the
            // polyfills, there's not much we can do about it...
            // Pretend it's ASCII and pray the browser renders it properly.
            return 'ASCII'; // @codeCoverageIgnore
        }

        return false;
    }

    /**
     * @psalm-param Encoding $encoding
     */
    public static function strlen(string $string, $encoding = false): int
    {
        if (\function_exists('mb_strlen')) {
            if (false === $encoding) {
                $encoding = self::detectEncoding($string);
            }

            if (false !== $encoding && 'ASCII' !== $encoding) {
                return \mb_strlen($string, $encoding);
            }
        }

        return \strlen($string);
    }

    /**
     * @psalm-param Encoding $encoding
     */
    public static function substr(string $string, int $start, ?int $length = null, $encoding = false): string
    {
        if (\function_exists('mb_substr')) {
            if (false === $encoding) {
                $encoding = self::detectEncoding($string);
            }

            if (false !== $encoding && 'ASCII' !== $encoding) {
                return \mb_substr($string, $start, $length, $encoding);
            }
        }

        // Special case for substr/mb_substr discrepancy
        if ('' === $string) {
            return '';
        }

        return (string) \substr($string, $start, $length ?? PHP_INT_MAX);
    }

    public static function shortenPath(string $file): string
    {
        $split = \explode('/', \str_replace('\\', '/', $file));

        $longest_match = 0;
        $match = '';

        foreach (self::$path_aliases as $path => $alias) {
            $path = \explode('/', \str_replace('\\', '/', $path));

            if (\count($path) < 2) {
                continue;
            }

            if (\array_slice($split, 0, \count($path)) === $path && \count($path) > $longest_match) {
                $longest_match = \count($path);
                $match = $alias;
            }
        }

        if ($longest_match) {
            $suffix = \implode('/', \array_slice($split, $longest_match));

            if (\preg_match('%^/*$%', $suffix)) {
                return $match;
            }

            return $match.'/'.$suffix;
        }

        // fallback to find common path with Kint dir
        $kint = \explode('/', \str_replace('\\', '/', KINT_DIR));
        $had_real_path_part = false;

        foreach ($split as $i => $part) {
            if (!isset($kint[$i]) || $kint[$i] !== $part) {
                if (!$had_real_path_part) {
                    break;
                }

                $suffix = \implode('/', \array_slice($split, $i));

                if (\preg_match('%^/*$%', $suffix)) {
                    break;
                }

                $prefix = $i > 1 ? '.../' : '/';

                return $prefix.$suffix;
            }

            if ($i > 0 && \strlen($kint[$i])) {
                $had_real_path_part = true;
            }
        }

        return $file;
    }

    public static function composerGetExtras(string $key = 'kint'): array
    {
        if (0 === \strpos(KINT_DIR, 'phar://')) {
            // Only run inside phar file, so skip for code coverage
            return []; // @codeCoverageIgnore
        }

        $extras = [];

        $folder = KINT_DIR.'/vendor';

        for ($i = 0; $i < 4; ++$i) {
            $installed = $folder.'/composer/installed.json';

            if (\file_exists($installed) && \is_readable($installed)) {
                $packages = \json_decode((string) \file_get_contents($installed), true);

                if (!\is_array($packages)) {
                    continue;
                }

                // Composer 2.0 Compatibility: packages are now wrapped into a "packages" top level key instead of the whole file being the package array
                // @see https://getcomposer.org/upgrade/UPGRADE-2.0.md
                foreach ($packages['packages'] ?? $packages as $package) {
                    if (\is_array($package['extra'][$key] ?? null)) {
                        $extras = \array_replace($extras, $package['extra'][$key]);
                    }
                }

                $folder = \dirname($folder);

                if (\file_exists($folder.'/composer.json') && \is_readable($folder.'/composer.json')) {
                    $composer = \json_decode((string) \file_get_contents($folder.'/composer.json'), true);

                    if (\is_array($composer['extra'][$key] ?? null)) {
                        $extras = \array_replace($extras, $composer['extra'][$key]);
                    }
                }

                break;
            }

            $folder = \dirname($folder);
        }

        return $extras;
    }

    /**
     * @codeCoverageIgnore
     */
    public static function composerSkipFlags(): void
    {
        if (\defined('KINT_SKIP_FACADE') && \defined('KINT_SKIP_HELPERS')) {
            return;
        }

        $extras = self::composerGetExtras();

        if (!empty($extras['disable-facade']) && !\defined('KINT_SKIP_FACADE')) {
            \define('KINT_SKIP_FACADE', true);
        }

        if (!empty($extras['disable-helpers']) && !\defined('KINT_SKIP_HELPERS')) {
            \define('KINT_SKIP_HELPERS', true);
        }
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;
use Kint\Value\Representation\RepresentationInterface;
use OutOfRangeException;

/**
 * @psalm-import-type ValueName from ContextInterface
 *
 * @psalm-type ValueFlags int-mask-of<AbstractValue::FLAG_*>
 */
abstract class AbstractValue
{
    public const FLAG_NONE = 0;
    public const FLAG_GENERATED = 1 << 0;
    public const FLAG_BLACKLIST = 1 << 1;
    public const FLAG_RECURSION = 1 << 2;
    public const FLAG_DEPTH_LIMIT = 1 << 3;
    public const FLAG_ARRAY_LIMIT = 1 << 4;

    /** @psalm-var ValueFlags */
    public int $flags = self::FLAG_NONE;

    /** @psalm-readonly */
    protected ContextInterface $context;
    /** @psalm-readonly string */
    protected string $type;

    /** @psalm-var RepresentationInterface[] */
    protected array $representations = [];

    public function __construct(ContextInterface $context, string $type)
    {
        $this->context = $context;
        $this->type = $type;
    }

    public function __clone()
    {
        $this->context = clone $this->context;
    }

    public function getContext(): ContextInterface
    {
        return $this->context;
    }

    public function getHint(): ?string
    {
        if (self::FLAG_NONE === $this->flags) {
            return null;
        }
        if ($this->flags & self::FLAG_BLACKLIST) {
            return 'blacklist';
        }
        if ($this->flags & self::FLAG_RECURSION) {
            return 'recursion';
        }
        if ($this->flags & self::FLAG_DEPTH_LIMIT) {
            return 'depth_limit';
        }
        if ($this->flags & self::FLAG_ARRAY_LIMIT) {
            return 'array_limit';
        }

        return null;
    }

    public function getType(): string
    {
        return $this->type;
    }

    public function addRepresentation(RepresentationInterface $rep, ?int $pos = null): void
    {
        if (isset($this->representations[$rep->getName()])) {
            throw new OutOfRangeException('Representation already exists');
        }

        if (null === $pos) {
            $this->representations[$rep->getName()] = $rep;
        } else {
            $this->representations = \array_merge(
                \array_slice($this->representations, 0, $pos),
                [$rep->getName() => $rep],
                \array_slice($this->representations, $pos)
            );
        }
    }

    public function replaceRepresentation(RepresentationInterface $rep, ?int $pos = null): void
    {
        if (null === $pos) {
            $this->representations[$rep->getName()] = $rep;
        } else {
            $this->removeRepresentation($rep);
            $this->addRepresentation($rep, $pos);
        }
    }

    /**
     * @param RepresentationInterface|string $rep
     */
    public function removeRepresentation($rep): void
    {
        if ($rep instanceof RepresentationInterface) {
            unset($this->representations[$rep->getName()]);
        } else { // String
            unset($this->representations[$rep]);
        }
    }

    public function getRepresentation(string $name): ?RepresentationInterface
    {
        return $this->representations[$name] ?? null;
    }

    /** @psalm-return RepresentationInterface[] */
    public function getRepresentations(): array
    {
        return $this->representations;
    }

    /** @psalm-param RepresentationInterface[] $reps */
    public function appendRepresentations(array $reps): void
    {
        foreach ($reps as $rep) {
            $this->addRepresentation($rep);
        }
    }

    /** @psalm-api */
    public function clearRepresentations(): void
    {
        $this->representations = [];
    }

    public function getDisplayType(): string
    {
        return $this->type;
    }

    public function getDisplayName(): string
    {
        return (string) $this->context->getName();
    }

    public function getDisplaySize(): ?string
    {
        return null;
    }

    public function getDisplayValue(): ?string
    {
        return null;
    }

    /** @psalm-return AbstractValue[] */
    public function getDisplayChildren(): array
    {
        return [];
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;

class ArrayValue extends AbstractValue
{
    /** @psalm-readonly */
    protected int $size;
    /**
     * @psalm-readonly
     *
     * @psalm-var AbstractValue[]
     */
    protected array $contents;

    /** @psalm-param AbstractValue[] $contents */
    public function __construct(ContextInterface $context, int $size, array $contents)
    {
        parent::__construct($context, 'array');
        $this->size = $size;
        $this->contents = $contents;
    }

    public function getSize(): int
    {
        return $this->size;
    }

    /** @psalm-return AbstractValue[] */
    public function getContents()
    {
        return $this->contents;
    }

    public function getDisplaySize(): string
    {
        return (string) $this->size;
    }

    public function getDisplayChildren(): array
    {
        return $this->contents;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;

class ClosedResourceValue extends AbstractValue
{
    public function __construct(ContextInterface $context)
    {
        parent::__construct($context, 'resource (closed)');
    }

    public function getDisplayType(): string
    {
        return 'closed resource';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Closure;
use Kint\Utils;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\ContextInterface;
use ReflectionFunction;

class ClosureValue extends InstanceValue
{
    use ParameterHoldingTrait;

    /** @psalm-readonly */
    protected ?string $filename;
    /** @psalm-readonly */
    protected ?int $startline;

    public function __construct(ContextInterface $context, Closure $cl)
    {
        parent::__construct($context, \get_class($cl), \spl_object_hash($cl), \spl_object_id($cl));

        /**
         * @psalm-suppress UnnecessaryVarAnnotation
         *
         * @psalm-var ContextInterface $this->context
         * Psalm bug #11113
         */
        $closure = new ReflectionFunction($cl);

        if ($closure->isUserDefined()) {
            $this->filename = $closure->getFileName();
            $this->startline = $closure->getStartLine();
        } else {
            $this->filename = null;
            $this->startline = null;
        }

        $parameters = [];
        foreach ($closure->getParameters() as $param) {
            $parameters[] = new ParameterBag($param);
        }
        $this->parameters = $parameters;

        if (!$this->context instanceof BaseContext) {
            return;
        }

        if (0 !== $this->context->getDepth()) {
            return;
        }

        $ap = $this->context->getAccessPath();

        if (null === $ap) {
            return;
        }

        if (\preg_match('/^\\((function|fn)\\s*\\(/i', $ap, $match)) {
            $this->context->name = \strtolower($match[1]);
        }
    }

    /** @psalm-api */
    public function getFileName(): ?string
    {
        return $this->filename;
    }

    /** @psalm-api */
    public function getStartLine(): ?int
    {
        return $this->startline;
    }

    public function getDisplaySize(): ?string
    {
        return null;
    }

    public function getDisplayName(): string
    {
        return $this->context->getName().'('.$this->getParams().')';
    }

    public function getDisplayValue(): ?string
    {
        if (null !== $this->filename && null !== $this->startline) {
            return Utils::shortenPath($this->filename).':'.$this->startline;
        }

        return parent::getDisplayValue();
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

class ColorValue extends StringValue
{
    public function getHint(): string
    {
        return parent::getHint() ?? 'color';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

class ArrayContext extends BaseContext
{
    public function getOperator(): ?string
    {
        return '=>';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

use InvalidArgumentException;

/**
 * @psalm-import-type ValueName from ContextInterface
 */
class BaseContext implements ContextInterface
{
    /** @psalm-var ValueName */
    public $name;
    public int $depth = 0;
    public bool $reference = false;
    public ?string $access_path = null;

    /** @psalm-param mixed $name */
    public function __construct($name)
    {
        if (!\is_string($name) && !\is_int($name)) {
            throw new InvalidArgumentException('Context names must be string|int');
        }

        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getDepth(): int
    {
        return $this->depth;
    }

    public function getOperator(): ?string
    {
        return null;
    }

    public function isRef(): bool
    {
        return $this->reference;
    }

    /** @psalm-param ?class-string $scope */
    public function isAccessible(?string $scope): bool
    {
        return true;
    }

    public function getAccessPath(): ?string
    {
        return $this->access_path;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

class ClassConstContext extends ClassDeclaredContext
{
    public bool $final = false;

    public function getName(): string
    {
        return $this->owner_class.'::'.$this->name;
    }

    public function getOperator(): string
    {
        return '::';
    }

    public function getModifiers(): string
    {
        $final = $this->final ? 'final ' : '';

        return $final.$this->getAccess().' const';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

use __PHP_Incomplete_Class;

abstract class ClassDeclaredContext extends ClassOwnedContext
{
    public const ACCESS_PUBLIC = 1;
    public const ACCESS_PROTECTED = 2;
    public const ACCESS_PRIVATE = 3;

    /** @psalm-var self::ACCESS_* */
    public int $access;

    /** @psalm-var class-string */
    public ?string $proto_class = null;

    /**
     * @psalm-param class-string $owner_class
     * @psalm-param self::ACCESS_* $access
     */
    public function __construct(string $name, string $owner_class, int $access)
    {
        parent::__construct($name, $owner_class);
        $this->access = $access;
    }

    abstract public function getModifiers(): string;

    /** @psalm-param ?class-string $scope */
    public function isAccessible(?string $scope): bool
    {
        if (__PHP_Incomplete_Class::class === $this->owner_class) {
            return false;
        }

        if (self::ACCESS_PUBLIC === $this->access) {
            return true;
        }

        if (null === $scope) {
            return false;
        }

        if (self::ACCESS_PRIVATE === $this->access) {
            return $scope === $this->owner_class;
        }

        if (KINT_PHP8412 && null !== $this->proto_class) {
            if (\is_a($scope, $this->proto_class, true)) {
                return true;
            }

            if (\is_a($this->proto_class, $scope, true)) {
                return true;
            }
        } else {
            if (\is_a($scope, $this->owner_class, true)) {
                return true;
            }

            if (\is_a($this->owner_class, $scope, true)) {
                return true;
            }
        }

        return false;
    }

    protected function getAccess(): string
    {
        switch ($this->access) {
            case self::ACCESS_PUBLIC:
                return 'public';
            case self::ACCESS_PROTECTED:
                return 'protected';
            case self::ACCESS_PRIVATE:
                return 'private';
        }
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

use __PHP_Incomplete_Class;

class ClassOwnedContext extends BaseContext
{
    /** @psalm-var class-string */
    public string $owner_class;

    /** @psalm-param class-string $owner_class */
    public function __construct(string $name, string $owner_class)
    {
        parent::__construct($name);
        $this->owner_class = $owner_class;
    }

    public function getName(): string
    {
        return (string) $this->name;
    }

    public function getOperator(): string
    {
        return '->';
    }

    /** @psalm-param ?class-string $scope */
    public function isAccessible(?string $scope): bool
    {
        return __PHP_Incomplete_Class::class !== $this->owner_class;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

/**
 * Contexts represent the data that has to be found out about a zval _before_
 * passing it into the next parse depth. This includes the access path, whether
 * it's a reference or not, and OOP related stuff like visibility.
 *
 * @psalm-type ValueName = string|int
 */
interface ContextInterface
{
    /** @psalm-return ValueName */
    public function getName();

    public function getDepth(): int;

    public function isRef(): bool;

    /** @psalm-param ?class-string $scope */
    public function isAccessible(?string $scope): bool;

    public function getAccessPath(): ?string;

    /** @psalm-return ?non-empty-string */
    public function getOperator(): ?string;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

abstract class DoubleAccessMemberContext extends ClassDeclaredContext
{
    /** @psalm-var ?self::ACCESS_* */
    public ?int $access_set = null;

    protected function getAccess(): string
    {
        switch ($this->access) {
            case self::ACCESS_PUBLIC:
                if (self::ACCESS_PRIVATE === $this->access_set) {
                    return 'private(set)';
                }
                if (self::ACCESS_PROTECTED === $this->access_set) {
                    return 'protected(set)';
                }

                return 'public';

            case self::ACCESS_PROTECTED:
                if (self::ACCESS_PRIVATE === $this->access_set) {
                    return 'protected private(set)';
                }

                return 'protected';

            case self::ACCESS_PRIVATE:
                return 'private';
        }
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

use Kint\Value\InstanceValue;
use ReflectionMethod;

class MethodContext extends ClassDeclaredContext
{
    public const MAGIC_NAMES = [
        '__construct' => true,
        '__destruct' => true,
        '__call' => true,
        '__callstatic' => true,
        '__get' => true,
        '__set' => true,
        '__isset' => true,
        '__unset' => true,
        '__sleep' => true,
        '__wakeup' => true,
        '__serialize' => true,
        '__unserialize' => true,
        '__tostring' => true,
        '__invoke' => true,
        '__set_state' => true,
        '__clone' => true,
        '__debuginfo' => true,
    ];

    public bool $final = false;
    public bool $abstract = false;
    public bool $static = false;

    /**
     * Whether the method was inherited from a parent class or interface.
     *
     * It's important to note that we never show static methods as
     * "inherited" except when abstract via an interface.
     */
    public bool $inherited = false;

    public function __construct(ReflectionMethod $method)
    {
        parent::__construct(
            $method->getName(),
            $method->getDeclaringClass()->name,
            ClassDeclaredContext::ACCESS_PUBLIC
        );
        $this->depth = 1;
        $this->static = $method->isStatic();
        $this->abstract = $method->isAbstract();
        $this->final = $method->isFinal();
        if ($method->isProtected()) {
            $this->access = ClassDeclaredContext::ACCESS_PROTECTED;
        } elseif ($method->isPrivate()) {
            $this->access = ClassDeclaredContext::ACCESS_PRIVATE;
        }
    }

    public function getOperator(): string
    {
        if ($this->static) {
            return '::';
        }

        return '->';
    }

    public function getModifiers(): string
    {
        if ($this->abstract) {
            $out = 'abstract ';
        } elseif ($this->final) {
            $out = 'final ';
        } else {
            $out = '';
        }

        $out .= $this->getAccess();

        if ($this->static) {
            $out .= ' static';
        }

        return $out;
    }

    public function setAccessPathFromParent(?InstanceValue $parent): void
    {
        $name = \strtolower($this->getName());

        if ($this->static && !isset(self::MAGIC_NAMES[$name])) {
            $this->access_path = '\\'.$this->owner_class.'::'.$this->name.'()';
        } elseif (null === $parent) {
            $this->access_path = null;
        } else {
            $c = $parent->getContext();
            if ('__construct' === $name) {
                $this->access_path = 'new \\'.$parent->getClassName().'()';
            } elseif (null === $c->getAccessPath()) {
                $this->access_path = null;
            } elseif ('__invoke' === $name) {
                $this->access_path = $c->getAccessPath().'()';
            } elseif ('__clone' === $name) {
                $this->access_path = 'clone '.$c->getAccessPath();
            } elseif ('__tostring' === $name) {
                $this->access_path = '(string) '.$c->getAccessPath();
            } elseif (isset(self::MAGIC_NAMES[$name])) {
                $this->access_path = null;
            } else {
                $this->access_path = $c->getAccessPath().'->'.$this->name.'()';
            }
        }
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

class PropertyContext extends DoubleAccessMemberContext
{
    public const HOOK_NONE = 0;
    public const HOOK_GET = 1 << 0;
    public const HOOK_GET_REF = 1 << 1;
    public const HOOK_SET = 1 << 2;
    public const HOOK_SET_TYPE = 1 << 3;

    public bool $readonly = false;
    /** @psalm-var int-mask-of<self::HOOK_*> */
    public int $hooks = self::HOOK_NONE;
    public ?string $hook_set_type = null;

    public function getModifiers(): string
    {
        $out = $this->getAccess();

        if ($this->readonly) {
            $out .= ' readonly';
        }

        return $out;
    }

    public function getHooks(): ?string
    {
        if (self::HOOK_NONE === $this->hooks) {
            return null;
        }

        $out = '{ ';
        if ($this->hooks & self::HOOK_GET) {
            if ($this->hooks & self::HOOK_GET_REF) {
                $out .= '&';
            }
            $out .= 'get; ';
        }
        if ($this->hooks & self::HOOK_SET) {
            if ($this->hooks & self::HOOK_SET_TYPE && '' !== ($this->hook_set_type ?? '')) {
                $out .= 'set('.$this->hook_set_type.'); ';
            } else {
                $out .= 'set; ';
            }
        }
        $out .= '}';

        return $out;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Context;

class StaticPropertyContext extends DoubleAccessMemberContext
{
    public bool $final = false;

    public function getName(): string
    {
        return $this->owner_class.'::$'.$this->name;
    }

    public function getOperator(): string
    {
        return '::';
    }

    public function getModifiers(): string
    {
        $final = $this->final ? 'final ' : '';

        return $final.$this->getAccess().' static';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use DateTimeInterface;
use Kint\Value\Context\ContextInterface;

class DateTimeValue extends InstanceValue
{
    /** @psalm-readonly */
    protected DateTimeInterface $dt;

    public function __construct(ContextInterface $context, DateTimeInterface $dt)
    {
        parent::__construct($context, \get_class($dt), \spl_object_hash($dt), \spl_object_id($dt));

        $this->dt = clone $dt;
    }

    public function getHint(): string
    {
        return parent::getHint() ?? 'datetime';
    }

    public function getDisplayValue(): string
    {
        $stamp = $this->dt->format('Y-m-d H:i:s');
        if ((int) ($micro = $this->dt->format('u'))) {
            $stamp .= '.'.$micro;
        }
        $stamp .= $this->dt->format(' P');

        $tzn = $this->dt->getTimezone()->getName();
        if ('+' !== $tzn[0] && '-' !== $tzn[0]) {
            $stamp .= $this->dt->format(' T');
        }

        return $stamp;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Utils;
use ReflectionFunctionAbstract;

/** @psalm-api */
final class DeclaredCallableBag
{
    use ParameterHoldingTrait;

    /** @psalm-readonly */
    public bool $internal;
    /** @psalm-readonly */
    public ?string $filename;
    /** @psalm-readonly */
    public ?int $startline;
    /** @psalm-readonly */
    public ?int $endline;
    /**
     * @psalm-readonly
     *
     * @psalm-var ?non-empty-string
     */
    public ?string $docstring;
    /** @psalm-readonly */
    public bool $return_reference;
    /** @psalm-readonly */
    public ?string $returntype = null;

    public function __construct(ReflectionFunctionAbstract $callable)
    {
        $this->internal = $callable->isInternal();
        $t = $callable->getFileName();
        $this->filename = false === $t ? null : $t;
        $t = $callable->getStartLine();
        $this->startline = false === $t ? null : $t;
        $t = $callable->getEndLine();
        $this->endline = false === $t ? null : $t;
        $t = $callable->getDocComment();
        $this->docstring = false === $t ? null : $t;
        $this->return_reference = $callable->returnsReference();

        $rt = $callable->getReturnType();
        if ($rt) {
            $this->returntype = Utils::getTypeString($rt);
        }

        $parameters = [];
        foreach ($callable->getParameters() as $param) {
            $parameters[] = new ParameterBag($param);
        }
        $this->parameters = $parameters;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Dom\NodeList;
use DOMNodeList;
use Kint\Value\Context\ContextInterface;

class DomNodeListValue extends InstanceValue
{
    protected int $length;

    /**
     * @psalm-param DOMNodeList|NodeList $node
     */
    public function __construct(ContextInterface $context, object $node)
    {
        parent::__construct($context, \get_class($node), \spl_object_hash($node), \spl_object_id($node));

        $this->length = $node->length;
    }

    public function getLength(): int
    {
        return $this->length;
    }

    public function getDisplaySize(): string
    {
        return (string) $this->length;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Dom\Node;
use DOMNode;
use Kint\Value\Context\ContextInterface;

class DomNodeValue extends InstanceValue
{
    /**
     * @psalm-param DOMNode|Node $node
     */
    public function __construct(ContextInterface $context, object $node)
    {
        parent::__construct($context, \get_class($node), \spl_object_hash($node), \spl_object_id($node));
    }

    public function getDisplaySize(): ?string
    {
        return null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use BackedEnum;
use Kint\Value\Context\ContextInterface;
use UnitEnum;

class EnumValue extends InstanceValue
{
    /** @psalm-readonly */
    protected UnitEnum $enumval;

    public function __construct(ContextInterface $context, UnitEnum $enumval)
    {
        parent::__construct($context, \get_class($enumval), \spl_object_hash($enumval), \spl_object_id($enumval));

        $this->enumval = $enumval;
    }

    public function getHint(): string
    {
        return parent::getHint() ?? 'enum';
    }

    public function getDisplayType(): string
    {
        return $this->classname.'::'.$this->enumval->name;
    }

    public function getDisplayValue(): ?string
    {
        if ($this->enumval instanceof BackedEnum) {
            if (\is_string($this->enumval->value)) {
                return '"'.$this->enumval->value.'"';
            }

            return (string) $this->enumval->value;
        }

        return null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use InvalidArgumentException;
use Kint\Value\Context\ContextInterface;

/**
 * @psalm-type FixedWidthType = null|boolean|integer|double
 */
class FixedWidthValue extends AbstractValue
{
    /**
     * @psalm-readonly
     *
     * @psalm-var FixedWidthType
     */
    protected $value;

    /** @psalm-param FixedWidthType $value */
    public function __construct(ContextInterface $context, $value)
    {
        $type = \strtolower(\gettype($value));

        if ('null' === $type || 'boolean' === $type || 'integer' === $type || 'double' === $type) {
            parent::__construct($context, $type);
            $this->value = $value;
        } else {
            throw new InvalidArgumentException('FixedWidthValue can only contain fixed width types, got '.$type);
        }
    }

    /**
     * @psalm-api
     *
     * @psalm-return FixedWidthType
     */
    public function getValue()
    {
        return $this->value;
    }

    public function getDisplaySize(): ?string
    {
        return null;
    }

    public function getDisplayValue(): ?string
    {
        if ('boolean' === $this->type) {
            return ((bool) $this->value) ? 'true' : 'false';
        }

        if ('integer' === $this->type || 'double' === $this->type) {
            return (string) $this->value;
        }

        return null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;
use Kint\Value\Representation\CallableDefinitionRepresentation;

class FunctionValue extends AbstractValue
{
    /** @psalm-readonly */
    protected DeclaredCallableBag $callable_bag;
    /** @psalm-readonly */
    protected ?CallableDefinitionRepresentation $definition_rep;

    public function __construct(ContextInterface $c, DeclaredCallableBag $bag)
    {
        parent::__construct($c, 'function');

        $this->callable_bag = $bag;

        if ($this->callable_bag->internal) {
            $this->definition_rep = null;

            return;
        }

        /**
         * @psalm-var string $this->callable_bag->filename
         * @psalm-var int $this->callable_bag->startline
         * Psalm issue #11121
         */
        $this->definition_rep = new CallableDefinitionRepresentation(
            $this->callable_bag->filename,
            $this->callable_bag->startline,
            $this->callable_bag->docstring
        );
        $this->addRepresentation($this->definition_rep);
    }

    public function getCallableBag(): DeclaredCallableBag
    {
        return $this->callable_bag;
    }

    /** @psalm-api */
    public function getDefinitionRepresentation(): ?CallableDefinitionRepresentation
    {
        return $this->definition_rep;
    }

    public function getDisplayName(): string
    {
        return $this->context->getName().'('.$this->callable_bag->getParams().')';
    }

    public function getDisplayValue(): ?string
    {
        if ($this->definition_rep instanceof CallableDefinitionRepresentation) {
            return $this->definition_rep->getDocstringFirstLine();
        }

        return parent::getDisplayValue();
    }

    public function getPhpDocUrl(): ?string
    {
        if (!$this->callable_bag->internal) {
            return null;
        }

        return 'https://www.php.net/function.'.\str_replace('_', '-', \strtolower((string) $this->context->getName()));
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;

class InstanceValue extends AbstractValue
{
    /**
     * @psalm-readonly
     *
     * @psalm-var class-string
     */
    protected string $classname;
    /** @psalm-readonly */
    protected string $spl_object_hash;
    /** @psalm-readonly */
    protected int $spl_object_id;

    /**
     * The canonical children of this value, for text renderers.
     *
     * @psalm-var null|list<AbstractValue>
     */
    protected ?array $children = null;

    /** @psalm-param class-string $classname */
    public function __construct(
        ContextInterface $context,
        string $classname,
        string $spl_object_hash,
        int $spl_object_id
    ) {
        parent::__construct($context, 'object');
        $this->classname = $classname;
        $this->spl_object_hash = $spl_object_hash;
        $this->spl_object_id = $spl_object_id;
    }

    /** @psalm-return class-string */
    public function getClassName(): string
    {
        return $this->classname;
    }

    public function getSplObjectHash(): string
    {
        return $this->spl_object_hash;
    }

    public function getSplObjectId(): int
    {
        return $this->spl_object_id;
    }

    /** @psalm-param null|list<AbstractValue> $children */
    public function setChildren(?array $children): void
    {
        $this->children = $children;
    }

    /** @psalm-return null|list<AbstractValue> */
    public function getChildren(): ?array
    {
        return $this->children;
    }

    public function getDisplayType(): string
    {
        return $this->classname;
    }

    public function getDisplaySize(): ?string
    {
        if (null === $this->children) {
            return null;
        }

        return (string) \count($this->children);
    }

    public function getDisplayChildren(): array
    {
        return $this->children ?? [];
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ClassDeclaredContext;
use Kint\Value\Context\MethodContext;
use Kint\Value\Representation\CallableDefinitionRepresentation;

class MethodValue extends AbstractValue
{
    /** @psalm-readonly */
    protected DeclaredCallableBag $callable_bag;
    /** @psalm-readonly */
    protected ?CallableDefinitionRepresentation $definition_rep;

    public function __construct(MethodContext $c, DeclaredCallableBag $bag)
    {
        parent::__construct($c, 'method');

        $this->callable_bag = $bag;

        if ($this->callable_bag->internal) {
            $this->definition_rep = null;

            return;
        }

        /**
         * @psalm-var string $this->callable_bag->filename
         * @psalm-var int $this->callable_bag->startline
         * Psalm issue #11121
         */
        $this->definition_rep = new CallableDefinitionRepresentation(
            $this->callable_bag->filename,
            $this->callable_bag->startline,
            $this->callable_bag->docstring
        );
        $this->addRepresentation($this->definition_rep);
    }

    public function getHint(): string
    {
        return parent::getHint() ?? 'callable';
    }

    public function getContext(): MethodContext
    {
        /**
         * @psalm-var MethodContext $this->context
         * Psalm discuss #11116
         */
        return $this->context;
    }

    public function getCallableBag(): DeclaredCallableBag
    {
        return $this->callable_bag;
    }

    /** @psalm-api */
    public function getDefinitionRepresentation(): ?CallableDefinitionRepresentation
    {
        return $this->definition_rep;
    }

    public function getFullyQualifiedDisplayName(): string
    {
        $c = $this->getContext();

        return $c->owner_class.'::'.$c->getName().'('.$this->callable_bag->getParams().')';
    }

    public function getDisplayName(): string
    {
        $c = $this->getContext();

        if ($c->static || (ClassDeclaredContext::ACCESS_PRIVATE === $c->access && $c->inherited)) {
            return $this->getFullyQualifiedDisplayName();
        }

        return $c->getName().'('.$this->callable_bag->getParams().')';
    }

    public function getDisplayValue(): ?string
    {
        if ($this->definition_rep instanceof CallableDefinitionRepresentation) {
            return $this->definition_rep->getDocstringFirstLine();
        }

        return parent::getDisplayValue();
    }

    public function getPhpDocUrl(): ?string
    {
        if (!$this->callable_bag->internal) {
            return null;
        }

        $c = $this->getContext();

        $class = \str_replace('\\', '-', \strtolower($c->owner_class));
        $funcname = \str_replace('_', '-', \strtolower($c->getName()));

        if (0 === \strpos($funcname, '--') && 0 !== \strpos($funcname, '-', 2)) {
            $funcname = (string) \substr($funcname, 2);
        }

        return 'https://www.php.net/'.$class.'.'.$funcname;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

class MicrotimeValue extends AbstractValue
{
    /** @psalm-readonly */
    protected AbstractValue $wrapped;

    public function __construct(AbstractValue $old)
    {
        $this->context = $old->context;
        $this->type = $old->type;
        $this->flags = $old->flags;
        $this->representations = $old->representations;
        $this->wrapped = $old;
    }

    public function getHint(): string
    {
        return parent::getHint() ?? 'microtime';
    }

    public function getDisplaySize(): ?string
    {
        return $this->wrapped->getDisplaySize();
    }

    public function getDisplayValue(): ?string
    {
        return $this->wrapped->getDisplayValue();
    }

    public function getDisplayType(): string
    {
        return $this->wrapped->getDisplayType();
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Utils;
use ReflectionParameter;

final class ParameterBag
{
    /** @psalm-readonly */
    public string $name;
    /** @psalm-readonly */
    public int $position;
    /** @psalm-readonly */
    public bool $ref;
    /** @psalm-readonly */
    public ?string $type_hint;
    /** @psalm-readonly */
    public ?string $default;

    public function __construct(ReflectionParameter $param)
    {
        $this->name = $param->getName();
        $this->position = $param->getPosition();
        $this->ref = $param->isPassedByReference();

        $this->type_hint = ($type = $param->getType()) ? Utils::getTypeString($type) : null;

        if ($param->isDefaultValueAvailable()) {
            $default = $param->getDefaultValue();
            switch (\gettype($default)) {
                case 'NULL':
                    $this->default = 'null';
                    break;
                case 'boolean':
                    $this->default = $default ? 'true' : 'false';
                    break;
                case 'array':
                    $this->default = \count($default) ? 'array(...)' : 'array()';
                    break;
                case 'double':
                case 'integer':
                case 'string':
                    $this->default = \var_export($default, true);
                    break;
                case 'object':
                    $this->default = 'object('.\get_class($default).')';
                    break;
                default:
                    $this->default = \gettype($default);
                    break;
            }
        } else {
            $this->default = null;
        }
    }

    public function __toString()
    {
        $type = $this->type_hint;
        if (null !== $type) {
            $type .= ' ';
        }

        $default = $this->default;
        if (null !== $default) {
            $default = ' = '.$default;
        }

        $ref = $this->ref ? '&' : '';

        return $type.$ref.'$'.$this->name.$default;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

trait ParameterHoldingTrait
{
    /**
     * @psalm-readonly
     *
     * @psalm-var ParameterBag[]
     */
    public array $parameters = [];

    public function getParams(): string
    {
        $out = [];

        foreach ($this->parameters as $p) {
            $out[] = (string) $p;
        }

        return \implode(', ', $out);
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

abstract class AbstractRepresentation implements RepresentationInterface
{
    /** @psalm-readonly */
    protected string $label;
    /** @psalm-readonly */
    protected string $name;
    /** @psalm-readonly */
    protected bool $implicit_label;

    public function __construct(string $label, ?string $name = null, bool $implicit_label = false)
    {
        $this->label = $label;
        /** @psalm-var string $name */
        $name = \preg_replace('/[^a-z0-9]+/', '_', \strtolower($name ?? $label));
        $this->name = $name;
        $this->implicit_label = $implicit_label;
    }

    public function getLabel(): string
    {
        return $this->label;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function labelIsImplicit(): bool
    {
        return $this->implicit_label;
    }

    public function getHint(): ?string
    {
        return null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

class BinaryRepresentation extends AbstractRepresentation
{
    /** @psalm-readonly */
    protected string $value;

    public function __construct(string $value, bool $implicit = false)
    {
        parent::__construct('Hex dump', 'binary', $implicit);
        $this->value = $value;
    }

    public function getHint(): string
    {
        return 'binary';
    }

    public function getValue(): string
    {
        return $this->value;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use InvalidArgumentException;

class CallableDefinitionRepresentation extends AbstractRepresentation
{
    /** @psalm-readonly */
    protected string $filename;
    /** @psalm-readonly */
    protected int $line;
    /**
     * @psalm-readonly
     *
     * @psalm-var ?non-empty-string
     */
    protected ?string $docstring;

    /**
     * @psalm-param ?non-empty-string $docstring
     */
    public function __construct(string $filename, int $line, ?string $docstring)
    {
        if (null !== $docstring && !\preg_match('%^/\\*\\*.+\\*/$%s', $docstring)) {
            throw new InvalidArgumentException('Docstring is invalid');
        }

        parent::__construct('Callable definition', null, true);

        $this->filename = $filename;
        $this->line = $line;
        $this->docstring = $docstring;
    }

    public function getHint(): string
    {
        return 'callable';
    }

    public function getFileName(): string
    {
        return $this->filename;
    }

    public function getLine(): int
    {
        return $this->line;
    }

    /**
     * @psalm-api
     *
     * @psalm-return ?non-empty-string
     */
    public function getDocstring(): ?string
    {
        return $this->docstring;
    }

    /**
     * Returns the representation's docstring without surrounding comments.
     *
     * Note that this will not work flawlessly.
     *
     * On comments with whitespace after the stars the lines will begin with
     * whitespace, since we can't accurately guess how much of an indentation
     * is required.
     *
     * And on lines without stars on the left this may eat bullet points.
     *
     * Long story short: If you want the docstring read the contents. If you
     * absolutely must have it without comments (ie renderValueShort) this will
     * probably do.
     */
    public function getDocstringWithoutComments(): ?string
    {
        if (null === ($ds = $this->getDocstring())) {
            return null;
        }

        $string = (string) \substr($ds, 3, -2);
        /** @psalm-var string $string */
        $string = \preg_replace('/^\\s*\\*\\s*?(\\S|$)/m', '\\1', $string);

        return \trim($string);
    }

    public function getDocstringFirstLine(): ?string
    {
        $ds = $this->getDocstringWithoutComments();

        if (null === $ds) {
            return null;
        }

        $ds = \explode("\n", $ds);

        $out = '';

        foreach ($ds as $line) {
            if (0 === \strlen(\trim($line)) || '@' === $line[0]) {
                break;
            }

            $out .= $line.' ';
        }

        if (\strlen($out)) {
            return \rtrim($out);
        }

        return null;
    }

    public function getDocstringTrimmed(): ?string
    {
        if (null === ($ds = $this->getDocstring())) {
            return null;
        }

        $docstring = [];
        foreach (\explode("\n", $ds) as $line) {
            $line = \trim($line);
            if (($line[0] ?? null) === '*') {
                $line = ' '.$line;
            }
            $docstring[] = $line;
        }

        return \implode("\n", $docstring);
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use InvalidArgumentException;
use LogicException;

class ColorRepresentation extends AbstractRepresentation
{
    public const COLOR_NAME = 1;
    public const COLOR_HEX_3 = 2;
    public const COLOR_HEX_6 = 3;
    public const COLOR_RGB = 4;
    public const COLOR_RGBA = 5;
    public const COLOR_HSL = 6;
    public const COLOR_HSLA = 7;
    public const COLOR_HEX_4 = 8;
    public const COLOR_HEX_8 = 9;

    /** @psalm-var array<truthy-string, truthy-string> */
    public static array $color_map = [
        'aliceblue' => 'f0f8ff',
        'antiquewhite' => 'faebd7',
        'aqua' => '00ffff',
        'aquamarine' => '7fffd4',
        'azure' => 'f0ffff',
        'beige' => 'f5f5dc',
        'bisque' => 'ffe4c4',
        'black' => '000000',
        'blanchedalmond' => 'ffebcd',
        'blue' => '0000ff',
        'blueviolet' => '8a2be2',
        'brown' => 'a52a2a',
        'burlywood' => 'deb887',
        'cadetblue' => '5f9ea0',
        'chartreuse' => '7fff00',
        'chocolate' => 'd2691e',
        'coral' => 'ff7f50',
        'cornflowerblue' => '6495ed',
        'cornsilk' => 'fff8dc',
        'crimson' => 'dc143c',
        'cyan' => '00ffff',
        'darkblue' => '00008b',
        'darkcyan' => '008b8b',
        'darkgoldenrod' => 'b8860b',
        'darkgray' => 'a9a9a9',
        'darkgreen' => '006400',
        'darkgrey' => 'a9a9a9',
        'darkkhaki' => 'bdb76b',
        'darkmagenta' => '8b008b',
        'darkolivegreen' => '556b2f',
        'darkorange' => 'ff8c00',
        'darkorchid' => '9932cc',
        'darkred' => '8b0000',
        'darksalmon' => 'e9967a',
        'darkseagreen' => '8fbc8f',
        'darkslateblue' => '483d8b',
        'darkslategray' => '2f4f4f',
        'darkslategrey' => '2f4f4f',
        'darkturquoise' => '00ced1',
        'darkviolet' => '9400d3',
        'deeppink' => 'ff1493',
        'deepskyblue' => '00bfff',
        'dimgray' => '696969',
        'dimgrey' => '696969',
        'dodgerblue' => '1e90ff',
        'firebrick' => 'b22222',
        'floralwhite' => 'fffaf0',
        'forestgreen' => '228b22',
        'fuchsia' => 'ff00ff',
        'gainsboro' => 'dcdcdc',
        'ghostwhite' => 'f8f8ff',
        'gold' => 'ffd700',
        'goldenrod' => 'daa520',
        'gray' => '808080',
        'green' => '008000',
        'greenyellow' => 'adff2f',
        'grey' => '808080',
        'honeydew' => 'f0fff0',
        'hotpink' => 'ff69b4',
        'indianred' => 'cd5c5c',
        'indigo' => '4b0082',
        'ivory' => 'fffff0',
        'khaki' => 'f0e68c',
        'lavender' => 'e6e6fa',
        'lavenderblush' => 'fff0f5',
        'lawngreen' => '7cfc00',
        'lemonchiffon' => 'fffacd',
        'lightblue' => 'add8e6',
        'lightcoral' => 'f08080',
        'lightcyan' => 'e0ffff',
        'lightgoldenrodyellow' => 'fafad2',
        'lightgray' => 'd3d3d3',
        'lightgreen' => '90ee90',
        'lightgrey' => 'd3d3d3',
        'lightpink' => 'ffb6c1',
        'lightsalmon' => 'ffa07a',
        'lightseagreen' => '20b2aa',
        'lightskyblue' => '87cefa',
        'lightslategray' => '778899',
        'lightslategrey' => '778899',
        'lightsteelblue' => 'b0c4de',
        'lightyellow' => 'ffffe0',
        'lime' => '00ff00',
        'limegreen' => '32cd32',
        'linen' => 'faf0e6',
        'magenta' => 'ff00ff',
        'maroon' => '800000',
        'mediumaquamarine' => '66cdaa',
        'mediumblue' => '0000cd',
        'mediumorchid' => 'ba55d3',
        'mediumpurple' => '9370db',
        'mediumseagreen' => '3cb371',
        'mediumslateblue' => '7b68ee',
        'mediumspringgreen' => '00fa9a',
        'mediumturquoise' => '48d1cc',
        'mediumvioletred' => 'c71585',
        'midnightblue' => '191970',
        'mintcream' => 'f5fffa',
        'mistyrose' => 'ffe4e1',
        'moccasin' => 'ffe4b5',
        'navajowhite' => 'ffdead',
        'navy' => '000080',
        'oldlace' => 'fdf5e6',
        'olive' => '808000',
        'olivedrab' => '6b8e23',
        'orange' => 'ffa500',
        'orangered' => 'ff4500',
        'orchid' => 'da70d6',
        'palegoldenrod' => 'eee8aa',
        'palegreen' => '98fb98',
        'paleturquoise' => 'afeeee',
        'palevioletred' => 'db7093',
        'papayawhip' => 'ffefd5',
        'peachpuff' => 'ffdab9',
        'peru' => 'cd853f',
        'pink' => 'ffc0cb',
        'plum' => 'dda0dd',
        'powderblue' => 'b0e0e6',
        'purple' => '800080',
        'rebeccapurple' => '663399',
        'red' => 'ff0000',
        'rosybrown' => 'bc8f8f',
        'royalblue' => '4169e1',
        'saddlebrown' => '8b4513',
        'salmon' => 'fa8072',
        'sandybrown' => 'f4a460',
        'seagreen' => '2e8b57',
        'seashell' => 'fff5ee',
        'sienna' => 'a0522d',
        'silver' => 'c0c0c0',
        'skyblue' => '87ceeb',
        'slateblue' => '6a5acd',
        'slategray' => '708090',
        'slategrey' => '708090',
        'snow' => 'fffafa',
        'springgreen' => '00ff7f',
        'steelblue' => '4682b4',
        'tan' => 'd2b48c',
        'teal' => '008080',
        'thistle' => 'd8bfd8',
        'tomato' => 'ff6347',
        // To quote MDN:
        // "Technically, transparent is a shortcut for rgba(0,0,0,0)."
        'transparent' => '00000000',
        'turquoise' => '40e0d0',
        'violet' => 'ee82ee',
        'wheat' => 'f5deb3',
        'white' => 'ffffff',
        'whitesmoke' => 'f5f5f5',
        'yellow' => 'ffff00',
        'yellowgreen' => '9acd32',
    ];

    protected int $r;
    protected int $g;
    protected int $b;
    protected float $a;
    /** @psalm-var self::COLOR_* */
    protected int $variant;

    public function __construct(string $value)
    {
        parent::__construct('Color', null, true);
        $this->setValues($value);
    }

    public function getHint(): string
    {
        return 'color';
    }

    /**
     * @psalm-api
     *
     * @psalm-return self::COLOR_*
     */
    public function getVariant(): int
    {
        return $this->variant;
    }

    /**
     * @psalm-param self::COLOR_* $variant
     *
     * @psalm-return ?truthy-string
     */
    public function getColor(?int $variant = null): ?string
    {
        $variant ??= $this->variant;

        switch ($variant) {
            case self::COLOR_NAME:
                $hex = \sprintf('%02x%02x%02x', $this->r, $this->g, $this->b);
                $hex_alpha = \sprintf('%02x%02x%02x%02x', $this->r, $this->g, $this->b, \round($this->a * 0xFF));

                return \array_search($hex, self::$color_map, true) ?: \array_search($hex_alpha, self::$color_map, true) ?: null;
            case self::COLOR_HEX_3:
                if (0 === $this->r % 0x11 && 0 === $this->g % 0x11 && 0 === $this->b % 0x11) {
                    /** @psalm-var truthy-string */
                    return \sprintf(
                        '#%1X%1X%1X',
                        \round($this->r / 0x11),
                        \round($this->g / 0x11),
                        \round($this->b / 0x11)
                    );
                }

                return null;
            case self::COLOR_HEX_6:
                /** @psalm-var truthy-string */
                return \sprintf('#%02X%02X%02X', $this->r, $this->g, $this->b);
            case self::COLOR_RGB:
                if (1.0 === $this->a) {
                    /** @psalm-var truthy-string */
                    return \sprintf('rgb(%d, %d, %d)', $this->r, $this->g, $this->b);
                }

                /** @psalm-var truthy-string */
                return \sprintf('rgb(%d, %d, %d, %s)', $this->r, $this->g, $this->b, \round($this->a, 4));
            case self::COLOR_RGBA:
                /** @psalm-var truthy-string */
                return \sprintf('rgba(%d, %d, %d, %s)', $this->r, $this->g, $this->b, \round($this->a, 4));
            case self::COLOR_HSL:
                $val = self::rgbToHsl($this->r, $this->g, $this->b);
                $val[1] = \round($val[1] * 100);
                $val[2] = \round($val[2] * 100);
                if (1.0 === $this->a) {
                    /** @psalm-var truthy-string */
                    return \vsprintf('hsl(%d, %d%%, %d%%)', $val);
                }

                /** @psalm-var truthy-string */
                return \sprintf('hsl(%d, %d%%, %d%%, %s)', $val[0], $val[1], $val[2], \round($this->a, 4));
            case self::COLOR_HSLA:
                $val = self::rgbToHsl($this->r, $this->g, $this->b);
                $val[1] = \round($val[1] * 100);
                $val[2] = \round($val[2] * 100);

                /** @psalm-var truthy-string */
                return \sprintf('hsla(%d, %d%%, %d%%, %s)', $val[0], $val[1], $val[2], \round($this->a, 4));
            case self::COLOR_HEX_4:
                if (0 === $this->r % 0x11 && 0 === $this->g % 0x11 && 0 === $this->b % 0x11 && 0 === ((int) ($this->a * 255)) % 0x11) {
                    /** @psalm-var truthy-string */
                    return \sprintf(
                        '#%1X%1X%1X%1X',
                        \round($this->r / 0x11),
                        \round($this->g / 0x11),
                        \round($this->b / 0x11),
                        \round($this->a * 0xF)
                    );
                }

                return null;

            case self::COLOR_HEX_8:
                /** @psalm-var truthy-string */
                return \sprintf('#%02X%02X%02X%02X', $this->r, $this->g, $this->b, \round($this->a * 0xFF));
        }

        return null;
    }

    public function hasAlpha(?int $variant = null): bool
    {
        $variant ??= $this->variant;

        switch ($variant) {
            case self::COLOR_NAME:
            case self::COLOR_RGB:
            case self::COLOR_HSL:
                return \abs($this->a - 1) >= 0.0001;
            case self::COLOR_RGBA:
            case self::COLOR_HSLA:
            case self::COLOR_HEX_4:
            case self::COLOR_HEX_8:
                return true;
            default:
                return false;
        }
    }

    protected function setValues(string $value): void
    {
        $this->a = 1.0;

        $value = \strtolower(\trim($value));
        // Find out which variant of color input it is
        if (isset(self::$color_map[$value])) {
            $this->setValuesFromHex(self::$color_map[$value]);
            $variant = self::COLOR_NAME;
        } elseif ('#' === $value[0]) {
            $variant = $this->setValuesFromHex((string) \substr($value, 1));
        } else {
            $variant = $this->setValuesFromFunction($value);
        }

        // If something has gone horribly wrong
        if ($this->r > 0xFF || $this->g > 0xFF || $this->b > 0xFF || $this->a > 1) {
            throw new LogicException('Something has gone wrong with color parsing'); // @codeCoverageIgnore
        }
        $this->variant = $variant;
    }

    /** @psalm-return self::COLOR_* */
    protected function setValuesFromHex(string $hex): int
    {
        if (!\ctype_xdigit($hex)) {
            throw new InvalidArgumentException('Hex color codes must be hexadecimal');
        }

        switch (\strlen($hex)) {
            case 3:
                $variant = self::COLOR_HEX_3;
                break;
            case 6:
                $variant = self::COLOR_HEX_6;
                break;
            case 4:
                $variant = self::COLOR_HEX_4;
                break;
            case 8:
                $variant = self::COLOR_HEX_8;
                break;
            default:
                throw new InvalidArgumentException('Hex color codes must have 3, 4, 6, or 8 characters');
        }

        switch ($variant) {
            case self::COLOR_HEX_4:
                $this->a = \hexdec($hex[3]) / 0xF;
                // no break
            case self::COLOR_HEX_3:
                $this->r = \hexdec($hex[0]) * 0x11;
                $this->g = \hexdec($hex[1]) * 0x11;
                $this->b = \hexdec($hex[2]) * 0x11;
                break;
            case self::COLOR_HEX_8:
                $this->a = \hexdec((string) \substr($hex, 6, 2)) / 0xFF;
                // no break
            case self::COLOR_HEX_6:
                $hex = \str_split($hex, 2);
                $this->r = \hexdec($hex[0]);
                $this->g = \hexdec($hex[1]);
                $this->b = \hexdec($hex[2]);
                break;
        }

        return $variant;
    }

    /** @psalm-return self::COLOR_* */
    protected function setValuesFromFunction(string $value): int
    {
        // We're not even going to attempt to support other color functions or
        // angle values. If that's ever going to be a thing we'll depend on a
        // color library and use php scopes for the phar file.
        if (!\preg_match('/^((?:rgb|hsl)a?)\\s*\\(([0-9\\.%,\\s\\/\\-]+)\\)$/i', $value, $match)) {
            throw new InvalidArgumentException('Couldn\'t parse color function string');
        }

        switch (\strtolower($match[1])) {
            case 'rgb':
                $variant = self::COLOR_RGB;
                break;
            case 'rgba':
                $variant = self::COLOR_RGBA;
                break;
            case 'hsl':
                $variant = self::COLOR_HSL;
                break;
            case 'hsla':
                $variant = self::COLOR_HSLA;
                break;
            default:
                // The regex should preclude this from ever happening
                throw new InvalidArgumentException('Color functions must be one of rgb/rgba/hsl/hsla'); // @codeCoverageIgnore
        }

        \preg_match('/^\\s*([^,\\s\\/]+)([,\\s]+)((?1))((?2))((?1))(?:([,\\s\\/]+)((?1)))?\\s*$/', $match[2], $match);

        if (!$match ||
            \trim($match[2]) !== \trim($match[4]) ||
            (isset($match[6]) && (
                ('' === \trim($match[2]) && '/' !== \trim($match[6])) ||
                ('' !== \trim($match[2]) && \trim($match[2]) !== \trim($match[6]))
            ))
        ) {
            throw new InvalidArgumentException('Couldn\'t parse color function string');
        }

        $params = [
            $match[1],
            $match[3],
            $match[5],
        ];

        if (isset($match[7])) {
            $params[] = $match[7];
        }

        $params = \array_map('trim', $params);

        foreach ($params as $i => &$color) {
            if (false !== \strpos($color, '%')) {
                $color = (float) \str_replace('%', '', $color);

                if (\in_array($variant, [self::COLOR_RGB, self::COLOR_RGBA], true) && 3 !== $i) {
                    $color = \round($color / 100 * 0xFF);
                } else {
                    $color = $color / 100;
                }
            }

            $color = (float) $color;

            if (0 === $i && \in_array($variant, [self::COLOR_HSL, self::COLOR_HSLA], true)) {
                $color = \fmod(\fmod($color, 360) + 360, 360);
            }
        }

        /**
         * @psalm-var non-empty-array<array-key, float> $params
         * Psalm bug #746 (wontfix)
         */
        switch ($variant) {
            case self::COLOR_RGBA:
            case self::COLOR_RGB:
                if (\min($params) < 0 || \max($params) > 0xFF) {
                    throw new InvalidArgumentException('RGB function arguments must be between 0 and 255');
                }
                break;
            case self::COLOR_HSLA:
            case self::COLOR_HSL:
                if ($params[0] < 0 || $params[0] > 360) {
                    // Should be impossible because of the fmod work
                    throw new InvalidArgumentException('Hue must be between 0 and 360'); // @codeCoverageIgnore
                }
                if (\min($params) < 0 || \max($params[1], $params[2]) > 1) {
                    throw new InvalidArgumentException('Saturation/lightness must be between 0 and 1');
                }
                break;
        }

        if (4 === \count($params)) {
            if ($params[3] > 1) {
                throw new InvalidArgumentException('Alpha must be between 0 and 1');
            }

            $this->a = $params[3];
        }

        if (self::COLOR_HSLA === $variant || self::COLOR_HSL === $variant) {
            $params = self::hslToRgb($params[0], $params[1], $params[2]);
        }

        [$this->r, $this->g, $this->b] = [(int) $params[0], (int) $params[1], (int) $params[2]];

        return $variant;
    }

    /**
     * Turns HSL color to RGB. Black magic.
     *
     * @param float $h Hue
     * @param float $s Saturation
     * @param float $l Lightness
     *
     * @return int[] RGB array
     */
    public static function hslToRgb(float $h, float $s, float $l): array
    {
        if (\min($h, $s, $l) < 0) {
            throw new InvalidArgumentException('The parameters for hslToRgb should be no less than 0');
        }

        if ($h > 360 || \max($s, $l) > 1) {
            throw new InvalidArgumentException('The parameters for hslToRgb should be no more than 360, 1, and 1 respectively');
        }

        $h /= 360;

        $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l * $s;
        $m1 = $l * 2 - $m2;

        return [
            (int) \round(self::hueToRgb($m1, $m2, $h + 1 / 3) * 0xFF),
            (int) \round(self::hueToRgb($m1, $m2, $h) * 0xFF),
            (int) \round(self::hueToRgb($m1, $m2, $h - 1 / 3) * 0xFF),
        ];
    }

    /**
     * Converts RGB to HSL. Color inversion of previous black magic is white magic?
     *
     * @param float $red   Red
     * @param float $green Green
     * @param float $blue  Blue
     *
     * @return float[] HSL array
     */
    public static function rgbToHsl(float $red, float $green, float $blue): array
    {
        if (\min($red, $green, $blue) < 0) {
            throw new InvalidArgumentException('The parameters for rgbToHsl should be no less than 0');
        }

        if (\max($red, $green, $blue) > 0xFF) {
            throw new InvalidArgumentException('The parameters for rgbToHsl should be no more than 255');
        }

        $clrMin = \min($red, $green, $blue);
        $clrMax = \max($red, $green, $blue);
        $deltaMax = $clrMax - $clrMin;

        $L = ($clrMax + $clrMin) / 510;

        if (0 == $deltaMax) {
            $H = 0.0;
            $S = 0.0;
        } else {
            if (0.5 > $L) {
                $S = $deltaMax / ($clrMax + $clrMin);
            } else {
                $S = $deltaMax / (510 - $clrMax - $clrMin);
            }

            if ($clrMax === $red) {
                $H = ($green - $blue) / (6.0 * $deltaMax);

                if (0 > $H) {
                    $H += 1.0;
                }
            } elseif ($clrMax === $green) {
                $H = 1 / 3 + ($blue - $red) / (6.0 * $deltaMax);
            } else {
                $H = 2 / 3 + ($red - $green) / (6.0 * $deltaMax);
            }
        }

        return [
            \fmod($H * 360, 360),
            $S,
            $L,
        ];
    }

    /**
     * Helper function for hslToRgb. Even blacker magic.
     *
     * @return float Color value
     */
    private static function hueToRgb(float $m1, float $m2, float $hue): float
    {
        $hue = ($hue < 0) ? $hue + 1 : (($hue > 1) ? $hue - 1 : $hue);
        if ($hue * 6 < 1) {
            return $m1 + ($m2 - $m1) * $hue * 6;
        }
        if ($hue * 2 < 1) {
            return $m2;
        }
        if ($hue * 3 < 2) {
            return $m1 + ($m2 - $m1) * (2 / 3 - $hue) * 6;
        }

        return $m1;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use InvalidArgumentException;
use Kint\Value\AbstractValue;

class ContainerRepresentation extends AbstractRepresentation
{
    /**
     * @psalm-readonly
     *
     * @psalm-var non-empty-array<AbstractValue>
     */
    protected array $contents;

    /** @psalm-param non-empty-array<AbstractValue> $contents */
    public function __construct(string $label, array $contents, ?string $name = null, bool $implicit_label = false)
    {
        if ([] === $contents) {
            throw new InvalidArgumentException("ContainerRepresentation can't take empty list");
        }

        parent::__construct($label, $name, $implicit_label);
        $this->contents = $contents;
    }

    /** @psalm-return non-empty-array<AbstractValue> */
    public function getContents(): array
    {
        return $this->contents;
    }

    public function getLabel(): string
    {
        return parent::getLabel().' ('.\count($this->contents).')';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use DateTimeImmutable;
use DateTimeInterface;

class MicrotimeRepresentation extends AbstractRepresentation
{
    /** @psalm-readonly */
    protected int $seconds;
    /** @psalm-readonly */
    protected int $microseconds;
    /** @psalm-readonly */
    protected string $group;
    /** @psalm-readonly */
    protected ?float $lap_time;
    /** @psalm-readonly */
    protected ?float $total_time;
    protected ?float $avg_time = null;
    /** @psalm-readonly */
    protected int $mem;
    /** @psalm-readonly */
    protected int $mem_real;
    /** @psalm-readonly */
    protected int $mem_peak;
    /** @psalm-readonly */
    protected int $mem_peak_real;

    public function __construct(int $seconds, int $microseconds, string $group, ?float $lap_time = null, ?float $total_time = null, int $i = 0)
    {
        parent::__construct('Microtime', null, true);

        $this->seconds = $seconds;
        $this->microseconds = $microseconds;

        $this->group = $group;
        $this->lap_time = $lap_time;
        $this->total_time = $total_time;

        if ($i > 0) {
            $this->avg_time = $total_time / $i;
        }

        $this->mem = \memory_get_usage();
        $this->mem_real = \memory_get_usage(true);
        $this->mem_peak = \memory_get_peak_usage();
        $this->mem_peak_real = \memory_get_peak_usage(true);
    }

    public function getHint(): string
    {
        return 'microtime';
    }

    public function getGroup(): string
    {
        return $this->group;
    }

    public function getLapTime(): ?float
    {
        return $this->lap_time;
    }

    public function getTotalTime(): ?float
    {
        return $this->total_time;
    }

    public function getAverageTime(): ?float
    {
        return $this->avg_time;
    }

    public function getMemoryUsage(): int
    {
        return $this->mem;
    }

    public function getMemoryUsageReal(): int
    {
        return $this->mem_real;
    }

    public function getMemoryPeakUsage(): int
    {
        return $this->mem_peak;
    }

    public function getMemoryPeakUsageReal(): int
    {
        return $this->mem_peak_real;
    }

    public function getDateTime(): ?DateTimeInterface
    {
        return DateTimeImmutable::createFromFormat('U u', $this->seconds.' '.\str_pad((string) $this->microseconds, 6, '0', STR_PAD_LEFT)) ?: null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

class ProfileRepresentation extends AbstractRepresentation
{
    /** @psalm-readonly */
    public int $complexity;
    public ?int $instance_counts = null;
    public ?int $instance_complexity = null;

    public function __construct(int $complexity)
    {
        parent::__construct('Performance profile', 'profiling', false);
        $this->complexity = $complexity;
    }

    public function getHint(): string
    {
        return 'profiling';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

interface RepresentationInterface
{
    public function getLabel(): string;

    public function getName(): string;

    public function getHint(): ?string;

    public function labelIsImplicit(): bool;
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use RuntimeException;

class SourceRepresentation extends AbstractRepresentation
{
    private const DEFAULT_PADDING = 7;

    /**
     * @psalm-readonly
     *
     * @psalm-var non-empty-array<string>
     */
    protected array $source;
    /** @psalm-readonly */
    protected string $filename;
    /** @psalm-readonly */
    protected int $line;
    /** @psalm-readonly */
    protected bool $showfilename;

    public function __construct(string $filename, int $line, ?int $padding = self::DEFAULT_PADDING, bool $showfilename = false)
    {
        parent::__construct('Source');

        $this->filename = $filename;
        $this->line = $line;
        $this->showfilename = $showfilename;

        $padding ??= self::DEFAULT_PADDING;

        $start_line = \max($line - $padding, 1);
        $length = $line + $padding + 1 - $start_line;
        $this->source = self::readSource($filename, $start_line, $length);
    }

    public function getHint(): string
    {
        return 'source';
    }

    /**
     * @psalm-api
     *
     * @psalm-return non-empty-string
     */
    public function getSourceSlice(): string
    {
        return \implode("\n", $this->source);
    }

    /** @psalm-return non-empty-array<string> */
    public function getSourceLines(): array
    {
        return $this->source;
    }

    public function getFileName(): string
    {
        return $this->filename;
    }

    public function getLine(): int
    {
        return $this->line;
    }

    public function showFileName(): bool
    {
        return $this->showfilename;
    }

    /**
     * Gets section of source code.
     *
     * @psalm-return non-empty-array<string>
     */
    private static function readSource(string $filename, int $start_line = 1, ?int $length = null): array
    {
        if (!$filename || !\file_exists($filename) || !\is_readable($filename)) {
            throw new RuntimeException("Couldn't read file");
        }

        /** @psalm-var non-empty-array<string> $source */
        $source = \preg_split("/\r\n|\n|\r/", (string) \file_get_contents($filename));
        /** @psalm-var array $source */
        $source = \array_combine(\range(1, \count($source)), $source);
        $source = \array_slice($source, $start_line - 1, $length, true);

        if (0 === \count($source)) {
            throw new RuntimeException('File seemed to be empty');
        }

        return $source;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use Kint\Utils;
use RuntimeException;
use SplFileInfo;

class SplFileInfoRepresentation extends StringRepresentation
{
    public function __construct(SplFileInfo $fileInfo)
    {
        $path = $fileInfo->getPathname();

        $perms = 0;
        $owner = null;
        $group = null;
        $mtime = null;
        $realpath = null;
        $linktarget = null;
        $size = null;
        $is_file = false;
        $is_dir = false;
        $is_link = false;
        $typename = 'Unknown file';

        try {
            // SplFileInfo::getRealPath will return cwd when path is ''
            if ('' !== $path && $fileInfo->getRealPath()) {
                $perms = $fileInfo->getPerms();
                $size = $fileInfo->getSize();
                $owner = $fileInfo->getOwner();
                $group = $fileInfo->getGroup();
                $mtime = $fileInfo->getMTime();
                $realpath = $fileInfo->getRealPath();
            }

            $is_dir = $fileInfo->isDir();
            $is_file = $fileInfo->isFile();
            $is_link = $fileInfo->isLink();

            if ($is_link) {
                $lt = $fileInfo->getLinkTarget();
                $linktarget = false === $lt ? null : $lt;
            }
        } catch (RuntimeException $e) {
            if (false === \strpos($e->getMessage(), ' open_basedir ')) {
                throw $e; // @codeCoverageIgnore
            }
        }

        $typeflag = '-';

        switch ($perms & 0xF000) {
            case 0xC000:
                $typename = 'Socket';
                $typeflag = 's';
                break;
            case 0x6000:
                $typename = 'Block device';
                $typeflag = 'b';
                break;
            case 0x2000:
                $typename = 'Character device';
                $typeflag = 'c';
                break;
            case 0x1000:
                $typename = 'Named pipe';
                $typeflag = 'p';
                break;
            default:
                if ($is_file) {
                    if ($is_link) {
                        $typename = 'File symlink';
                        $typeflag = 'l';
                    } else {
                        $typename = 'File';
                        $typeflag = '-';
                    }
                } elseif ($is_dir) {
                    if ($is_link) {
                        $typename = 'Directory symlink';
                        $typeflag = 'l';
                    } else {
                        $typename = 'Directory';
                        $typeflag = 'd';
                    }
                }
                break;
        }

        $flags = [$typeflag];

        // User
        $flags[] = (($perms & 0400) ? 'r' : '-');
        $flags[] = (($perms & 0200) ? 'w' : '-');
        if ($perms & 0100) {
            $flags[] = ($perms & 04000) ? 's' : 'x';
        } else {
            $flags[] = ($perms & 04000) ? 'S' : '-';
        }

        // Group
        $flags[] = (($perms & 0040) ? 'r' : '-');
        $flags[] = (($perms & 0020) ? 'w' : '-');
        if ($perms & 0010) {
            $flags[] = ($perms & 02000) ? 's' : 'x';
        } else {
            $flags[] = ($perms & 02000) ? 'S' : '-';
        }

        // Other
        $flags[] = (($perms & 0004) ? 'r' : '-');
        $flags[] = (($perms & 0002) ? 'w' : '-');
        if ($perms & 0001) {
            $flags[] = ($perms & 01000) ? 's' : 'x';
        } else {
            $flags[] = ($perms & 01000) ? 'S' : '-';
        }

        $contents = \implode($flags).' '.$owner.' '.$group.' '.$size.' ';

        if (null !== $mtime) {
            if (\date('Y', $mtime) === \date('Y')) {
                $contents .= \date('M d H:i', $mtime);
            } else {
                $contents .= \date('M d Y', $mtime);
            }
        }

        $contents .= ' ';

        if ($is_link && null !== $linktarget) {
            $contents .= $path.' -> '.$linktarget;
        } elseif (null !== $realpath && \strlen($realpath) < \strlen($path)) {
            $contents .= $realpath;
        } else {
            $contents .= $path;
        }

        $label = $typename;

        if (null !== $size && $is_file) {
            $size = Utils::getHumanReadableBytes($size);
            $label .= ' ('.$size['value'].$size['unit'].')';
        }

        parent::__construct($label, $contents, 'splfileinfo');
    }

    public function getHint(): string
    {
        return 'splfileinfo';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use InvalidArgumentException;

class StringRepresentation extends AbstractRepresentation
{
    /**
     * @psalm-readonly
     *
     * @psalm-var non-empty-string
     */
    protected string $value;

    /** @psalm-assert non-empty-string $value */
    public function __construct(string $label, string $value, ?string $name = null, bool $implicit = false)
    {
        if ('' === $value) {
            throw new InvalidArgumentException("StringRepresentation can't take empty string");
        }

        parent::__construct($label, $name, $implicit);
        $this->value = $value;
    }

    /** @psalm-return non-empty-string */
    public function getValue(): string
    {
        return $this->value;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use Kint\Value\AbstractValue;

class TableRepresentation extends ContainerRepresentation
{
    /** @psalm-param non-empty-array<AbstractValue> $contents */
    public function __construct(array $contents, ?string $name = null)
    {
        parent::__construct('Table', $contents, $name, false);
    }

    public function getHint(): string
    {
        return 'table';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value\Representation;

use Kint\Value\AbstractValue;

class ValueRepresentation extends AbstractRepresentation
{
    /** @psalm-readonly */
    protected AbstractValue $value;

    public function __construct(string $label, AbstractValue $value, ?string $name = null, bool $implicit_label = false)
    {
        parent::__construct($label, $name, $implicit_label);
        $this->value = $value;
    }

    public function getValue(): AbstractValue
    {
        return $this->value;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;

class ResourceValue extends AbstractValue
{
    /** @psalm-readonly */
    protected string $resource_type;

    public function __construct(ContextInterface $context, string $resource_type)
    {
        parent::__construct($context, 'resource');
        $this->resource_type = $resource_type;
    }

    public function getDisplayType(): string
    {
        return $this->resource_type.' resource';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;
use SimpleXMLElement;

class SimpleXMLElementValue extends InstanceValue
{
    /** @psalm-readonly */
    protected ?string $text_content;

    /** @psalm-param list<SimpleXMLElementValue> $children */
    public function __construct(
        ContextInterface $context,
        SimpleXMLElement $element,
        array $children,
        ?string $text_content
    ) {
        parent::__construct($context, \get_class($element), \spl_object_hash($element), \spl_object_id($element));

        $this->children = $children;
        $this->text_content = $text_content;
    }

    public function getHint(): string
    {
        return parent::getHint() ?? 'simplexml_element';
    }

    public function getDisplaySize(): ?string
    {
        if ((bool) $this->children) {
            return (string) \count($this->children);
        }

        if (null !== $this->text_content) {
            return (string) \strlen($this->text_content);
        }

        return null;
    }

    public function getDisplayValue(): ?string
    {
        if ((bool) $this->children) {
            return parent::getDisplayValue();
        }

        if (null !== $this->text_content) {
            return '"'.$this->text_content.'"';
        }

        return null;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Utils;
use Kint\Value\Context\ContextInterface;
use RuntimeException;
use SplFileInfo;

class SplFileInfoValue extends InstanceValue
{
    /** @psalm-readonly */
    protected string $path;
    /** @psalm-readonly */
    protected ?int $filesize = null;

    public function __construct(ContextInterface $context, SplFileInfo $info)
    {
        parent::__construct($context, \get_class($info), \spl_object_hash($info), \spl_object_id($info));

        $this->path = $info->getPathname();

        try {
            // SplFileInfo::getRealPath will return cwd when path is ''
            if ('' !== $this->path && $info->getRealPath()) {
                $this->filesize = $info->getSize();
            }
        } catch (RuntimeException $e) {
            if (false === \strpos($e->getMessage(), ' open_basedir ')) {
                throw $e; // @codeCoverageIgnore
            }
        }
    }

    public function getHint(): string
    {
        return parent::getHint() ?? 'splfileinfo';
    }

    /** @psalm-api */
    public function getFileSize(): ?int
    {
        return $this->filesize;
    }

    public function getDisplaySize(): ?string
    {
        if (null === $this->filesize) {
            return null;
        }

        $size = Utils::getHumanReadableBytes($this->filesize);

        return $size['value'].$size['unit'];
    }

    public function getDisplayValue(): ?string
    {
        $shortpath = Utils::shortenPath($this->path);

        if ($shortpath !== $this->path) {
            return $shortpath;
        }

        return parent::getDisplayValue();
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Utils;
use Kint\Value\Context\ContextInterface;
use Kint\Value\Representation\ContainerRepresentation;

class StreamValue extends ResourceValue
{
    /**
     * @psalm-readonly
     *
     * @psalm-var AbstractValue[]
     */
    protected array $stream_meta;
    /** @psalm-readonly */
    protected ?string $uri;

    /** @psalm-param AbstractValue[] $stream_meta */
    public function __construct(ContextInterface $context, array $stream_meta, ?string $uri)
    {
        parent::__construct($context, 'stream');
        $this->stream_meta = $stream_meta;
        $this->uri = $uri;

        if ($stream_meta) {
            $this->addRepresentation(new ContainerRepresentation('Stream', $stream_meta, null, true));
        }
    }

    public function getHint(): string
    {
        return parent::getHint() ?? 'stream';
    }

    public function getDisplayValue(): ?string
    {
        if (null === $this->uri) {
            return null;
        }

        if ('/' === $this->uri[0] && \stream_is_local($this->uri)) {
            return Utils::shortenPath($this->uri);
        }

        return $this->uri;
    }

    public function getDisplayChildren(): array
    {
        return $this->stream_meta;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use DomainException;
use Kint\Value\Context\ContextInterface;

/**
 * @psalm-type Encoding = string|false
 */
class StringValue extends AbstractValue
{
    /** @psalm-readonly */
    protected string $value;

    /**
     * @psalm-readonly
     *
     * @psalm-var Encoding
     */
    protected $encoding;

    /** @psalm-readonly */
    protected int $length;

    /** @psalm-param Encoding $encoding */
    public function __construct(ContextInterface $context, string $value, $encoding = false)
    {
        parent::__construct($context, 'string');
        $this->value = $value;
        $this->encoding = $encoding;
        $this->length = \strlen($value);
    }

    public function getValue(): string
    {
        return $this->value;
    }

    public function getValueUtf8(): string
    {
        if (false === $this->encoding) {
            throw new DomainException('StringValue with no encoding can\'t be converted to UTF-8');
        }

        if ('ASCII' === $this->encoding || 'UTF-8' === $this->encoding) {
            return $this->value;
        }

        /** @psalm-var string $encoded */
        $encoded = \mb_convert_encoding($this->value, 'UTF-8', $this->encoding);

        return $encoded;
    }

    /** @psalm-api */
    public function getLength(): int
    {
        return $this->length;
    }

    /** @psalm-return Encoding */
    public function getEncoding()
    {
        return $this->encoding;
    }

    public function getDisplayType(): string
    {
        if (false === $this->encoding) {
            return 'binary '.$this->type;
        }

        if ('ASCII' === $this->encoding) {
            return $this->type;
        }

        return $this->encoding.' '.$this->type;
    }

    public function getDisplaySize(): string
    {
        return (string) $this->length;
    }

    public function getDisplayValue(): string
    {
        return '"'.$this->value.'"';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;
use Throwable;

class ThrowableValue extends InstanceValue
{
    /** @psalm-readonly */
    protected string $message;

    public function __construct(ContextInterface $context, Throwable $throw)
    {
        parent::__construct($context, \get_class($throw), \spl_object_hash($throw), \spl_object_id($throw));

        $this->message = $throw->getMessage();
    }

    public function getDisplayValue(): string
    {
        return '"'.$this->message.'"';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use InvalidArgumentException;
use Kint\Value\Context\BaseContext;
use Kint\Value\Context\MethodContext;
use ReflectionFunction;
use ReflectionMethod;

/**
 * @psalm-type TraceFrame array{
 *   function: string,
 *   line?: int,
 *   file?: string,
 *   class?: class-string,
 *   object?: object,
 *   type?: string,
 *   args?: list<mixed>
 * }
 */
class TraceFrameValue extends ArrayValue
{
    /** @psalm-readonly */
    protected ?string $file;

    /** @psalm-readonly */
    protected ?int $line;

    /**
     * @psalm-readonly
     *
     * @psalm-var null|FunctionValue|MethodValue
     */
    protected $callable;

    /**
     * @psalm-readonly
     *
     * @psalm-var list<AbstractValue>
     */
    protected array $args;

    /** @psalm-readonly */
    protected ?InstanceValue $object;

    /**
     * @psalm-param TraceFrame $raw_frame
     */
    public function __construct(ArrayValue $old, $raw_frame)
    {
        parent::__construct($old->getContext(), $old->getSize(), $old->getContents());

        $this->file = $raw_frame['file'] ?? null;
        $this->line = $raw_frame['line'] ?? null;

        if (isset($raw_frame['class']) && \method_exists($raw_frame['class'], $raw_frame['function'])) {
            $func = new ReflectionMethod($raw_frame['class'], $raw_frame['function']);
            $this->callable = new MethodValue(
                new MethodContext($func),
                new DeclaredCallableBag($func)
            );
        } elseif (!isset($raw_frame['class']) && \function_exists($raw_frame['function'])) {
            $func = new ReflectionFunction($raw_frame['function']);
            $this->callable = new FunctionValue(
                new BaseContext($raw_frame['function']),
                new DeclaredCallableBag($func)
            );
        } else {
            // Mostly closures, no way to get them
            $this->callable = null;
        }

        foreach ($this->contents as $frame_prop) {
            $c = $frame_prop->getContext();

            if ('object' === $c->getName()) {
                if (!$frame_prop instanceof InstanceValue) {
                    throw new InvalidArgumentException('object key of TraceFrameValue must be parsed to InstanceValue');
                }

                $this->object = $frame_prop;
            }

            if ('args' === $c->getName()) {
                if (!$frame_prop instanceof ArrayValue) {
                    throw new InvalidArgumentException('args key of TraceFrameValue must be parsed to ArrayValue');
                }

                $args = \array_values($frame_prop->getContents());

                if ($this->callable) {
                    foreach ($this->callable->getCallableBag()->parameters as $param) {
                        if (!isset($args[$param->position])) {
                            break; // Optional args follow
                        }

                        $arg = $args[$param->position];

                        if ($arg->getContext() instanceof BaseContext) {
                            $arg = clone $arg;
                            $c = $arg->getContext();

                            if (!$c instanceof BaseContext) {
                                throw new InvalidArgumentException('TraceFrameValue expects arg contexts to be instanceof BaseContext');
                            }

                            $c->name = '$'.$param->name;

                            $args[$param->position] = $arg;
                        }
                    }
                }

                $this->args = $args;
            }
        }

        /**
         * @psalm-suppress DocblockTypeContradiction
         * @psalm-suppress RedundantPropertyInitializationCheck
         * Psalm bug #11124
         */
        $this->args ??= [];
        $this->object ??= null;
    }

    public function getHint(): string
    {
        return parent::getHint() ?? 'trace_frame';
    }

    public function getFile(): ?string
    {
        return $this->file;
    }

    public function getLine(): ?int
    {
        return $this->line;
    }

    /** @psalm-return null|FunctionValue|MethodValue */
    public function getCallable()
    {
        return $this->callable;
    }

    /** @psalm-return list<AbstractValue> */
    public function getArgs(): array
    {
        return $this->args;
    }

    public function getObject(): ?InstanceValue
    {
        return $this->object;
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

class TraceValue extends ArrayValue
{
    public function getHint(): string
    {
        return parent::getHint() ?? 'trace';
    }

    public function getDisplayType(): string
    {
        return 'Debug Backtrace';
    }

    public function getDisplaySize(): string
    {
        if ($this->size > 0) {
            return parent::getDisplaySize();
        }

        return 'empty';
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;

class UninitializedValue extends AbstractValue
{
    public function __construct(ContextInterface $context)
    {
        parent::__construct($context, 'uninitialized');
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;

class UnknownValue extends AbstractValue
{
    public function __construct(ContextInterface $context)
    {
        parent::__construct($context, 'unknown');
    }
}
<?php

declare(strict_types=1);

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
 *
 * 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.
 */

namespace Kint\Value;

use Kint\Value\Context\ContextInterface;

class VirtualValue extends AbstractValue
{
    public function __construct(ContextInterface $context)
    {
        parent::__construct($context, 'virtual');
    }
}
Yy
IW&t=K%l&>_x 9Qq   GBMB