vendor/symfony/symfony/src/Symfony/Component/Debug/ExceptionHandler.php line 145

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Debug;
  11. use Symfony\Component\Debug\Exception\FlattenException;
  12. use Symfony\Component\Debug\Exception\OutOfMemoryException;
  13. use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
  14. /**
  15.  * ExceptionHandler converts an exception to a Response object.
  16.  *
  17.  * It is mostly useful in debug mode to replace the default PHP/XDebug
  18.  * output with something prettier and more useful.
  19.  *
  20.  * As this class is mainly used during Kernel boot, where nothing is yet
  21.  * available, the Response content is always HTML.
  22.  *
  23.  * @author Fabien Potencier <fabien@symfony.com>
  24.  * @author Nicolas Grekas <p@tchwork.com>
  25.  */
  26. class ExceptionHandler
  27. {
  28.     private $debug;
  29.     private $charset;
  30.     private $handler;
  31.     private $caughtBuffer;
  32.     private $caughtLength;
  33.     private $fileLinkFormat;
  34.     public function __construct($debug true$charset null$fileLinkFormat null)
  35.     {
  36.         $this->debug $debug;
  37.         $this->charset $charset ?: ini_get('default_charset') ?: 'UTF-8';
  38.         $this->fileLinkFormat $fileLinkFormat;
  39.     }
  40.     /**
  41.      * Registers the exception handler.
  42.      *
  43.      * @param bool        $debug          Enable/disable debug mode, where the stack trace is displayed
  44.      * @param string|null $charset        The charset used by exception messages
  45.      * @param string|null $fileLinkFormat The IDE link template
  46.      *
  47.      * @return static
  48.      */
  49.     public static function register($debug true$charset null$fileLinkFormat null)
  50.     {
  51.         $handler = new static($debug$charset$fileLinkFormat);
  52.         $prev set_exception_handler([$handler'handle']);
  53.         if (\is_array($prev) && $prev[0] instanceof ErrorHandler) {
  54.             restore_exception_handler();
  55.             $prev[0]->setExceptionHandler([$handler'handle']);
  56.         }
  57.         return $handler;
  58.     }
  59.     /**
  60.      * Sets a user exception handler.
  61.      *
  62.      * @param callable $handler An handler that will be called on Exception
  63.      *
  64.      * @return callable|null The previous exception handler if any
  65.      */
  66.     public function setHandler(callable $handler null)
  67.     {
  68.         $old $this->handler;
  69.         $this->handler $handler;
  70.         return $old;
  71.     }
  72.     /**
  73.      * Sets the format for links to source files.
  74.      *
  75.      * @param string|FileLinkFormatter $fileLinkFormat The format for links to source files
  76.      *
  77.      * @return string The previous file link format
  78.      */
  79.     public function setFileLinkFormat($fileLinkFormat)
  80.     {
  81.         $old $this->fileLinkFormat;
  82.         $this->fileLinkFormat $fileLinkFormat;
  83.         return $old;
  84.     }
  85.     /**
  86.      * Sends a response for the given Exception.
  87.      *
  88.      * To be as fail-safe as possible, the exception is first handled
  89.      * by our simple exception handler, then by the user exception handler.
  90.      * The latter takes precedence and any output from the former is cancelled,
  91.      * if and only if nothing bad happens in this handling path.
  92.      */
  93.     public function handle(\Exception $exception)
  94.     {
  95.         if (null === $this->handler || $exception instanceof OutOfMemoryException) {
  96.             $this->sendPhpResponse($exception);
  97.             return;
  98.         }
  99.         $caughtLength $this->caughtLength 0;
  100.         ob_start(function ($buffer) {
  101.             $this->caughtBuffer $buffer;
  102.             return '';
  103.         });
  104.         $this->sendPhpResponse($exception);
  105.         while (null === $this->caughtBuffer && ob_end_flush()) {
  106.             // Empty loop, everything is in the condition
  107.         }
  108.         if (isset($this->caughtBuffer[0])) {
  109.             ob_start(function ($buffer) {
  110.                 if ($this->caughtLength) {
  111.                     // use substr_replace() instead of substr() for mbstring overloading resistance
  112.                     $cleanBuffer substr_replace($buffer''0$this->caughtLength);
  113.                     if (isset($cleanBuffer[0])) {
  114.                         $buffer $cleanBuffer;
  115.                     }
  116.                 }
  117.                 return $buffer;
  118.             });
  119.             echo $this->caughtBuffer;
  120.             $caughtLength ob_get_length();
  121.         }
  122.         $this->caughtBuffer null;
  123.         try {
  124.             \call_user_func($this->handler$exception);
  125.             $this->caughtLength $caughtLength;
  126.         } catch (\Exception $e) {
  127.             if (!$caughtLength) {
  128.                 // All handlers failed. Let PHP handle that now.
  129.                 throw $exception;
  130.             }
  131.         }
  132.     }
  133.     /**
  134.      * Sends the error associated with the given Exception as a plain PHP response.
  135.      *
  136.      * This method uses plain PHP functions like header() and echo to output
  137.      * the response.
  138.      *
  139.      * @param \Exception|FlattenException $exception An \Exception or FlattenException instance
  140.      */
  141.     public function sendPhpResponse($exception)
  142.     {
  143.         if (!$exception instanceof FlattenException) {
  144.             $exception FlattenException::create($exception);
  145.         }
  146.         if (!headers_sent()) {
  147.             header(sprintf('HTTP/1.0 %s'$exception->getStatusCode()));
  148.             foreach ($exception->getHeaders() as $name => $value) {
  149.                 header($name.': '.$valuefalse);
  150.             }
  151.             header('Content-Type: text/html; charset='.$this->charset);
  152.         }
  153.         echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
  154.     }
  155.     /**
  156.      * Gets the full HTML content associated with the given exception.
  157.      *
  158.      * @param \Exception|FlattenException $exception An \Exception or FlattenException instance
  159.      *
  160.      * @return string The HTML content as a string
  161.      */
  162.     public function getHtml($exception)
  163.     {
  164.         if (!$exception instanceof FlattenException) {
  165.             $exception FlattenException::create($exception);
  166.         }
  167.         return $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
  168.     }
  169.     /**
  170.      * Gets the HTML content associated with the given exception.
  171.      *
  172.      * @return string The content as a string
  173.      */
  174.     public function getContent(FlattenException $exception)
  175.     {
  176.         switch ($exception->getStatusCode()) {
  177.             case 404:
  178.                 $title 'Sorry, the page you are looking for could not be found.';
  179.                 break;
  180.             default:
  181.                 $title 'Whoops, looks like something went wrong.';
  182.         }
  183.         if (!$this->debug) {
  184.             return <<<EOF
  185.                 <div class="container">
  186.                     <h1>$title</h1>
  187.                 </div>
  188. EOF;
  189.         }
  190.         $content '';
  191.         try {
  192.             $count = \count($exception->getAllPrevious());
  193.             $total $count 1;
  194.             foreach ($exception->toArray() as $position => $e) {
  195.                 $ind $count $position 1;
  196.                 $class $this->formatClass($e['class']);
  197.                 $message nl2br($this->escapeHtml($e['message']));
  198.                 $content .= sprintf(<<<'EOF'
  199.                     <div class="trace trace-as-html">
  200.                         <table class="trace-details">
  201.                             <thead class="trace-head"><tr><th>
  202.                                 <h3 class="trace-class">
  203.                                     <span class="text-muted">(%d/%d)</span>
  204.                                     <span class="exception_title">%s</span>
  205.                                 </h3>
  206.                                 <p class="break-long-words trace-message">%s</p>
  207.                             </th></tr></thead>
  208.                             <tbody>
  209. EOF
  210.                     , $ind$total$class$message);
  211.                 foreach ($e['trace'] as $trace) {
  212.                     $content .= '<tr><td>';
  213.                     if ($trace['function']) {
  214.                         $content .= sprintf('at <span class="trace-class">%s</span><span class="trace-type">%s</span><span class="trace-method">%s</span>(<span class="trace-arguments">%s</span>)'$this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
  215.                     }
  216.                     if (isset($trace['file']) && isset($trace['line'])) {
  217.                         $content .= $this->formatPath($trace['file'], $trace['line']);
  218.                     }
  219.                     $content .= "</td></tr>\n";
  220.                 }
  221.                 $content .= "</tbody>\n</table>\n</div>\n";
  222.             }
  223.         } catch (\Exception $e) {
  224.             // something nasty happened and we cannot throw an exception anymore
  225.             if ($this->debug) {
  226.                 $title sprintf('Exception thrown when handling an exception (%s: %s)', \get_class($e), $this->escapeHtml($e->getMessage()));
  227.             } else {
  228.                 $title 'Whoops, looks like something went wrong.';
  229.             }
  230.         }
  231.         $symfonyGhostImageContents $this->getSymfonyGhostAsSvg();
  232.         return <<<EOF
  233.             <div class="exception-summary">
  234.                 <div class="container">
  235.                     <div class="exception-message-wrapper">
  236.                         <h1 class="break-long-words exception-message">$title</h1>
  237.                         <div class="exception-illustration hidden-xs-down">$symfonyGhostImageContents</div>
  238.                     </div>
  239.                 </div>
  240.             </div>
  241.             <div class="container">
  242.                 $content
  243.             </div>
  244. EOF;
  245.     }
  246.     /**
  247.      * Gets the stylesheet associated with the given exception.
  248.      *
  249.      * @return string The stylesheet as a string
  250.      */
  251.     public function getStylesheet(FlattenException $exception)
  252.     {
  253.         if (!$this->debug) {
  254.             return <<<'EOF'
  255.                 body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; }
  256.                 .container { margin: 30px; max-width: 600px; }
  257.                 h1 { color: #dc3545; font-size: 24px; }
  258. EOF;
  259.         }
  260.         return <<<'EOF'
  261.             body { background-color: #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; }
  262.             a { cursor: pointer; text-decoration: none; }
  263.             a:hover { text-decoration: underline; }
  264.             abbr[title] { border-bottom: none; cursor: help; text-decoration: none; }
  265.             code, pre { font: 13px/1.5 Consolas, Monaco, Menlo, "Ubuntu Mono", "Liberation Mono", monospace; }
  266.             table, tr, th, td { background: #FFF; border-collapse: collapse; vertical-align: top; }
  267.             table { background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; width: 100%; }
  268.             table th, table td { border: solid #E0E0E0; border-width: 1px 0; padding: 8px 10px; }
  269.             table th { background-color: #E0E0E0; font-weight: bold; text-align: left; }
  270.             .hidden-xs-down { display: none; }
  271.             .block { display: block; }
  272.             .break-long-words { -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; }
  273.             .text-muted { color: #999; }
  274.             .container { max-width: 1024px; margin: 0 auto; padding: 0 15px; }
  275.             .container::after { content: ""; display: table; clear: both; }
  276.             .exception-summary { background: #B0413E; border-bottom: 2px solid rgba(0, 0, 0, 0.1); border-top: 1px solid rgba(0, 0, 0, .3); flex: 0 0 auto; margin-bottom: 30px; }
  277.             .exception-message-wrapper { display: flex; align-items: center; min-height: 70px; }
  278.             .exception-message { flex-grow: 1; padding: 30px 0; }
  279.             .exception-message, .exception-message a { color: #FFF; font-size: 21px; font-weight: 400; margin: 0; }
  280.             .exception-message.long { font-size: 18px; }
  281.             .exception-message a { border-bottom: 1px solid rgba(255, 255, 255, 0.5); font-size: inherit; text-decoration: none; }
  282.             .exception-message a:hover { border-bottom-color: #ffffff; }
  283.             .exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; }
  284.             .trace + .trace { margin-top: 30px; }
  285.             .trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; }
  286.             .trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; }
  287.             .trace-file-path, .trace-file-path a { color: #222; margin-top: 3px; font-size: 13px; }
  288.             .trace-class { color: #B0413E; }
  289.             .trace-type { padding: 0 2px; }
  290.             .trace-method { color: #B0413E; font-weight: bold; }
  291.             .trace-arguments { color: #777; font-weight: normal; padding-left: 2px; }
  292.             @media (min-width: 575px) {
  293.                 .hidden-xs-down { display: initial; }
  294.             }
  295. EOF;
  296.     }
  297.     private function decorate($content$css)
  298.     {
  299.         return <<<EOF
  300. <!DOCTYPE html>
  301. <html>
  302.     <head>
  303.         <meta charset="{$this->charset}" />
  304.         <meta name="robots" content="noindex,nofollow" />
  305.         <style>$css</style>
  306.     </head>
  307.     <body>
  308.         $content
  309.     </body>
  310. </html>
  311. EOF;
  312.     }
  313.     private function formatClass($class)
  314.     {
  315.         $parts explode('\\'$class);
  316.         return sprintf('<abbr title="%s">%s</abbr>'$classarray_pop($parts));
  317.     }
  318.     private function formatPath($path$line)
  319.     {
  320.         $file $this->escapeHtml(preg_match('#[^/\\\\]*+$#'$path$file) ? $file[0] : $path);
  321.         $fmt $this->fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
  322.         if (!$fmt) {
  323.             return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>'$this->escapeHtml($path), $file$line ' line '.$line '');
  324.         }
  325.         if (\is_string($fmt)) {
  326.             $i strpos($f $fmt'&'max(strrpos($f'%f'), strrpos($f'%l'))) ?: \strlen($f);
  327.             $fmt = [substr($f0$i)] + preg_split('/&([^>]++)>/'substr($f$i), -1, \PREG_SPLIT_DELIM_CAPTURE);
  328.             for ($i 1; isset($fmt[$i]); ++$i) {
  329.                 if (=== strpos($path$k $fmt[$i++])) {
  330.                     $path substr_replace($path$fmt[$i], 0, \strlen($k));
  331.                     break;
  332.                 }
  333.             }
  334.             $link strtr($fmt[0], ['%f' => $path'%l' => $line]);
  335.         } else {
  336.             try {
  337.                 $link $fmt->format($path$line);
  338.             } catch (\Exception $e) {
  339.                 return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>'$this->escapeHtml($path), $file$line ' line '.$line '');
  340.             }
  341.         }
  342.         return sprintf('<span class="block trace-file-path">in <a href="%s" title="Go to source"><strong>%s</string>%s</a></span>'$this->escapeHtml($link), $file$line ' line '.$line '');
  343.     }
  344.     /**
  345.      * Formats an array as a string.
  346.      *
  347.      * @param array $args The argument array
  348.      *
  349.      * @return string
  350.      */
  351.     private function formatArgs(array $args)
  352.     {
  353.         $result = [];
  354.         foreach ($args as $key => $item) {
  355.             if ('object' === $item[0]) {
  356.                 $formattedValue sprintf('<em>object</em>(%s)'$this->formatClass($item[1]));
  357.             } elseif ('array' === $item[0]) {
  358.                 $formattedValue sprintf('<em>array</em>(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
  359.             } elseif ('null' === $item[0]) {
  360.                 $formattedValue '<em>null</em>';
  361.             } elseif ('boolean' === $item[0]) {
  362.                 $formattedValue '<em>'.strtolower(var_export($item[1], true)).'</em>';
  363.             } elseif ('resource' === $item[0]) {
  364.                 $formattedValue '<em>resource</em>';
  365.             } else {
  366.                 $formattedValue str_replace("\n"''$this->escapeHtml(var_export($item[1], true)));
  367.             }
  368.             $result[] = \is_int($key) ? $formattedValue sprintf("'%s' => %s"$this->escapeHtml($key), $formattedValue);
  369.         }
  370.         return implode(', '$result);
  371.     }
  372.     /**
  373.      * HTML-encodes a string.
  374.      */
  375.     private function escapeHtml($str)
  376.     {
  377.         return htmlspecialchars($str, \ENT_COMPAT | \ENT_SUBSTITUTE$this->charset);
  378.     }
  379.     private function getSymfonyGhostAsSvg()
  380.     {
  381.         return '<svg viewBox="0 0 136 81" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><path d="M92.4 20.4a23.2 23.2 0 0 1 9 1.9 23.7 23.7 0 0 1 5.2 3 24.3 24.3 0 0 1 3.4 3.4 24.8 24.8 0 0 1 5 9.4c.5 1.7.8 3.4 1 5.2v14.5h.4l.5.2a7.4 7.4 0 0 0 2.5.2l.2-.2.6-.8.8-1.3-.2-.1a5.5 5.5 0 0 1-.8-.3 5.6 5.6 0 0 1-2.3-1.8 5.7 5.7 0 0 1-.9-1.6 6.5 6.5 0 0 1-.2-2.8 7.3 7.3 0 0 1 .5-2l.3-.3.8-.9.3-.3c.2-.2.5-.3.8-.3H120.7c.2 0 .3-.1.4 0h.4l.2.1.3.2.2-.4.3-.4.1-.1 1.2-1 .3-.2.4-.1.4-.1h.3l1.5.1.4.1.8.5.1.2 1 1.1v.2H129.4l.4-.2 1.4-.5h1.1c.3 0 .7.2 1 .4.2 0 .3.2.5.3l.2.2.5.3.4.6.1.3.4 1.4.1.4v.6a7.8 7.8 0 0 1-.1.6 9.9 9.9 0 0 1-.8 2.4 7.8 7.8 0 0 1-3 3.3 6.4 6.4 0 0 1-1 .5 6.1 6.1 0 0 1-.6.2l-.7.1h-.1a23.4 23.4 0 0 1-.2 1.7 14.3 14.3 0 0 1-.6 2.1l-.8 2a9.2 9.2 0 0 1-.4.6l-.7 1a9.1 9.1 0 0 1-2.3 2.2c-.9.5-2 .6-3 .7l-1.4.1h-.5l-.4.1a15.8 15.8 0 0 1-2.8-.1v4.2a9.7 9.7 0 0 1-.7 3.5 9.6 9.6 0 0 1-1.7 2.8 9.3 9.3 0 0 1-3 2.3 9 9 0 0 1-5.4.7 9 9 0 0 1-3-1 9.4 9.4 0 0 1-2.7-2.5 10 10 0 0 1-1 1.2 9.3 9.3 0 0 1-2 1.3 9 9 0 0 1-2.4 1 9 9 0 0 1-6.5-1.1A9.4 9.4 0 0 1 85 77V77a10.9 10.9 0 0 1-.6.6 9.3 9.3 0 0 1-2.7 2 9 9 0 0 1-6 .8 9 9 0 0 1-2.4-1 9.3 9.3 0 0 1-2.3-1.7 9.6 9.6 0 0 1-1.8-2.8 9.7 9.7 0 0 1-.8-3.7v-4a18.5 18.5 0 0 1-2.9.2l-1.2-.1c-1.9-.3-3.7-1-5.1-2.1A8.2 8.2 0 0 1 58 64a10.2 10.2 0 0 1-.9-1.2 15.3 15.3 0 0 1-.7-1.3 20.8 20.8 0 0 1-1.9-6.2v-.2a6.5 6.5 0 0 1-1-.3 6.1 6.1 0 0 1-.6-.3 6.6 6.6 0 0 1-.9-.5 8.2 8.2 0 0 1-2.7-3.8 10 10 0 0 1-.3-1 10.3 10.3 0 0 1-.3-1.9V47v-.4l.1-.4.6-1.4.1-.2a2 2 0 0 1 .8-.8l.3-.2.3-.2a3.2 3.2 0 0 1 1.8-.5h.4l.3.2 1.4.6.2.2.4.3.3.4.7-.7.2-.2.4-.2.6-.2h2.1l.4.2.4.2.3.2.8 1 .2-.1h.1v-.1H63l1.1.1h.3l.8.5.3.4.7 1 .2.3.1.5a11 11 0 0 1 .2 1.5c0 .8 0 1.6-.3 2.3a6 6 0 0 1-.5 1.2 5.5 5.5 0 0 1-3.3 2.5 12.3 12.3 0 0 0 1.4 3h.1l.2.1 1 .2h1.5l.5-.2H67.8l.5-.2h.1V44v-.4a26.7 26.7 0 0 1 .3-2.3 24.7 24.7 0 0 1 5.7-12.5 24.2 24.2 0 0 1 3.5-3.3 23.7 23.7 0 0 1 4.9-3 23.2 23.2 0 0 1 5.6-1.7 23.7 23.7 0 0 1 4-.3zm-.3 2a21.2 21.2 0 0 0-8 1.7 21.6 21.6 0 0 0-4.8 2.7 22.2 22.2 0 0 0-3.2 3 22.7 22.7 0 0 0-5 9.2 23.4 23.4 0 0 0-.7 4.9v15.7l-.5.1a34.3 34.3 0 0 1-1.5.3h-.2l-.4.1h-.4l-.9.2a10 10 0 0 1-1.9 0c-.5 0-1-.2-1.5-.4a1.8 1.8 0 0 1-.3-.2 2 2 0 0 1-.3-.3 5.2 5.2 0 0 1-.1-.2 9 9 0 0 1-.6-.9 13.8 13.8 0 0 1-1-2 14.3 14.3 0 0 1-.6-2 14 14 0 0 1-.1-.8v-.2h.3a12.8 12.8 0 0 0 1.4-.2 4.4 4.4 0 0 0 .3 0 3.6 3.6 0 0 0 1.1-.7 3.4 3.4 0 0 0 1.2-1.7l.2-1.2a5.1 5.1 0 0 0 0-.8 7.2 7.2 0 0 0-.1-.8l-.7-1-1.2-.2-1 .7-.1 1.3a5 5 0 0 1 .1.4v.6a1 1 0 0 1 0 .3c-.1.3-.4.4-.7.5l-1.2.4v-.7A9.9 9.9 0 0 1 60 49l.3-.6v-.2l.1-.1v-1.6l-1-1.2h-1.5l-1 1.1v.4a5.3 5.3 0 0 0-.2.6 5.5 5.5 0 0 0 0 .5c0 .7 0 1.4.3 2 0 .4.2.8.4 1.2L57 51a9.5 9.5 0 0 1-1.1-.5h-.2a2 2 0 0 1-.4-.3c-.4-.4-.5-1-.6-1.6a5.6 5.6 0 0 1 0-.5v-.5-.5l-.6-1.5-1.4-.6-.9.3s-.2 0-.3.2a2 2 0 0 1-.1 0l-.6 1.4v.7a8.5 8.5 0 0 0 .5 2c.4 1.1 1 2.1 2 2.8a4.7 4.7 0 0 0 2.1.9h1a22.8 22.8 0 0 0 .1 1 18.1 18.1 0 0 0 .8 3.8 18.2 18.2 0 0 0 1.6 3.7l1 1.3c1 1 2.3 1.6 3.7 2a11.7 11.7 0 0 0 4.8 0h.4l.5-.2.5-.1.6-.2v6.6a8 8 0 0 0 .1 1.3 7.5 7.5 0 0 0 2.4 4.3 7.2 7.2 0 0 0 2.3 1.3 7 7 0 0 0 7-1.1 7.5 7.5 0 0 0 2-2.6A7.7 7.7 0 0 0 85 72V71a8.2 8.2 0 0 0 .2 1.3c0 .7.3 1.4.6 2a7.5 7.5 0 0 0 1.7 2.3 7.3 7.3 0 0 0 2.2 1.4 7.1 7.1 0 0 0 4.6.2 7.2 7.2 0 0 0 2.4-1.2 7.5 7.5 0 0 0 2.1-2.7 7.8 7.8 0 0 0 .7-2.4V71a9.3 9.3 0 0 0 .1.6 7.6 7.6 0 0 0 .6 2.5 7.5 7.5 0 0 0 2.4 3 7.1 7.1 0 0 0 7 .8 7.3 7.3 0 0 0 2.3-1.5 7.5 7.5 0 0 0 1.6-2.3 7.6 7.6 0 0 0 .5-2l.1-1.1v-6.7l.4.1a12.2 12.2 0 0 0 2 .5 11.1 11.1 0 0 0 2.5 0h.8l1.2-.1a9.5 9.5 0 0 0 1.4-.2l.9-.3a3.5 3.5 0 0 0 .6-.4l1.2-1.4a12.2 12.2 0 0 0 .8-1.2c0-.3.2-.5.3-.7a15.9 15.9 0 0 0 .7-2l.3-1.6v-1.3l.2-.9V54.6a15.5 15.5 0 0 0 1.8 0 4.5 4.5 0 0 0 1.4-.5 5.7 5.7 0 0 0 2.5-3.2 7.6 7.6 0 0 0 .4-1.5v-.3l-.4-1.4a5.2 5.2 0 0 1-.2-.1l-.4-.4a3.8 3.8 0 0 0-.2 0 1.4 1.4 0 0 0-.5-.2l-1.4.4-.7 1.3v.7a5.7 5.7 0 0 1-.1.8l-.7 1.4a1.9 1.9 0 0 1-.5.3h-.3a9.6 9.6 0 0 1-.8.3 8.8 8.8 0 0 1-.6 0l.2-.4.2-.5.2-.3v-.4l.1-.2V50l.1-1 .1-.6v-.6a4.8 4.8 0 0 0 0-.8v-.2l-1-1.1-1.5-.2-1.1 1-.2 1.4v.1l.2.4.2.3v.4l.1 1.1v.3l.1.5v.8a9.6 9.6 0 0 1-.8-.3l-.2-.1h-.3l-.8-.1h-.2a1.6 1.6 0 0 1-.2-.2.9.9 0 0 1-.2-.2 1 1 0 0 1-.1-.5l.2-.9v-1.2l-.9-.8h-1.2l-.8.9v.3a4.8 4.8 0 0 0-.3 2l.3.9a3.5 3.5 0 0 0 1.2 1.6l1 .5.8.2 1.4.1h.4l.2.1a12.1 12.1 0 0 1-1 2.6 13.2 13.2 0 0 1-.8 1.5 9.5 9.5 0 0 1-1 1.2l-.2.3a1.7 1.7 0 0 1-.4.3 2.4 2.4 0 0 1-.7.2h-2.5a7.8 7.8 0 0 1-.6-.2l-.7-.2h-.2a14.8 14.8 0 0 1-.6-.2 23.4 23.4 0 0 1-.4-.1l-.4-.1-.3-.1V43.9a34.6 34.6 0 0 0 0-.6 23.6 23.6 0 0 0-.4-3 22.7 22.7 0 0 0-1.5-4.7 22.6 22.6 0 0 0-4.6-6.7 21.9 21.9 0 0 0-6.9-4.7 21.2 21.2 0 0 0-8.1-1.8H92zm9.1 33.7l.3.1a1 1 0 0 1 .6.8v.4a8.4 8.4 0 0 1 0 .5 8.8 8.8 0 0 1-1.6 4.2l-1 1.3A10 10 0 0 1 95 66c-1.3.3-2.7.4-4 .3a10.4 10.4 0 0 1-2.7-.8 10 10 0 0 1-3.6-2.5 9.3 9.3 0 0 1-.8-1 9 9 0 0 1-.7-1.2 8.6 8.6 0 0 1-.8-3.4V57a1 1 0 0 1 .3-.6 1 1 0 0 1 1.3-.2 1 1 0 0 1 .4.8v.4a6.5 6.5 0 0 0 .5 2.2 7 7 0 0 0 2.1 2.8l1 .6c2.6 1.6 6 1.6 8.5 0a8 8 0 0 0 1.1-.6 7.6 7.6 0 0 0 1.2-1.2 7 7 0 0 0 1-1.7 6.5 6.5 0 0 0 .4-2.5 1 1 0 0 1 .7-1h.4zM30.7 43.7c-15.5 1-28.5-6-30.1-16.4C-1.2 15.7 11.6 4 29 1.3 46.6-1.7 62.3 5.5 64 17.1c1.6 10.4-8.7 21-23.7 25a31.2 31.2 0 0 0 0 .9v.3a19 19 0 0 0 .1 1l.1.4.1.9a4.7 4.7 0 0 0 .5 1l.7 1a9.2 9.2 0 0 0 1.2 1l1.5.8.6.8-.7.6-1.1.3a11.2 11.2 0 0 1-2.6.4 8.6 8.6 0 0 1-3-.5 8.5 8.5 0 0 1-1-.4 11.2 11.2 0 0 1-1.8-1.2 13.3 13.3 0 0 1-1-1 18 18 0 0 1-.7-.6l-.4-.4a23.4 23.4 0 0 1-1.3-1.8l-.1-.1-.3-.5V45l-.3-.6v-.7zM83.1 36c3.6 0 6.5 3.2 6.5 7.1 0 4-3 7.2-6.5 7.2S76.7 47 76.7 43 79.6 36 83 36zm18 0c3.6 0 6.5 3.2 6.5 7.1 0 4-2.9 7.2-6.4 7.2S94.7 47 94.7 43s3-7.1 6.5-7.1zm-18 6.1c2 0 3.5 1.6 3.5 3.6S85 49.2 83 49.2s-3.4-1.6-3.4-3.6S81.2 42 83 42zm17.9 0c1.9 0 3.4 1.6 3.4 3.6s-1.5 3.6-3.4 3.6c-2 0-3.5-1.6-3.5-3.6S99.1 42 101 42zM17 28c-.3 1.6-1.8 5-5.2 5.8-2.5.6-4.1-.8-4.5-2.6-.4-1.9.7-3.5 2.1-4.5A3.5 3.5 0 0 1 8 24.6c-.4-2 .8-3.7 3.2-4.2 1.9-.5 3.1.2 3.4 1.5.3 1.1-.5 2.2-1.8 2.5-.9.3-1.6 0-1.7-.6a1.4 1.4 0 0 1 0-.7s.3.2 1 0c.7-.1 1-.7.9-1.2-.2-.6-1-.8-1.8-.6-1 .2-2 1-1.7 2.6.3 1 .9 1.6 1.5 1.8l.7-.2c1-.2 1.5 0 1.6.5 0 .4-.2 1-1.2 1.2a3.3 3.3 0 0 1-1.5 0c-.9.7-1.6 1.9-1.3 3.2.3 1.3 1.3 2.2 3 1.8 2.5-.7 3.8-3.7 4.2-5-.3-.5-.6-1-.7-1.6-.1-.5.1-1 .9-1.2.4 0 .7.2.8.8a2.8 2.8 0 0 1 0 1l.7 1c.6-2 1.4-4 1.7-4 .6-.2 1.5.6 1.5.6-.8.7-1.7 2.4-2.3 4.2.8.6 1.6 1 2.1 1 .5-.1.8-.6 1-1.2-.3-2.2 1-4.3 2.3-4.6.7-.2 1.3.2 1.4.8.1.5 0 1.3-.9 1.7-.2-1-.6-1.3-1-1.3-.4.1-.7 1.4-.4 2.8.2 1 .7 1.5 1.3 1.4.8-.2 1.3-1.2 1.7-2.1-.3-2.1.9-4.2 2.2-4.5.7-.2 1.2.1 1.4 1 .4 1.4-1 2.8-2.2 3.4.3.7.7 1 1.3.9 1-.3 1.6-1.5 2-2.5l-.5-3v-.3s1.6-.3 1.8.6v.1c.2-.6.7-1.2 1.3-1.4.8-.1 1.5.6 1.7 1.6.5 2.2-.5 4.4-1.8 4.7H33a31.9 31.9 0 0 0 1 5.2c-.4.1-1.8.4-2-.4l-.5-5.6c-.5 1-1.3 2.2-2.5 2.4-1 .3-1.6-.3-2-1.1-.5 1-1.3 2.1-2.4 2.4-.8.2-1.5-.1-2-1-.3.8-.9 1.5-1.5 1.7-.7.1-1.5-.3-2.4-1-.3.8-.4 1.6-.4 2.2 0 0-.7 0-.8-.4-.1-.5 0-1.5.3-2.7a10.3 10.3 0 0 1-.7-.8zm38.2-17.8l.2.9c.5 1.9.4 4.4.8 6.4 0 .6-.4 3-1.4 3.3-.2 0-.3 0-.4-.4-.1-.7 0-1.6-.3-2.6-.2-1.1-.8-1.6-1.5-1.5-.8.2-1.3 1-1.6 2l-.1-.5c-.2-1-1.8-.6-1.8-.6a6.2 6.2 0 0 1 .4 1.3l.2 1c-.2.5-.6 1-1.2 1l-.2.1a7 7 0 0 0-.1-.8c-.3-1.1-1-2-1.6-1.8a.7.7 0 0 0-.4.3c-1.3.3-2.4 2-2.1 3.9-.2.9-.6 1.7-1 1.9-.5 0-.8-.5-1.1-1.8l-.1-1.2a4 4 0 0 0 0-1.7c0-.4-.4-.7-.8-.6-.7.2-.9 1.7-.5 3.8-.2 1-.6 2-1.3 2-.4.2-.8-.2-1-1l-.2-3c1.2-.5 2-1 1.8-1.7-.1-.5-.8-.7-.8-.7s0 .7-1 1.2l-.2-1.4c-.1-.6-.4-1-1.7-.6l.4 1 .2 1.5h-1v.8c0 .3.4.3 1 .2 0 1.3 0 2.7.2 3.6.3 1.4 1.2 2 2 1.7 1-.2 1.6-1.3 2-2.3.3 1.2 1 2 1.9 1.7.7-.2 1.2-1.1 1.6-2.2.4.8 1.1 1.1 2 1 1.2-.4 1.7-1.6 1.8-2.8h.2c.6-.2 1-.6 1.3-1 0 .8 0 1.5.2 2.1.1.5.3.7.6.6.5-.1 1-.9 1-.9a4 4 0 0 1-.3-1c-.3-1.3.3-3.6 1-3.7.2 0 .3.2.5.7v.8l.2 1.5v.7c.2.7.7 1.3 1.5 1 1.3-.2 2-2.6 2.1-3.9.3.2.6.2 1 .1-.6-2.2 0-6.1-.3-7.9-.1-.4-1-.5-1.7-.5h-.4zm-21.5 12c.4 0 .7.3 1 1.1.2 1.3-.3 2.6-.9 2.8-.2 0-.7 0-1-1.2v-.4c0-1.3.4-2 1-2.2zm-5.2 1c.3 0 .6.2.6.5.2.6-.3 1.3-1.2 2-.3-1.4.1-2.3.6-2.5zm18-.4c-.5.2-1-.4-1.2-1.2-.2-1 0-2.1.7-2.5v.5c.2.7.6 1.5 1.3 1.9 0 .7-.2 1.2-.7 1.3zm10-1.6c0 .5.4.7 1 .6.8-.2 1-1 .8-1.6 0-.5-.4-1-1-.8-.5.1-1 .9-.8 1.8zm-14.3-5.5c0-.4-.5-.7-1-.5-.8.2-1 1-.9 1.5.2.6.5 1 1 .8.5 0 1.1-1 1-1.8z" fill="#fff" fill-opacity=".6"/></svg>';
  382.     }
  383. }