The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .mailmap
├── CHANGELOG.md
├── LICENSE.md
├── SECURITY.md
├── composer.json
└── src
    └── Whoops
        ├── Exception
            ├── ErrorException.php
            ├── Formatter.php
            ├── Frame.php
            ├── FrameCollection.php
            └── Inspector.php
        ├── Handler
            ├── CallbackHandler.php
            ├── Handler.php
            ├── HandlerInterface.php
            ├── JsonResponseHandler.php
            ├── PlainTextHandler.php
            ├── PrettyPageHandler.php
            └── XmlResponseHandler.php
        ├── Inspector
            ├── InspectorFactory.php
            ├── InspectorFactoryInterface.php
            └── InspectorInterface.php
        ├── Resources
            ├── css
            │   ├── prism.css
            │   └── whoops.base.css
            ├── js
            │   ├── clipboard.min.js
            │   ├── prism.js
            │   ├── whoops.base.js
            │   └── zepto.min.js
            └── views
            │   ├── env_details.html.php
            │   ├── frame_code.html.php
            │   ├── frame_list.html.php
            │   ├── frames_container.html.php
            │   ├── frames_description.html.php
            │   ├── header.html.php
            │   ├── header_outer.html.php
            │   ├── layout.html.php
            │   ├── panel_details.html.php
            │   ├── panel_details_outer.html.php
            │   ├── panel_left.html.php
            │   └── panel_left_outer.html.php
        ├── Run.php
        ├── RunInterface.php
        └── Util
            ├── HtmlDumperOutput.php
            ├── Misc.php
            ├── SystemFacade.php
            └── TemplateHelper.php


/.mailmap:
--------------------------------------------------------------------------------
1 | Denis Sokolov <denis@sokolov.cc>
2 | Filipe Dobreira <dobreira@gmail.com>
3 | 


--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
  1 | # CHANGELOG
  2 | 
  3 | ## v2.18.0
  4 | 
  5 | * Line numbers are now clickable.
  6 | 
  7 | ## v2.17.0
  8 | 
  9 | * Support cursor IDE.
 10 | 
 11 | ## v2.16.0
 12 | 
 13 | * Support PHP `8.4`.
 14 | * Drop support for PHP older than `7.1`.
 15 | 
 16 | ## v2.15.4
 17 | 
 18 | * Improve link color in comments.
 19 | 
 20 | ## v2.15.3
 21 | 
 22 | * Improve performance of the syntax highlighting (#758).
 23 | 
 24 | ## v2.15.2
 25 | 
 26 | * Fixed missing code highlight, which additionally led to issue with switching tabs, between application and all frames ([#747](https://github.com/filp/whoops/issues/747)).
 27 | 
 28 | ## v2.15.1
 29 | 
 30 | * Fixed bug with PrettyPageHandler "*Calling `getFrameFilters` method on null*" ([#751](https://github.com/filp/whoops/pull/751)).
 31 | 
 32 | ## v2.15.0
 33 | 
 34 | * Add addFrameFilter ([#749](https://github.com/filp/whoops/pull/749))
 35 | 
 36 | ## v2.14.6
 37 | 
 38 | * Upgraded prismJS to version `1.29.0` due to security issue ([#741][i741]).
 39 | 
 40 | [i741]: https://github.com/filp/whoops/pull/741
 41 | 
 42 | ## v2.14.5
 43 | 
 44 | * Allow `ArrayAccess` on super globals.
 45 | 
 46 | ## v2.14.4
 47 | 
 48 | * Fix PHP `5.5` support.
 49 | * Allow to use psr/log `2` or `3`.
 50 | 
 51 | ## v2.14.3
 52 | 
 53 | * Support PHP `8.1`.
 54 | 
 55 | ## v2.14.1
 56 | 
 57 | * Fix syntax highlighting scrolling too far.
 58 | * Improve the way we detect xdebug linkformat.
 59 | 
 60 | ## v2.14.0
 61 | 
 62 | * Switched syntax highlighting to Prism.js.
 63 | 
 64 | Avoids licensing issues with prettify, and uses a maintained, modern project.
 65 | 
 66 | ## v2.13.0
 67 | 
 68 | * Add Netbeans editor.
 69 | 
 70 | ## v2.12.1
 71 | 
 72 | * Avoid redirecting away from an error.
 73 | 
 74 | ## v2.12.0
 75 | 
 76 | * Hide non-string values in super globals when requested.
 77 | 
 78 | ## v2.11.0
 79 | 
 80 | * Customize exit code.
 81 | 
 82 | ## v2.10.0
 83 | 
 84 | * Better chaining on handler classes.
 85 | 
 86 | ## v2.9.2
 87 | 
 88 | * Fix copy button styles.
 89 | 
 90 | ## v2.9.1
 91 | 
 92 | * Fix xdebug function crash on PHP `8`.
 93 | 
 94 | ## v2.9.0
 95 | 
 96 | * `JsonResponseHandler` includes the exception code.
 97 | 
 98 | ## v2.8.0
 99 | 
100 | * Support PHP 8.
101 | 
102 | ## v2.7.3
103 | 
104 | * `PrettyPageHandler` functionality to hide superglobal keys has a clearer name 
105 | (`hideSuperglobalKey`).
106 | 
107 | ## v2.7.2
108 | 
109 | * `PrettyPageHandler` now accepts custom js files.
110 | * `PrettyPageHandler` and `templateHelper` is now accessible through inheritance.
111 | 
112 | ## v2.7.1
113 | 
114 | * Fix a PHP warning in some cases with anonymous classes.
115 | 
116 | ## v2.7.0
117 | 
118 | * Added `removeFirstHandler` and `removeLastHandler`.
119 | 
120 | ## v2.6.0
121 | 
122 | * Fix 2.4.0 `pushHandler` changing the order of handlers.
123 | 
124 | ## v2.5.1
125 | 
126 | * Fix error messaging in a rare case.
127 | 
128 | ## v2.5.0
129 | 
130 | * Automatically configure xdebug if available.
131 | 
132 | ## v2.4.1
133 | 
134 | * Try harder to close all output buffers.
135 | 
136 | ## v2.4.0
137 | 
138 | * Allow to prepend and append handlers.
139 | 
140 | ## v2.3.2
141 | 
142 | * Various fixes from the community.
143 | 
144 | ## v2.3.1
145 | 
146 | * Prevent exception in Whoops when caught exception frame is not related to real file.
147 | 
148 | ## v2.3.0
149 | 
150 | * Show previous exception messages.
151 | 
152 | ## v2.2.0
153 | 
154 | * Support PHP `7.2`.
155 | 
156 | ## v2.1.0
157 | 
158 | * Add a `SystemFacade` to allow clients to override Whoops behavior.
159 | * Show frame arguments in `PrettyPageHandler`.
160 | * Highlight the line with the error.
161 | * Add icons to search on Google and Stack Overflow.
162 | 
163 | ## v2.0.0
164 | 
165 | Backwards compatibility breaking changes:
166 | 
167 | * `Run` class is now `final`. If you inherited from `Run`, please now instead use a custom `SystemFacade` injected into the `Run` constructor, or contribute your changes to our core.
168 | * PHP < 5.5 support dropped.
169 | 


--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
 1 | # The MIT License
 2 | 
 3 | Permission is hereby granted, free of charge, to any person obtaining a copy
 4 | of this software and associated documentation files (the "Software"), to deal
 5 | in the Software without restriction, including without limitation the rights
 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 7 | copies of the Software, and to permit persons to whom the Software is
 8 | furnished to do so, subject to the following conditions:
 9 | 
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 | 
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 | 


--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
 1 | # Security Policy
 2 | 
 3 | ## Supported Versions
 4 | 
 5 | Only the latest released version of Whoops is supported.
 6 | To facilitate upgrades we almost never make backwards-incompatible changes.
 7 | 
 8 | ## Reporting a Vulnerability
 9 | 
10 | Please report vulnerabilities over email, by sending an email to `denis` at `sokolov` dot `cc`.
11 | 
12 | 
13 | 


--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "name": "filp/whoops",
 3 |     "license": "MIT",
 4 |     "description": "php error handling for cool kids",
 5 |     "keywords": ["library", "error", "handling", "exception", "whoops", "throwable"],
 6 |     "homepage": "https://filp.github.io/whoops/",
 7 |     "authors": [
 8 |         {
 9 |             "name": "Filipe Dobreira",
10 |             "homepage": "https://github.com/filp",
11 |             "role": "Developer"
12 |         }
13 |     ],
14 |     "scripts": {
15 |         "demo": "php -S localhost:8000 ./examples/example.php",
16 |         "test": "phpunit --testdox tests"
17 |     },
18 |     "require": {
19 |         "php": "^7.1 || ^8.0",
20 |         "psr/log": "^1.0.1 || ^2.0 || ^3.0"
21 |     },
22 |     "require-dev": {
23 |         "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3",
24 |         "mockery/mockery": "^1.0",
25 |         "symfony/var-dumper": "^4.0 || ^5.0"
26 |     },
27 |     "suggest": {
28 |         "symfony/var-dumper": "Pretty print complex values better with var-dumper available",
29 |         "whoops/soap": "Formats errors as SOAP responses"
30 |     },
31 |     "autoload": {
32 |         "psr-4": {
33 |             "Whoops\\": "src/Whoops/"
34 |         }
35 |     },
36 |     "autoload-dev": {
37 |         "psr-4": {
38 |             "Whoops\\": "tests/Whoops/"
39 |         }
40 |     },
41 |     "extra": {
42 |         "branch-alias": {
43 |             "dev-master": "2.7-dev"
44 |         }
45 |     }
46 | }
47 | 


--------------------------------------------------------------------------------
/src/Whoops/Exception/ErrorException.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Exception;
 8 | 
 9 | use ErrorException as BaseErrorException;
10 | 
11 | /**
12 |  * Wraps ErrorException; mostly used for typing (at least now)
13 |  * to easily cleanup the stack trace of redundant info.
14 |  */
15 | class ErrorException extends BaseErrorException
16 | {
17 | }
18 | 


--------------------------------------------------------------------------------
/src/Whoops/Exception/Formatter.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Exception;
 8 | 
 9 | use Whoops\Inspector\InspectorInterface;
10 | 
11 | class Formatter
12 | {
13 |     /**
14 |      * Returns all basic information about the exception in a simple array
15 |      * for further convertion to other languages
16 |      * @param  InspectorInterface $inspector
17 |      * @param  bool               $shouldAddTrace
18 |      * @param  array<callable>    $frameFilters
19 |      * @return array
20 |      */
21 |     public static function formatExceptionAsDataArray(InspectorInterface $inspector, $shouldAddTrace, array $frameFilters = [])
22 |     {
23 |         $exception = $inspector->getException();
24 |         $response = [
25 |             'type'    => get_class($exception),
26 |             'message' => $exception->getMessage(),
27 |             'code'    => $exception->getCode(),
28 |             'file'    => $exception->getFile(),
29 |             'line'    => $exception->getLine(),
30 |         ];
31 | 
32 |         if ($shouldAddTrace) {
33 |             $frames    = $inspector->getFrames($frameFilters);
34 |             $frameData = [];
35 | 
36 |             foreach ($frames as $frame) {
37 |                 /** @var Frame $frame */
38 |                 $frameData[] = [
39 |                     'file'     => $frame->getFile(),
40 |                     'line'     => $frame->getLine(),
41 |                     'function' => $frame->getFunction(),
42 |                     'class'    => $frame->getClass(),
43 |                     'args'     => $frame->getArgs(),
44 |                 ];
45 |             }
46 | 
47 |             $response['trace'] = $frameData;
48 |         }
49 | 
50 |         return $response;
51 |     }
52 | 
53 |     public static function formatExceptionPlain(InspectorInterface $inspector)
54 |     {
55 |         $message = $inspector->getException()->getMessage();
56 |         $frames = $inspector->getFrames();
57 | 
58 |         $plain = $inspector->getExceptionName();
59 |         $plain .= ' thrown with message "';
60 |         $plain .= $message;
61 |         $plain .= '"'."\n\n";
62 | 
63 |         $plain .= "Stacktrace:\n";
64 |         foreach ($frames as $i => $frame) {
65 |             $plain .= "#". (count($frames) - $i - 1). " ";
66 |             $plain .= $frame->getClass() ?: '';
67 |             $plain .= $frame->getClass() && $frame->getFunction() ? ":" : "";
68 |             $plain .= $frame->getFunction() ?: '';
69 |             $plain .= ' in ';
70 |             $plain .= ($frame->getFile() ?: '<#unknown>');
71 |             $plain .= ':';
72 |             $plain .= (int) $frame->getLine(). "\n";
73 |         }
74 | 
75 |         return $plain;
76 |     }
77 | }
78 | 


--------------------------------------------------------------------------------
/src/Whoops/Exception/Frame.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 |  * Whoops - php errors for cool kids
  4 |  * @author Filipe Dobreira <http://github.com/filp>
  5 |  */
  6 | 
  7 | namespace Whoops\Exception;
  8 | 
  9 | use InvalidArgumentException;
 10 | use Serializable;
 11 | 
 12 | class Frame implements Serializable
 13 | {
 14 |     /**
 15 |      * @var array
 16 |      */
 17 |     protected $frame;
 18 | 
 19 |     /**
 20 |      * @var string
 21 |      */
 22 |     protected $fileContentsCache;
 23 | 
 24 |     /**
 25 |      * @var array[]
 26 |      */
 27 |     protected $comments = [];
 28 | 
 29 |     /**
 30 |      * @var bool
 31 |      */
 32 |     protected $application;
 33 | 
 34 |     public function __construct(array $frame)
 35 |     {
 36 |         $this->frame = $frame;
 37 |     }
 38 | 
 39 |     /**
 40 |      * @param  bool        $shortened
 41 |      * @return string|null
 42 |      */
 43 |     public function getFile($shortened = false)
 44 |     {
 45 |         if (empty($this->frame['file'])) {
 46 |             return null;
 47 |         }
 48 | 
 49 |         $file = $this->frame['file'];
 50 | 
 51 |         // Check if this frame occurred within an eval().
 52 |         // @todo: This can be made more reliable by checking if we've entered
 53 |         // eval() in a previous trace, but will need some more work on the upper
 54 |         // trace collector(s).
 55 |         if (preg_match('/^(.*)\((\d+)\) : (?:eval\(\)\'d|assert) code$/', $file, $matches)) {
 56 |             $file = $this->frame['file'] = $matches[1];
 57 |             $this->frame['line'] = (int) $matches[2];
 58 |         }
 59 | 
 60 |         if ($shortened && is_string($file)) {
 61 |             // Replace the part of the path that all frames have in common, and add 'soft hyphens' for smoother line-breaks.
 62 |             $dirname = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__))))));
 63 |             if ($dirname !== '/') {
 64 |                 $file = str_replace($dirname, "&hellip;", $file);
 65 |             }
 66 |             $file = str_replace("/", "/&shy;", $file);
 67 |         }
 68 | 
 69 |         return $file;
 70 |     }
 71 | 
 72 |     /**
 73 |      * @return int|null
 74 |      */
 75 |     public function getLine()
 76 |     {
 77 |         return isset($this->frame['line']) ? $this->frame['line'] : null;
 78 |     }
 79 | 
 80 |     /**
 81 |      * @return string|null
 82 |      */
 83 |     public function getClass()
 84 |     {
 85 |         return isset($this->frame['class']) ? $this->frame['class'] : null;
 86 |     }
 87 | 
 88 |     /**
 89 |      * @return string|null
 90 |      */
 91 |     public function getFunction()
 92 |     {
 93 |         return isset($this->frame['function']) ? $this->frame['function'] : null;
 94 |     }
 95 | 
 96 |     /**
 97 |      * @return array
 98 |      */
 99 |     public function getArgs()
100 |     {
101 |         return isset($this->frame['args']) ? (array) $this->frame['args'] : [];
102 |     }
103 | 
104 |     /**
105 |      * Returns the full contents of the file for this frame,
106 |      * if it's known.
107 |      * @return string|null
108 |      */
109 |     public function getFileContents()
110 |     {
111 |         if ($this->fileContentsCache === null && $filePath = $this->getFile()) {
112 |             // Leave the stage early when 'Unknown' or '[internal]' is passed
113 |             // this would otherwise raise an exception when
114 |             // open_basedir is enabled.
115 |             if ($filePath === "Unknown" || $filePath === '[internal]') {
116 |                 return null;
117 |             }
118 | 
119 |             try {
120 |                 $this->fileContentsCache = file_get_contents($filePath);
121 |             } catch (ErrorException $exception) {
122 |                 // Internal file paths of PHP extensions cannot be opened
123 |             }
124 |         }
125 | 
126 |         return $this->fileContentsCache;
127 |     }
128 | 
129 |     /**
130 |      * Adds a comment to this frame, that can be received and
131 |      * used by other handlers. For example, the PrettyPage handler
132 |      * can attach these comments under the code for each frame.
133 |      *
134 |      * An interesting use for this would be, for example, code analysis
135 |      * & annotations.
136 |      *
137 |      * @param string $comment
138 |      * @param string $context Optional string identifying the origin of the comment
139 |      */
140 |     public function addComment($comment, $context = 'global')
141 |     {
142 |         $this->comments[] = [
143 |             'comment' => $comment,
144 |             'context' => $context,
145 |         ];
146 |     }
147 | 
148 |     /**
149 |      * Returns all comments for this frame. Optionally allows
150 |      * a filter to only retrieve comments from a specific
151 |      * context.
152 |      *
153 |      * @param  string  $filter
154 |      * @return array[]
155 |      */
156 |     public function getComments($filter = null)
157 |     {
158 |         $comments = $this->comments;
159 | 
160 |         if ($filter !== null) {
161 |             $comments = array_filter($comments, function ($c) use ($filter) {
162 |                 return $c['context'] == $filter;
163 |             });
164 |         }
165 | 
166 |         return $comments;
167 |     }
168 | 
169 |     /**
170 |      * Returns the array containing the raw frame data from which
171 |      * this Frame object was built
172 |      *
173 |      * @return array
174 |      */
175 |     public function getRawFrame()
176 |     {
177 |         return $this->frame;
178 |     }
179 | 
180 |     /**
181 |      * Returns the contents of the file for this frame as an
182 |      * array of lines, and optionally as a clamped range of lines.
183 |      *
184 |      * NOTE: lines are 0-indexed
185 |      *
186 |      * @example
187 |      *     Get all lines for this file
188 |      *     $frame->getFileLines(); // => array( 0 => '<?php', 1 => '...', ...)
189 |      * @example
190 |      *     Get one line for this file, starting at line 10 (zero-indexed, remember!)
191 |      *     $frame->getFileLines(9, 1); // array( 9 => '...' )
192 |      *
193 |      * @throws InvalidArgumentException if $length is less than or equal to 0
194 |      * @param  int                      $start
195 |      * @param  int                      $length
196 |      * @return string[]|null
197 |      */
198 |     public function getFileLines($start = 0, $length = null)
199 |     {
200 |         if (null !== ($contents = $this->getFileContents())) {
201 |             $lines = explode("\n", $contents);
202 | 
203 |             // Get a subset of lines from $start to $end
204 |             if ($length !== null) {
205 |                 $start  = (int) $start;
206 |                 $length = (int) $length;
207 |                 if ($start < 0) {
208 |                     $start = 0;
209 |                 }
210 | 
211 |                 if ($length <= 0) {
212 |                     throw new InvalidArgumentException(
213 |                         "\$length($length) cannot be lower or equal to 0"
214 |                     );
215 |                 }
216 | 
217 |                 $lines = array_slice($lines, $start, $length, true);
218 |             }
219 | 
220 |             return $lines;
221 |         }
222 |     }
223 | 
224 |     /**
225 |      * Implements the Serializable interface, with special
226 |      * steps to also save the existing comments.
227 |      *
228 |      * @see Serializable::serialize
229 |      * @return string
230 |      */
231 |     public function serialize()
232 |     {
233 |         $frame = $this->frame;
234 |         if (!empty($this->comments)) {
235 |             $frame['_comments'] = $this->comments;
236 |         }
237 | 
238 |         return serialize($frame);
239 |     }
240 | 
241 |     public function __serialize()
242 |     {
243 |         $frame = $this->frame;
244 |         if (!empty($this->comments)) {
245 |             $frame['_comments'] = $this->comments;
246 |         }
247 |         return $frame;
248 |     }
249 | 
250 |     /**
251 |      * Unserializes the frame data, while also preserving
252 |      * any existing comment data.
253 |      *
254 |      * @see Serializable::unserialize
255 |      * @param string $serializedFrame
256 |      */
257 |     public function unserialize($serializedFrame)
258 |     {
259 |         $frame = unserialize($serializedFrame);
260 | 
261 |         if (!empty($frame['_comments'])) {
262 |             $this->comments = $frame['_comments'];
263 |             unset($frame['_comments']);
264 |         }
265 | 
266 |         $this->frame = $frame;
267 |     }
268 | 
269 |     public function __unserialize($frame)
270 |     {
271 |         if (!empty($frame['_comments'])) {
272 |             $this->comments = $frame['_comments'];
273 |             unset($frame['_comments']);
274 |         }
275 | 
276 |         $this->frame = $frame;
277 |     }
278 | 
279 |     /**
280 |      * Compares Frame against one another
281 |      * @param  Frame $frame
282 |      * @return bool
283 |      */
284 |     public function equals(Frame $frame)
285 |     {
286 |         if (!$this->getFile() || $this->getFile() === 'Unknown' || !$this->getLine()) {
287 |             return false;
288 |         }
289 |         return $frame->getFile() === $this->getFile() && $frame->getLine() === $this->getLine();
290 |     }
291 | 
292 |     /**
293 |      * Returns whether this frame belongs to the application or not.
294 |      *
295 |      * @return boolean
296 |      */
297 |     public function isApplication()
298 |     {
299 |         return $this->application;
300 |     }
301 | 
302 |     /**
303 |      * Mark as an frame belonging to the application.
304 |      *
305 |      * @param boolean $application
306 |      */
307 |     public function setApplication($application)
308 |     {
309 |         $this->application = $application;
310 |     }
311 | }
312 | 


--------------------------------------------------------------------------------
/src/Whoops/Exception/FrameCollection.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 |  * Whoops - php errors for cool kids
  4 |  * @author Filipe Dobreira <http://github.com/filp>
  5 |  */
  6 | 
  7 | namespace Whoops\Exception;
  8 | 
  9 | use ArrayAccess;
 10 | use ArrayIterator;
 11 | use Countable;
 12 | use IteratorAggregate;
 13 | use ReturnTypeWillChange;
 14 | use Serializable;
 15 | use UnexpectedValueException;
 16 | 
 17 | /**
 18 |  * Exposes a fluent interface for dealing with an ordered list
 19 |  * of stack-trace frames.
 20 |  */
 21 | class FrameCollection implements ArrayAccess, IteratorAggregate, Serializable, Countable
 22 | {
 23 |     /**
 24 |      * @var array[]
 25 |      */
 26 |     private $frames;
 27 | 
 28 |     public function __construct(array $frames)
 29 |     {
 30 |         $this->frames = array_map(function ($frame) {
 31 |             return new Frame($frame);
 32 |         }, $frames);
 33 |     }
 34 | 
 35 |     /**
 36 |      * Filters frames using a callable, returns the same FrameCollection
 37 |      *
 38 |      * @param  callable        $callable
 39 |      * @return FrameCollection
 40 |      */
 41 |     public function filter($callable)
 42 |     {
 43 |         $this->frames = array_values(array_filter($this->frames, $callable));
 44 |         return $this;
 45 |     }
 46 | 
 47 |     /**
 48 |      * Map the collection of frames
 49 |      *
 50 |      * @param  callable        $callable
 51 |      * @return FrameCollection
 52 |      */
 53 |     public function map($callable)
 54 |     {
 55 |         // Contain the map within a higher-order callable
 56 |         // that enforces type-correctness for the $callable
 57 |         $this->frames = array_map(function ($frame) use ($callable) {
 58 |             $frame = call_user_func($callable, $frame);
 59 | 
 60 |             if (!$frame instanceof Frame) {
 61 |                 throw new UnexpectedValueException(
 62 |                     "Callable to " . __CLASS__ . "::map must return a Frame object"
 63 |                 );
 64 |             }
 65 | 
 66 |             return $frame;
 67 |         }, $this->frames);
 68 | 
 69 |         return $this;
 70 |     }
 71 | 
 72 |     /**
 73 |      * Returns an array with all frames, does not affect
 74 |      * the internal array.
 75 |      *
 76 |      * @todo   If this gets any more complex than this,
 77 |      *         have getIterator use this method.
 78 |      * @see    FrameCollection::getIterator
 79 |      * @return array
 80 |      */
 81 |     public function getArray()
 82 |     {
 83 |         return $this->frames;
 84 |     }
 85 | 
 86 |     /**
 87 |      * @see IteratorAggregate::getIterator
 88 |      * @return ArrayIterator
 89 |      */
 90 |     #[ReturnTypeWillChange]
 91 |     public function getIterator()
 92 |     {
 93 |         return new ArrayIterator($this->frames);
 94 |     }
 95 | 
 96 |     /**
 97 |      * @see ArrayAccess::offsetExists
 98 |      * @param int $offset
 99 |      */
100 |     #[ReturnTypeWillChange]
101 |     public function offsetExists($offset)
102 |     {
103 |         return isset($this->frames[$offset]);
104 |     }
105 | 
106 |     /**
107 |      * @see ArrayAccess::offsetGet
108 |      * @param int $offset
109 |      */
110 |     #[ReturnTypeWillChange]
111 |     public function offsetGet($offset)
112 |     {
113 |         return $this->frames[$offset];
114 |     }
115 | 
116 |     /**
117 |      * @see ArrayAccess::offsetSet
118 |      * @param int $offset
119 |      */
120 |     #[ReturnTypeWillChange]
121 |     public function offsetSet($offset, $value)
122 |     {
123 |         throw new \Exception(__CLASS__ . ' is read only');
124 |     }
125 | 
126 |     /**
127 |      * @see ArrayAccess::offsetUnset
128 |      * @param int $offset
129 |      */
130 |     #[ReturnTypeWillChange]
131 |     public function offsetUnset($offset)
132 |     {
133 |         throw new \Exception(__CLASS__ . ' is read only');
134 |     }
135 | 
136 |     /**
137 |      * @see Countable::count
138 |      * @return int
139 |      */
140 |     #[ReturnTypeWillChange]
141 |     public function count()
142 |     {
143 |         return count($this->frames);
144 |     }
145 | 
146 |     /**
147 |      * Count the frames that belongs to the application.
148 |      *
149 |      * @return int
150 |      */
151 |     public function countIsApplication()
152 |     {
153 |         return count(array_filter($this->frames, function (Frame $f) {
154 |             return $f->isApplication();
155 |         }));
156 |     }
157 | 
158 |     /**
159 |      * @see Serializable::serialize
160 |      * @return string
161 |      */
162 |     #[ReturnTypeWillChange]
163 |     public function serialize()
164 |     {
165 |         return serialize($this->frames);
166 |     }
167 | 
168 |     /**
169 |      * @see Serializable::unserialize
170 |      * @param string $serializedFrames
171 |      */
172 |     #[ReturnTypeWillChange]
173 |     public function unserialize($serializedFrames)
174 |     {
175 |         $this->frames = unserialize($serializedFrames);
176 |     }
177 | 
178 |     public function __serialize()
179 |     {
180 |         return $this->frames;
181 |     }
182 | 
183 |     public function __unserialize(array $serializedFrames)
184 |     {
185 |         $this->frames = $serializedFrames;
186 |     }
187 | 
188 |     /**
189 |      * @param Frame[] $frames Array of Frame instances, usually from $e->getPrevious()
190 |      */
191 |     public function prependFrames(array $frames)
192 |     {
193 |         $this->frames = array_merge($frames, $this->frames);
194 |     }
195 | 
196 |     /**
197 |      * Gets the innermost part of stack trace that is not the same as that of outer exception
198 |      *
199 |      * @param  FrameCollection $parentFrames Outer exception frames to compare tail against
200 |      * @return Frame[]
201 |      */
202 |     public function topDiff(FrameCollection $parentFrames)
203 |     {
204 |         $diff = $this->frames;
205 | 
206 |         $parentFrames = $parentFrames->getArray();
207 |         $p = count($parentFrames)-1;
208 | 
209 |         for ($i = count($diff)-1; $i >= 0 && $p >= 0; $i--) {
210 |             /** @var Frame $tailFrame */
211 |             $tailFrame = $diff[$i];
212 |             if ($tailFrame->equals($parentFrames[$p])) {
213 |                 unset($diff[$i]);
214 |             }
215 |             $p--;
216 |         }
217 |         return $diff;
218 |     }
219 | }
220 | 


--------------------------------------------------------------------------------
/src/Whoops/Exception/Inspector.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 |  * Whoops - php errors for cool kids
  4 |  * @author Filipe Dobreira <http://github.com/filp>
  5 |  */
  6 | 
  7 | namespace Whoops\Exception;
  8 | 
  9 | use Whoops\Inspector\InspectorFactory;
 10 | use Whoops\Inspector\InspectorInterface;
 11 | use Whoops\Util\Misc;
 12 | 
 13 | class Inspector implements InspectorInterface
 14 | {
 15 |     /**
 16 |      * @var \Throwable
 17 |      */
 18 |     private $exception;
 19 | 
 20 |     /**
 21 |      * @var \Whoops\Exception\FrameCollection
 22 |      */
 23 |     private $frames;
 24 | 
 25 |     /**
 26 |      * @var \Whoops\Exception\Inspector
 27 |      */
 28 |     private $previousExceptionInspector;
 29 | 
 30 |     /**
 31 |      * @var \Throwable[]
 32 |      */
 33 |     private $previousExceptions;
 34 | 
 35 |     /**
 36 |      * @var \Whoops\Inspector\InspectorFactoryInterface|null
 37 |      */
 38 |     protected $inspectorFactory;
 39 | 
 40 |     /**
 41 |      * @param \Throwable $exception The exception to inspect
 42 |      * @param \Whoops\Inspector\InspectorFactoryInterface $factory
 43 |      */
 44 |     public function __construct($exception, $factory = null)
 45 |     {
 46 |         $this->exception = $exception;
 47 |         $this->inspectorFactory = $factory ?: new InspectorFactory();
 48 |     }
 49 | 
 50 |     /**
 51 |      * @return \Throwable
 52 |      */
 53 |     public function getException()
 54 |     {
 55 |         return $this->exception;
 56 |     }
 57 | 
 58 |     /**
 59 |      * @return string
 60 |      */
 61 |     public function getExceptionName()
 62 |     {
 63 |         return get_class($this->exception);
 64 |     }
 65 | 
 66 |     /**
 67 |      * @return string
 68 |      */
 69 |     public function getExceptionMessage()
 70 |     {
 71 |         return $this->extractDocrefUrl($this->exception->getMessage())['message'];
 72 |     }
 73 | 
 74 |     /**
 75 |      * @return string[]
 76 |      */
 77 |     public function getPreviousExceptionMessages()
 78 |     {
 79 |         return array_map(function ($prev) {
 80 |             /** @var \Throwable $prev */
 81 |             return $this->extractDocrefUrl($prev->getMessage())['message'];
 82 |         }, $this->getPreviousExceptions());
 83 |     }
 84 | 
 85 |     /**
 86 |      * @return int[]
 87 |      */
 88 |     public function getPreviousExceptionCodes()
 89 |     {
 90 |         return array_map(function ($prev) {
 91 |             /** @var \Throwable $prev */
 92 |             return $prev->getCode();
 93 |         }, $this->getPreviousExceptions());
 94 |     }
 95 | 
 96 |     /**
 97 |      * Returns a url to the php-manual related to the underlying error - when available.
 98 |      *
 99 |      * @return string|null
100 |      */
101 |     public function getExceptionDocrefUrl()
102 |     {
103 |         return $this->extractDocrefUrl($this->exception->getMessage())['url'];
104 |     }
105 | 
106 |     private function extractDocrefUrl($message)
107 |     {
108 |         $docref = [
109 |             'message' => $message,
110 |             'url' => null,
111 |         ];
112 | 
113 |         // php embbeds urls to the manual into the Exception message with the following ini-settings defined
114 |         // http://php.net/manual/en/errorfunc.configuration.php#ini.docref-root
115 |         if (!ini_get('html_errors') || !ini_get('docref_root')) {
116 |             return $docref;
117 |         }
118 | 
119 |         $pattern = "/\[<a href='([^']+)'>(?:[^<]+)<\/a>\]/";
120 |         if (preg_match($pattern, $message, $matches)) {
121 |             // -> strip those automatically generated links from the exception message
122 |             $docref['message'] = preg_replace($pattern, '', $message, 1);
123 |             $docref['url'] = $matches[1];
124 |         }
125 | 
126 |         return $docref;
127 |     }
128 | 
129 |     /**
130 |      * Does the wrapped Exception has a previous Exception?
131 |      * @return bool
132 |      */
133 |     public function hasPreviousException()
134 |     {
135 |         return $this->previousExceptionInspector || $this->exception->getPrevious();
136 |     }
137 | 
138 |     /**
139 |      * Returns an Inspector for a previous Exception, if any.
140 |      * @todo   Clean this up a bit, cache stuff a bit better.
141 |      * @return Inspector
142 |      */
143 |     public function getPreviousExceptionInspector()
144 |     {
145 |         if ($this->previousExceptionInspector === null) {
146 |             $previousException = $this->exception->getPrevious();
147 | 
148 |             if ($previousException) {
149 |                 $this->previousExceptionInspector = $this->inspectorFactory->create($previousException);
150 |             }
151 |         }
152 | 
153 |         return $this->previousExceptionInspector;
154 |     }
155 | 
156 | 
157 |     /**
158 |      * Returns an array of all previous exceptions for this inspector's exception
159 |      * @return \Throwable[]
160 |      */
161 |     public function getPreviousExceptions()
162 |     {
163 |         if ($this->previousExceptions === null) {
164 |             $this->previousExceptions = [];
165 | 
166 |             $prev = $this->exception->getPrevious();
167 |             while ($prev !== null) {
168 |                 $this->previousExceptions[] = $prev;
169 |                 $prev = $prev->getPrevious();
170 |             }
171 |         }
172 | 
173 |         return $this->previousExceptions;
174 |     }
175 | 
176 |     /**
177 |      * Returns an iterator for the inspected exception's
178 |      * frames.
179 |      * 
180 |      * @param array<callable> $frameFilters
181 |      * 
182 |      * @return \Whoops\Exception\FrameCollection
183 |      */
184 |     public function getFrames(array $frameFilters = [])
185 |     {
186 |         if ($this->frames === null) {
187 |             $frames = $this->getTrace($this->exception);
188 | 
189 |             // Fill empty line/file info for call_user_func_array usages (PHP Bug #44428)
190 |             foreach ($frames as $k => $frame) {
191 |                 if (empty($frame['file'])) {
192 |                     // Default values when file and line are missing
193 |                     $file = '[internal]';
194 |                     $line = 0;
195 | 
196 |                     $next_frame = !empty($frames[$k + 1]) ? $frames[$k + 1] : [];
197 | 
198 |                     if ($this->isValidNextFrame($next_frame)) {
199 |                         $file = $next_frame['file'];
200 |                         $line = $next_frame['line'];
201 |                     }
202 | 
203 |                     $frames[$k]['file'] = $file;
204 |                     $frames[$k]['line'] = $line;
205 |                 }
206 |             }
207 | 
208 |             // Find latest non-error handling frame index ($i) used to remove error handling frames
209 |             $i = 0;
210 |             foreach ($frames as $k => $frame) {
211 |                 if ($frame['file'] == $this->exception->getFile() && $frame['line'] == $this->exception->getLine()) {
212 |                     $i = $k;
213 |                 }
214 |             }
215 | 
216 |             // Remove error handling frames
217 |             if ($i > 0) {
218 |                 array_splice($frames, 0, $i);
219 |             }
220 | 
221 |             $firstFrame = $this->getFrameFromException($this->exception);
222 |             array_unshift($frames, $firstFrame);
223 | 
224 |             $this->frames = new FrameCollection($frames);
225 | 
226 |             if ($previousInspector = $this->getPreviousExceptionInspector()) {
227 |                 // Keep outer frame on top of the inner one
228 |                 $outerFrames = $this->frames;
229 |                 $newFrames = clone $previousInspector->getFrames();
230 |                 // I assume it will always be set, but let's be safe
231 |                 if (isset($newFrames[0])) {
232 |                     $newFrames[0]->addComment(
233 |                         $previousInspector->getExceptionMessage(),
234 |                         'Exception message:'
235 |                     );
236 |                 }
237 |                 $newFrames->prependFrames($outerFrames->topDiff($newFrames));
238 |                 $this->frames = $newFrames;
239 |             }
240 | 
241 |             // Apply frame filters callbacks on the frames stack
242 |             if (!empty($frameFilters)) {
243 |                 foreach ($frameFilters as $filterCallback) {
244 |                     $this->frames->filter($filterCallback);
245 |                 }
246 |             }
247 |         }
248 | 
249 |         return $this->frames;
250 |     }
251 | 
252 |     /**
253 |      * Gets the backtrace from an exception.
254 |      *
255 |      * If xdebug is installed
256 |      *
257 |      * @param \Throwable $e
258 |      * @return array
259 |      */
260 |     protected function getTrace($e)
261 |     {
262 |         $traces = $e->getTrace();
263 | 
264 |         // Get trace from xdebug if enabled, failure exceptions only trace to the shutdown handler by default
265 |         if (!$e instanceof \ErrorException) {
266 |             return $traces;
267 |         }
268 | 
269 |         if (!Misc::isLevelFatal($e->getSeverity())) {
270 |             return $traces;
271 |         }
272 | 
273 |         if (!extension_loaded('xdebug') || !function_exists('xdebug_is_enabled') || !xdebug_is_enabled()) {
274 |             return $traces;
275 |         }
276 | 
277 |         // Use xdebug to get the full stack trace and remove the shutdown handler stack trace
278 |         $stack = array_reverse(xdebug_get_function_stack());
279 |         $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
280 |         $traces = array_diff_key($stack, $trace);
281 | 
282 |         return $traces;
283 |     }
284 | 
285 |     /**
286 |      * Given an exception, generates an array in the format
287 |      * generated by Exception::getTrace()
288 |      * @param  \Throwable $exception
289 |      * @return array
290 |      */
291 |     protected function getFrameFromException($exception)
292 |     {
293 |         return [
294 |             'file'  => $exception->getFile(),
295 |             'line'  => $exception->getLine(),
296 |             'class' => get_class($exception),
297 |             'args'  => [
298 |                 $exception->getMessage(),
299 |             ],
300 |         ];
301 |     }
302 | 
303 |     /**
304 |      * Given an error, generates an array in the format
305 |      * generated by ErrorException
306 |      * @param  ErrorException $exception
307 |      * @return array
308 |      */
309 |     protected function getFrameFromError(ErrorException $exception)
310 |     {
311 |         return [
312 |             'file'  => $exception->getFile(),
313 |             'line'  => $exception->getLine(),
314 |             'class' => null,
315 |             'args'  => [],
316 |         ];
317 |     }
318 | 
319 |     /**
320 |      * Determine if the frame can be used to fill in previous frame's missing info
321 |      * happens for call_user_func and call_user_func_array usages (PHP Bug #44428)
322 |      *
323 |      * @return bool
324 |      */
325 |     protected function isValidNextFrame(array $frame)
326 |     {
327 |         if (empty($frame['file'])) {
328 |             return false;
329 |         }
330 | 
331 |         if (empty($frame['line'])) {
332 |             return false;
333 |         }
334 | 
335 |         if (empty($frame['function']) || !stristr($frame['function'], 'call_user_func')) {
336 |             return false;
337 |         }
338 | 
339 |         return true;
340 |     }
341 | }
342 | 


--------------------------------------------------------------------------------
/src/Whoops/Handler/CallbackHandler.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Handler;
 8 | 
 9 | use InvalidArgumentException;
10 | 
11 | /**
12 |  * Wrapper for Closures passed as handlers. Can be used
13 |  * directly, or will be instantiated automagically by Whoops\Run
14 |  * if passed to Run::pushHandler
15 |  */
16 | class CallbackHandler extends Handler
17 | {
18 |     /**
19 |      * @var callable
20 |      */
21 |     protected $callable;
22 | 
23 |     /**
24 |      * @throws InvalidArgumentException If argument is not callable
25 |      * @param  callable                 $callable
26 |      */
27 |     public function __construct($callable)
28 |     {
29 |         if (!is_callable($callable)) {
30 |             throw new InvalidArgumentException(
31 |                 'Argument to ' . __METHOD__ . ' must be valid callable'
32 |             );
33 |         }
34 | 
35 |         $this->callable = $callable;
36 |     }
37 | 
38 |     /**
39 |      * @return int|null
40 |      */
41 |     public function handle()
42 |     {
43 |         $exception = $this->getException();
44 |         $inspector = $this->getInspector();
45 |         $run       = $this->getRun();
46 |         $callable  = $this->callable;
47 | 
48 |         // invoke the callable directly, to get simpler stacktraces (in comparison to call_user_func).
49 |         // this assumes that $callable is a properly typed php-callable, which we check in __construct().
50 |         return $callable($exception, $inspector, $run);
51 |     }
52 | }
53 | 


--------------------------------------------------------------------------------
/src/Whoops/Handler/Handler.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Handler;
 8 | 
 9 | use Whoops\Inspector\InspectorInterface;
10 | use Whoops\RunInterface;
11 | 
12 | /**
13 |  * Abstract implementation of a Handler.
14 |  */
15 | abstract class Handler implements HandlerInterface
16 | {
17 |     /*
18 |      Return constants that can be returned from Handler::handle
19 |      to message the handler walker.
20 |      */
21 |     const DONE         = 0x10; // returning this is optional, only exists for
22 |                                // semantic purposes
23 |     /**
24 |      * The Handler has handled the Throwable in some way, and wishes to skip any other Handler.
25 |      * Execution will continue.
26 |      */
27 |     const LAST_HANDLER = 0x20;
28 |     /**
29 |      * The Handler has handled the Throwable in some way, and wishes to quit/stop execution
30 |      */
31 |     const QUIT         = 0x30;
32 | 
33 |     /**
34 |      * @var RunInterface
35 |      */
36 |     private $run;
37 | 
38 |     /**
39 |      * @var InspectorInterface $inspector
40 |      */
41 |     private $inspector;
42 | 
43 |     /**
44 |      * @var \Throwable $exception
45 |      */
46 |     private $exception;
47 | 
48 |     /**
49 |      * @param RunInterface $run
50 |      */
51 |     public function setRun(RunInterface $run)
52 |     {
53 |         $this->run = $run;
54 |     }
55 | 
56 |     /**
57 |      * @return RunInterface
58 |      */
59 |     protected function getRun()
60 |     {
61 |         return $this->run;
62 |     }
63 | 
64 |     /**
65 |      * @param InspectorInterface $inspector
66 |      */
67 |     public function setInspector(InspectorInterface $inspector)
68 |     {
69 |         $this->inspector = $inspector;
70 |     }
71 | 
72 |     /**
73 |      * @return InspectorInterface
74 |      */
75 |     protected function getInspector()
76 |     {
77 |         return $this->inspector;
78 |     }
79 | 
80 |     /**
81 |      * @param \Throwable $exception
82 |      */
83 |     public function setException($exception)
84 |     {
85 |         $this->exception = $exception;
86 |     }
87 | 
88 |     /**
89 |      * @return \Throwable
90 |      */
91 |     protected function getException()
92 |     {
93 |         return $this->exception;
94 |     }
95 | }
96 | 


--------------------------------------------------------------------------------
/src/Whoops/Handler/HandlerInterface.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Handler;
 8 | 
 9 | use Whoops\Inspector\InspectorInterface;
10 | use Whoops\RunInterface;
11 | 
12 | interface HandlerInterface
13 | {
14 |     /**
15 |      * @return int|null A handler may return nothing, or a Handler::HANDLE_* constant
16 |      */
17 |     public function handle();
18 | 
19 |     /**
20 |      * @param  RunInterface  $run
21 |      * @return void
22 |      */
23 |     public function setRun(RunInterface $run);
24 | 
25 |     /**
26 |      * @param  \Throwable $exception
27 |      * @return void
28 |      */
29 |     public function setException($exception);
30 | 
31 |     /**
32 |      * @param  InspectorInterface $inspector
33 |      * @return void
34 |      */
35 |     public function setInspector(InspectorInterface $inspector);
36 | }
37 | 


--------------------------------------------------------------------------------
/src/Whoops/Handler/JsonResponseHandler.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Handler;
 8 | 
 9 | use Whoops\Exception\Formatter;
10 | 
11 | /**
12 |  * Catches an exception and converts it to a JSON
13 |  * response. Additionally can also return exception
14 |  * frames for consumption by an API.
15 |  */
16 | class JsonResponseHandler extends Handler
17 | {
18 |     /**
19 |      * @var bool
20 |      */
21 |     private $returnFrames = false;
22 | 
23 |     /**
24 |      * @var bool
25 |      */
26 |     private $jsonApi = false;
27 | 
28 |     /**
29 |      * Returns errors[[]] instead of error[] to be in compliance with the json:api spec
30 |      * @param bool $jsonApi Default is false
31 |      * @return static
32 |      */
33 |     public function setJsonApi($jsonApi = false)
34 |     {
35 |         $this->jsonApi = (bool) $jsonApi;
36 |         return $this;
37 |     }
38 | 
39 |     /**
40 |      * @param  bool|null  $returnFrames
41 |      * @return bool|static
42 |      */
43 |     public function addTraceToOutput($returnFrames = null)
44 |     {
45 |         if (func_num_args() == 0) {
46 |             return $this->returnFrames;
47 |         }
48 | 
49 |         $this->returnFrames = (bool) $returnFrames;
50 |         return $this;
51 |     }
52 | 
53 |     /**
54 |      * @return int
55 |      */
56 |     public function handle()
57 |     {
58 |         if ($this->jsonApi === true) {
59 |             $response = [
60 |                 'errors' => [
61 |                     Formatter::formatExceptionAsDataArray(
62 |                         $this->getInspector(),
63 |                         $this->addTraceToOutput(),
64 |                         $this->getRun()->getFrameFilters()
65 |                     ),
66 |                 ]
67 |             ];
68 |         } else {
69 |             $response = [
70 |                 'error' => Formatter::formatExceptionAsDataArray(
71 |                     $this->getInspector(),
72 |                     $this->addTraceToOutput(),
73 |                     $this->getRun()->getFrameFilters()
74 |                 ),
75 |             ];
76 |         }
77 | 
78 |         echo json_encode($response, defined('JSON_PARTIAL_OUTPUT_ON_ERROR') ? JSON_PARTIAL_OUTPUT_ON_ERROR : 0);
79 | 
80 |         return Handler::QUIT;
81 |     }
82 | 
83 |     /**
84 |      * @return string
85 |      */
86 |     public function contentType()
87 |     {
88 |         return 'application/json';
89 |     }
90 | }
91 | 


--------------------------------------------------------------------------------
/src/Whoops/Handler/PlainTextHandler.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 | * Whoops - php errors for cool kids
  4 | * @author Filipe Dobreira <http://github.com/filp>
  5 | * Plaintext handler for command line and logs.
  6 | * @author Pierre-Yves Landuré <https://howto.biapy.com/>
  7 | */
  8 | 
  9 | namespace Whoops\Handler;
 10 | 
 11 | use InvalidArgumentException;
 12 | use Psr\Log\LoggerInterface;
 13 | use Whoops\Exception\Frame;
 14 | 
 15 | /**
 16 | * Handler outputing plaintext error messages. Can be used
 17 | * directly, or will be instantiated automagically by Whoops\Run
 18 | * if passed to Run::pushHandler
 19 | */
 20 | class PlainTextHandler extends Handler
 21 | {
 22 |     const VAR_DUMP_PREFIX = '   | ';
 23 | 
 24 |     /**
 25 |      * @var \Psr\Log\LoggerInterface
 26 |      */
 27 |     protected $logger;
 28 | 
 29 |     /**
 30 |      * @var callable
 31 |      */
 32 |     protected $dumper;
 33 | 
 34 |     /**
 35 |      * @var bool
 36 |      */
 37 |     private $addTraceToOutput = true;
 38 | 
 39 |     /**
 40 |      * @var bool|integer
 41 |      */
 42 |     private $addTraceFunctionArgsToOutput = false;
 43 | 
 44 |     /**
 45 |      * @var integer
 46 |      */
 47 |     private $traceFunctionArgsOutputLimit = 1024;
 48 | 
 49 |     /**
 50 |      * @var bool
 51 |      */
 52 |     private $addPreviousToOutput = true;
 53 | 
 54 |     /**
 55 |      * @var bool
 56 |      */
 57 |     private $loggerOnly = false;
 58 | 
 59 |     /**
 60 |      * Constructor.
 61 |      * @throws InvalidArgumentException     If argument is not null or a LoggerInterface
 62 |      * @param  \Psr\Log\LoggerInterface|null $logger
 63 |      */
 64 |     public function __construct($logger = null)
 65 |     {
 66 |         $this->setLogger($logger);
 67 |     }
 68 | 
 69 |     /**
 70 |      * Set the output logger interface.
 71 |      * @throws InvalidArgumentException     If argument is not null or a LoggerInterface
 72 |      * @param  \Psr\Log\LoggerInterface|null $logger
 73 |      */
 74 |     public function setLogger($logger = null)
 75 |     {
 76 |         if (! (is_null($logger)
 77 |             || $logger instanceof LoggerInterface)) {
 78 |             throw new InvalidArgumentException(
 79 |                 'Argument to ' . __METHOD__ .
 80 |                 " must be a valid Logger Interface (aka. Monolog), " .
 81 |                 get_class($logger) . ' given.'
 82 |             );
 83 |         }
 84 | 
 85 |         $this->logger = $logger;
 86 |     }
 87 | 
 88 |     /**
 89 |      * @return \Psr\Log\LoggerInterface|null
 90 |      */
 91 |     public function getLogger()
 92 |     {
 93 |         return $this->logger;
 94 |     }
 95 | 
 96 |     /**
 97 |      * Set var dumper callback function.
 98 |      *
 99 |      * @param  callable $dumper
100 |      * @return static
101 |      */
102 |     public function setDumper(callable $dumper)
103 |     {
104 |         $this->dumper = $dumper;
105 |         return $this;
106 |     }
107 | 
108 |     /**
109 |      * Add error trace to output.
110 |      * @param  bool|null  $addTraceToOutput
111 |      * @return bool|static
112 |      */
113 |     public function addTraceToOutput($addTraceToOutput = null)
114 |     {
115 |         if (func_num_args() == 0) {
116 |             return $this->addTraceToOutput;
117 |         }
118 | 
119 |         $this->addTraceToOutput = (bool) $addTraceToOutput;
120 |         return $this;
121 |     }
122 | 
123 |     /**
124 |      * Add previous exceptions to output.
125 |      * @param  bool|null $addPreviousToOutput
126 |      * @return bool|static
127 |      */
128 |     public function addPreviousToOutput($addPreviousToOutput = null)
129 |     {
130 |         if (func_num_args() == 0) {
131 |             return $this->addPreviousToOutput;
132 |         }
133 | 
134 |         $this->addPreviousToOutput = (bool) $addPreviousToOutput;
135 |         return $this;
136 |     }
137 | 
138 |     /**
139 |      * Add error trace function arguments to output.
140 |      * Set to True for all frame args, or integer for the n first frame args.
141 |      * @param  bool|integer|null $addTraceFunctionArgsToOutput
142 |      * @return static|bool|integer
143 |      */
144 |     public function addTraceFunctionArgsToOutput($addTraceFunctionArgsToOutput = null)
145 |     {
146 |         if (func_num_args() == 0) {
147 |             return $this->addTraceFunctionArgsToOutput;
148 |         }
149 | 
150 |         if (! is_integer($addTraceFunctionArgsToOutput)) {
151 |             $this->addTraceFunctionArgsToOutput = (bool) $addTraceFunctionArgsToOutput;
152 |         } else {
153 |             $this->addTraceFunctionArgsToOutput = $addTraceFunctionArgsToOutput;
154 |         }
155 |         return $this;
156 |     }
157 | 
158 |     /**
159 |      * Set the size limit in bytes of frame arguments var_dump output.
160 |      * If the limit is reached, the var_dump output is discarded.
161 |      * Prevent memory limit errors.
162 |      * @var integer
163 |      * @return static
164 |      */
165 |     public function setTraceFunctionArgsOutputLimit($traceFunctionArgsOutputLimit)
166 |     {
167 |         $this->traceFunctionArgsOutputLimit = (integer) $traceFunctionArgsOutputLimit;
168 |         return $this;
169 |     }
170 | 
171 |     /**
172 |      * Create plain text response and return it as a string
173 |      * @return string
174 |      */
175 |     public function generateResponse()
176 |     {
177 |         $exception = $this->getException();
178 |         $message = $this->getExceptionOutput($exception);
179 | 
180 |         if ($this->addPreviousToOutput) {
181 |             $previous = $exception->getPrevious();
182 |             while ($previous) {
183 |                 $message .= "\n\nCaused by\n" . $this->getExceptionOutput($previous);
184 |                 $previous = $previous->getPrevious();
185 |             }
186 |         }
187 | 
188 | 
189 |         return $message . $this->getTraceOutput() . "\n";
190 |     }
191 | 
192 |     /**
193 |      * Get the size limit in bytes of frame arguments var_dump output.
194 |      * If the limit is reached, the var_dump output is discarded.
195 |      * Prevent memory limit errors.
196 |      * @return integer
197 |      */
198 |     public function getTraceFunctionArgsOutputLimit()
199 |     {
200 |         return $this->traceFunctionArgsOutputLimit;
201 |     }
202 | 
203 |     /**
204 |      * Only output to logger.
205 |      * @param  bool|null $loggerOnly
206 |      * @return static|bool
207 |      */
208 |     public function loggerOnly($loggerOnly = null)
209 |     {
210 |         if (func_num_args() == 0) {
211 |             return $this->loggerOnly;
212 |         }
213 | 
214 |         $this->loggerOnly = (bool) $loggerOnly;
215 |         return $this;
216 |     }
217 | 
218 |     /**
219 |      * Test if handler can output to stdout.
220 |      * @return bool
221 |      */
222 |     private function canOutput()
223 |     {
224 |         return !$this->loggerOnly();
225 |     }
226 | 
227 |     /**
228 |      * Get the frame args var_dump.
229 |      * @param  \Whoops\Exception\Frame $frame [description]
230 |      * @param  integer                 $line  [description]
231 |      * @return string
232 |      */
233 |     private function getFrameArgsOutput(Frame $frame, $line)
234 |     {
235 |         if ($this->addTraceFunctionArgsToOutput() === false
236 |             || $this->addTraceFunctionArgsToOutput() < $line) {
237 |             return '';
238 |         }
239 | 
240 |         // Dump the arguments:
241 |         ob_start();
242 |         $this->dump($frame->getArgs());
243 |         if (ob_get_length() > $this->getTraceFunctionArgsOutputLimit()) {
244 |             // The argument var_dump is to big.
245 |             // Discarded to limit memory usage.
246 |             ob_clean();
247 |             return sprintf(
248 |                 "\n%sArguments dump length greater than %d Bytes. Discarded.",
249 |                 self::VAR_DUMP_PREFIX,
250 |                 $this->getTraceFunctionArgsOutputLimit()
251 |             );
252 |         }
253 | 
254 |         return sprintf(
255 |             "\n%s",
256 |             preg_replace('/^/m', self::VAR_DUMP_PREFIX, ob_get_clean())
257 |         );
258 |     }
259 | 
260 |     /**
261 |      * Dump variable.
262 |      *
263 |      * @param mixed $var
264 |      * @return void
265 |      */
266 |     protected function dump($var)
267 |     {
268 |         if ($this->dumper) {
269 |             call_user_func($this->dumper, $var);
270 |         } else {
271 |             var_dump($var);
272 |         }
273 |     }
274 | 
275 |     /**
276 |      * Get the exception trace as plain text.
277 |      * @return string
278 |      */
279 |     private function getTraceOutput()
280 |     {
281 |         if (! $this->addTraceToOutput()) {
282 |             return '';
283 |         }
284 |         $inspector = $this->getInspector();
285 |         $frames = $inspector->getFrames($this->getRun()->getFrameFilters());
286 | 
287 |         $response = "\nStack trace:";
288 | 
289 |         $line = 1;
290 |         foreach ($frames as $frame) {
291 |             /** @var Frame $frame */
292 |             $class = $frame->getClass();
293 | 
294 |             $template = "\n%3d. %s->%s() %s:%d%s";
295 |             if (! $class) {
296 |                 // Remove method arrow (->) from output.
297 |                 $template = "\n%3d. %s%s() %s:%d%s";
298 |             }
299 | 
300 |             $response .= sprintf(
301 |                 $template,
302 |                 $line,
303 |                 $class,
304 |                 $frame->getFunction(),
305 |                 $frame->getFile(),
306 |                 $frame->getLine(),
307 |                 $this->getFrameArgsOutput($frame, $line)
308 |             );
309 | 
310 |             $line++;
311 |         }
312 | 
313 |         return $response;
314 |     }
315 | 
316 |     /**
317 |      * Get the exception as plain text.
318 |      * @param \Throwable $exception
319 |      * @return string
320 |      */
321 |     private function getExceptionOutput($exception)
322 |     {
323 |         return sprintf(
324 |             "%s: %s in file %s on line %d",
325 |             get_class($exception),
326 |             $exception->getMessage(),
327 |             $exception->getFile(),
328 |             $exception->getLine()
329 |         );
330 |     }
331 | 
332 |     /**
333 |      * @return int
334 |      */
335 |     public function handle()
336 |     {
337 |         $response = $this->generateResponse();
338 | 
339 |         if ($this->getLogger()) {
340 |             $this->getLogger()->error($response);
341 |         }
342 | 
343 |         if (! $this->canOutput()) {
344 |             return Handler::DONE;
345 |         }
346 | 
347 |         echo $response;
348 | 
349 |         return Handler::QUIT;
350 |     }
351 | 
352 |     /**
353 |      * @return string
354 |      */
355 |     public function contentType()
356 |     {
357 |         return 'text/plain';
358 |     }
359 | }
360 | 


--------------------------------------------------------------------------------
/src/Whoops/Handler/XmlResponseHandler.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 |  * Whoops - php errors for cool kids
  4 |  * @author Filipe Dobreira <http://github.com/filp>
  5 |  */
  6 | 
  7 | namespace Whoops\Handler;
  8 | 
  9 | use SimpleXMLElement;
 10 | use Whoops\Exception\Formatter;
 11 | 
 12 | /**
 13 |  * Catches an exception and converts it to an XML
 14 |  * response. Additionally can also return exception
 15 |  * frames for consumption by an API.
 16 |  */
 17 | class XmlResponseHandler extends Handler
 18 | {
 19 |     /**
 20 |      * @var bool
 21 |      */
 22 |     private $returnFrames = false;
 23 | 
 24 |     /**
 25 |      * @param  bool|null  $returnFrames
 26 |      * @return bool|static
 27 |      */
 28 |     public function addTraceToOutput($returnFrames = null)
 29 |     {
 30 |         if (func_num_args() == 0) {
 31 |             return $this->returnFrames;
 32 |         }
 33 | 
 34 |         $this->returnFrames = (bool) $returnFrames;
 35 |         return $this;
 36 |     }
 37 | 
 38 |     /**
 39 |      * @return int
 40 |      */
 41 |     public function handle()
 42 |     {
 43 |         $response = [
 44 |             'error' => Formatter::formatExceptionAsDataArray(
 45 |                 $this->getInspector(),
 46 |                 $this->addTraceToOutput(),
 47 |                 $this->getRun()->getFrameFilters()
 48 |             ),
 49 |         ];
 50 | 
 51 |         echo self::toXml($response);
 52 | 
 53 |         return Handler::QUIT;
 54 |     }
 55 | 
 56 |     /**
 57 |      * @return string
 58 |      */
 59 |     public function contentType()
 60 |     {
 61 |         return 'application/xml';
 62 |     }
 63 | 
 64 |     /**
 65 |      * @param  SimpleXMLElement  $node Node to append data to, will be modified in place
 66 |      * @param  array|\Traversable $data
 67 |      * @return SimpleXMLElement  The modified node, for chaining
 68 |      */
 69 |     private static function addDataToNode(\SimpleXMLElement $node, $data)
 70 |     {
 71 |         assert(is_array($data) || $data instanceof Traversable);
 72 | 
 73 |         foreach ($data as $key => $value) {
 74 |             if (is_numeric($key)) {
 75 |                 // Convert the key to a valid string
 76 |                 $key = "unknownNode_". (string) $key;
 77 |             }
 78 | 
 79 |             // Delete any char not allowed in XML element names
 80 |             $key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
 81 | 
 82 |             if (is_array($value)) {
 83 |                 $child = $node->addChild($key);
 84 |                 self::addDataToNode($child, $value);
 85 |             } else {
 86 |                 $value = str_replace('&', '&amp;', print_r($value, true));
 87 |                 $node->addChild($key, $value);
 88 |             }
 89 |         }
 90 | 
 91 |         return $node;
 92 |     }
 93 | 
 94 |     /**
 95 |      * The main function for converting to an XML document.
 96 |      *
 97 |      * @param  array|\Traversable $data
 98 |      * @return string            XML
 99 |      */
100 |     private static function toXml($data)
101 |     {
102 |         assert(is_array($data) || $data instanceof Traversable);
103 | 
104 |         $node = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><root />");
105 | 
106 |         return self::addDataToNode($node, $data)->asXML();
107 |     }
108 | }
109 | 


--------------------------------------------------------------------------------
/src/Whoops/Inspector/InspectorFactory.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Inspector;
 8 | 
 9 | use Whoops\Exception\Inspector;
10 | 
11 | class InspectorFactory implements InspectorFactoryInterface
12 | {
13 |     /**
14 |      * @param \Throwable $exception
15 |      * @return InspectorInterface
16 |      */
17 |     public function create($exception)
18 |     {
19 |         return new Inspector($exception, $this);
20 |     }
21 | }
22 | 


--------------------------------------------------------------------------------
/src/Whoops/Inspector/InspectorFactoryInterface.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Inspector;
 8 | 
 9 | interface InspectorFactoryInterface
10 | {
11 |     /**
12 |      * @param \Throwable $exception
13 |      * @return InspectorInterface
14 |      */
15 |     public function create($exception);
16 | }
17 | 


--------------------------------------------------------------------------------
/src/Whoops/Inspector/InspectorInterface.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Inspector;
 8 | 
 9 | interface InspectorInterface
10 | {
11 |     /**
12 |      * @return \Throwable
13 |      */
14 |     public function getException();
15 | 
16 |     /**
17 |      * @return string
18 |      */
19 |     public function getExceptionName();
20 | 
21 |     /**
22 |      * @return string
23 |      */
24 |     public function getExceptionMessage();
25 | 
26 |     /**
27 |      * @return string[]
28 |      */
29 |     public function getPreviousExceptionMessages();
30 | 
31 |     /**
32 |      * @return int[]
33 |      */
34 |     public function getPreviousExceptionCodes();
35 | 
36 |     /**
37 |      * Returns a url to the php-manual related to the underlying error - when available.
38 |      *
39 |      * @return string|null
40 |      */
41 |     public function getExceptionDocrefUrl();
42 | 
43 |     /**
44 |      * Does the wrapped Exception has a previous Exception?
45 |      * @return bool
46 |      */
47 |     public function hasPreviousException();
48 | 
49 |     /**
50 |      * Returns an Inspector for a previous Exception, if any.
51 |      * @todo   Clean this up a bit, cache stuff a bit better.
52 |      * @return InspectorInterface
53 |      */
54 |     public function getPreviousExceptionInspector();
55 | 
56 |     /**
57 |      * Returns an array of all previous exceptions for this inspector's exception
58 |      * @return \Throwable[]
59 |      */
60 |     public function getPreviousExceptions();
61 | 
62 |     /**
63 |      * Returns an iterator for the inspected exception's
64 |      * frames.
65 |      * 
66 |      * @param array<callable> $frameFilters
67 |      * 
68 |      * @return \Whoops\Exception\FrameCollection
69 |      */
70 |     public function getFrames(array $frameFilters = []);
71 | }
72 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/css/prism.css:
--------------------------------------------------------------------------------
1 | /* PrismJS 1.30.0
2 | https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */
3 | code[class*=language-],pre[class*=language-]{color:#ccc;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}
4 | pre[data-line]{position:relative;padding:1em 0 1em 3em}.line-highlight{position:absolute;left:0;right:0;padding:inherit 0;margin-top:1em;background:hsla(24,20%,50%,.08);background:linear-gradient(to right,hsla(24,20%,50%,.1) 70%,hsla(24,20%,50%,0));pointer-events:none;line-height:inherit;white-space:pre}@media print{.line-highlight{-webkit-print-color-adjust:exact;color-adjust:exact}}.line-highlight:before,.line-highlight[data-end]:after{content:attr(data-start);position:absolute;top:.4em;left:.6em;min-width:1em;padding:0 .5em;background-color:hsla(24,20%,50%,.4);color:#f4f1ef;font:bold 65%/1.5 sans-serif;text-align:center;vertical-align:.3em;border-radius:999px;text-shadow:none;box-shadow:0 1px #fff}.line-highlight[data-end]:after{content:attr(data-end);top:auto;bottom:.4em}.line-numbers .line-highlight:after,.line-numbers .line-highlight:before{content:none}pre[id].linkable-line-numbers span.line-numbers-rows{pointer-events:all}pre[id].linkable-line-numbers span.line-numbers-rows>span:before{cursor:pointer}pre[id].linkable-line-numbers span.line-numbers-rows>span:hover:before{background-color:rgba(128,128,128,.2)}
5 | pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}
6 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/css/whoops.base.css:
--------------------------------------------------------------------------------
  1 | body {
  2 |   font: 12px "Helvetica Neue", helvetica, arial, sans-serif;
  3 |   color: #131313;
  4 |   background: #eeeeee;
  5 |   padding:0;
  6 |   margin: 0;
  7 |   max-height: 100%;
  8 | 
  9 |   text-rendering: optimizeLegibility;
 10 | }
 11 |   a {
 12 |     text-decoration: none;
 13 |   }
 14 | 
 15 | .Whoops.container {
 16 |     position: relative;
 17 |     z-index: 9999999999;
 18 | }
 19 | 
 20 | .panel {
 21 |     overflow-y: scroll;
 22 |     height: 100%;
 23 |     position: fixed;
 24 |     margin: 0;
 25 |     left: 0;
 26 |     top: 0;
 27 | }
 28 | 
 29 | .branding {
 30 |   position: absolute;
 31 |   top: 10px;
 32 |   right: 20px;
 33 |   color: #777777;
 34 |   font-size: 10px;
 35 |     z-index: 100;
 36 | }
 37 |   .branding a {
 38 |     color: #e95353;
 39 |   }
 40 | 
 41 | header {
 42 |   color: white;
 43 |   box-sizing: border-box;
 44 |   background-color: #2a2a2a;
 45 |   padding: 35px 40px;
 46 |   max-height: 180px;
 47 |   overflow: hidden;
 48 |   transition: 0.5s;
 49 | }
 50 | 
 51 |   header.header-expand {
 52 |     max-height: 1000px;
 53 |   }
 54 | 
 55 |   .exc-title {
 56 |     margin: 0;
 57 |     color: #bebebe;
 58 |     font-size: 14px;
 59 |   }
 60 |     .exc-title-primary, .exc-title-secondary {
 61 |       color: #e95353;
 62 |     }
 63 | 
 64 |     .exc-message {
 65 |       font-size: 20px;
 66 |       word-wrap: break-word;
 67 |       margin: 4px 0 0 0;
 68 |       color: white;
 69 |     }
 70 |       .exc-message span {
 71 |         display: block;
 72 |       }
 73 |       .exc-message-empty-notice {
 74 |         color: #a29d9d;
 75 |         font-weight: 300;
 76 |       }
 77 | 
 78 | .prev-exc-title {
 79 |   margin: 10px 0;
 80 | }
 81 | 
 82 | .prev-exc-title + ul {
 83 |   margin: 0;
 84 |   padding: 0 0 0 20px;
 85 |   line-height: 12px;
 86 | }
 87 | 
 88 | .prev-exc-title + ul li {
 89 |   font: 12px "Helvetica Neue", helvetica, arial, sans-serif;
 90 | }
 91 | 
 92 | .prev-exc-title + ul li .prev-exc-code {
 93 |   display: inline-block;
 94 |   color: #bebebe;
 95 | }
 96 | 
 97 | .details-container {
 98 |   left: 30%;
 99 |   width: 70%;
100 |   background: #fafafa;
101 | }
102 |   .details {
103 |     padding: 5px;
104 |   }
105 | 
106 |     .details-heading {
107 |       color: #4288CE;
108 |       font-weight: 300;
109 |       padding-bottom: 10px;
110 |       margin-bottom: 10px;
111 |       border-bottom: 1px solid rgba(0, 0, 0, .1);
112 |     }
113 | 
114 |     .details pre.sf-dump {
115 |       white-space: pre;
116 |       word-wrap: inherit;
117 |     }
118 | 
119 |     .details pre.sf-dump,
120 |     .details pre.sf-dump .sf-dump-num,
121 |     .details pre.sf-dump .sf-dump-const,
122 |     .details pre.sf-dump .sf-dump-str,
123 |     .details pre.sf-dump .sf-dump-note,
124 |     .details pre.sf-dump .sf-dump-ref,
125 |     .details pre.sf-dump .sf-dump-public,
126 |     .details pre.sf-dump .sf-dump-protected,
127 |     .details pre.sf-dump .sf-dump-private,
128 |     .details pre.sf-dump .sf-dump-meta,
129 |     .details pre.sf-dump .sf-dump-key,
130 |     .details pre.sf-dump .sf-dump-index {
131 |       color: #463C54;
132 |     }
133 | 
134 | .left-panel {
135 |   width: 30%;
136 |   background: #ded8d8;
137 | }
138 | 
139 |   .frames-description {
140 |     background: rgba(0, 0, 0, .05);
141 |     padding: 8px 15px;
142 |     color: #a29d9d;
143 |     font-size: 11px;
144 |   }
145 | 
146 |   .frames-description.frames-description-application {
147 |     text-align: center;
148 |     font-size: 12px;
149 |   }
150 |   .frames-container.frames-container-application .frame:not(.frame-application) {
151 |     display: none;
152 |   }
153 | 
154 |   .frames-tab {
155 |     color: #a29d9d;
156 |     display: inline-block;
157 |     padding: 4px 8px;
158 |     margin: 0 2px;
159 |     border-radius: 3px;
160 |   }
161 | 
162 |   .frames-tab.frames-tab-active {
163 |     background-color: #2a2a2a;
164 |     color: #bebebe;
165 |   }
166 | 
167 |   .frame {
168 |     padding: 14px;
169 |     cursor: pointer;
170 |     transition: all 0.1s ease;
171 |     background: #eeeeee;
172 |   }
173 |     .frame:not(:last-child) {
174 |       border-bottom: 1px solid rgba(0, 0, 0, .05);
175 |     }
176 | 
177 |     .frame.active {
178 |       box-shadow: inset -5px 0 0 0 #4288CE;
179 |       color: #4288CE;
180 |     }
181 | 
182 |     .frame:not(.active):hover {
183 |       background: #BEE9EA;
184 |     }
185 | 
186 |     .frame-method-info {
187 |       margin-bottom: 10px;
188 |     }
189 | 
190 |     .frame-class, .frame-function, .frame-index {
191 |       font-size: 14px;
192 |     }
193 | 
194 |     .frame-index {
195 |       float: left;
196 |     }
197 | 
198 |     .frame-method-info {
199 |       margin-left: 24px;
200 |     }
201 | 
202 |     .frame-index {
203 |       font-size: 11px;
204 |       color: #a29d9d;
205 |       background-color: rgba(0, 0, 0, .05);
206 |       height: 18px;
207 |       width: 18px;
208 |       line-height: 18px;
209 |       border-radius: 5px;
210 |       padding: 0 1px 0 1px;
211 |       text-align: center;
212 |       display: inline-block;
213 |     }
214 | 
215 |     .frame-application .frame-index {
216 |       background-color: #2a2a2a;
217 |       color: #bebebe;
218 |     }
219 | 
220 |     .frame-file {
221 |       font-family: "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace;
222 |       color: #a29d9d;
223 |     }
224 | 
225 |       .frame-file .editor-link {
226 |         color: #a29d9d;
227 |       }
228 | 
229 |     .frame-line {
230 |       font-weight: bold;
231 |     }
232 | 
233 |     .frame-line:before {
234 |       content: ":";
235 |     }
236 | 
237 |     .frame-code {
238 |       padding: 5px;
239 |       background: #303030;
240 |       display: none;
241 |     }
242 | 
243 |     .frame-code.active {
244 |       display: block;
245 |     }
246 | 
247 |     .frame-code .frame-file {
248 |       color: #a29d9d;
249 |       padding: 12px 6px;
250 | 
251 |       border-bottom: none;
252 |     }
253 | 
254 |     .code-block {
255 |       padding: 10px;
256 |       margin: 0;
257 |       border-radius: 6px;
258 |       box-shadow: 0 3px 0 rgba(0, 0, 0, .05),
259 |                   0 10px 30px rgba(0, 0, 0, .05),
260 |                   inset 0 0 1px 0 rgba(255, 255, 255, .07);
261 |       -moz-tab-size: 4;
262 |       -o-tab-size: 4;
263 |       tab-size: 4;
264 |     }
265 | 
266 |     .linenums {
267 |       margin: 0;
268 |       margin-left: 10px;
269 |     }
270 | 
271 |     .frame-comments {
272 |       border-top: none;
273 |       margin-top: 15px;
274 | 
275 |       font-size: 12px;
276 |     }
277 | 
278 |     .frame-comments.empty {
279 |     }
280 | 
281 |     .frame-comments.empty:before {
282 |       content: "No comments for this stack frame.";
283 |       font-weight: 300;
284 |       color: #a29d9d;
285 |     }
286 | 
287 |     .frame-comment {
288 |       padding: 10px;
289 |       color: #e3e3e3;
290 |       border-radius: 6px;
291 |       background-color: rgba(255, 255, 255, .05);
292 |     }
293 | 
294 |     .frame-comment a {
295 |       font-weight: bold;
296 |       text-decoration: underline;
297 |       color: #c6c6c6;
298 |     }
299 | 
300 |     .frame-comment:not(:last-child) {
301 |       border-bottom: 1px dotted rgba(0, 0, 0, .3);
302 |     }
303 | 
304 |     .frame-comment-context {
305 |       font-size: 10px;
306 |       color: white;
307 |     }
308 | 
309 | .delimiter {
310 |   display: inline-block;
311 | }
312 | 
313 | .data-table-container label {
314 |   font-size: 16px;
315 |   color: #303030;
316 |   font-weight: bold;
317 |   margin: 10px 0;
318 | 
319 |   display: block;
320 | 
321 |   margin-bottom: 5px;
322 |   padding-bottom: 5px;
323 | }
324 |   .data-table {
325 |     width: 100%;
326 |     margin-bottom: 10px;
327 |   }
328 | 
329 |   .data-table tbody {
330 |     font: 13px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace;
331 |   }
332 | 
333 |   .data-table thead {
334 |     display: none;
335 |   }
336 | 
337 |   .data-table tr {
338 |     padding: 5px 0;
339 |   }
340 | 
341 |   .data-table td:first-child {
342 |     width: 20%;
343 |     min-width: 130px;
344 |     overflow: hidden;
345 |     font-weight: bold;
346 |     color: #463C54;
347 |     padding-right: 5px;
348 | 
349 |   }
350 | 
351 |   .data-table td:last-child {
352 |     width: 80%;
353 |     -ms-word-break: break-all;
354 |     word-break: break-all;
355 |     word-break: break-word;
356 |     -webkit-hyphens: auto;
357 |     -moz-hyphens: auto;
358 |     hyphens: auto;
359 |   }
360 | 
361 |   .data-table span.empty {
362 |     color: rgba(0, 0, 0, .3);
363 |     font-weight: 300;
364 |   }
365 |   .data-table label.empty {
366 |     display: inline;
367 |   }
368 | 
369 | .handler {
370 |   padding: 4px 0;
371 |   font: 14px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace;
372 | }
373 | 
374 | #plain-exception {
375 |   display: none;
376 | }
377 | 
378 | .rightButton {
379 |   cursor: pointer;
380 |   border: 0;
381 |   opacity: .8;
382 |   background: none;
383 | 
384 |   color: rgba(255, 255, 255, 0.1);
385 |   box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.1);
386 | 
387 |   border-radius: 3px;
388 | 
389 |   outline: none !important;
390 | }
391 | 
392 |   .rightButton:hover {
393 |     box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.3);
394 |     color: rgba(255, 255, 255, 0.3);
395 |   }
396 | 
397 | /* inspired by githubs kbd styles */
398 | kbd {
399 |   -moz-border-bottom-colors: none;
400 |   -moz-border-left-colors: none;
401 |   -moz-border-right-colors: none;
402 |   -moz-border-top-colors: none;
403 |   background-color: #fcfcfc;
404 |   border-color: #ccc #ccc #bbb;
405 |   border-image: none;
406 |   border-style: solid;
407 |   border-width: 1px;
408 |   color: #555;
409 |   display: inline-block;
410 |   font-size: 11px;
411 |   line-height: 10px;
412 |   padding: 3px 5px;
413 |   vertical-align: middle;
414 | }
415 | 
416 | 
417 | /* == Media queries */
418 | 
419 | /* Expand the spacing in the details section */
420 | @media (min-width: 1000px) {
421 |   .details, .frame-code {
422 |     padding: 20px 40px;
423 |   }
424 | 
425 |   .details-container {
426 |     left: 32%;
427 |     width: 68%;
428 |   }
429 | 
430 |   .frames-container {
431 |     margin: 5px;
432 |   }
433 | 
434 |   .left-panel {
435 |     width: 32%;
436 |   }
437 | }
438 | 
439 | /* Stack panels */
440 | @media (max-width: 600px) {
441 |   .panel {
442 |     position: static;
443 |     width: 100%;
444 |   }
445 | }
446 | 
447 | /* Stack details tables */
448 | @media (max-width: 400px) {
449 |   .data-table,
450 |   .data-table tbody,
451 |   .data-table tbody tr,
452 |   .data-table tbody td {
453 |     display: block;
454 |     width: 100%;
455 |   }
456 | 
457 |     .data-table tbody tr:first-child {
458 |       padding-top: 0;
459 |     }
460 | 
461 |       .data-table tbody td:first-child,
462 |       .data-table tbody td:last-child {
463 |         padding-left: 0;
464 |         padding-right: 0;
465 |       }
466 | 
467 |       .data-table tbody td:last-child {
468 |         padding-top: 3px;
469 |       }
470 | }
471 | 
472 | .tooltipped {
473 |   position: relative
474 | }
475 | .tooltipped:after {
476 |   position: absolute;
477 |   z-index: 1000000;
478 |   display: none;
479 |   padding: 5px 8px;
480 |   color: #fff;
481 |   text-align: center;
482 |   text-decoration: none;
483 |   text-shadow: none;
484 |   text-transform: none;
485 |   letter-spacing: normal;
486 |   word-wrap: break-word;
487 |   white-space: pre;
488 |   pointer-events: none;
489 |   content: attr(aria-label);
490 |   background: rgba(0, 0, 0, 0.8);
491 |   border-radius: 3px;
492 |   -webkit-font-smoothing: subpixel-antialiased
493 | }
494 | .tooltipped:before {
495 |   position: absolute;
496 |   z-index: 1000001;
497 |   display: none;
498 |   width: 0;
499 |   height: 0;
500 |   color: rgba(0, 0, 0, 0.8);
501 |   pointer-events: none;
502 |   content: "";
503 |   border: 5px solid transparent
504 | }
505 | .tooltipped:hover:before,
506 | .tooltipped:hover:after,
507 | .tooltipped:active:before,
508 | .tooltipped:active:after,
509 | .tooltipped:focus:before,
510 | .tooltipped:focus:after {
511 |   display: inline-block;
512 |   text-decoration: none
513 | }
514 | .tooltipped-s:after {
515 |   top: 100%;
516 |   right: 50%;
517 |   margin-top: 5px
518 | }
519 | .tooltipped-s:before {
520 |   top: auto;
521 |   right: 50%;
522 |   bottom: -5px;
523 |   margin-right: -5px;
524 |   border-bottom-color: rgba(0, 0, 0, 0.8)
525 | }
526 | 
527 | pre.sf-dump {
528 |   padding: 0px !important;
529 |   margin: 0px !important;
530 | }
531 | 
532 | .search-for-help {
533 |   width: 85%;
534 |   padding: 0;
535 |   margin: 10px 0;
536 |   list-style-type: none;
537 |   display: inline-block;
538 | }
539 |   .search-for-help li {
540 |     display: inline-block;
541 |     margin-right: 5px;
542 |   }
543 |   .search-for-help li:last-child {
544 |     margin-right: 0;
545 |   }
546 |     .search-for-help li a {
547 | 
548 |     }
549 |       .search-for-help li a i {
550 |         width: 16px;
551 |         height: 16px;
552 |         overflow: hidden;
553 |         display: block;
554 |       }
555 |       .search-for-help li a svg {
556 |         fill: #fff;
557 |       }
558 |       .search-for-help li a svg path {
559 |         background-size: contain;
560 |       }
561 | 
562 | .line-numbers-rows span {
563 |   pointer-events: auto;
564 |   cursor: pointer;
565 | }
566 | .line-numbers-rows span:hover {
567 |   text-decoration: underline;
568 | }
569 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/js/clipboard.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 |  * clipboard.js v2.0.11
3 |  * https://clipboardjs.com/
4 |  *
5 |  * Licensed MIT © Zeno Rocha
6 |  */
7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body},n="";return"string"==typeof t?n=o(t,e):t instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(null==t?void 0:t.type)?n=o(t.value,e):(n=r()(t),c("copy")),n};function l(t){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var s=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},e=t.action,n=void 0===e?"copy":e,o=t.container,e=t.target,t=t.text;if("copy"!==n&&"cut"!==n)throw new Error('Invalid "action" value, use either "copy" or "cut"');if(void 0!==e){if(!e||"object"!==l(e)||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===n&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===n&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes')}return t?f(t,{container:o}):e?"cut"===n?a(e):f(e,{container:o}):void 0};function p(t){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function d(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function y(t,e){return(y=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(n){var o=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}();return function(){var t,e=v(n);return t=o?(t=v(this).constructor,Reflect.construct(e,arguments,t)):e.apply(this,arguments),e=this,!(t=t)||"object"!==p(t)&&"function"!=typeof t?function(t){if(void 0!==t)return t;throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}(e):t}}function v(t){return(v=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function m(t,e){t="data-clipboard-".concat(t);if(e.hasAttribute(t))return e.getAttribute(t)}var b=function(){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&y(t,e)}(r,i());var t,e,n,o=h(r);function r(t,e){var n;return function(t){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}(this),(n=o.call(this)).resolveOptions(e),n.listenClick(t),n}return t=r,n=[{key:"copy",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body};return f(t,e)}},{key:"cut",value:function(t){return a(t)}},{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof t?[t]:t,e=!!document.queryCommandSupported;return t.forEach(function(t){e=e&&!!document.queryCommandSupported(t)}),e}}],(e=[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===p(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=u()(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget,n=this.action(e)||"copy",t=s({action:n,container:this.container,target:this.target(e),text:this.text(e)});this.emit(t?"success":"error",{action:n,text:t,trigger:e,clearSelection:function(){e&&e.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(t){return m("action",t)}},{key:"defaultTarget",value:function(t){t=m("target",t);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(t){return m("text",t)}},{key:"destroy",value:function(){this.listener.destroy()}}])&&d(t.prototype,e),n&&d(t,n),r}()},828:function(t){var e;"undefined"==typeof Element||Element.prototype.matches||((e=Element.prototype).matches=e.matchesSelector||e.mozMatchesSelector||e.msMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector),t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}},438:function(t,e,n){var u=n(828);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=u(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},879:function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},370:function(t,e,n){var f=n(879),l=n(438);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!f.string(e))throw new TypeError("Second argument must be a String");if(!f.fn(n))throw new TypeError("Third argument must be a Function");if(f.node(t))return c=e,a=n,(u=t).addEventListener(c,a),{destroy:function(){u.removeEventListener(c,a)}};if(f.nodeList(t))return o=t,r=e,i=n,Array.prototype.forEach.call(o,function(t){t.addEventListener(r,i)}),{destroy:function(){Array.prototype.forEach.call(o,function(t){t.removeEventListener(r,i)})}};if(f.string(t))return t=t,e=e,n=n,l(document.body,t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,u,c,a}},817:function(t){t.exports=function(t){var e,n="SELECT"===t.nodeName?(t.focus(),t.value):"INPUT"===t.nodeName||"TEXTAREA"===t.nodeName?((e=t.hasAttribute("readonly"))||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),e||t.removeAttribute("readonly"),t.value):(t.hasAttribute("contenteditable")&&t.focus(),n=window.getSelection(),(e=document.createRange()).selectNodeContents(t),n.removeAllRanges(),n.addRange(e),n.toString());return n}},279:function(t){function e(){}e.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,u=o.length;i<u;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=e,t.exports.TinyEmitter=e}},r={},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,{a:e}),e},o.d=function(t,e){for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o(686).default;function o(t){if(r[t])return r[t].exports;var e=r[t]={exports:{}};return n[t](e,e.exports,o),e.exports}var n,r});


--------------------------------------------------------------------------------
/src/Whoops/Resources/js/prism.js:
--------------------------------------------------------------------------------
1 | /* PrismJS 1.30.0
2 | https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */
3 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(n,t){var r,i;switch(t=t||{},a.util.type(n)){case"Object":if(i=a.util.objId(n),t[i])return t[i];for(var l in r={},t[i]=r,n)n.hasOwnProperty(l)&&(r[l]=e(n[l],t));return r;case"Array":return i=a.util.objId(n),t[i]?t[i]:(r=[],t[i]=r,n.forEach((function(n,a){r[a]=e(n,t)})),r);default:return n}},getLanguage:function(e){for(;e;){var t=n.exec(e.className);if(t)return t[1].toLowerCase();e=e.parentElement}return"none"},setLanguage:function(e,t){e.className=e.className.replace(RegExp(n,"gi"),""),e.classList.add("language-"+t)},currentScript:function(){if("undefined"==typeof document)return null;if(document.currentScript&&"SCRIPT"===document.currentScript.tagName)return document.currentScript;try{throw new Error}catch(r){var e=(/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(r.stack)||[])[1];if(e){var n=document.getElementsByTagName("script");for(var t in n)if(n[t].src==e)return n[t]}return null}},isActive:function(e,n,t){for(var r="no-"+n;e;){var a=e.classList;if(a.contains(n))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!t}},languages:{plain:r,plaintext:r,text:r,txt:r,extend:function(e,n){var t=a.util.clone(a.languages[e]);for(var r in n)t[r]=n[r];return t},insertBefore:function(e,n,t,r){var i=(r=r||a.languages)[e],l={};for(var o in i)if(i.hasOwnProperty(o)){if(o==n)for(var s in t)t.hasOwnProperty(s)&&(l[s]=t[s]);t.hasOwnProperty(o)||(l[o]=i[o])}var u=r[e];return r[e]=l,a.languages.DFS(a.languages,(function(n,t){t===u&&n!=e&&(this[n]=l)})),l},DFS:function e(n,t,r,i){i=i||{};var l=a.util.objId;for(var o in n)if(n.hasOwnProperty(o)){t.call(n,o,n[o],r||o);var s=n[o],u=a.util.type(s);"Object"!==u||i[l(s)]?"Array"!==u||i[l(s)]||(i[l(s)]=!0,e(s,t,o,i)):(i[l(s)]=!0,e(s,t,null,i))}}},plugins:{},highlightAll:function(e,n){a.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,t){var r={callback:t,container:e,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};a.hooks.run("before-highlightall",r),r.elements=Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)),a.hooks.run("before-all-elements-highlight",r);for(var i,l=0;i=r.elements[l++];)a.highlightElement(i,!0===n,r.callback)},highlightElement:function(n,t,r){var i=a.util.getLanguage(n),l=a.languages[i];a.util.setLanguage(n,i);var o=n.parentElement;o&&"pre"===o.nodeName.toLowerCase()&&a.util.setLanguage(o,i);var s={element:n,language:i,grammar:l,code:n.textContent};function u(e){s.highlightedCode=e,a.hooks.run("before-insert",s),s.element.innerHTML=s.highlightedCode,a.hooks.run("after-highlight",s),a.hooks.run("complete",s),r&&r.call(s.element)}if(a.hooks.run("before-sanity-check",s),(o=s.element.parentElement)&&"pre"===o.nodeName.toLowerCase()&&!o.hasAttribute("tabindex")&&o.setAttribute("tabindex","0"),!s.code)return a.hooks.run("complete",s),void(r&&r.call(s.element));if(a.hooks.run("before-highlight",s),s.grammar)if(t&&e.Worker){var c=new Worker(a.filename);c.onmessage=function(e){u(e.data)},c.postMessage(JSON.stringify({language:s.language,code:s.code,immediateClose:!0}))}else u(a.highlight(s.code,s.grammar,s.language));else u(a.util.encode(s.code))},highlight:function(e,n,t){var r={code:e,grammar:n,language:t};if(a.hooks.run("before-tokenize",r),!r.grammar)throw new Error('The language "'+r.language+'" has no grammar.');return r.tokens=a.tokenize(r.code,r.grammar),a.hooks.run("after-tokenize",r),i.stringify(a.util.encode(r.tokens),r.language)},tokenize:function(e,n){var t=n.rest;if(t){for(var r in t)n[r]=t[r];delete n.rest}var a=new s;return u(a,a.head,e),o(e,a,n,a.head,0),function(e){for(var n=[],t=e.head.next;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=a.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=a.hooks.all[e];if(t&&t.length)for(var r,i=0;r=t[i++];)r(n)}},Token:i};function i(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||"").length}function l(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function o(e,n,t,r,s,g){for(var f in t)if(t.hasOwnProperty(f)&&t[f]){var h=t[f];h=Array.isArray(h)?h:[h];for(var d=0;d<h.length;++d){if(g&&g.cause==f+","+d)return;var v=h[d],p=v.inside,m=!!v.lookbehind,y=!!v.greedy,k=v.alias;if(y&&!v.pattern.global){var x=v.pattern.toString().match(/[imsuy]*$/)[0];v.pattern=RegExp(v.pattern.source,x+"g")}for(var b=v.pattern||v,w=r.next,A=s;w!==n.tail&&!(g&&A>=g.reach);A+=w.value.length,w=w.next){var P=w.value;if(n.length>e.length)return;if(!(P instanceof i)){var E,S=1;if(y){if(!(E=l(b,A,e,m))||E.index>=e.length)break;var L=E.index,O=E.index+E[0].length,C=A;for(C+=w.value.length;L>=C;)C+=(w=w.next).value.length;if(A=C-=w.value.length,w.value instanceof i)continue;for(var j=w;j!==n.tail&&(C<O||"string"==typeof j.value);j=j.next)S++,C+=j.value.length;S--,P=e.slice(A,C),E.index-=A}else if(!(E=l(b,0,P,m)))continue;L=E.index;var N=E[0],_=P.slice(0,L),M=P.slice(L+N.length),W=A+P.length;g&&W>g.reach&&(g.reach=W);var I=w.prev;if(_&&(I=u(n,I,_),A+=_.length),c(n,I,S),w=u(n,I,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),S>1){var T={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,T),g&&T.reach>g.reach&&(g.reach=T.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;n.next=r,r.prev=n,e.length-=a}if(e.Prism=a,i.stringify=function e(n,t){if("string"==typeof n)return n;if(Array.isArray(n)){var r="";return n.forEach((function(n){r+=e(n,t)})),r}var i={type:n.type,content:e(n.content,t),tag:"span",classes:["token",n.type],attributes:{},language:t},l=n.alias;l&&(Array.isArray(l)?Array.prototype.push.apply(i.classes,l):i.classes.push(l)),a.hooks.run("wrap",i);var o="";for(var s in i.attributes)o+=" "+s+'="'+(i.attributes[s]||"").replace(/"/g,"&quot;")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+o+">"+i.content+"</"+i.tag+">"},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
4 | Prism.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=
lt;%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",(function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,"&"))})),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^<!\[CDATA\[|\]\]>$/i;var t={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:s}};t["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp("(<__[^>]*>)(?:<!\\[CDATA\\[(?:[^\\]]|\\](?!\\]>))*\\]\\]>|(?!<!\\[CDATA\\[)[^])*?(?=</__>)".replace(/__/g,(function(){return a})),"i"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(a,e){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+a+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[e,"language-"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml;
5 | !function(e){function n(e,n){return"___"+e.toUpperCase()+n+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(t,a,r,o){if(t.language===a){var c=t.tokenStack=[];t.code=t.code.replace(r,(function(e){if("function"==typeof o&&!o(e))return e;for(var r,i=c.length;-1!==t.code.indexOf(r=n(a,i));)++i;return c[i]=e,r})),t.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(t,a){if(t.language===a&&t.tokenStack){t.grammar=e.languages[a];var r=0,o=Object.keys(t.tokenStack);!function c(i){for(var u=0;u<i.length&&!(r>=o.length);u++){var g=i[u];if("string"==typeof g||g.content&&"string"==typeof g.content){var l=o[r],s=t.tokenStack[l],f="string"==typeof g?g:g.content,p=n(a,l),k=f.indexOf(p);if(k>-1){++r;var m=f.substring(0,k),d=new e.Token(a,e.tokenize(s,t.grammar),"language-"+a,s),h=f.substring(k+p.length),v=[];m&&v.push.apply(v,c([m])),v.push(d),h&&v.push.apply(v,c([h])),"string"==typeof g?i.splice.apply(i,[u,1].concat(v)):g.content=v}}else g.content&&c(g.content)}return i}(t.tokens)}}}})}(Prism);
6 | !function(e){var a=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,t=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],i=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,n=/<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,s=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:a,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:t,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:i,operator:n,punctuation:s};var l={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},r=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:l}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:l}}];e.languages.insertBefore("php","variable",{string:r,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:a,string:r,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:t,number:i,operator:n,punctuation:s}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(a){/<\?/.test(a.code)&&e.languages["markup-templating"].buildPlaceholders(a,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)})),e.hooks.add("after-tokenize",(function(a){e.languages["markup-templating"].tokenizePlaceholders(a,"php")}))}(Prism);
7 | !function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document&&document.querySelector){var e,t="line-numbers",i="linkable-line-numbers",n=/\n(?!$)/g,r=!0;Prism.plugins.lineHighlight={highlightLines:function(o,u,c){var h=(u="string"==typeof u?u:o.getAttribute("data-line")||"").replace(/\s+/g,"").split(",").filter(Boolean),d=+o.getAttribute("data-line-offset")||0,f=(function(){if(void 0===e){var t=document.createElement("div");t.style.fontSize="13px",t.style.lineHeight="1.5",t.style.padding="0",t.style.border="0",t.innerHTML="&nbsp;<br />&nbsp;",document.body.appendChild(t),e=38===t.offsetHeight,document.body.removeChild(t)}return e}()?parseInt:parseFloat)(getComputedStyle(o).lineHeight),p=Prism.util.isActive(o,t),g=o.querySelector("code"),m=p?o:g||o,v=[],y=g.textContent.match(n),b=y?y.length+1:1,A=g&&m!=g?function(e,t){var i=getComputedStyle(e),n=getComputedStyle(t);function r(e){return+e.substr(0,e.length-2)}return t.offsetTop+r(n.borderTopWidth)+r(n.paddingTop)-r(i.paddingTop)}(o,g):0;h.forEach((function(e){var t=e.split("-"),i=+t[0],n=+t[1]||i;if(!((n=Math.min(b+d,n))<i)){var r=o.querySelector('.line-highlight[data-range="'+e+'"]')||document.createElement("div");if(v.push((function(){r.setAttribute("aria-hidden","true"),r.setAttribute("data-range",e),r.className=(c||"")+" line-highlight"})),p&&Prism.plugins.lineNumbers){var s=Prism.plugins.lineNumbers.getLine(o,i),l=Prism.plugins.lineNumbers.getLine(o,n);if(s){var a=s.offsetTop+A+"px";v.push((function(){r.style.top=a}))}if(l){var u=l.offsetTop-s.offsetTop+l.offsetHeight+"px";v.push((function(){r.style.height=u}))}}else v.push((function(){r.setAttribute("data-start",String(i)),n>i&&r.setAttribute("data-end",String(n)),r.style.top=(i-d-1)*f+A+"px",r.textContent=new Array(n-i+2).join(" \n")}));v.push((function(){r.style.width=o.scrollWidth+"px"})),v.push((function(){m.appendChild(r)}))}}));var P=o.id;if(p&&Prism.util.isActive(o,i)&&P){l(o,i)||v.push((function(){o.classList.add(i)}));var E=parseInt(o.getAttribute("data-start")||"1");s(".line-numbers-rows > span",o).forEach((function(e,t){var i=t+E;e.onclick=function(){var e=P+"."+i;r=!1,location.hash=e,setTimeout((function(){r=!0}),1)}}))}return function(){v.forEach(a)}}};var o=0;Prism.hooks.add("before-sanity-check",(function(e){var t=e.element.parentElement;if(u(t)){var i=0;s(".line-highlight",t).forEach((function(e){i+=e.textContent.length,e.parentNode.removeChild(e)})),i&&/^(?: \n)+$/.test(e.code.slice(-i))&&(e.code=e.code.slice(0,-i))}})),Prism.hooks.add("complete",(function e(i){var n=i.element.parentElement;if(u(n)){clearTimeout(o);var r=Prism.plugins.lineNumbers,s=i.plugins&&i.plugins.lineNumbers;l(n,t)&&r&&!s?Prism.hooks.add("line-numbers",e):(Prism.plugins.lineHighlight.highlightLines(n)(),o=setTimeout(c,1))}})),window.addEventListener("hashchange",c),window.addEventListener("resize",(function(){s("pre").filter(u).map((function(e){return Prism.plugins.lineHighlight.highlightLines(e)})).forEach(a)}))}function s(e,t){return Array.prototype.slice.call((t||document).querySelectorAll(e))}function l(e,t){return e.classList.contains(t)}function a(e){e()}function u(e){return!!(e&&/pre/i.test(e.nodeName)&&(e.hasAttribute("data-line")||e.id&&Prism.util.isActive(e,i)))}function c(){var e=location.hash.slice(1);s(".temporary.line-highlight").forEach((function(e){e.parentNode.removeChild(e)}));var t=(e.match(/\.([\d,-]+)$/)||[,""])[1];if(t&&!document.getElementById(e)){var i=e.slice(0,e.lastIndexOf(".")),n=document.getElementById(i);n&&(n.hasAttribute("data-line")||n.setAttribute("data-line",""),Prism.plugins.lineHighlight.highlightLines(n,t,"temporary ")(),r&&document.querySelector(".temporary.line-highlight").scrollIntoView())}}}();
8 | !function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document){var e="line-numbers",n=/\n(?!$)/g,t=Prism.plugins.lineNumbers={getLine:function(n,t){if("PRE"===n.tagName&&n.classList.contains(e)){var i=n.querySelector(".line-numbers-rows");if(i){var r=parseInt(n.getAttribute("data-start"),10)||1,s=r+(i.children.length-1);t<r&&(t=r),t>s&&(t=s);var l=t-r;return i.children[l]}}},resize:function(e){r([e])},assumeViewportIndependence:!0},i=void 0;window.addEventListener("resize",(function(){t.assumeViewportIndependence&&i===window.innerWidth||(i=window.innerWidth,r(Array.prototype.slice.call(document.querySelectorAll("pre.line-numbers"))))})),Prism.hooks.add("complete",(function(t){if(t.code){var i=t.element,s=i.parentNode;if(s&&/pre/i.test(s.nodeName)&&!i.querySelector(".line-numbers-rows")&&Prism.util.isActive(i,e)){i.classList.remove(e),s.classList.add(e);var l,o=t.code.match(n),a=o?o.length+1:1,u=new Array(a+1).join("<span></span>");(l=document.createElement("span")).setAttribute("aria-hidden","true"),l.className="line-numbers-rows",l.innerHTML=u,s.hasAttribute("data-start")&&(s.style.counterReset="linenumber "+(parseInt(s.getAttribute("data-start"),10)-1)),t.element.appendChild(l),r([s]),Prism.hooks.run("line-numbers",t)}}})),Prism.hooks.add("line-numbers",(function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0}))}function r(e){if(0!=(e=e.filter((function(e){var n,t=(n=e,n?window.getComputedStyle?getComputedStyle(n):n.currentStyle||null:null)["white-space"];return"pre-wrap"===t||"pre-line"===t}))).length){var t=e.map((function(e){var t=e.querySelector("code"),i=e.querySelector(".line-numbers-rows");if(t&&i){var r=e.querySelector(".line-numbers-sizer"),s=t.textContent.split(n);r||((r=document.createElement("span")).className="line-numbers-sizer",t.appendChild(r)),r.innerHTML="0",r.style.display="block";var l=r.getBoundingClientRect().height;return r.innerHTML="",{element:e,lines:s,lineHeights:[],oneLinerHeight:l,sizer:r}}})).filter(Boolean);t.forEach((function(e){var n=e.sizer,t=e.lines,i=e.lineHeights,r=e.oneLinerHeight;i[t.length-1]=void 0,t.forEach((function(e,t){if(e&&e.length>1){var s=n.appendChild(document.createElement("span"));s.style.display="block",s.textContent=e}else i[t]=r}))})),t.forEach((function(e){for(var n=e.sizer,t=e.lineHeights,i=0,r=0;r<t.length;r++)void 0===t[r]&&(t[r]=n.children[i++].getBoundingClientRect().height)})),t.forEach((function(e){var n=e.sizer,t=e.element.querySelector(".line-numbers-rows");n.style.display="none",n.innerHTML="",e.lineHeights.forEach((function(e,n){t.children[n].style.height=e+"px"}))}))}}}();
9 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/js/whoops.base.js:
--------------------------------------------------------------------------------
  1 | Zepto(function($) {
  2 |   var $leftPanel      = $('.left-panel');
  3 |   var $frameContainer = $('.frames-container');
  4 |   var $appFramesTab   = $('#application-frames-tab');
  5 |   var $allFramesTab   = $('#all-frames-tab');
  6 |   var $container      = $('.details-container');
  7 |   var $activeLine     = $frameContainer.find('.frame.active');
  8 |   var $activeFrame    = $container.find('.frame-code.active');
  9 |   var $ajaxEditors    = $('.editor-link[data-ajax]');
 10 |   var $header         = $('header');
 11 | 
 12 |   $header.on('mouseenter', function () {
 13 |     if ($header.find('.exception').height() >= 145) {
 14 |       $header.addClass('header-expand');
 15 |     }
 16 |   });
 17 |   $header.on('mouseleave', function () {
 18 |     $header.removeClass('header-expand');
 19 |   });
 20 | 
 21 |   /*
 22 |    * add prettyprint classes to our current active codeblock
 23 |    * run prettyPrint() to highlight the active code
 24 |    * scroll to the line when prettyprint is done
 25 |    * highlight the current line
 26 |    */
 27 |   var renderCurrentCodeblock = function(id) {
 28 |     Prism.highlightAllUnder(document.querySelector('.frame-code-container .frame-code.active'));
 29 |     highlightCurrentLine();
 30 |   }
 31 | 
 32 |   /*
 33 |    * Highlight the active and neighboring lines for the current frame
 34 |    * Adjust the offset to make sure that line is veritcally centered
 35 |    */
 36 | 
 37 |   var highlightCurrentLine = function() {
 38 |     // We show more code than needed, purely for proper syntax highlighting
 39 |     // Let’s hide a big chunk of that code and then scroll the remaining block
 40 |     $activeFrame.find('.code-block').first().css({
 41 |       maxHeight: 345,
 42 |       overflow: 'hidden',
 43 |     });
 44 | 
 45 |     var line = $activeFrame.find('.code-block .line-highlight').first()[0];
 46 |     // [internal] frames might not contain a code-block
 47 |     if (line) {
 48 |       line.scrollIntoView();
 49 |       line.parentElement.scrollTop -= 180;
 50 |     }
 51 | 
 52 |     $container.scrollTop(0);
 53 |   }
 54 | 
 55 |   /*
 56 |    * click handler for loading codeblocks
 57 |    */
 58 | 
 59 |   $frameContainer.on('click', '.frame', function() {
 60 | 
 61 |     var $this  = $(this);
 62 |     var id     = /frame\-line\-([\d]*)/.exec($this.attr('id'))[1];
 63 |     var $codeFrame = $('#frame-code-' + id);
 64 | 
 65 |     if ($codeFrame) {
 66 | 
 67 |       $activeLine.removeClass('active');
 68 |       $activeFrame.removeClass('active');
 69 | 
 70 |       $this.addClass('active');
 71 |       $codeFrame.addClass('active');
 72 | 
 73 |       $activeLine  = $this;
 74 |       $activeFrame = $codeFrame;
 75 | 
 76 |       renderCurrentCodeblock(id);
 77 | 
 78 |     }
 79 | 
 80 |   });
 81 | 
 82 |   var clipboard = new ClipboardJS('.clipboard');
 83 |   var showTooltip = function(elem, msg) {
 84 |     elem.classList.add('tooltipped', 'tooltipped-s');
 85 |     elem.setAttribute('aria-label', msg);
 86 |   };
 87 | 
 88 |   clipboard.on('success', function(e) {
 89 |       e.clearSelection();
 90 | 
 91 |       showTooltip(e.trigger, 'Copied!');
 92 |   });
 93 | 
 94 |   clipboard.on('error', function(e) {
 95 |       showTooltip(e.trigger, fallbackMessage(e.action));
 96 |   });
 97 | 
 98 |   var btn = document.querySelector('.clipboard');
 99 | 
100 |   btn.addEventListener('mouseleave', function(e) {
101 |     e.currentTarget.classList.remove('tooltipped', 'tooltipped-s');
102 |     e.currentTarget.removeAttribute('aria-label');
103 |   });
104 | 
105 |   function fallbackMessage(action) {
106 |     var actionMsg = '';
107 |     var actionKey = (action === 'cut' ? 'X' : 'C');
108 | 
109 |     if (/Mac/i.test(navigator.userAgent)) {
110 |         actionMsg = 'Press ⌘-' + actionKey + ' to ' + action;
111 |     } else {
112 |         actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action;
113 |     }
114 | 
115 |     return actionMsg;
116 |   }
117 | 
118 |   function scrollIntoView($node, $parent) {
119 |     var nodeOffset = $node.offset();
120 |     var nodeTop = nodeOffset.top;
121 |     var nodeBottom = nodeTop + nodeOffset.height;
122 |     var parentScrollTop = $parent.scrollTop();
123 |     var parentHeight = $parent.height();
124 | 
125 |     if (nodeTop < 0) {
126 |       $parent.scrollTop(parentScrollTop + nodeTop);
127 |     } else if (nodeBottom > parentHeight) {
128 |       $parent.scrollTop(parentScrollTop + nodeBottom - parentHeight);
129 |     }
130 |   }
131 | 
132 |   $(document).on('keydown', function(e) {
133 |     var applicationFrames = $frameContainer.hasClass('frames-container-application'),
134 |         frameClass = applicationFrames ? '.frame.frame-application' : '.frame';
135 | 
136 | 	  if(e.ctrlKey || e.which === 74  || e.which === 75) {
137 | 		  // CTRL+Arrow-UP/k and Arrow-Down/j support:
138 | 		  // 1) select the next/prev element
139 | 		  // 2) make sure the newly selected element is within the view-scope
140 | 		  // 3) focus the (right) container, so arrow-up/down (without ctrl) scroll the details
141 | 		  if (e.which === 38 /* arrow up */ || e.which === 75 /* k */) {
142 | 			  $activeLine.prev(frameClass).click();
143 | 			  scrollIntoView($activeLine, $leftPanel);
144 | 			  $container.focus();
145 | 			  e.preventDefault();
146 | 		  } else if (e.which === 40 /* arrow down */ || e.which === 74 /* j */) {
147 | 			  $activeLine.next(frameClass).click();
148 | 			  scrollIntoView($activeLine, $leftPanel);
149 | 			  $container.focus();
150 | 			  e.preventDefault();
151 | 		  }
152 | 	  } else if (e.which == 78 /* n */) {
153 |       if ($appFramesTab.length) {
154 |         setActiveFramesTab($('.frames-tab:not(.frames-tab-active)'));
155 |       }
156 |     }
157 |   });
158 | 
159 |   // Avoid to quit the page with some protocol (e.g. IntelliJ Platform REST API)
160 |   $ajaxEditors.on('click', function(e){
161 |     e.preventDefault();
162 |     $.get(this.href);
163 |   });
164 | 
165 |   // Symfony VarDumper: Close the by default expanded objects
166 |   $('.sf-dump-expanded')
167 |     .removeClass('sf-dump-expanded')
168 |     .addClass('sf-dump-compact');
169 |   $('.sf-dump-toggle span').html('&#9654;');
170 | 
171 |   // Make the given frames-tab active
172 |   function setActiveFramesTab($tab) {
173 |     $tab.addClass('frames-tab-active');
174 | 
175 |     if ($tab.attr('id') == 'application-frames-tab') {
176 |       $frameContainer.addClass('frames-container-application');
177 |       $allFramesTab.removeClass('frames-tab-active');
178 |     } else {
179 |       $frameContainer.removeClass('frames-container-application');
180 |       $appFramesTab.removeClass('frames-tab-active');
181 |     }
182 |   }
183 | 
184 |   $('a.frames-tab').on('click', function(e) {
185 |     e.preventDefault();
186 |     setActiveFramesTab($(this));
187 |   });
188 | 
189 |     // Open editor from code block rows number
190 |   $(document).delegate('.line-numbers-rows > span', 'click', function(e) {
191 |     var linkTag = $(this).closest('.frame-code').find('.editor-link');
192 |     if (!linkTag) return;
193 |     var editorUrl = linkTag.attr('href');
194 |     var requiresAjax = linkTag.data('ajax');
195 | 
196 |     var lineOffset = $(this).closest('[data-line-offset]').data('line-offset');
197 |     var lineNumber = lineOffset + $(this).index();
198 | 
199 |     var realLine = $(this).closest('[data-line]').data('line');
200 |     if (!realLine) return;
201 |     var fileUrl = editorUrl.replace(
202 |       new RegExp('([:=])' + realLine),
203 |       '$1' + lineNumber
204 |     );
205 | 
206 |     if (requiresAjax) {
207 |       $.get(fileUrl);
208 |     } else {
209 |       $('<a>').attr('href', fileUrl).trigger('click');
210 |     }
211 |   });
212 | 
213 |   // Render late enough for highlightCurrentLine to be ready
214 |   renderCurrentCodeblock();
215 | });
216 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/js/zepto.min.js:
--------------------------------------------------------------------------------
1 | /* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */
2 | !function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t)}):e(t)}(this,function(t){var e=function(){function $(t){return null==t?String(t):S[C.call(t)]||"object"}function F(t){return"function"==$(t)}function k(t){return null!=t&&t==t.window}function M(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function R(t){return"object"==$(t)}function Z(t){return R(t)&&!k(t)&&Object.getPrototypeOf(t)==Object.prototype}function z(t){var e=!!t&&"length"in t&&t.length,n=r.type(t);return"function"!=n&&!k(t)&&("array"==n||0===e||"number"==typeof e&&e>0&&e-1 in t)}function q(t){return a.call(t,function(t){return null!=t})}function H(t){return t.length>0?r.fn.concat.apply([],t):t}function I(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function V(t){return t in l?l[t]:l[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function _(t,e){return"number"!=typeof e||h[I(t)]?e:e+"px"}function B(t){var e,n;return c[t]||(e=f.createElement(t),f.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),c[t]=n),c[t]}function U(t){return"children"in t?u.call(t.children):r.map(t.childNodes,function(t){return 1==t.nodeType?t:void 0})}function X(t,e){var n,r=t?t.length:0;for(n=0;r>n;n++)this[n]=t[n];this.length=r,this.selector=e||""}function J(t,r,i){for(n in r)i&&(Z(r[n])||L(r[n]))?(Z(r[n])&&!Z(t[n])&&(t[n]={}),L(r[n])&&!L(t[n])&&(t[n]=[]),J(t[n],r[n],i)):r[n]!==e&&(t[n]=r[n])}function W(t,e){return null==e?r(t):r(t).filter(e)}function Y(t,e,n,r){return F(e)?e.call(t,n,r):e}function G(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function K(t,n){var r=t.className||"",i=r&&r.baseVal!==e;return n===e?i?r.baseVal:r:void(i?r.baseVal=n:t.className=n)}function Q(t){try{return t?"true"==t||("false"==t?!1:"null"==t?null:+t+""==t?+t:/^[\[\{]/.test(t)?r.parseJSON(t):t):t}catch(e){return t}}function tt(t,e){e(t);for(var n=0,r=t.childNodes.length;r>n;n++)tt(t.childNodes[n],e)}var e,n,r,i,O,P,o=[],s=o.concat,a=o.filter,u=o.slice,f=t.document,c={},l={},h={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},p=/^\s*<(\w+|!)[^>]*>/,d=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,m=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,g=/^(?:body|html)$/i,v=/([A-Z])/g,y=["val","css","html","text","data","width","height","offset"],x=["after","prepend","before","append"],b=f.createElement("table"),E=f.createElement("tr"),j={tr:f.createElement("tbody"),tbody:b,thead:b,tfoot:b,td:E,th:E,"*":f.createElement("div")},w=/complete|loaded|interactive/,T=/^[\w-]*$/,S={},C=S.toString,N={},A=f.createElement("div"),D={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},L=Array.isArray||function(t){return t instanceof Array};return N.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var r,i=t.parentNode,o=!i;return o&&(i=A).appendChild(t),r=~N.qsa(i,e).indexOf(t),o&&A.removeChild(t),r},O=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},P=function(t){return a.call(t,function(e,n){return t.indexOf(e)==n})},N.fragment=function(t,n,i){var o,s,a;return d.test(t)&&(o=r(f.createElement(RegExp.$1))),o||(t.replace&&(t=t.replace(m,"<$1></$2>")),n===e&&(n=p.test(t)&&RegExp.$1),n in j||(n="*"),a=j[n],a.innerHTML=""+t,o=r.each(u.call(a.childNodes),function(){a.removeChild(this)})),Z(i)&&(s=r(o),r.each(i,function(t,e){y.indexOf(t)>-1?s[t](e):s.attr(t,e)})),o},N.Z=function(t,e){return new X(t,e)},N.isZ=function(t){return t instanceof N.Z},N.init=function(t,n){var i;if(!t)return N.Z();if("string"==typeof t)if(t=t.trim(),"<"==t[0]&&p.test(t))i=N.fragment(t,RegExp.$1,n),t=null;else{if(n!==e)return r(n).find(t);i=N.qsa(f,t)}else{if(F(t))return r(f).ready(t);if(N.isZ(t))return t;if(L(t))i=q(t);else if(R(t))i=[t],t=null;else if(p.test(t))i=N.fragment(t.trim(),RegExp.$1,n),t=null;else{if(n!==e)return r(n).find(t);i=N.qsa(f,t)}}return N.Z(i,t)},r=function(t,e){return N.init(t,e)},r.extend=function(t){var e,n=u.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){J(t,n,e)}),t},N.qsa=function(t,e){var n,r="#"==e[0],i=!r&&"."==e[0],o=r||i?e.slice(1):e,s=T.test(o);return t.getElementById&&s&&r?(n=t.getElementById(o))?[n]:[]:1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType?[]:u.call(s&&!r&&t.getElementsByClassName?i?t.getElementsByClassName(o):t.getElementsByTagName(e):t.querySelectorAll(e))},r.contains=f.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},r.type=$,r.isFunction=F,r.isWindow=k,r.isArray=L,r.isPlainObject=Z,r.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},r.isNumeric=function(t){var e=Number(t),n=typeof t;return null!=t&&"boolean"!=n&&("string"!=n||t.length)&&!isNaN(e)&&isFinite(e)||!1},r.inArray=function(t,e,n){return o.indexOf.call(e,t,n)},r.camelCase=O,r.trim=function(t){return null==t?"":String.prototype.trim.call(t)},r.uuid=0,r.support={},r.expr={},r.noop=function(){},r.map=function(t,e){var n,i,o,r=[];if(z(t))for(i=0;i<t.length;i++)n=e(t[i],i),null!=n&&r.push(n);else for(o in t)n=e(t[o],o),null!=n&&r.push(n);return H(r)},r.each=function(t,e){var n,r;if(z(t)){for(n=0;n<t.length;n++)if(e.call(t[n],n,t[n])===!1)return t}else for(r in t)if(e.call(t[r],r,t[r])===!1)return t;return t},r.grep=function(t,e){return a.call(t,e)},t.JSON&&(r.parseJSON=JSON.parse),r.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(t,e){S["[object "+e+"]"]=e.toLowerCase()}),r.fn={constructor:N.Z,length:0,forEach:o.forEach,reduce:o.reduce,push:o.push,sort:o.sort,splice:o.splice,indexOf:o.indexOf,concat:function(){var t,e,n=[];for(t=0;t<arguments.length;t++)e=arguments[t],n[t]=N.isZ(e)?e.toArray():e;return s.apply(N.isZ(this)?this.toArray():this,n)},map:function(t){return r(r.map(this,function(e,n){return t.call(e,n,e)}))},slice:function(){return r(u.apply(this,arguments))},ready:function(t){return w.test(f.readyState)&&f.body?t(r):f.addEventListener("DOMContentLoaded",function(){t(r)},!1),this},get:function(t){return t===e?u.call(this):this[t>=0?t:t+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return o.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return F(t)?this.not(this.not(t)):r(a.call(this,function(e){return N.matches(e,t)}))},add:function(t,e){return r(P(this.concat(r(t,e))))},is:function(t){return this.length>0&&N.matches(this[0],t)},not:function(t){var n=[];if(F(t)&&t.call!==e)this.each(function(e){t.call(this,e)||n.push(this)});else{var i="string"==typeof t?this.filter(t):z(t)&&F(t.item)?u.call(t):r(t);this.forEach(function(t){i.indexOf(t)<0&&n.push(t)})}return r(n)},has:function(t){return this.filter(function(){return R(t)?r.contains(this,t):r(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!R(t)?t:r(t)},last:function(){var t=this[this.length-1];return t&&!R(t)?t:r(t)},find:function(t){var e,n=this;return e=t?"object"==typeof t?r(t).filter(function(){var t=this;return o.some.call(n,function(e){return r.contains(e,t)})}):1==this.length?r(N.qsa(this[0],t)):this.map(function(){return N.qsa(this,t)}):r()},closest:function(t,e){var n=[],i="object"==typeof t&&r(t);return this.each(function(r,o){for(;o&&!(i?i.indexOf(o)>=0:N.matches(o,t));)o=o!==e&&!M(o)&&o.parentNode;o&&n.indexOf(o)<0&&n.push(o)}),r(n)},parents:function(t){for(var e=[],n=this;n.length>0;)n=r.map(n,function(t){return(t=t.parentNode)&&!M(t)&&e.indexOf(t)<0?(e.push(t),t):void 0});return W(e,t)},parent:function(t){return W(P(this.pluck("parentNode")),t)},children:function(t){return W(this.map(function(){return U(this)}),t)},contents:function(){return this.map(function(){return this.contentDocument||u.call(this.childNodes)})},siblings:function(t){return W(this.map(function(t,e){return a.call(U(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(t){return r.map(this,function(e){return e[t]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=B(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=F(t);if(this[0]&&!e)var n=r(t).get(0),i=n.parentNode||this.length>1;return this.each(function(o){r(this).wrapAll(e?t.call(this,o):i?n.cloneNode(!0):n)})},wrapAll:function(t){if(this[0]){r(this[0]).before(t=r(t));for(var e;(e=t.children()).length;)t=e.first();r(t).append(this)}return this},wrapInner:function(t){var e=F(t);return this.each(function(n){var i=r(this),o=i.contents(),s=e?t.call(this,n):t;o.length?o.wrapAll(s):i.append(s)})},unwrap:function(){return this.parent().each(function(){r(this).replaceWith(r(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(t){return this.each(function(){var n=r(this);(t===e?"none"==n.css("display"):t)?n.show():n.hide()})},prev:function(t){return r(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return r(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0 in arguments?this.each(function(e){var n=this.innerHTML;r(this).empty().append(Y(this,t,e,n))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=Y(this,t,e,this.textContent);this.textContent=null==n?"":""+n}):0 in this?this.pluck("textContent").join(""):null},attr:function(t,r){var i;return"string"!=typeof t||1 in arguments?this.each(function(e){if(1===this.nodeType)if(R(t))for(n in t)G(this,n,t[n]);else G(this,t,Y(this,r,e,this.getAttribute(t)))}):0 in this&&1==this[0].nodeType&&null!=(i=this[0].getAttribute(t))?i:e},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(" ").forEach(function(t){G(this,t)},this)})},prop:function(t,e){return t=D[t]||t,1 in arguments?this.each(function(n){this[t]=Y(this,e,n,this[t])}):this[0]&&this[0][t]},removeProp:function(t){return t=D[t]||t,this.each(function(){delete this[t]})},data:function(t,n){var r="data-"+t.replace(v,"-$1").toLowerCase(),i=1 in arguments?this.attr(r,n):this.attr(r);return null!==i?Q(i):e},val:function(t){return 0 in arguments?(null==t&&(t=""),this.each(function(e){this.value=Y(this,t,e,this.value)})):this[0]&&(this[0].multiple?r(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value)},offset:function(e){if(e)return this.each(function(t){var n=r(this),i=Y(this,e,t,n.offset()),o=n.offsetParent().offset(),s={top:i.top-o.top,left:i.left-o.left};"static"==n.css("position")&&(s.position="relative"),n.css(s)});if(!this.length)return null;if(f.documentElement!==this[0]&&!r.contains(f.documentElement,this[0]))return{top:0,left:0};var n=this[0].getBoundingClientRect();return{left:n.left+t.pageXOffset,top:n.top+t.pageYOffset,width:Math.round(n.width),height:Math.round(n.height)}},css:function(t,e){if(arguments.length<2){var i=this[0];if("string"==typeof t){if(!i)return;return i.style[O(t)]||getComputedStyle(i,"").getPropertyValue(t)}if(L(t)){if(!i)return;var o={},s=getComputedStyle(i,"");return r.each(t,function(t,e){o[e]=i.style[O(e)]||s.getPropertyValue(e)}),o}}var a="";if("string"==$(t))e||0===e?a=I(t)+":"+_(t,e):this.each(function(){this.style.removeProperty(I(t))});else for(n in t)t[n]||0===t[n]?a+=I(n)+":"+_(n,t[n])+";":this.each(function(){this.style.removeProperty(I(n))});return this.each(function(){this.style.cssText+=";"+a})},index:function(t){return t?this.indexOf(r(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return t?o.some.call(this,function(t){return this.test(K(t))},V(t)):!1},addClass:function(t){return t?this.each(function(e){if("className"in this){i=[];var n=K(this),o=Y(this,t,e,n);o.split(/\s+/g).forEach(function(t){r(this).hasClass(t)||i.push(t)},this),i.length&&K(this,n+(n?" ":"")+i.join(" "))}}):this},removeClass:function(t){return this.each(function(n){if("className"in this){if(t===e)return K(this,"");i=K(this),Y(this,t,n,i).split(/\s+/g).forEach(function(t){i=i.replace(V(t)," ")}),K(this,i.trim())}})},toggleClass:function(t,n){return t?this.each(function(i){var o=r(this),s=Y(this,t,i,K(this));s.split(/\s+/g).forEach(function(t){(n===e?!o.hasClass(t):n)?o.addClass(t):o.removeClass(t)})}):this},scrollTop:function(t){if(this.length){var n="scrollTop"in this[0];return t===e?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=t}:function(){this.scrollTo(this.scrollX,t)})}},scrollLeft:function(t){if(this.length){var n="scrollLeft"in this[0];return t===e?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=t}:function(){this.scrollTo(t,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),n=this.offset(),i=g.test(e[0].nodeName)?{top:0,left:0}:e.offset();return n.top-=parseFloat(r(t).css("margin-top"))||0,n.left-=parseFloat(r(t).css("margin-left"))||0,i.top+=parseFloat(r(e[0]).css("border-top-width"))||0,i.left+=parseFloat(r(e[0]).css("border-left-width"))||0,{top:n.top-i.top,left:n.left-i.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||f.body;t&&!g.test(t.nodeName)&&"static"==r(t).css("position");)t=t.offsetParent;return t})}},r.fn.detach=r.fn.remove,["width","height"].forEach(function(t){var n=t.replace(/./,function(t){return t[0].toUpperCase()});r.fn[t]=function(i){var o,s=this[0];return i===e?k(s)?s["inner"+n]:M(s)?s.documentElement["scroll"+n]:(o=this.offset())&&o[t]:this.each(function(e){s=r(this),s.css(t,Y(this,i,e,s[t]()))})}}),x.forEach(function(n,i){var o=i%2;r.fn[n]=function(){var n,a,s=r.map(arguments,function(t){var i=[];return n=$(t),"array"==n?(t.forEach(function(t){return t.nodeType!==e?i.push(t):r.zepto.isZ(t)?i=i.concat(t.get()):void(i=i.concat(N.fragment(t)))}),i):"object"==n||null==t?t:N.fragment(t)}),u=this.length>1;return s.length<1?this:this.each(function(e,n){a=o?n:n.parentNode,n=0==i?n.nextSibling:1==i?n.firstChild:2==i?n:null;var c=r.contains(f.documentElement,a);s.forEach(function(e){if(u)e=e.cloneNode(!0);else if(!a)return r(e).remove();a.insertBefore(e,n),c&&tt(e,function(e){if(!(null==e.nodeName||"SCRIPT"!==e.nodeName.toUpperCase()||e.type&&"text/javascript"!==e.type||e.src)){var n=e.ownerDocument?e.ownerDocument.defaultView:t;n.eval.call(n,e.innerHTML)}})})})},r.fn[o?n+"To":"insert"+(i?"Before":"After")]=function(t){return r(t)[n](this),this}}),N.Z.prototype=X.prototype=r.fn,N.uniq=P,N.deserializeValue=Q,r.zepto=N,r}();return t.Zepto=e,void 0===t.
amp;&(t.$=e),function(e){function h(t){return t._zid||(t._zid=n++)}function p(t,e,n,r){if(e=d(e),e.ns)var i=m(e.ns);return(a[h(t)]||[]).filter(function(t){return t&&(!e.e||t.e==e.e)&&(!e.ns||i.test(t.ns))&&(!n||h(t.fn)===h(n))&&(!r||t.sel==r)})}function d(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function m(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function g(t,e){return t.del&&!f&&t.e in c||!!e}function v(t){return l[t]||f&&c[t]||t}function y(t,n,i,o,s,u,f){var c=h(t),p=a[c]||(a[c]=[]);n.split(/\s/).forEach(function(n){if("ready"==n)return e(document).ready(i);var a=d(n);a.fn=i,a.sel=s,a.e in l&&(i=function(t){var n=t.relatedTarget;return!n||n!==this&&!e.contains(this,n)?a.fn.apply(this,arguments):void 0}),a.del=u;var c=u||i;a.proxy=function(e){if(e=T(e),!e.isImmediatePropagationStopped()){e.data=o;var n=c.apply(t,e._args==r?[e]:[e].concat(e._args));return n===!1&&(e.preventDefault(),e.stopPropagation()),n}},a.i=p.length,p.push(a),"addEventListener"in t&&t.addEventListener(v(a.e),a.proxy,g(a,f))})}function x(t,e,n,r,i){var o=h(t);(e||"").split(/\s/).forEach(function(e){p(t,e,n,r).forEach(function(e){delete a[o][e.i],"removeEventListener"in t&&t.removeEventListener(v(e.e),e.proxy,g(e,i))})})}function T(t,n){return(n||!t.isDefaultPrevented)&&(n||(n=t),e.each(w,function(e,r){var i=n[e];t[e]=function(){return this[r]=b,i&&i.apply(n,arguments)},t[r]=E}),t.timeStamp||(t.timeStamp=Date.now()),(n.defaultPrevented!==r?n.defaultPrevented:"returnValue"in n?n.returnValue===!1:n.getPreventDefault&&n.getPreventDefault())&&(t.isDefaultPrevented=b)),t}function S(t){var e,n={originalEvent:t};for(e in t)j.test(e)||t[e]===r||(n[e]=t[e]);return T(n,t)}var r,n=1,i=Array.prototype.slice,o=e.isFunction,s=function(t){return"string"==typeof t},a={},u={},f="onfocusin"in t,c={focus:"focusin",blur:"focusout"},l={mouseenter:"mouseover",mouseleave:"mouseout"};u.click=u.mousedown=u.mouseup=u.mousemove="MouseEvents",e.event={add:y,remove:x},e.proxy=function(t,n){var r=2 in arguments&&i.call(arguments,2);if(o(t)){var a=function(){return t.apply(n,r?r.concat(i.call(arguments)):arguments)};return a._zid=h(t),a}if(s(n))return r?(r.unshift(t[n],t),e.proxy.apply(null,r)):e.proxy(t[n],t);throw new TypeError("expected function")},e.fn.bind=function(t,e,n){return this.on(t,e,n)},e.fn.unbind=function(t,e){return this.off(t,e)},e.fn.one=function(t,e,n,r){return this.on(t,e,n,r,1)};var b=function(){return!0},E=function(){return!1},j=/^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/,w={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};e.fn.delegate=function(t,e,n){return this.on(e,t,n)},e.fn.undelegate=function(t,e,n){return this.off(e,t,n)},e.fn.live=function(t,n){return e(document.body).delegate(this.selector,t,n),this},e.fn.die=function(t,n){return e(document.body).undelegate(this.selector,t,n),this},e.fn.on=function(t,n,a,u,f){var c,l,h=this;return t&&!s(t)?(e.each(t,function(t,e){h.on(t,n,a,e,f)}),h):(s(n)||o(u)||u===!1||(u=a,a=n,n=r),(u===r||a===!1)&&(u=a,a=r),u===!1&&(u=E),h.each(function(r,o){f&&(c=function(t){return x(o,t.type,u),u.apply(this,arguments)}),n&&(l=function(t){var r,s=e(t.target).closest(n,o).get(0);return s&&s!==o?(r=e.extend(S(t),{currentTarget:s,liveFired:o}),(c||u).apply(s,[r].concat(i.call(arguments,1)))):void 0}),y(o,t,u,a,n,l||c)}))},e.fn.off=function(t,n,i){var a=this;return t&&!s(t)?(e.each(t,function(t,e){a.off(t,n,e)}),a):(s(n)||o(i)||i===!1||(i=n,n=r),i===!1&&(i=E),a.each(function(){x(this,t,i,n)}))},e.fn.trigger=function(t,n){return t=s(t)||e.isPlainObject(t)?e.Event(t):T(t),t._args=n,this.each(function(){t.type in c&&"function"==typeof this[t.type]?this[t.type]():"dispatchEvent"in this?this.dispatchEvent(t):e(this).triggerHandler(t,n)})},e.fn.triggerHandler=function(t,n){var r,i;return this.each(function(o,a){r=S(s(t)?e.Event(t):t),r._args=n,r.target=a,e.each(p(a,t.type||t),function(t,e){return i=e.proxy(r),r.isImmediatePropagationStopped()?!1:void 0})}),i},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(t){e.fn[t]=function(e){return 0 in arguments?this.bind(t,e):this.trigger(t)}}),e.Event=function(t,e){s(t)||(e=t,t=e.type);var n=document.createEvent(u[t]||"Events"),r=!0;if(e)for(var i in e)"bubbles"==i?r=!!e[i]:n[i]=e[i];return n.initEvent(t,r,!0),T(n)}}(e),function(e){function p(t,n,r){var i=e.Event(n);return e(t).trigger(i,r),!i.isDefaultPrevented()}function d(t,e,n,i){return t.global?p(e||r,n,i):void 0}function m(t){t.global&&0===e.active++&&d(t,null,"ajaxStart")}function g(t){t.global&&!--e.active&&d(t,null,"ajaxStop")}function v(t,e){var n=e.context;return e.beforeSend.call(n,t,e)===!1||d(e,n,"ajaxBeforeSend",[t,e])===!1?!1:void d(e,n,"ajaxSend",[t,e])}function y(t,e,n,r){var i=n.context,o="success";n.success.call(i,t,o,e),r&&r.resolveWith(i,[t,o,e]),d(n,i,"ajaxSuccess",[e,n,t]),b(o,e,n)}function x(t,e,n,r,i){var o=r.context;r.error.call(o,n,e,t),i&&i.rejectWith(o,[n,e,t]),d(r,o,"ajaxError",[n,r,t||e]),b(e,n,r)}function b(t,e,n){var r=n.context;n.complete.call(r,e,t),d(n,r,"ajaxComplete",[e,n]),g(n)}function E(t,e,n){if(n.dataFilter==j)return t;var r=n.context;return n.dataFilter.call(r,t,e)}function j(){}function w(t){return t&&(t=t.split(";",2)[0]),t&&(t==c?"html":t==f?"json":a.test(t)?"script":u.test(t)&&"xml")||"text"}function T(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function S(t){t.processData&&t.data&&"string"!=e.type(t.data)&&(t.data=e.param(t.data,t.traditional)),!t.data||t.type&&"GET"!=t.type.toUpperCase()&&"jsonp"!=t.dataType||(t.url=T(t.url,t.data),t.data=void 0)}function C(t,n,r,i){return e.isFunction(n)&&(i=r,r=n,n=void 0),e.isFunction(r)||(i=r,r=void 0),{url:t,data:n,success:r,dataType:i}}function O(t,n,r,i){var o,s=e.isArray(n),a=e.isPlainObject(n);e.each(n,function(n,u){o=e.type(u),i&&(n=r?i:i+"["+(a||"object"==o||"array"==o?n:"")+"]"),!i&&s?t.add(u.name,u.value):"array"==o||!r&&"object"==o?O(t,u,r,n):t.add(n,u)})}var i,o,n=+new Date,r=t.document,s=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,a=/^(?:text|application)\/javascript/i,u=/^(?:text|application)\/xml/i,f="application/json",c="text/html",l=/^\s*$/,h=r.createElement("a");h.href=t.location.href,e.active=0,e.ajaxJSONP=function(i,o){if(!("type"in i))return e.ajax(i);var c,p,s=i.jsonpCallback,a=(e.isFunction(s)?s():s)||"Zepto"+n++,u=r.createElement("script"),f=t[a],l=function(t){e(u).triggerHandler("error",t||"abort")},h={abort:l};return o&&o.promise(h),e(u).on("load error",function(n,r){clearTimeout(p),e(u).off().remove(),"error"!=n.type&&c?y(c[0],h,i,o):x(null,r||"error",h,i,o),t[a]=f,c&&e.isFunction(f)&&f(c[0]),f=c=void 0}),v(h,i)===!1?(l("abort"),h):(t[a]=function(){c=arguments},u.src=i.url.replace(/\?(.+)=\?/,"?$1="+a),r.head.appendChild(u),i.timeout>0&&(p=setTimeout(function(){l("timeout")},i.timeout)),h)},e.ajaxSettings={type:"GET",beforeSend:j,success:j,error:j,complete:j,context:null,global:!0,xhr:function(){return new t.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:f,xml:"application/xml, text/xml",html:c,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0,dataFilter:j},e.ajax=function(n){var u,f,s=e.extend({},n||{}),a=e.Deferred&&e.Deferred();for(i in e.ajaxSettings)void 0===s[i]&&(s[i]=e.ajaxSettings[i]);m(s),s.crossDomain||(u=r.createElement("a"),u.href=s.url,u.href=u.href,s.crossDomain=h.protocol+"//"+h.host!=u.protocol+"//"+u.host),s.url||(s.url=t.location.toString()),(f=s.url.indexOf("#"))>-1&&(s.url=s.url.slice(0,f)),S(s);var c=s.dataType,p=/\?.+=\?/.test(s.url);if(p&&(c="jsonp"),s.cache!==!1&&(n&&n.cache===!0||"script"!=c&&"jsonp"!=c)||(s.url=T(s.url,"_="+Date.now())),"jsonp"==c)return p||(s.url=T(s.url,s.jsonp?s.jsonp+"=?":s.jsonp===!1?"":"callback=?")),e.ajaxJSONP(s,a);var P,d=s.accepts[c],g={},b=function(t,e){g[t.toLowerCase()]=[t,e]},C=/^([\w-]+:)\/\//.test(s.url)?RegExp.$1:t.location.protocol,N=s.xhr(),O=N.setRequestHeader;if(a&&a.promise(N),s.crossDomain||b("X-Requested-With","XMLHttpRequest"),b("Accept",d||"*/*"),(d=s.mimeType||d)&&(d.indexOf(",")>-1&&(d=d.split(",",2)[0]),N.overrideMimeType&&N.overrideMimeType(d)),(s.contentType||s.contentType!==!1&&s.data&&"GET"!=s.type.toUpperCase())&&b("Content-Type",s.contentType||"application/x-www-form-urlencoded"),s.headers)for(o in s.headers)b(o,s.headers[o]);if(N.setRequestHeader=b,N.onreadystatechange=function(){if(4==N.readyState){N.onreadystatechange=j,clearTimeout(P);var t,n=!1;if(N.status>=200&&N.status<300||304==N.status||0==N.status&&"file:"==C){if(c=c||w(s.mimeType||N.getResponseHeader("content-type")),"arraybuffer"==N.responseType||"blob"==N.responseType)t=N.response;else{t=N.responseText;try{t=E(t,c,s),"script"==c?(1,eval)(t):"xml"==c?t=N.responseXML:"json"==c&&(t=l.test(t)?null:e.parseJSON(t))}catch(r){n=r}if(n)return x(n,"parsererror",N,s,a)}y(t,N,s,a)}else x(N.statusText||null,N.status?"error":"abort",N,s,a)}},v(N,s)===!1)return N.abort(),x(null,"abort",N,s,a),N;var A="async"in s?s.async:!0;if(N.open(s.type,s.url,A,s.username,s.password),s.xhrFields)for(o in s.xhrFields)N[o]=s.xhrFields[o];for(o in g)O.apply(N,g[o]);return s.timeout>0&&(P=setTimeout(function(){N.onreadystatechange=j,N.abort(),x(null,"timeout",N,s,a)},s.timeout)),N.send(s.data?s.data:null),N},e.get=function(){return e.ajax(C.apply(null,arguments))},e.post=function(){var t=C.apply(null,arguments);return t.type="POST",e.ajax(t)},e.getJSON=function(){var t=C.apply(null,arguments);return t.dataType="json",e.ajax(t)},e.fn.load=function(t,n,r){if(!this.length)return this;var a,i=this,o=t.split(/\s/),u=C(t,n,r),f=u.success;return o.length>1&&(u.url=o[0],a=o[1]),u.success=function(t){i.html(a?e("<div>").html(t.replace(s,"")).find(a):t),f&&f.apply(i,arguments)},e.ajax(u),this};var N=encodeURIComponent;e.param=function(t,n){var r=[];return r.add=function(t,n){e.isFunction(n)&&(n=n()),null==n&&(n=""),this.push(N(t)+"="+N(n))},O(r,t,n),r.join("&").replace(/%20/g,"+")}}(e),function(t){t.fn.serializeArray=function(){var e,n,r=[],i=function(t){return t.forEach?t.forEach(i):void r.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(r,o){n=o.type,e=o.name,e&&"fieldset"!=o.nodeName.toLowerCase()&&!o.disabled&&"submit"!=n&&"reset"!=n&&"button"!=n&&"file"!=n&&("radio"!=n&&"checkbox"!=n||o.checked)&&i(t(o).val())}),r},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+"="+encodeURIComponent(e.value))}),t.join("&")},t.fn.submit=function(e){if(0 in arguments)this.bind("submit",e);else if(this.length){var n=t.Event("submit");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(e),function(){try{getComputedStyle(void 0)}catch(e){var n=getComputedStyle;t.getComputedStyle=function(t,e){try{return n(t,e)}catch(r){return null}}}}(),e});


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/env_details.html.php:
--------------------------------------------------------------------------------
 1 | <?php /* List data-table values, i.e: $_SERVER, $_GET, .... */ ?>
 2 | <div class="details">
 3 |   <h2 class="details-heading">Environment &amp; details:</h2>
 4 | 
 5 |   <div class="data-table-container" id="data-tables">
 6 |     <?php foreach ($tables as $label => $data): ?>
 7 |       <div class="data-table" id="sg-<?php echo $tpl->escape($tpl->slug($label)) ?>">
 8 |         <?php if (!empty($data)): ?>
 9 |             <label><?php echo $tpl->escape($label) ?></label>
10 |             <table class="data-table">
11 |               <thead>
12 |                 <tr>
13 |                   <td class="data-table-k">Key</td>
14 |                   <td class="data-table-v">Value</td>
15 |                 </tr>
16 |               </thead>
17 |             <?php foreach ($data as $k => $value): ?>
18 |               <tr>
19 |                 <td><?php echo $tpl->escape($k) ?></td>
20 |                 <td><?php echo $tpl->dump($value) ?></td>
21 |               </tr>
22 |             <?php endforeach ?>
23 |             </table>
24 |         <?php else: ?>
25 |             <label class="empty"><?php echo $tpl->escape($label) ?></label>
26 |             <span class="empty">empty</span>
27 |         <?php endif ?>
28 |       </div>
29 |     <?php endforeach ?>
30 |   </div>
31 | 
32 |   <?php /* List registered handlers, in order of first to last registered */ ?>
33 |   <div class="data-table-container" id="handlers">
34 |     <label>Registered Handlers</label>
35 |     <?php foreach ($handlers as $i => $h): ?>
36 |       <div class="handler <?php echo ($h === $handler) ? 'active' : ''?>">
37 |         <?php echo $i ?>. <?php echo $tpl->escape(get_class($h)) ?>
38 |       </div>
39 |     <?php endforeach ?>
40 |   </div>
41 | 
42 | </div>
43 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/frame_code.html.php:
--------------------------------------------------------------------------------
 1 | <?php /* Display a code block for all frames in the stack.
 2 |        * @todo: This should PROBABLY be done on-demand, lest
 3 |        * we get 200 frames to process. */ ?>
 4 | <div class="frame-code-container <?php echo (!$has_frames ? 'empty' : '') ?>">
 5 |   <?php foreach ($frames as $i => $frame): ?>
 6 |     <?php $line = $frame->getLine(); ?>
 7 |       <div class="frame-code <?php echo ($i == 0 ) ? 'active' : '' ?>" id="frame-code-<?php echo $i ?>">
 8 |         <div class="frame-file">
 9 |           <?php $filePath = $frame->getFile(); ?>
10 |           <?php if ($filePath && $editorHref = $handler->getEditorHref($filePath, (int) $line)): ?>
11 |             <a href="<?php echo $editorHref ?>" class="editor-link"<?php echo ($handler->getEditorAjax($filePath, (int) $line) ? ' data-ajax' : '') ?>>
12 |               Open:
13 |               <strong><?php echo $tpl->breakOnDelimiter('/', $tpl->escape($filePath ?: '<#unknown>')) ?></strong>
14 |             </a>
15 |           <?php else: ?>
16 |             <strong><?php echo $tpl->breakOnDelimiter('/', $tpl->escape($filePath ?: '<#unknown>')) ?></strong>
17 |           <?php endif ?>
18 |         </div>
19 |         <?php
20 |           // Do nothing if there's no line to work off
21 |           if ($line !== null):
22 | 
23 |           // the $line is 1-indexed, we nab -1 where needed to account for this
24 |           $range = $frame->getFileLines($line - 20, 40);
25 | 
26 |           // getFileLines can return null if there is no source code
27 |           if ($range):
28 |             $range = array_map(function ($line) { return empty($line) ? ' ' : $line;}, $range);
29 |             $start = key($range) + 1;
30 |             $code  = join("\n", $range);
31 |         ?>
32 |             <pre class="code-block line-numbers"
33 |               data-line="<?php echo $line ?>"
34 |               data-line-offset="<?php echo $start ?>"
35 |               data-start="<?php echo $start ?>"
36 |             ><code class="language-php"><?php echo $tpl->escape($code) ?></code></pre>
37 | 
38 |           <?php endif ?>
39 |         <?php endif ?>
40 | 
41 |         <?php $frameArgs = $tpl->dumpArgs($frame); ?>
42 |         <?php if ($frameArgs): ?>
43 |           <div class="frame-file">
44 |               Arguments
45 |           </div>
46 |           <div id="frame-code-args-<?=$i?>" class="code-block frame-args">
47 |               <?php echo $frameArgs; ?>
48 |           </div>
49 |         <?php endif ?>
50 | 
51 |         <?php
52 |           // Append comments for this frame
53 |           $comments = $frame->getComments();
54 |         ?>
55 |         <div class="frame-comments <?php echo empty($comments) ? 'empty' : '' ?>">
56 |           <?php foreach ($comments as $commentNo => $comment): ?>
57 |             <?php extract($comment) ?>
58 |             <div class="frame-comment" id="comment-<?php echo $i . '-' . $commentNo ?>">
59 |               <span class="frame-comment-context"><?php echo $tpl->escape($context) ?></span>
60 |               <?php echo $tpl->escapeButPreserveUris($comment) ?>
61 |             </div>
62 |           <?php endforeach ?>
63 |         </div>
64 | 
65 |       </div>
66 |   <?php endforeach ?>
67 | </div>
68 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/frame_list.html.php:
--------------------------------------------------------------------------------
 1 | <?php /* List file names & line numbers for all stack frames;
 2 |          clicking these links/buttons will display the code view
 3 |          for that particular frame */ ?>
 4 | <?php foreach ($frames as $i => $frame): ?>
 5 |   <div class="frame <?php echo ($i == 0 ? 'active' : '') ?> <?php echo ($frame->isApplication() ? 'frame-application' : '') ?>" id="frame-line-<?php echo $i ?>">
 6 |       <span class="frame-index"><?php echo (count($frames) - $i - 1) ?></span>
 7 |       <div class="frame-method-info">
 8 |         <span class="frame-class"><?php echo $tpl->breakOnDelimiter('\\', $tpl->escape($frame->getClass() ?: '')) ?></span>
 9 |         <span class="frame-function"><?php echo $tpl->breakOnDelimiter('\\', $tpl->escape($frame->getFunction() ?: '')) ?></span>
10 |       </div>
11 | 
12 |     <div class="frame-file">
13 |         <?php echo $frame->getFile() ? $tpl->breakOnDelimiter('/', $tpl->shorten($tpl->escape($frame->getFile()))) : '<#unknown>' ?><!--
14 |    --><span class="frame-line"><?php echo (int) $frame->getLine() ?></span>
15 |     </div>
16 |   </div>
17 | <?php endforeach;
18 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/frames_container.html.php:
--------------------------------------------------------------------------------
1 | <div class="frames-container <?php echo $active_frames_tab == 'application' ? 'frames-container-application' : '' ?>">
2 |   <?php $tpl->render($frame_list) ?>
3 | </div>


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/frames_description.html.php:
--------------------------------------------------------------------------------
 1 | <div class="frames-description <?php echo $has_frames_tabs ? 'frames-description-application' : '' ?>">
 2 |   <?php if ($has_frames_tabs): ?>
 3 |     <a href="#" id="application-frames-tab" class="frames-tab <?php echo $active_frames_tab == 'application' ? 'frames-tab-active' : '' ?>">
 4 |         Application frames (<?php echo $frames->countIsApplication() ?>)
 5 |     </a>
 6 |     <a href="#" id="all-frames-tab" class="frames-tab <?php echo $active_frames_tab == 'all' ? 'frames-tab-active' : '' ?>">
 7 |       All frames (<?php echo count($frames) ?>)
 8 |     </a>
 9 |   <?php else: ?>
10 |     <span>
11 |         Stack frames (<?php echo count($frames) ?>)
12 |     </span>
13 |   <?php endif; ?>
14 | </div>
15 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/header.html.php:
--------------------------------------------------------------------------------
 1 | <div class="exception">
 2 |   <div class="exc-title">
 3 |     <?php foreach ($name as $i => $nameSection): ?>
 4 |       <?php if ($i == count($name) - 1): ?>
 5 |         <span class="exc-title-primary"><?php echo $tpl->escape($nameSection) ?></span>
 6 |       <?php else: ?>
 7 |         <?php echo $tpl->escape($nameSection) . ' \\' ?>
 8 |       <?php endif ?>
 9 |     <?php endforeach ?>
10 |     <?php if ($code): ?>
11 |       <span title="Exception Code">(<?php echo $tpl->escape($code) ?>)</span>
12 |     <?php endif ?>
13 |   </div>
14 | 
15 |   <div class="exc-message">
16 |     <?php if (!empty($message)): ?>
17 |       <span><?php echo $tpl->escape($message) ?></span>
18 | 
19 | 
20 |       <?php if (count($previousMessages)): ?>
21 |         <div class="exc-title prev-exc-title">
22 |           <span class="exc-title-secondary">Previous exceptions</span>
23 |         </div>
24 | 
25 |         <ul>
26 |           <?php foreach ($previousMessages as $i => $previousMessage): ?>
27 |             <li>
28 |               <?php echo $tpl->escape($previousMessage) ?>
29 |               <span class="prev-exc-code">(<?php echo $previousCodes[$i] ?>)</span>
30 |             </li>
31 |           <?php endforeach; ?>
32 |         </ul>
33 |       <?php endif ?>
34 | 
35 | 
36 | 
37 |     <?php else: ?>
38 |       <span class="exc-message-empty-notice">No message</span>
39 |     <?php endif ?>
40 | 
41 |     <ul class="search-for-help">
42 |       <?php if (!empty($docref_url)): ?>
43 |       <li>
44 |         <a rel="noopener noreferrer" target="_blank" href="<?php echo $docref_url; ?>" title="Search for help in the PHP manual.">
45 |           <!-- PHP icon by Icons Solid -->
46 |           <!-- https://www.iconfinder.com/icons/322421/book_icon -->
47 |           <!-- Free for commercial use -->
48 |           <svg height="16px" id="Layer_1" style="enable-background:new 0 0 32 32;" version="1.1" viewBox="0 0 32 32" width="16px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g transform="translate(240 0)"><path d="M-211,4v26h-24c-1.104,0-2-0.895-2-2s0.896-2,2-2h22V0h-22c-2.209,0-4,1.791-4,4v24c0,2.209,1.791,4,4,4h26V4H-211z    M-235,8V2h20v22h-20V8z M-219,6h-12V4h12V6z M-223,10h-8V8h8V10z M-227,14h-4v-2h4V14z"/></g></svg>
49 |         </a>
50 |       </li>
51 |       <?php endif ?>
52 |       <li>
53 |         <a rel="noopener noreferrer" target="_blank" href="https://google.com/search?q=<?php echo urlencode(implode('\\', $name).' '.$message) ?>" title="Search for help on Google.">
54 |           <!-- Google icon by Alfredo H, from https://www.iconfinder.com/alfredoh -->
55 |           <!-- Creative Commons (Attribution 3.0 Unported) -->
56 |           <!-- http://creativecommons.org/licenses/by/3.0/ -->
57 |           <svg class="google" height="16" viewBox="0 0 512 512" width="16" xmlns="http://www.w3.org/2000/svg">
58 |             <path d="M457.732 216.625c2.628 14.04 4.063 28.743 4.063 44.098C461.795 380.688 381.48 466 260.205 466c-116.024 0-210-93.977-210-210s93.976-210 210-210c56.703 0 104.076 20.867 140.44 54.73l-59.205 59.197v-.135c-22.046-21.002-50-31.762-81.236-31.762-69.297 0-125.604 58.537-125.604 127.84 0 69.29 56.306 127.97 125.604 127.97 62.87 0 105.653-35.966 114.46-85.313h-114.46v-81.902h197.528z"/>
59 |           </svg>
60 |         </a>
61 |       </li>
62 |       <li>
63 |         <a rel="noopener noreferrer" target="_blank" href="https://duckduckgo.com/?q=<?php echo urlencode(implode('\\', $name).' '.$message) ?>" title="Search for help on DuckDuckGo.">
64 |           <!-- DuckDuckGo icon by IconBaandar Team, from https://www.iconfinder.com/iconbaandar -->
65 |           <!-- Creative Commons (Attribution 3.0 Unported) -->
66 |           <!-- http://creativecommons.org/licenses/by/3.0/ -->
67 |           <svg class="duckduckgo" height="16" viewBox="150 150 1675 1675" width="16" xmlns="http://www.w3.org/2000/svg">
68 |             <path d="M1792 1024c0 204.364-80.472 398.56-224.955 543.04-144.483 144.48-338.68 224.95-543.044 224.95-204.36 0-398.56-80.47-543.04-224.95-144.48-144.482-224.95-338.676-224.95-543.04 0-204.365 80.47-398.562 224.96-543.045C625.44 336.47 819.64 256 1024 256c204.367 0 398.565 80.47 543.05 224.954C1711.532 625.437 1792 819.634 1792 1024zm-270.206 497.787C1654.256 1389.327 1728 1211.36 1728 1024c0-187.363-73.74-365.332-206.203-497.796C1389.332 393.74 1211.363 320 1024 320s-365.33 73.742-497.795 206.205C393.742 658.67 320 836.637 320 1024c0 187.36 73.744 365.326 206.206 497.787C658.67 1654.25 836.638 1727.99 1024 1727.99c187.362 0 365.33-73.74 497.794-206.203z"/>
69 |             <path d="M1438.64 1177.41c0-.03-.005-.017-.01.004l.01-.004z"/>
70 |             <path d="M1499.8 976.878c.03-.156-.024-.048-.11.107l.11-.107z"/>
71 |             <path d="M1105.19 991.642zm-68.013-376.128c-8.087-10.14-18.028-19.965-29.89-29.408-13.29-10.582-29-20.76-47.223-30.443-35.07-18.624-74.482-31.61-115.265-38.046-39.78-6.28-80.84-6.256-120.39.917l1.37 31.562c1.8.164 7.7 3.9 14.36 8.32-20.68 5.94-39.77 14.447-39.48 39.683l.2 17.48 17.3-1.73c29.38-2.95 60.17-2.06 90.32 2.61 9.21 1.42 18.36 3.2 27.38 5.32l-4.33 1.15c-20.45 5.58-38.93 12.52-54.25 20.61-46.28 24.32-75.51 60.85-90.14 108.37-14.14 45.95-14.27 101.81-2.72 166.51l.06.06c15.14 84.57 64.16 316.39 104.11 505.39 19.78 93.59 37.38 176.83 47.14 224.4 3.26 15.84 5.03 31.02 5.52 45.52.3 9.08.09 17.96-.58 26.62-.45 5.8-1.11 11.51-1.96 17.112l31.62 4.75c.71-4.705 1.3-9.494 1.76-14.373 48.964 10.517 99.78 16.05 151.88 16.05 60.68 0 119.61-7.505 175.91-21.64 3.04 6.08 6.08 12.19 9.11 18.32l28.62-14.128c-2.11-4.27-4.235-8.55-6.37-12.84-23.005-46.124-47.498-93.01-68.67-133.534-15.39-29.466-29.01-55.53-39.046-75.58-26.826-53.618-53.637-119.47-68.28-182.368-8.78-37.705-13.128-74.098-10.308-105.627-15.31-6.28-26.69-11.8-31.968-15.59l-.01.015c-14.22-10.2-31.11-28.12-41.82-49.717-8.618-17.376-13.4-37.246-10.147-57.84 3.17-19.84 27.334-46.714 57.843-67.46v-.063c26.554-18.05 58.75-32.506 86.32-34.31 7.835-.51 16.31-1.008 23.99-1.45 33.45-1.95 50.243-2.93 84.475-11.42 10.88-2.697 26.19-6.56 43.53-11.09 2.364-40.7-5.947-87.596-21.04-133.234-22.004-66.53-58.68-131.25-97.627-170.21-12.543-12.55-28.17-22.79-45.9-30.933-16.88-7.753-35.64-13.615-55.436-17.782zm-10.658 178.553s6.77-42.485 58.39-33.977c27.96 4.654 37.89 29.833 37.89 29.833s-25.31-14.46-44.95-14.198c-40.33.53-51.35 18.342-51.35 18.342zm-240.45-18.802c48.49-19.853 72.11 11.298 72.11 11.298s-35.21-15.928-69.46 5.59c-34.19 21.477-32.92 43.452-32.92 43.452s-18.17-40.5 30.26-60.34zm296.5 95.4c0-6.677 2.68-12.694 7.01-17.02 4.37-4.37 10.42-7.074 17.1-7.074 6.73 0 12.79 2.7 17.15 7.05 4.33 4.33 7.01 10.36 7.01 17.05 0 6.74-2.7 12.81-7.07 17.18-4.33 4.33-10.37 7.01-17.1 7.01-6.68 0-12.72-2.69-17.05-7.03-4.36-4.37-7.07-10.43-7.07-17.16zm-268.42 51.27c0-8.535 3.41-16.22 8.93-21.738 5.55-5.55 13.25-8.982 21.81-8.982 8.51 0 16.18 3.415 21.7 8.934 5.55 5.55 8.98 13.25 8.98 21.78 0 8.53-3.44 16.23-8.98 21.79-5.52 5.52-13.19 8.93-21.71 8.93-8.55 0-16.26-3.43-21.82-8.99-5.52-5.52-8.93-13.2-8.93-21.74z"/>
72 |             <path d="M1102.48 986.34zm390.074-64.347c-28.917-11.34-74.89-12.68-93.32-3.778-11.5 5.567-35.743 13.483-63.565 21.707-25.75 7.606-53.9 15.296-78.15 21.702-17.69 4.67-33.3 8.66-44.4 11.435-34.92 8.76-52.05 9.77-86.17 11.78-7.84.46-16.48.97-24.48 1.5-28.12 1.86-60.97 16.77-88.05 35.4v.06c-31.12 21.4-55.77 49.12-59.01 69.59-3.32 21.24 1.56 41.74 10.35 59.67 10.92 22.28 28.15 40.77 42.66 51.29l.01-.02c5.38 3.9 16.98 9.6 32.6 16.08 26.03 10.79 63.2 23.76 101.25 34.23 43.6 11.99 89.11 21.05 121.69 20.41 34.26-.69 77.73-10.52 114.54-24.67 22.15-8.52 42.21-18.71 56.88-29.58 17.85-13.22 28.7-28.42 28.4-44.74-.07-3.89-.72-7.63-1.97-11.21l-.02.01c-11.6-33.06-50.37-23.59-105.53-10.12-46.86 11.445-107.94 26.365-169.01 20.434-32.56-3.167-54.45-10.61-67.88-20.133-5.96-4.224-9.93-8.67-12.18-13.11-1.96-3.865-2.68-7.84-2.33-11.714.39-4.42 2.17-9.048 5.1-13.57l-.05-.03c7.86-12.118 23.082-9.72 43.93-6.43 25.91 4.08 58.2 9.172 99.013-3.61 39.63-12.378 87.76-29.9 131.184-47.39 42.405-17.08 80.08-34.078 100.74-46.18 25.46-14.87 37.57-29.428 40.59-42.866 2.725-12.152-.89-22.48-8.903-31.07-5.87-6.29-14.254-11.31-23.956-15.115z"/>
73 |           </svg>
74 |         </a>
75 |       </li>
76 |       <li>
77 |         <a rel="noopener noreferrer" target="_blank" href="https://stackoverflow.com/search?q=<?php echo urlencode(implode('\\', $name).' '.$message) ?>" title="Search for help on Stack Overflow.">
78 |           <!-- Stack Overflow icon by Picons.me, from https://www.iconfinder.com/Picons -->
79 |           <!-- Free for commercial use -->
80 |           <svg class="stackoverflow" height="16" viewBox="-1163 1657.697 56.693 56.693" width="16" xmlns="http://www.w3.org/2000/svg">
81 |             <path d="M-1126.04 1689.533l-16.577-9.778 2.088-3.54 16.578 9.778zM-1127.386 1694.635l-18.586-4.996 1.068-3.97 18.586 4.995zM-1127.824 1700.137l-19.165-1.767.378-4.093 19.165 1.767zM-1147.263 1701.293h19.247v4.11h-19.247z"/>
82 |             <path d="M-1121.458 1710.947s0 .96-.032.96v.016h-30.796s-.96 0-.96-.016h-.032v-20.03h3.288v16.805h25.244v-16.804h3.288v19.07zM-1130.667 1667.04l10.844 15.903-3.396 2.316-10.843-15.903zM-1118.313 1663.044l3.29 18.963-4.05.703-3.29-18.963z"/>
83 |           </svg>
84 |         </a>
85 |       </li>
86 |     </ul>
87 | 
88 |     <span id="plain-exception"><?php echo $tpl->escape($plain_exception) ?></span>
89 |     <button id="copy-button" class="rightButton clipboard" data-clipboard-text="<?php echo $tpl->escape($plain_exception) ?>" title="Copy exception details to clipboard">
90 |       COPY
91 |     </button>
92 |     <button id="hide-error" class="rightButton" title="Hide error message" onclick="document.getElementsByClassName('Whoops')[0].style.display = 'none';">
93 |       HIDE
94 |     </button>
95 |   </div>
96 | </div>
97 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/header_outer.html.php:
--------------------------------------------------------------------------------
1 | <header>
2 |   <?php $tpl->render($header) ?>
3 | </header>
4 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/layout.html.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 | * Layout template file for Whoops's pretty error output.
 4 | */
 5 | ?>
 6 | <!DOCTYPE html><?php echo $preface; ?>
 7 | <html>
 8 |   <head>
 9 |     <meta charset="utf-8">
10 |     <meta name="robots" content="noindex,nofollow"/>
11 |     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
12 |     <title><?php echo $tpl->escape($page_title) ?></title>
13 | 
14 |     <style><?php echo $stylesheet ?></style>
15 |     <style><?php echo $prismCss ?></style>
16 |   </head>
17 |   <body>
18 | 
19 |     <div class="Whoops container">
20 |       <div class="stack-container">
21 | 
22 |         <?php $tpl->render($panel_left_outer) ?>
23 | 
24 |         <?php $tpl->render($panel_details_outer) ?>
25 | 
26 |       </div>
27 |     </div>
28 | 
29 |     <script data-manual><?php echo $prismJs ?></script>
30 |     <script><?php echo $zepto ?></script>
31 |     <script><?php echo $clipboard ?></script>
32 |     <script><?php echo $javascript ?></script>
33 |   </body>
34 | </html>
35 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/panel_details.html.php:
--------------------------------------------------------------------------------
1 | <?php $tpl->render($frame_code) ?>
2 | <?php $tpl->render($env_details) ?>


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/panel_details_outer.html.php:
--------------------------------------------------------------------------------
1 | <div class="panel details-container cf">
2 |   <?php $tpl->render($panel_details) ?>
3 | </div>


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/panel_left.html.php:
--------------------------------------------------------------------------------
1 | <?php 
2 | $tpl->render($header_outer);
3 | $tpl->render($frames_description);
4 | $tpl->render($frames_container);
5 | 


--------------------------------------------------------------------------------
/src/Whoops/Resources/views/panel_left_outer.html.php:
--------------------------------------------------------------------------------
1 | <div class="panel left-panel cf <?php echo (!$has_frames ? 'empty' : '') ?>">
2 |   <?php $tpl->render($panel_left) ?>
3 | </div>


--------------------------------------------------------------------------------
/src/Whoops/Run.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 |  * Whoops - php errors for cool kids
  4 |  * @author Filipe Dobreira <http://github.com/filp>
  5 |  */
  6 | 
  7 | namespace Whoops;
  8 | 
  9 | use InvalidArgumentException;
 10 | use Throwable;
 11 | use Whoops\Exception\ErrorException;
 12 | use Whoops\Handler\CallbackHandler;
 13 | use Whoops\Handler\Handler;
 14 | use Whoops\Handler\HandlerInterface;
 15 | use Whoops\Inspector\CallableInspectorFactory;
 16 | use Whoops\Inspector\InspectorFactory;
 17 | use Whoops\Inspector\InspectorFactoryInterface;
 18 | use Whoops\Inspector\InspectorInterface;
 19 | use Whoops\Util\Misc;
 20 | use Whoops\Util\SystemFacade;
 21 | 
 22 | final class Run implements RunInterface
 23 | {
 24 |     /**
 25 |      * @var bool
 26 |      */
 27 |     private $isRegistered;
 28 | 
 29 |     /**
 30 |      * @var bool
 31 |      */
 32 |     private $allowQuit       = true;
 33 | 
 34 |     /**
 35 |      * @var bool
 36 |      */
 37 |     private $sendOutput      = true;
 38 | 
 39 |     /**
 40 |      * @var integer|false
 41 |      */
 42 |     private $sendHttpCode    = 500;
 43 | 
 44 |     /**
 45 |      * @var integer|false
 46 |      */
 47 |     private $sendExitCode    = 1;
 48 | 
 49 |     /**
 50 |      * @var HandlerInterface[]
 51 |      */
 52 |     private $handlerStack = [];
 53 | 
 54 |     /**
 55 |      * @var array
 56 |      * @psalm-var list<array{patterns: string, levels: int}>
 57 |      */
 58 |     private $silencedPatterns = [];
 59 | 
 60 |     /**
 61 |      * @var SystemFacade
 62 |      */
 63 |     private $system;
 64 | 
 65 |     /**
 66 |      * In certain scenarios, like in shutdown handler, we can not throw exceptions.
 67 |      *
 68 |      * @var bool
 69 |      */
 70 |     private $canThrowExceptions = true;
 71 | 
 72 |     /**
 73 |      * The inspector factory to create inspectors.
 74 |      *
 75 |      * @var InspectorFactoryInterface
 76 |      */
 77 |     private $inspectorFactory;
 78 | 
 79 |     /**
 80 |      * @var array<callable>
 81 |      */
 82 |     private $frameFilters = [];
 83 | 
 84 |     public function __construct(?SystemFacade $system = null)
 85 |     {
 86 |         $this->system = $system ?: new SystemFacade;
 87 |         $this->inspectorFactory = new InspectorFactory();
 88 |     }
 89 | 
 90 |     public function __destruct()
 91 |     {
 92 |         $this->unregister();
 93 |     }
 94 | 
 95 |     /**
 96 |      * Explicitly request your handler runs as the last of all currently registered handlers.
 97 |      *
 98 |      * @param callable|HandlerInterface $handler
 99 |      *
100 |      * @return Run
101 |      */
102 |     public function appendHandler($handler)
103 |     {
104 |         array_unshift($this->handlerStack, $this->resolveHandler($handler));
105 |         return $this;
106 |     }
107 | 
108 |     /**
109 |      * Explicitly request your handler runs as the first of all currently registered handlers.
110 |      *
111 |      * @param callable|HandlerInterface $handler
112 |      *
113 |      * @return Run
114 |      */
115 |     public function prependHandler($handler)
116 |     {
117 |         return $this->pushHandler($handler);
118 |     }
119 | 
120 |     /**
121 |      * Register your handler as the last of all currently registered handlers (to be executed first).
122 |      * Prefer using appendHandler and prependHandler for clarity.
123 |      *
124 |      * @param callable|HandlerInterface $handler
125 |      *
126 |      * @return Run
127 |      *
128 |      * @throws InvalidArgumentException If argument is not callable or instance of HandlerInterface.
129 |      */
130 |     public function pushHandler($handler)
131 |     {
132 |         $this->handlerStack[] = $this->resolveHandler($handler);
133 |         return $this;
134 |     }
135 | 
136 |     /**
137 |      * Removes and returns the last handler pushed to the handler stack.
138 |      *
139 |      * @see Run::removeFirstHandler(), Run::removeLastHandler()
140 |      *
141 |      * @return HandlerInterface|null
142 |      */
143 |     public function popHandler()
144 |     {
145 |         return array_pop($this->handlerStack);
146 |     }
147 | 
148 |     /**
149 |      * Removes the first handler.
150 |      *
151 |      * @return void
152 |      */
153 |     public function removeFirstHandler()
154 |     {
155 |         array_pop($this->handlerStack);
156 |     }
157 | 
158 |     /**
159 |      * Removes the last handler.
160 |      *
161 |      * @return void
162 |      */
163 |     public function removeLastHandler()
164 |     {
165 |         array_shift($this->handlerStack);
166 |     }
167 | 
168 |     /**
169 |      * Returns an array with all handlers, in the order they were added to the stack.
170 |      *
171 |      * @return array
172 |      */
173 |     public function getHandlers()
174 |     {
175 |         return $this->handlerStack;
176 |     }
177 | 
178 |     /**
179 |      * Clears all handlers in the handlerStack, including the default PrettyPage handler.
180 |      *
181 |      * @return Run
182 |      */
183 |     public function clearHandlers()
184 |     {
185 |         $this->handlerStack = [];
186 |         return $this;
187 |     }
188 | 
189 |     public function getFrameFilters()
190 |     {
191 |         return $this->frameFilters;
192 |     }
193 | 
194 |     public function clearFrameFilters()
195 |     {
196 |         $this->frameFilters = [];
197 |         return $this;
198 |     }
199 | 
200 |     /**
201 |      * Registers this instance as an error handler.
202 |      *
203 |      * @return Run
204 |      */
205 |     public function register()
206 |     {
207 |         if (!$this->isRegistered) {
208 |             // Workaround PHP bug 42098
209 |             // https://bugs.php.net/bug.php?id=42098
210 |             class_exists("\\Whoops\\Exception\\ErrorException");
211 |             class_exists("\\Whoops\\Exception\\FrameCollection");
212 |             class_exists("\\Whoops\\Exception\\Frame");
213 |             class_exists("\\Whoops\\Exception\\Inspector");
214 |             class_exists("\\Whoops\\Inspector\\InspectorFactory");
215 | 
216 |             $this->system->setErrorHandler([$this, self::ERROR_HANDLER]);
217 |             $this->system->setExceptionHandler([$this, self::EXCEPTION_HANDLER]);
218 |             $this->system->registerShutdownFunction([$this, self::SHUTDOWN_HANDLER]);
219 | 
220 |             $this->isRegistered = true;
221 |         }
222 | 
223 |         return $this;
224 |     }
225 | 
226 |     /**
227 |      * Unregisters all handlers registered by this Whoops\Run instance.
228 |      *
229 |      * @return Run
230 |      */
231 |     public function unregister()
232 |     {
233 |         if ($this->isRegistered) {
234 |             $this->system->restoreExceptionHandler();
235 |             $this->system->restoreErrorHandler();
236 | 
237 |             $this->isRegistered = false;
238 |         }
239 | 
240 |         return $this;
241 |     }
242 | 
243 |     /**
244 |      * Should Whoops allow Handlers to force the script to quit?
245 |      *
246 |      * @param bool|int $exit
247 |      *
248 |      * @return bool
249 |      */
250 |     public function allowQuit($exit = null)
251 |     {
252 |         if (func_num_args() == 0) {
253 |             return $this->allowQuit;
254 |         }
255 | 
256 |         return $this->allowQuit = (bool) $exit;
257 |     }
258 | 
259 |     /**
260 |      * Silence particular errors in particular files.
261 |      *
262 |      * @param array|string $patterns List or a single regex pattern to match.
263 |      * @param int          $levels   Defaults to E_STRICT | E_DEPRECATED.
264 |      *
265 |      * @return Run
266 |      */
267 |     public function silenceErrorsInPaths($patterns, $levels = 10240)
268 |     {
269 |         $this->silencedPatterns = array_merge(
270 |             $this->silencedPatterns,
271 |             array_map(
272 |                 function ($pattern) use ($levels) {
273 |                     return [
274 |                         "pattern" => $pattern,
275 |                         "levels" => $levels,
276 |                     ];
277 |                 },
278 |                 (array) $patterns
279 |             )
280 |         );
281 | 
282 |         return $this;
283 |     }
284 | 
285 |     /**
286 |      * Returns an array with silent errors in path configuration.
287 |      *
288 |      * @return array
289 |      */
290 |     public function getSilenceErrorsInPaths()
291 |     {
292 |         return $this->silencedPatterns;
293 |     }
294 | 
295 |     /**
296 |      * Should Whoops send HTTP error code to the browser if possible?
297 |      * Whoops will by default send HTTP code 500, but you may wish to
298 |      * use 502, 503, or another 5xx family code.
299 |      *
300 |      * @param bool|int $code
301 |      *
302 |      * @return int|false
303 |      *
304 |      * @throws InvalidArgumentException
305 |      */
306 |     public function sendHttpCode($code = null)
307 |     {
308 |         if (func_num_args() == 0) {
309 |             return $this->sendHttpCode;
310 |         }
311 | 
312 |         if (!$code) {
313 |             return $this->sendHttpCode = false;
314 |         }
315 | 
316 |         if ($code === true) {
317 |             $code = 500;
318 |         }
319 | 
320 |         if ($code < 400 || 600 <= $code) {
321 |             throw new InvalidArgumentException(
322 |                 "Invalid status code '$code', must be 4xx or 5xx"
323 |             );
324 |         }
325 | 
326 |         return $this->sendHttpCode = $code;
327 |     }
328 | 
329 |     /**
330 |      * Should Whoops exit with a specific code on the CLI if possible?
331 |      * Whoops will exit with 1 by default, but you can specify something else.
332 |      *
333 |      * @param int $code
334 |      *
335 |      * @return int
336 |      *
337 |      * @throws InvalidArgumentException
338 |      */
339 |     public function sendExitCode($code = null)
340 |     {
341 |         if (func_num_args() == 0) {
342 |             return $this->sendExitCode;
343 |         }
344 | 
345 |         if ($code < 0 || 255 <= $code) {
346 |             throw new InvalidArgumentException(
347 |                 "Invalid status code '$code', must be between 0 and 254"
348 |             );
349 |         }
350 | 
351 |         return $this->sendExitCode = (int) $code;
352 |     }
353 | 
354 |     /**
355 |      * Should Whoops push output directly to the client?
356 |      * If this is false, output will be returned by handleException.
357 |      *
358 |      * @param bool|int $send
359 |      *
360 |      * @return bool
361 |      */
362 |     public function writeToOutput($send = null)
363 |     {
364 |         if (func_num_args() == 0) {
365 |             return $this->sendOutput;
366 |         }
367 | 
368 |         return $this->sendOutput = (bool) $send;
369 |     }
370 | 
371 |     /**
372 |      * Handles an exception, ultimately generating a Whoops error page.
373 |      *
374 |      * @param Throwable $exception
375 |      *
376 |      * @return string Output generated by handlers.
377 |      */
378 |     public function handleException($exception)
379 |     {
380 |         // Walk the registered handlers in the reverse order
381 |         // they were registered, and pass off the exception
382 |         $inspector = $this->getInspector($exception);
383 | 
384 |         // Capture output produced while handling the exception,
385 |         // we might want to send it straight away to the client,
386 |         // or return it silently.
387 |         $this->system->startOutputBuffering();
388 | 
389 |         // Just in case there are no handlers:
390 |         $handlerResponse = null;
391 |         $handlerContentType = null;
392 | 
393 |         try {
394 |             foreach (array_reverse($this->handlerStack) as $handler) {
395 |                 $handler->setRun($this);
396 |                 $handler->setInspector($inspector);
397 |                 $handler->setException($exception);
398 | 
399 |                 // The HandlerInterface does not require an Exception passed to handle()
400 |                 // and neither of our bundled handlers use it.
401 |                 // However, 3rd party handlers may have already relied on this parameter,
402 |                 // and removing it would be possibly breaking for users.
403 |                 $handlerResponse = $handler->handle($exception);
404 | 
405 |                 // Collect the content type for possible sending in the headers.
406 |                 $handlerContentType = method_exists($handler, 'contentType') ? $handler->contentType() : null;
407 | 
408 |                 if (in_array($handlerResponse, [Handler::LAST_HANDLER, Handler::QUIT])) {
409 |                     // The Handler has handled the exception in some way, and
410 |                     // wishes to quit execution (Handler::QUIT), or skip any
411 |                     // other handlers (Handler::LAST_HANDLER). If $this->allowQuit
412 |                     // is false, Handler::QUIT behaves like Handler::LAST_HANDLER
413 |                     break;
414 |                 }
415 |             }
416 | 
417 |             $willQuit = $handlerResponse == Handler::QUIT && $this->allowQuit();
418 |         } finally {
419 |             $output = $this->system->cleanOutputBuffer();
420 |         }
421 | 
422 |         // If we're allowed to, send output generated by handlers directly
423 |         // to the output, otherwise, and if the script doesn't quit, return
424 |         // it so that it may be used by the caller
425 |         if ($this->writeToOutput()) {
426 |             // @todo Might be able to clean this up a bit better
427 |             if ($willQuit) {
428 |                 // Cleanup all other output buffers before sending our output:
429 |                 while ($this->system->getOutputBufferLevel() > 0) {
430 |                     $this->system->endOutputBuffering();
431 |                 }
432 | 
433 |                 // Send any headers if needed:
434 |                 if (Misc::canSendHeaders() && $handlerContentType) {
435 |                     header("Content-Type: {$handlerContentType}");
436 |                 }
437 |             }
438 | 
439 |             $this->writeToOutputNow($output);
440 |         }
441 | 
442 |         if ($willQuit) {
443 |             // HHVM fix for https://github.com/facebook/hhvm/issues/4055
444 |             $this->system->flushOutputBuffer();
445 | 
446 |             $this->system->stopExecution(
447 |                 $this->sendExitCode()
448 |             );
449 |         }
450 | 
451 |         return $output;
452 |     }
453 | 
454 |     /**
455 |      * Converts generic PHP errors to \ErrorException instances, before passing them off to be handled.
456 |      *
457 |      * This method MUST be compatible with set_error_handler.
458 |      *
459 |      * @param int         $level
460 |      * @param string      $message
461 |      * @param string|null $file
462 |      * @param int|null    $line
463 |      *
464 |      * @return bool
465 |      *
466 |      * @throws ErrorException
467 |      */
468 |     public function handleError($level, $message, $file = null, $line = null)
469 |     {
470 |         if ($level & $this->system->getErrorReportingLevel()) {
471 |             foreach ($this->silencedPatterns as $entry) {
472 |                 $pathMatches = (bool) preg_match($entry["pattern"], $file);
473 |                 $levelMatches = $level & $entry["levels"];
474 |                 if ($pathMatches && $levelMatches) {
475 |                     // Ignore the error, abort handling
476 |                     // See https://github.com/filp/whoops/issues/418
477 |                     return true;
478 |                 }
479 |             }
480 | 
481 |             // XXX we pass $level for the "code" param only for BC reasons.
482 |             // see https://github.com/filp/whoops/issues/267
483 |             $exception = new ErrorException($message, /*code*/ $level, /*severity*/ $level, $file, $line);
484 |             if ($this->canThrowExceptions) {
485 |                 throw $exception;
486 |             } else {
487 |                 $this->handleException($exception);
488 |             }
489 |             // Do not propagate errors which were already handled by Whoops.
490 |             return true;
491 |         }
492 | 
493 |         // Propagate error to the next handler, allows error_get_last() to
494 |         // work on silenced errors.
495 |         return false;
496 |     }
497 | 
498 |     /**
499 |      * Special case to deal with Fatal errors and the like.
500 |      *
501 |      * @return void
502 |      */
503 |     public function handleShutdown()
504 |     {
505 |         // If we reached this step, we are in shutdown handler.
506 |         // An exception thrown in a shutdown handler will not be propagated
507 |         // to the exception handler. Pass that information along.
508 |         $this->canThrowExceptions = false;
509 | 
510 |         // If we are not currently registered, we should not do anything
511 |         if (!$this->isRegistered) {
512 |             return;
513 |         }
514 | 
515 |         $error = $this->system->getLastError();
516 |         if ($error && Misc::isLevelFatal($error['type'])) {
517 |             // If there was a fatal error,
518 |             // it was not handled in handleError yet.
519 |             $this->allowQuit = false;
520 |             $this->handleError(
521 |                 $error['type'],
522 |                 $error['message'],
523 |                 $error['file'],
524 |                 $error['line']
525 |             );
526 |         }
527 |     }
528 | 
529 | 
530 |     /**
531 |      * @param InspectorFactoryInterface $factory
532 |      *
533 |      * @return void
534 |      */
535 |     public function setInspectorFactory(InspectorFactoryInterface $factory)
536 |     {
537 |         $this->inspectorFactory = $factory;
538 |     }
539 | 
540 |     public function addFrameFilter($filterCallback)
541 |     {
542 |         if (!is_callable($filterCallback)) {
543 |             throw new \InvalidArgumentException(sprintf(
544 |                 "A frame filter must be of type callable, %s type given.",
545 |                 gettype($filterCallback)
546 |             ));
547 |         }
548 | 
549 |         $this->frameFilters[] = $filterCallback;
550 |         return $this;
551 |     }
552 | 
553 |     /**
554 |      * @param Throwable $exception
555 |      *
556 |      * @return InspectorInterface
557 |      */
558 |     private function getInspector($exception)
559 |     {
560 |         return $this->inspectorFactory->create($exception);
561 |     }
562 | 
563 |     /**
564 |      * Resolves the giving handler.
565 |      *
566 |      * @param callable|HandlerInterface $handler
567 |      *
568 |      * @return HandlerInterface
569 |      *
570 |      * @throws InvalidArgumentException
571 |      */
572 |     private function resolveHandler($handler)
573 |     {
574 |         if (is_callable($handler)) {
575 |             $handler = new CallbackHandler($handler);
576 |         }
577 | 
578 |         if (!$handler instanceof HandlerInterface) {
579 |             throw new InvalidArgumentException(
580 |                 "Handler must be a callable, or instance of "
581 |                 . "Whoops\\Handler\\HandlerInterface"
582 |             );
583 |         }
584 | 
585 |         return $handler;
586 |     }
587 | 
588 |     /**
589 |      * Echo something to the browser.
590 |      *
591 |      * @param string $output
592 |      *
593 |      * @return Run
594 |      */
595 |     private function writeToOutputNow($output)
596 |     {
597 |         if ($this->sendHttpCode() && Misc::canSendHeaders()) {
598 |             $this->system->setHttpResponseCode(
599 |                 $this->sendHttpCode()
600 |             );
601 |         }
602 | 
603 |         echo $output;
604 | 
605 |         return $this;
606 |     }
607 | }
608 | 


--------------------------------------------------------------------------------
/src/Whoops/RunInterface.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 |  * Whoops - php errors for cool kids
  4 |  * @author Filipe Dobreira <http://github.com/filp>
  5 |  */
  6 | 
  7 | namespace Whoops;
  8 | 
  9 | use InvalidArgumentException;
 10 | use Whoops\Exception\ErrorException;
 11 | use Whoops\Handler\HandlerInterface;
 12 | 
 13 | interface RunInterface
 14 | {
 15 |     const EXCEPTION_HANDLER = "handleException";
 16 |     const ERROR_HANDLER     = "handleError";
 17 |     const SHUTDOWN_HANDLER  = "handleShutdown";
 18 | 
 19 |     /**
 20 |      * Pushes a handler to the end of the stack
 21 |      *
 22 |      * @throws InvalidArgumentException  If argument is not callable or instance of HandlerInterface
 23 |      * @param  Callable|HandlerInterface $handler
 24 |      * @return Run
 25 |      */
 26 |     public function pushHandler($handler);
 27 | 
 28 |     /**
 29 |      * Removes the last handler in the stack and returns it.
 30 |      * Returns null if there"s nothing else to pop.
 31 |      *
 32 |      * @return null|HandlerInterface
 33 |      */
 34 |     public function popHandler();
 35 | 
 36 |     /**
 37 |      * Returns an array with all handlers, in the
 38 |      * order they were added to the stack.
 39 |      *
 40 |      * @return array
 41 |      */
 42 |     public function getHandlers();
 43 | 
 44 |     /**
 45 |      * Clears all handlers in the handlerStack, including
 46 |      * the default PrettyPage handler.
 47 |      *
 48 |      * @return Run
 49 |      */
 50 |     public function clearHandlers();
 51 | 
 52 |     /**
 53 |      * @return array<callable>
 54 |      */
 55 |     public function getFrameFilters();
 56 | 
 57 |     /**
 58 |      * @return Run
 59 |      */
 60 |     public function clearFrameFilters();
 61 | 
 62 |     /**
 63 |      * Registers this instance as an error handler.
 64 |      *
 65 |      * @return Run
 66 |      */
 67 |     public function register();
 68 | 
 69 |     /**
 70 |      * Unregisters all handlers registered by this Whoops\Run instance
 71 |      *
 72 |      * @return Run
 73 |      */
 74 |     public function unregister();
 75 | 
 76 |     /**
 77 |      * Should Whoops allow Handlers to force the script to quit?
 78 |      *
 79 |      * @param  bool|int $exit
 80 |      * @return bool
 81 |      */
 82 |     public function allowQuit($exit = null);
 83 | 
 84 |     /**
 85 |      * Silence particular errors in particular files
 86 |      *
 87 |      * @param  array|string $patterns List or a single regex pattern to match
 88 |      * @param  int          $levels   Defaults to E_STRICT | E_DEPRECATED
 89 |      * @return \Whoops\Run
 90 |      */
 91 |     public function silenceErrorsInPaths($patterns, $levels = 10240);
 92 | 
 93 |     /**
 94 |      * Should Whoops send HTTP error code to the browser if possible?
 95 |      * Whoops will by default send HTTP code 500, but you may wish to
 96 |      * use 502, 503, or another 5xx family code.
 97 |      *
 98 |      * @param bool|int $code
 99 |      * @return int|false
100 |      */
101 |     public function sendHttpCode($code = null);
102 | 
103 |     /**
104 |      * Should Whoops exit with a specific code on the CLI if possible?
105 |      * Whoops will exit with 1 by default, but you can specify something else.
106 |      *
107 |      * @param int $code
108 |      * @return int
109 |      */
110 |     public function sendExitCode($code = null);
111 | 
112 |     /**
113 |      * Should Whoops push output directly to the client?
114 |      * If this is false, output will be returned by handleException
115 |      *
116 |      * @param  bool|int $send
117 |      * @return bool
118 |      */
119 |     public function writeToOutput($send = null);
120 | 
121 |     /**
122 |      * Handles an exception, ultimately generating a Whoops error
123 |      * page.
124 |      *
125 |      * @param  \Throwable $exception
126 |      * @return string     Output generated by handlers
127 |      */
128 |     public function handleException($exception);
129 | 
130 |     /**
131 |      * Converts generic PHP errors to \ErrorException
132 |      * instances, before passing them off to be handled.
133 |      *
134 |      * This method MUST be compatible with set_error_handler.
135 |      *
136 |      * @param int    $level
137 |      * @param string $message
138 |      * @param string $file
139 |      * @param int    $line
140 |      *
141 |      * @return bool
142 |      * @throws ErrorException
143 |      */
144 |     public function handleError($level, $message, $file = null, $line = null);
145 | 
146 |     /**
147 |      * Special case to deal with Fatal errors and the like.
148 |      */
149 |     public function handleShutdown();
150 | 
151 |     /**
152 |      * Registers a filter callback in the frame filters stack.
153 |      *
154 |      * @param callable $filterCallback
155 |      * @return \Whoops\Run
156 |      */
157 |     public function addFrameFilter($filterCallback);
158 | }
159 | 


--------------------------------------------------------------------------------
/src/Whoops/Util/HtmlDumperOutput.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Util;
 8 | 
 9 | /**
10 |  * Used as output callable for Symfony\Component\VarDumper\Dumper\HtmlDumper::dump()
11 |  *
12 |  * @see TemplateHelper::dump()
13 |  */
14 | class HtmlDumperOutput
15 | {
16 |     private $output;
17 | 
18 |     public function __invoke($line, $depth)
19 |     {
20 |         // A negative depth means "end of dump"
21 |         if ($depth >= 0) {
22 |             // Adds a two spaces indentation to the line
23 |             $this->output .= str_repeat('  ', $depth) . $line . "\n";
24 |         }
25 |     }
26 | 
27 |     public function getOutput()
28 |     {
29 |         return $this->output;
30 |     }
31 | 
32 |     public function clear()
33 |     {
34 |         $this->output = null;
35 |     }
36 | }
37 | 


--------------------------------------------------------------------------------
/src/Whoops/Util/Misc.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | /**
 3 |  * Whoops - php errors for cool kids
 4 |  * @author Filipe Dobreira <http://github.com/filp>
 5 |  */
 6 | 
 7 | namespace Whoops\Util;
 8 | 
 9 | class Misc
10 | {
11 |     /**
12 |      * Can we at this point in time send HTTP headers?
13 |      *
14 |      * Currently this checks if we are even serving an HTTP request,
15 |      * as opposed to running from a command line.
16 |      *
17 |      * If we are serving an HTTP request, we check if it's not too late.
18 |      *
19 |      * @return bool
20 |      */
21 |     public static function canSendHeaders()
22 |     {
23 |         return isset($_SERVER["REQUEST_URI"]) && !headers_sent();
24 |     }
25 | 
26 |     public static function isAjaxRequest()
27 |     {
28 |         return (
29 |             !empty($_SERVER['HTTP_X_REQUESTED_WITH'])
30 |             && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
31 |     }
32 | 
33 |     /**
34 |      * Check, if possible, that this execution was triggered by a command line.
35 |      * @return bool
36 |      */
37 |     public static function isCommandLine()
38 |     {
39 |         return PHP_SAPI == 'cli';
40 |     }
41 | 
42 |     /**
43 |      * Translate ErrorException code into the represented constant.
44 |      *
45 |      * @param int $error_code
46 |      * @return string
47 |      */
48 |     public static function translateErrorCode($error_code)
49 |     {
50 |         $constants = get_defined_constants(true);
51 |         if (array_key_exists('Core', $constants)) {
52 |             foreach ($constants['Core'] as $constant => $value) {
53 |                 if (substr($constant, 0, 2) == 'E_' && $value == $error_code) {
54 |                     return $constant;
55 |                 }
56 |             }
57 |         }
58 |         return "E_UNKNOWN";
59 |     }
60 |     
61 |     /**
62 |      * Determine if an error level is fatal (halts execution)
63 |      *
64 |      * @param int $level
65 |      * @return bool
66 |      */
67 |     public static function isLevelFatal($level)
68 |     {
69 |         $errors = E_ERROR;
70 |         $errors |= E_PARSE;
71 |         $errors |= E_CORE_ERROR;
72 |         $errors |= E_CORE_WARNING;
73 |         $errors |= E_COMPILE_ERROR;
74 |         $errors |= E_COMPILE_WARNING;
75 |         return ($level & $errors) > 0;
76 |     }
77 | }
78 | 


--------------------------------------------------------------------------------
/src/Whoops/Util/SystemFacade.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 |  * Whoops - php errors for cool kids
  4 |  * @author Filipe Dobreira <http://github.com/filp>
  5 |  */
  6 | 
  7 | namespace Whoops\Util;
  8 | 
  9 | class SystemFacade
 10 | {
 11 |     /**
 12 |      * Turns on output buffering.
 13 |      *
 14 |      * @return bool
 15 |      */
 16 |     public function startOutputBuffering()
 17 |     {
 18 |         return ob_start();
 19 |     }
 20 | 
 21 |     /**
 22 |      * @param callable $handler
 23 |      * @param int      $types
 24 |      *
 25 |      * @return callable|null
 26 |      */
 27 |     public function setErrorHandler(callable $handler, $types = 'use-php-defaults')
 28 |     {
 29 |         // Since PHP 5.4 the constant E_ALL contains all errors (even E_STRICT)
 30 |         if ($types === 'use-php-defaults') {
 31 |             $types = E_ALL;
 32 |         }
 33 |         return set_error_handler($handler, $types);
 34 |     }
 35 | 
 36 |     /**
 37 |      * @param callable $handler
 38 |      *
 39 |      * @return callable|null
 40 |      */
 41 |     public function setExceptionHandler(callable $handler)
 42 |     {
 43 |         return set_exception_handler($handler);
 44 |     }
 45 | 
 46 |     /**
 47 |      * @return void
 48 |      */
 49 |     public function restoreExceptionHandler()
 50 |     {
 51 |         restore_exception_handler();
 52 |     }
 53 | 
 54 |     /**
 55 |      * @return void
 56 |      */
 57 |     public function restoreErrorHandler()
 58 |     {
 59 |         restore_error_handler();
 60 |     }
 61 | 
 62 |     /**
 63 |      * @param callable $function
 64 |      *
 65 |      * @return void
 66 |      */
 67 |     public function registerShutdownFunction(callable $function)
 68 |     {
 69 |         register_shutdown_function($function);
 70 |     }
 71 | 
 72 |     /**
 73 |      * @return string|false
 74 |      */
 75 |     public function cleanOutputBuffer()
 76 |     {
 77 |         return ob_get_clean();
 78 |     }
 79 | 
 80 |     /**
 81 |      * @return int
 82 |      */
 83 |     public function getOutputBufferLevel()
 84 |     {
 85 |         return ob_get_level();
 86 |     }
 87 | 
 88 |     /**
 89 |      * @return bool
 90 |      */
 91 |     public function endOutputBuffering()
 92 |     {
 93 |         return ob_end_clean();
 94 |     }
 95 | 
 96 |     /**
 97 |      * @return void
 98 |      */
 99 |     public function flushOutputBuffer()
100 |     {
101 |         flush();
102 |     }
103 | 
104 |     /**
105 |      * @return int
106 |      */
107 |     public function getErrorReportingLevel()
108 |     {
109 |         return error_reporting();
110 |     }
111 | 
112 |     /**
113 |      * @return array|null
114 |      */
115 |     public function getLastError()
116 |     {
117 |         return error_get_last();
118 |     }
119 | 
120 |     /**
121 |      * @param int $httpCode
122 |      *
123 |      * @return int
124 |      */
125 |     public function setHttpResponseCode($httpCode)
126 |     {
127 |         if (!headers_sent()) {
128 |             // Ensure that no 'location' header is present as otherwise this
129 |             // will override the HTTP code being set here, and mask the
130 |             // expected error page.
131 |             header_remove('location');
132 |         }
133 | 
134 |         return http_response_code($httpCode);
135 |     }
136 | 
137 |     /**
138 |      * @param int $exitStatus
139 |      */
140 |     public function stopExecution($exitStatus)
141 |     {
142 |         exit($exitStatus);
143 |     }
144 | }
145 | 


--------------------------------------------------------------------------------
/src/Whoops/Util/TemplateHelper.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | /**
  3 |  * Whoops - php errors for cool kids
  4 |  * @author Filipe Dobreira <http://github.com/filp>
  5 |  */
  6 | 
  7 | namespace Whoops\Util;
  8 | 
  9 | use Symfony\Component\VarDumper\Caster\Caster;
 10 | use Symfony\Component\VarDumper\Cloner\AbstractCloner;
 11 | use Symfony\Component\VarDumper\Cloner\VarCloner;
 12 | use Symfony\Component\VarDumper\Dumper\HtmlDumper;
 13 | use Whoops\Exception\Frame;
 14 | 
 15 | /**
 16 |  * Exposes useful tools for working with/in templates
 17 |  */
 18 | class TemplateHelper
 19 | {
 20 |     /**
 21 |      * An array of variables to be passed to all templates
 22 |      * @var array
 23 |      */
 24 |     private $variables = [];
 25 | 
 26 |     /**
 27 |      * @var HtmlDumper
 28 |      */
 29 |     private $htmlDumper;
 30 | 
 31 |     /**
 32 |      * @var HtmlDumperOutput
 33 |      */
 34 |     private $htmlDumperOutput;
 35 | 
 36 |     /**
 37 |      * @var AbstractCloner
 38 |      */
 39 |     private $cloner;
 40 | 
 41 |     /**
 42 |      * @var string
 43 |      */
 44 |     private $applicationRootPath;
 45 | 
 46 |     public function __construct()
 47 |     {
 48 |         // root path for ordinary composer projects
 49 |         $this->applicationRootPath = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__))))));
 50 |     }
 51 | 
 52 |     /**
 53 |      * Escapes a string for output in an HTML document
 54 |      *
 55 |      * @param  string $raw
 56 |      * @return string
 57 |      */
 58 |     public function escape($raw)
 59 |     {
 60 |         $flags = ENT_QUOTES;
 61 | 
 62 |         // HHVM has all constants defined, but only ENT_IGNORE
 63 |         // works at the moment
 64 |         if (defined("ENT_SUBSTITUTE") && !defined("HHVM_VERSION")) {
 65 |             $flags |= ENT_SUBSTITUTE;
 66 |         } else {
 67 |             // This is for 5.3.
 68 |             // The documentation warns of a potential security issue,
 69 |             // but it seems it does not apply in our case, because
 70 |             // we do not blacklist anything anywhere.
 71 |             $flags |= ENT_IGNORE;
 72 |         }
 73 | 
 74 |         $raw = str_replace(chr(9), '    ', $raw);
 75 | 
 76 |         return htmlspecialchars($raw, $flags, "UTF-8");
 77 |     }
 78 | 
 79 |     /**
 80 |      * Escapes a string for output in an HTML document, but preserves
 81 |      * URIs within it, and converts them to clickable anchor elements.
 82 |      *
 83 |      * @param  string $raw
 84 |      * @return string
 85 |      */
 86 |     public function escapeButPreserveUris($raw)
 87 |     {
 88 |         $escaped = $this->escape($raw);
 89 |         return preg_replace(
 90 |             "@([A-z]+?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@",
 91 |             "<a href=\"$1\" target=\"_blank\" rel=\"noreferrer noopener\">$1</a>",
 92 |             $escaped
 93 |         );
 94 |     }
 95 | 
 96 |     /**
 97 |      * Makes sure that the given string breaks on the delimiter.
 98 |      *
 99 |      * @param  string $delimiter
100 |      * @param  string $s
101 |      * @return string
102 |      */
103 |     public function breakOnDelimiter($delimiter, $s)
104 |     {
105 |         $parts = explode($delimiter, $s);
106 |         foreach ($parts as &$part) {
107 |             $part = '<span class="delimiter">' . $part . '</span>';
108 |         }
109 | 
110 |         return implode($delimiter, $parts);
111 |     }
112 | 
113 |     /**
114 |      * Replace the part of the path that all files have in common.
115 |      *
116 |      * @param  string $path
117 |      * @return string
118 |      */
119 |     public function shorten($path)
120 |     {
121 |         if ($this->applicationRootPath != "/") {
122 |             $path = str_replace($this->applicationRootPath, '&hellip;', $path);
123 |         }
124 | 
125 |         return $path;
126 |     }
127 | 
128 |     private function getDumper()
129 |     {
130 |         if (!$this->htmlDumper && class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) {
131 |             $this->htmlDumperOutput = new HtmlDumperOutput();
132 |             // re-use the same var-dumper instance, so it won't re-render the global styles/scripts on each dump.
133 |             $this->htmlDumper = new HtmlDumper($this->htmlDumperOutput);
134 | 
135 |             $styles = [
136 |                 'default' => 'color:#FFFFFF; line-height:normal; font:12px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace !important; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: normal',
137 |                 'num' => 'color:#BCD42A',
138 |                 'const' => 'color: #4bb1b1;',
139 |                 'str' => 'color:#BCD42A',
140 |                 'note' => 'color:#ef7c61',
141 |                 'ref' => 'color:#A0A0A0',
142 |                 'public' => 'color:#FFFFFF',
143 |                 'protected' => 'color:#FFFFFF',
144 |                 'private' => 'color:#FFFFFF',
145 |                 'meta' => 'color:#FFFFFF',
146 |                 'key' => 'color:#BCD42A',
147 |                 'index' => 'color:#ef7c61',
148 |             ];
149 |             $this->htmlDumper->setStyles($styles);
150 |         }
151 | 
152 |         return $this->htmlDumper;
153 |     }
154 | 
155 |     /**
156 |      * Format the given value into a human readable string.
157 |      *
158 |      * @param  mixed $value
159 |      * @return string
160 |      */
161 |     public function dump($value)
162 |     {
163 |         $dumper = $this->getDumper();
164 | 
165 |         if ($dumper) {
166 |             // re-use the same DumpOutput instance, so it won't re-render the global styles/scripts on each dump.
167 |             // exclude verbose information (e.g. exception stack traces)
168 |             if (class_exists('Symfony\Component\VarDumper\Caster\Caster')) {
169 |                 $cloneVar = $this->getCloner()->cloneVar($value, Caster::EXCLUDE_VERBOSE);
170 |                 // Symfony VarDumper 2.6 Caster class dont exist.
171 |             } else {
172 |                 $cloneVar = $this->getCloner()->cloneVar($value);
173 |             }
174 | 
175 |             $dumper->dump(
176 |                 $cloneVar,
177 |                 $this->htmlDumperOutput
178 |             );
179 | 
180 |             $output = $this->htmlDumperOutput->getOutput();
181 |             $this->htmlDumperOutput->clear();
182 | 
183 |             return $output;
184 |         }
185 | 
186 |         return htmlspecialchars(print_r($value, true));
187 |     }
188 | 
189 |     /**
190 |      * Format the args of the given Frame as a human readable html string
191 |      *
192 |      * @param  Frame $frame
193 |      * @return string the rendered html
194 |      */
195 |     public function dumpArgs(Frame $frame)
196 |     {
197 |         // we support frame args only when the optional dumper is available
198 |         if (!$this->getDumper()) {
199 |             return '';
200 |         }
201 | 
202 |         $html = '';
203 |         $numFrames = count($frame->getArgs());
204 | 
205 |         if ($numFrames > 0) {
206 |             $html = '<ol class="linenums">';
207 |             foreach ($frame->getArgs() as $j => $frameArg) {
208 |                 $html .= '<li>'. $this->dump($frameArg) .'</li>';
209 |             }
210 |             $html .= '</ol>';
211 |         }
212 | 
213 |         return $html;
214 |     }
215 | 
216 |     /**
217 |      * Convert a string to a slug version of itself
218 |      *
219 |      * @param  string $original
220 |      * @return string
221 |      */
222 |     public function slug($original)
223 |     {
224 |         $slug = str_replace(" ", "-", $original);
225 |         $slug = preg_replace('/[^\w\d\-\_]/i', '', $slug);
226 |         return strtolower($slug);
227 |     }
228 | 
229 |     /**
230 |      * Given a template path, render it within its own scope. This
231 |      * method also accepts an array of additional variables to be
232 |      * passed to the template.
233 |      *
234 |      * @param string $template
235 |      */
236 |     public function render($template, ?array $additionalVariables = null)
237 |     {
238 |         $variables = $this->getVariables();
239 | 
240 |         // Pass the helper to the template:
241 |         $variables["tpl"] = $this;
242 | 
243 |         if ($additionalVariables !== null) {
244 |             $variables = array_replace($variables, $additionalVariables);
245 |         }
246 | 
247 |         call_user_func(function () {
248 |             extract(func_get_arg(1));
249 |             require func_get_arg(0);
250 |         }, $template, $variables);
251 |     }
252 | 
253 |     /**
254 |      * Sets the variables to be passed to all templates rendered
255 |      * by this template helper.
256 |      */
257 |     public function setVariables(array $variables)
258 |     {
259 |         $this->variables = $variables;
260 |     }
261 | 
262 |     /**
263 |      * Sets a single template variable, by its name:
264 |      *
265 |      * @param string $variableName
266 |      * @param mixed  $variableValue
267 |      */
268 |     public function setVariable($variableName, $variableValue)
269 |     {
270 |         $this->variables[$variableName] = $variableValue;
271 |     }
272 | 
273 |     /**
274 |      * Gets a single template variable, by its name, or
275 |      * $defaultValue if the variable does not exist
276 |      *
277 |      * @param  string $variableName
278 |      * @param  mixed  $defaultValue
279 |      * @return mixed
280 |      */
281 |     public function getVariable($variableName, $defaultValue = null)
282 |     {
283 |         return isset($this->variables[$variableName]) ?
284 |             $this->variables[$variableName] : $defaultValue;
285 |     }
286 | 
287 |     /**
288 |      * Unsets a single template variable, by its name
289 |      *
290 |      * @param string $variableName
291 |      */
292 |     public function delVariable($variableName)
293 |     {
294 |         unset($this->variables[$variableName]);
295 |     }
296 | 
297 |     /**
298 |      * Returns all variables for this helper
299 |      *
300 |      * @return array
301 |      */
302 |     public function getVariables()
303 |     {
304 |         return $this->variables;
305 |     }
306 | 
307 |     /**
308 |      * Set the cloner used for dumping variables.
309 |      *
310 |      * @param AbstractCloner $cloner
311 |      */
312 |     public function setCloner($cloner)
313 |     {
314 |         $this->cloner = $cloner;
315 |     }
316 | 
317 |     /**
318 |      * Get the cloner used for dumping variables.
319 |      *
320 |      * @return AbstractCloner
321 |      */
322 |     public function getCloner()
323 |     {
324 |         if (!$this->cloner) {
325 |             $this->cloner = new VarCloner();
326 |         }
327 |         return $this->cloner;
328 |     }
329 | 
330 |     /**
331 |      * Set the application root path.
332 |      *
333 |      * @param string $applicationRootPath
334 |      */
335 |     public function setApplicationRootPath($applicationRootPath)
336 |     {
337 |         $this->applicationRootPath = $applicationRootPath;
338 |     }
339 | 
340 |     /**
341 |      * Return the application root path.
342 |      *
343 |      * @return string
344 |      */
345 |     public function getApplicationRootPath()
346 |     {
347 |         return $this->applicationRootPath;
348 |     }
349 | }
350 | 


--------------------------------------------------------------------------------