Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

ExceptionHandler.php

Zuletzt modifiziert: 01.05.2026, 11:26 - Dateigröße: 24.31 KiB


 001  <?php
 002   
 003  /*
 004   * This file is part of the Symfony package.
 005   *
 006   * (c) Fabien Potencier <fabien@symfony.com>
 007   *
 008   * For the full copyright and license information, please view the LICENSE
 009   * file that was distributed with this source code.
 010   */
 011   
 012  namespace Symfony\Component\Debug;
 013   
 014  use Symfony\Component\Debug\Exception\FlattenException;
 015  use Symfony\Component\Debug\Exception\OutOfMemoryException;
 016  use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
 017   
 018  /**
 019   * ExceptionHandler converts an exception to a Response object.
 020   *
 021   * It is mostly useful in debug mode to replace the default PHP/XDebug
 022   * output with something prettier and more useful.
 023   *
 024   * As this class is mainly used during Kernel boot, where nothing is yet
 025   * available, the Response content is always HTML.
 026   *
 027   * @author Fabien Potencier <fabien@symfony.com>
 028   * @author Nicolas Grekas <p@tchwork.com>
 029   */
 030  class ExceptionHandler
 031  {
 032      private $debug;
 033      private $charset;
 034      private $handler;
 035      private $caughtBuffer;
 036      private $caughtLength;
 037      private $fileLinkFormat;
 038   
 039      public function __construct($debug = true, $charset = null, $fileLinkFormat = null)
 040      {
 041          $this->debug = $debug;
 042          $this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8';
 043          $this->fileLinkFormat = $fileLinkFormat;
 044      }
 045   
 046      /**
 047       * Registers the exception handler.
 048       *
 049       * @param bool        $debug          Enable/disable debug mode, where the stack trace is displayed
 050       * @param string|null $charset        The charset used by exception messages
 051       * @param string|null $fileLinkFormat The IDE link template
 052       *
 053       * @return static
 054       */
 055      public static function register($debug = true, $charset = null, $fileLinkFormat = null)
 056      {
 057          $handler = new static($debug, $charset, $fileLinkFormat);
 058   
 059          $prev = set_exception_handler([$handler, 'handle']);
 060          if (\is_array($prev) && $prev[0] instanceof ErrorHandler) {
 061              restore_exception_handler();
 062              $prev[0]->setExceptionHandler([$handler, 'handle']);
 063          }
 064   
 065          return $handler;
 066      }
 067   
 068      /**
 069       * Sets a user exception handler.
 070       *
 071       * @param callable $handler An handler that will be called on Exception
 072       *
 073       * @return callable|null The previous exception handler if any
 074       */
 075      public function setHandler(callable $handler = null)
 076      {
 077          $old = $this->handler;
 078          $this->handler = $handler;
 079   
 080          return $old;
 081      }
 082   
 083      /**
 084       * Sets the format for links to source files.
 085       *
 086       * @param string|FileLinkFormatter $fileLinkFormat The format for links to source files
 087       *
 088       * @return string The previous file link format
 089       */
 090      public function setFileLinkFormat($fileLinkFormat)
 091      {
 092          $old = $this->fileLinkFormat;
 093          $this->fileLinkFormat = $fileLinkFormat;
 094   
 095          return $old;
 096      }
 097   
 098      /**
 099       * Sends a response for the given Exception.
 100       *
 101       * To be as fail-safe as possible, the exception is first handled
 102       * by our simple exception handler, then by the user exception handler.
 103       * The latter takes precedence and any output from the former is cancelled,
 104       * if and only if nothing bad happens in this handling path.
 105       */
 106      public function handle(\Exception $exception)
 107      {
 108          if (null === $this->handler || $exception instanceof OutOfMemoryException) {
 109              $this->sendPhpResponse($exception);
 110   
 111              return;
 112          }
 113   
 114          $caughtLength = $this->caughtLength = 0;
 115   
 116          ob_start(function ($buffer) {
 117              $this->caughtBuffer = $buffer;
 118   
 119              return '';
 120          });
 121   
 122          $this->sendPhpResponse($exception);
 123          while (null === $this->caughtBuffer && ob_end_flush()) {
 124              // Empty loop, everything is in the condition
 125          }
 126          if (isset($this->caughtBuffer[0])) {
 127              ob_start(function ($buffer) {
 128                  if ($this->caughtLength) {
 129                      // use substr_replace() instead of substr() for mbstring overloading resistance
 130                      $cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength);
 131                      if (isset($cleanBuffer[0])) {
 132                          $buffer = $cleanBuffer;
 133                      }
 134                  }
 135   
 136                  return $buffer;
 137              });
 138   
 139              echo $this->caughtBuffer;
 140              $caughtLength = ob_get_length();
 141          }
 142          $this->caughtBuffer = null;
 143   
 144          try {
 145              \call_user_func($this->handler, $exception);
 146              $this->caughtLength = $caughtLength;
 147          } catch (\Exception $e) {
 148              if (!$caughtLength) {
 149                  // All handlers failed. Let PHP handle that now.
 150                  throw $exception;
 151              }
 152          }
 153      }
 154   
 155      /**
 156       * Sends the error associated with the given Exception as a plain PHP response.
 157       *
 158       * This method uses plain PHP functions like header() and echo to output
 159       * the response.
 160       *
 161       * @param \Exception|FlattenException $exception An \Exception or FlattenException instance
 162       */
 163      public function sendPhpResponse($exception)
 164      {
 165          if (!$exception instanceof FlattenException) {
 166              $exception = FlattenException::create($exception);
 167          }
 168   
 169          if (!headers_sent()) {
 170              header(sprintf('HTTP/1.0 %s', $exception->getStatusCode()));
 171              foreach ($exception->getHeaders() as $name => $value) {
 172                  header($name.': '.$value, false);
 173              }
 174              header('Content-Type: text/html; charset='.$this->charset);
 175          }
 176   
 177          echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
 178      }
 179   
 180      /**
 181       * Gets the full HTML content associated with the given exception.
 182       *
 183       * @param \Exception|FlattenException $exception An \Exception or FlattenException instance
 184       *
 185       * @return string The HTML content as a string
 186       */
 187      public function getHtml($exception)
 188      {
 189          if (!$exception instanceof FlattenException) {
 190              $exception = FlattenException::create($exception);
 191          }
 192   
 193          return $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
 194      }
 195   
 196      /**
 197       * Gets the HTML content associated with the given exception.
 198       *
 199       * @return string The content as a string
 200       */
 201      public function getContent(FlattenException $exception)
 202      {
 203          switch ($exception->getStatusCode()) {
 204              case 404:
 205                  $title = 'Sorry, the page you are looking for could not be found.';
 206                  break;
 207              default:
 208                  $title = 'Whoops, looks like something went wrong.';
 209          }
 210   
 211          if (!$this->debug) {
 212              return <<<EOF
 213                  <div class="container">
 214                      <h1>$title</h1>
 215                  </div>
 216  EOF;
 217   
 218          }
 219   
 220          $content = '';
 221          try {
 222              $count = \count($exception->getAllPrevious());
 223              $total = $count + 1;
 224              foreach ($exception->toArray() as $position => $e) {
 225                  $ind = $count - $position + 1;
 226                  $class = $this->formatClass($e['class']);
 227                  $message = nl2br($this->escapeHtml($e['message']));
 228                  $content .= sprintf(<<<'EOF'
 229                      <div class="trace trace-as-html">
 230                          <table class="trace-details">
 231                              <thead class="trace-head"><tr><th>
 232                                  <h3 class="trace-class">
 233                                      <span class="text-muted">(%d/%d)</span>
 234                                      <span class="exception_title">%s</span>
 235                                  </h3>
 236                                  <p class="break-long-words trace-message">%s</p>
 237                              </th></tr></thead>
 238                              <tbody>
 239  EOF
 240                      , $ind, $total, $class, $message);
 241                  foreach ($e['trace'] as $trace) {
 242                      $content .= '<tr><td>';
 243                      if ($trace['function']) {
 244                          $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']));
 245                      }
 246                      if (isset($trace['file']) && isset($trace['line'])) {
 247                          $content .= $this->formatPath($trace['file'], $trace['line']);
 248                      }
 249                      $content .= "</td></tr>\n";
 250                  }
 251   
 252                  $content .= "</tbody>\n</table>\n</div>\n";
 253              }
 254          } catch (\Exception $e) {
 255              // something nasty happened and we cannot throw an exception anymore
 256              if ($this->debug) {
 257                  $title = sprintf('Exception thrown when handling an exception (%s: %s)', \get_class($e), $this->escapeHtml($e->getMessage()));
 258              } else {
 259                  $title = 'Whoops, looks like something went wrong.';
 260              }
 261          }
 262   
 263          $symfonyGhostImageContents = $this->getSymfonyGhostAsSvg();
 264   
 265          return <<<EOF
 266              <div class="exception-summary">
 267                  <div class="container">
 268                      <div class="exception-message-wrapper">
 269                          <h1 class="break-long-words exception-message">$title</h1>
 270                          <div class="exception-illustration hidden-xs-down">$symfonyGhostImageContents</div>
 271                      </div>
 272                  </div>
 273              </div>
 274   
 275              <div class="container">
 276                  $content
 277              </div>
 278  EOF;
 279   
 280      }
 281   
 282      /**
 283       * Gets the stylesheet associated with the given exception.
 284       *
 285       * @return string The stylesheet as a string
 286       */
 287      public function getStylesheet(FlattenException $exception)
 288      {
 289          if (!$this->debug) {
 290              return <<<'EOF'
 291                  body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; }
 292                  .container { margin: 30px; max-width: 600px; }
 293                  h1 { color: #dc3545; font-size: 24px; }
 294  EOF;
 295   
 296          }
 297   
 298          return <<<'EOF'
 299              body { background-color: #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; }
 300   
 301              a { cursor: pointer; text-decoration: none; }
 302              a:hover { text-decoration: underline; }
 303              abbr[title] { border-bottom: none; cursor: help; text-decoration: none; }
 304   
 305              code, pre { font: 13px/1.5 Consolas, Monaco, Menlo, "Ubuntu Mono", "Liberation Mono", monospace; }
 306   
 307              table, tr, th, td { background: #FFF; border-collapse: collapse; vertical-align: top; }
 308              table { background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; width: 100%; }
 309              table th, table td { border: solid #E0E0E0; border-width: 1px 0; padding: 8px 10px; }
 310              table th { background-color: #E0E0E0; font-weight: bold; text-align: left; }
 311   
 312              .hidden-xs-down { display: none; }
 313              .block { display: block; }
 314              .break-long-words { -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; }
 315              .text-muted { color: #999; }
 316   
 317              .container { max-width: 1024px; margin: 0 auto; padding: 0 15px; }
 318              .container::after { content: ""; display: table; clear: both; }
 319   
 320              .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; }
 321   
 322              .exception-message-wrapper { display: flex; align-items: center; min-height: 70px; }
 323              .exception-message { flex-grow: 1; padding: 30px 0; }
 324              .exception-message, .exception-message a { color: #FFF; font-size: 21px; font-weight: 400; margin: 0; }
 325              .exception-message.long { font-size: 18px; }
 326              .exception-message a { border-bottom: 1px solid rgba(255, 255, 255, 0.5); font-size: inherit; text-decoration: none; }
 327              .exception-message a:hover { border-bottom-color: #ffffff; }
 328   
 329              .exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; }
 330   
 331              .trace + .trace { margin-top: 30px; }
 332              .trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; }
 333   
 334              .trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; }
 335   
 336              .trace-file-path, .trace-file-path a { color: #222; margin-top: 3px; font-size: 13px; }
 337              .trace-class { color: #B0413E; }
 338              .trace-type { padding: 0 2px; }
 339              .trace-method { color: #B0413E; font-weight: bold; }
 340              .trace-arguments { color: #777; font-weight: normal; padding-left: 2px; }
 341   
 342              @media (min-width: 575px) {
 343                  .hidden-xs-down { display: initial; }
 344              }
 345  EOF;
 346   
 347      }
 348   
 349      private function decorate($content, $css)
 350      {
 351          return <<<EOF
 352  <!DOCTYPE html>
 353  <html>
 354      <head>
 355          <meta charset="{$this->charset}" />
 356          <meta name="robots" content="noindex,nofollow" />
 357          <style>$css</style>
 358      </head>
 359      <body>
 360          $content
 361      </body>
 362  </html>
 363  EOF;
 364   
 365      }
 366   
 367      private function formatClass($class)
 368      {
 369          $parts = explode('\\', $class);
 370   
 371          return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts));
 372      }
 373   
 374      private function formatPath($path, $line)
 375      {
 376          $file = $this->escapeHtml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path);
 377          $fmt = $this->fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
 378   
 379          if (!$fmt) {
 380              return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : '');
 381          }
 382   
 383          if (\is_string($fmt)) {
 384              $i = strpos($f = $fmt, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f);
 385              $fmt = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE);
 386   
 387              for ($i = 1; isset($fmt[$i]); ++$i) {
 388                  if (0 === strpos($path, $k = $fmt[$i++])) {
 389                      $path = substr_replace($path, $fmt[$i], 0, \strlen($k));
 390                      break;
 391                  }
 392              }
 393   
 394              $link = strtr($fmt[0], ['%f' => $path, '%l' => $line]);
 395          } else {
 396              try {
 397                  $link = $fmt->format($path, $line);
 398              } catch (\Exception $e) {
 399                  return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : '');
 400              }
 401          }
 402   
 403          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, 0 < $line ? ' line '.$line : '');
 404      }
 405   
 406      /**
 407       * Formats an array as a string.
 408       *
 409       * @param array $args The argument array
 410       *
 411       * @return string
 412       */
 413      private function formatArgs(array $args)
 414      {
 415          $result = [];
 416          foreach ($args as $key => $item) {
 417              if ('object' === $item[0]) {
 418                  $formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1]));
 419              } elseif ('array' === $item[0]) {
 420                  $formattedValue = sprintf('<em>array</em>(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
 421              } elseif ('null' === $item[0]) {
 422                  $formattedValue = '<em>null</em>';
 423              } elseif ('boolean' === $item[0]) {
 424                  $formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
 425              } elseif ('resource' === $item[0]) {
 426                  $formattedValue = '<em>resource</em>';
 427              } else {
 428                  $formattedValue = str_replace("\n", '', $this->escapeHtml(var_export($item[1], true)));
 429              }
 430   
 431              $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formattedValue);
 432          }
 433   
 434          return implode(', ', $result);
 435      }
 436   
 437      /**
 438       * HTML-encodes a string.
 439       */
 440      private function escapeHtml($str)
 441      {
 442          return htmlspecialchars($str, \ENT_COMPAT | \ENT_SUBSTITUTE, $this->charset);
 443      }
 444   
 445      private function getSymfonyGhostAsSvg()
 446      {
 447          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>';
 448      }
 449  }
 450