Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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: 02.04.2025, 15:02 - 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