2013-03-20 17:09:46 +00:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\Debug ;
use Symfony\Component\Debug\Exception\FlattenException ;
2014-05-20 08:49:05 +01:00
use Symfony\Component\Debug\Exception\OutOfMemoryException ;
2016-09-19 13:07:31 +01:00
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter ;
2013-03-20 17:09:46 +00:00
/**
* ExceptionHandler converts an exception to a Response object .
*
* It is mostly useful in debug mode to replace the default PHP / XDebug
* output with something prettier and more useful .
*
* As this class is mainly used during Kernel boot , where nothing is yet
* available , the Response content is always HTML .
*
* @ author Fabien Potencier < fabien @ symfony . com >
2014-06-11 10:41:20 +01:00
* @ author Nicolas Grekas < p @ tchwork . com >
2013-03-20 17:09:46 +00:00
*/
2014-05-19 11:15:59 +01:00
class ExceptionHandler
2013-03-20 17:09:46 +00:00
{
private $debug ;
2015-03-11 13:18:58 +00:00
private $charset ;
2014-05-19 11:15:59 +01:00
private $handler ;
2014-06-11 15:52:49 +01:00
private $caughtBuffer ;
private $caughtLength ;
2014-09-25 18:46:28 +01:00
private $fileLinkFormat ;
2013-03-20 17:09:46 +00:00
2015-03-11 13:18:58 +00:00
public function __construct ( $debug = true , $charset = null , $fileLinkFormat = null )
2013-03-20 17:09:46 +00:00
{
$this -> debug = $debug ;
2015-03-11 13:18:58 +00:00
$this -> charset = $charset ? : ini_get ( 'default_charset' ) ? : 'UTF-8' ;
2018-04-30 13:25:22 +01:00
$this -> fileLinkFormat = $fileLinkFormat ;
2013-03-20 17:09:46 +00:00
}
/**
2013-03-21 07:33:19 +00:00
* Registers the exception handler .
2013-03-20 17:09:46 +00:00
*
2015-03-11 13:18:58 +00:00
* @ param bool $debug Enable / disable debug mode , where the stack trace is displayed
* @ param string | null $charset The charset used by exception messages
* @ param string | null $fileLinkFormat The IDE link template
2013-03-20 17:09:46 +00:00
*
2016-12-26 07:50:27 +00:00
* @ return static
2013-03-20 17:09:46 +00:00
*/
2015-03-11 13:18:58 +00:00
public static function register ( $debug = true , $charset = null , $fileLinkFormat = null )
2013-03-20 17:09:46 +00:00
{
2015-03-11 13:18:58 +00:00
$handler = new static ( $debug , $charset , $fileLinkFormat );
2013-03-20 17:09:46 +00:00
2014-05-26 11:29:25 +01:00
$prev = set_exception_handler ( array ( $handler , 'handle' ));
if ( is_array ( $prev ) && $prev [ 0 ] instanceof ErrorHandler ) {
restore_exception_handler ();
$prev [ 0 ] -> setExceptionHandler ( array ( $handler , 'handle' ));
}
2013-03-20 17:09:46 +00:00
return $handler ;
}
2014-05-19 11:15:59 +01:00
/**
* Sets a user exception handler .
*
* @ param callable $handler An handler that will be called on Exception
2014-05-20 08:49:05 +01:00
*
* @ return callable | null The previous exception handler if any
2014-05-19 11:15:59 +01:00
*/
2015-04-12 20:00:20 +01:00
public function setHandler ( callable $handler = null )
2014-05-19 11:15:59 +01:00
{
$old = $this -> handler ;
$this -> handler = $handler ;
return $old ;
}
2014-09-25 18:46:28 +01:00
/**
* Sets the format for links to source files .
*
2017-03-28 22:38:21 +01:00
* @ param string | FileLinkFormatter $fileLinkFormat The format for links to source files
2014-09-25 18:46:28 +01:00
*
2016-06-28 06:50:50 +01:00
* @ return string The previous file link format
2014-09-25 18:46:28 +01:00
*/
2016-08-31 09:43:03 +01:00
public function setFileLinkFormat ( $fileLinkFormat )
2014-09-25 18:46:28 +01:00
{
$old = $this -> fileLinkFormat ;
2016-08-31 09:43:03 +01:00
$this -> fileLinkFormat = $fileLinkFormat ;
2014-09-25 18:46:28 +01:00
return $old ;
}
2013-03-20 17:09:46 +00:00
/**
2013-03-21 07:03:05 +00:00
* Sends a response for the given Exception .
*
2014-06-11 10:41:20 +01:00
* To be as fail - safe as possible , the exception is first handled
* by our simple exception handler , then by the user exception handler .
* The latter takes precedence and any output from the former is cancelled ,
* if and only if nothing bad happens in this handling path .
2013-03-20 17:09:46 +00:00
*/
public function handle ( \Exception $exception )
{
2014-06-11 10:41:20 +01:00
if ( null === $this -> handler || $exception instanceof OutOfMemoryException ) {
2015-08-01 07:54:07 +01:00
$this -> sendPhpResponse ( $exception );
2014-05-20 08:49:05 +01:00
return ;
}
2014-06-11 15:52:49 +01:00
$caughtLength = $this -> caughtLength = 0 ;
2014-05-19 11:15:59 +01:00
2015-09-03 20:36:13 +01:00
ob_start ( function ( $buffer ) {
2014-12-03 22:04:33 +00:00
$this -> caughtBuffer = $buffer ;
return '' ;
});
2015-08-01 07:54:07 +01:00
$this -> sendPhpResponse ( $exception );
2014-06-11 15:52:49 +01:00
while ( null === $this -> caughtBuffer && ob_end_flush ()) {
// Empty loop, everything is in the condition
2014-05-19 11:15:59 +01:00
}
2014-06-11 15:52:49 +01:00
if ( isset ( $this -> caughtBuffer [ 0 ])) {
2015-09-03 20:36:13 +01:00
ob_start ( function ( $buffer ) {
2014-12-03 22:04:33 +00:00
if ( $this -> caughtLength ) {
// use substr_replace() instead of substr() for mbstring overloading resistance
$cleanBuffer = substr_replace ( $buffer , '' , 0 , $this -> caughtLength );
if ( isset ( $cleanBuffer [ 0 ])) {
$buffer = $cleanBuffer ;
}
}
return $buffer ;
});
2014-06-11 15:52:49 +01:00
echo $this -> caughtBuffer ;
$caughtLength = ob_get_length ();
2014-05-19 11:15:59 +01:00
}
2014-06-11 15:52:49 +01:00
$this -> caughtBuffer = null ;
2014-05-19 11:15:59 +01:00
2014-06-11 10:41:20 +01:00
try {
call_user_func ( $this -> handler , $exception );
2014-06-11 15:52:49 +01:00
$this -> caughtLength = $caughtLength ;
2014-06-11 10:41:20 +01:00
} catch ( \Exception $e ) {
2014-06-11 15:52:49 +01:00
if ( ! $caughtLength ) {
2014-06-11 10:41:20 +01:00
// All handlers failed. Let PHP handle that now.
throw $exception ;
2014-05-19 11:15:59 +01:00
}
2013-03-21 07:03:05 +00:00
}
}
/**
* Sends the error associated with the given Exception as a plain PHP response .
*
* This method uses plain PHP functions like header () and echo to output
* the response .
*
2015-09-07 14:09:39 +01:00
* @ param \Exception | FlattenException $exception An \Exception or FlattenException instance
2013-03-21 07:03:05 +00:00
*/
public function sendPhpResponse ( $exception )
{
if ( ! $exception instanceof FlattenException ) {
$exception = FlattenException :: create ( $exception );
}
2014-03-24 14:16:05 +00:00
if ( ! headers_sent ()) {
header ( sprintf ( 'HTTP/1.0 %s' , $exception -> getStatusCode ()));
foreach ( $exception -> getHeaders () as $name => $value ) {
header ( $name . ': ' . $value , false );
}
2015-03-11 15:56:34 +00:00
header ( 'Content-Type: text/html; charset=' . $this -> charset );
2013-03-21 07:03:05 +00:00
}
echo $this -> decorate ( $this -> getContent ( $exception ), $this -> getStylesheet ( $exception ));
2013-03-20 17:09:46 +00:00
}
2015-09-07 14:09:39 +01:00
/**
* Gets the full HTML content associated with the given exception .
*
* @ param \Exception | FlattenException $exception An \Exception or FlattenException instance
*
* @ return string The HTML content as a string
*/
public function getHtml ( $exception )
{
if ( ! $exception instanceof FlattenException ) {
$exception = FlattenException :: create ( $exception );
}
return $this -> decorate ( $this -> getContent ( $exception ), $this -> getStylesheet ( $exception ));
2013-03-20 17:09:46 +00:00
}
/**
* Gets the HTML content associated with the given exception .
*
* @ return string The content as a string
*/
public function getContent ( FlattenException $exception )
{
switch ( $exception -> getStatusCode ()) {
case 404 :
$title = 'Sorry, the page you are looking for could not be found.' ;
break ;
default :
$title = 'Whoops, looks like something went wrong.' ;
}
$content = '' ;
if ( $this -> debug ) {
try {
$count = count ( $exception -> getAllPrevious ());
$total = $count + 1 ;
foreach ( $exception -> toArray () as $position => $e ) {
$ind = $count - $position + 1 ;
2014-05-26 11:16:49 +01:00
$class = $this -> formatClass ( $e [ 'class' ]);
2015-03-11 13:18:58 +00:00
$message = nl2br ( $this -> escapeHtml ( $e [ 'message' ]));
2015-12-21 11:01:57 +00:00
$content .= sprintf ( <<< 'EOF'
2017-05-21 19:56:28 +01:00
< div class = " trace trace-as-html " >
< table class = " trace-details " >
< thead class = " trace-head " >< tr >< th >
< h3 class = " trace-class " >
< span class = " text-muted " > ( % d /% d ) </ span >
< span class = " exception_title " >% s </ span >
</ h3 >
< p class = " break-long-words trace-message " >% s </ p >
</ th ></ tr ></ thead >
< tbody >
2013-03-20 17:09:46 +00:00
EOF
2017-05-21 19:56:28 +01:00
, $ind , $total , $class , $message );
2013-03-20 17:09:46 +00:00
foreach ( $e [ 'trace' ] as $trace ) {
2017-05-21 19:56:28 +01:00
$content .= '<tr><td>' ;
2013-03-20 17:09:46 +00:00
if ( $trace [ 'function' ]) {
2017-05-21 19:56:28 +01:00
$content .= sprintf ( 'at <span class="trace-class">%s</span><span class="trace-type">%s</span><span class="trace-method">%s</span>(<span class="trace-arguments">%s</span>)' , $this -> formatClass ( $trace [ 'class' ]), $trace [ 'type' ], $trace [ 'function' ], $this -> formatArgs ( $trace [ 'args' ]));
2013-03-20 17:09:46 +00:00
}
if ( isset ( $trace [ 'file' ]) && isset ( $trace [ 'line' ])) {
2014-05-26 11:16:49 +01:00
$content .= $this -> formatPath ( $trace [ 'file' ], $trace [ 'line' ]);
2013-03-20 17:09:46 +00:00
}
2017-05-21 19:56:28 +01:00
$content .= " </td></tr> \n " ;
2013-03-20 17:09:46 +00:00
}
2017-05-21 19:56:28 +01:00
$content .= " </tbody> \n </table> \n </div> \n " ;
2013-03-20 17:09:46 +00:00
}
} catch ( \Exception $e ) {
// something nasty happened and we cannot throw an exception anymore
if ( $this -> debug ) {
2015-03-11 13:18:58 +00:00
$title = sprintf ( 'Exception thrown when handling an exception (%s: %s)' , get_class ( $e ), $this -> escapeHtml ( $e -> getMessage ()));
2013-03-20 17:09:46 +00:00
} else {
$title = 'Whoops, looks like something went wrong.' ;
}
}
}
2017-05-21 19:56:28 +01:00
$symfonyGhostImageContents = $this -> getSymfonyGhostAsSvg ();
2013-03-20 17:09:46 +00:00
return <<< EOF
2017-05-21 19:56:28 +01:00
< div class = " exception-summary " >
< div class = " container " >
< div class = " exception-message-wrapper " >
< h1 class = " break-long-words exception-message " > $title </ h1 >
< div class = " exception-illustration hidden-xs-down " > $symfonyGhostImageContents </ div >
</ div >
</ div >
</ div >
< div class = " container " >
2013-03-20 17:09:46 +00:00
$content
</ div >
EOF ;
}
/**
* Gets the stylesheet associated with the given exception .
*
* @ return string The stylesheet as a string
*/
public function getStylesheet ( FlattenException $exception )
{
2015-12-21 11:01:57 +00:00
return <<< 'EOF'
2017-05-21 19:56:28 +01:00
body { background - color : #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; }
a { cursor : pointer ; text - decoration : none ; }
a : hover { text - decoration : underline ; }
abbr [ title ] { border - bottom : none ; cursor : help ; text - decoration : none ; }
code , pre { font : 13 px / 1.5 Consolas , Monaco , Menlo , " Ubuntu Mono " , " Liberation Mono " , monospace ; }
table , tr , th , td { background : #FFF; border-collapse: collapse; vertical-align: top; }
table { background : #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; width: 100%; }
table th , table td { border : solid #E0E0E0; border-width: 1px 0; padding: 8px 10px; }
table th { background - color : #E0E0E0; font-weight: bold; text-align: left; }
. hidden - xs - down { display : none ; }
. block { display : block ; }
. break - long - words { - ms - word - break : break - all ; word - break : break - all ; word - break : break - word ; - webkit - hyphens : auto ; - moz - hyphens : auto ; hyphens : auto ; }
. text - muted { color : #999; }
. container { max - width : 1024 px ; margin : 0 auto ; padding : 0 15 px ; }
. container :: after { content : " " ; display : table ; clear : both ; }
. exception - summary { background : #B0413E; border-bottom: 2px solid rgba(0, 0, 0, 0.1); border-top: 1px solid rgba(0, 0, 0, .3); flex: 0 0 auto; margin-bottom: 30px; }
. exception - message - wrapper { display : flex ; align - items : center ; min - height : 70 px ; }
. exception - message { flex - grow : 1 ; padding : 30 px 0 ; }
. exception - message , . exception - message a { color : #FFF; font-size: 21px; font-weight: 400; margin: 0; }
. exception - message . long { font - size : 18 px ; }
2017-09-01 14:23:39 +01:00
. exception - message a { border - bottom : 1 px solid rgba ( 255 , 255 , 255 , 0.5 ); font - size : inherit ; text - decoration : none ; }
. exception - message a : hover { border - bottom - color : #ffffff; }
2017-05-21 19:56:28 +01:00
. exception - illustration { flex - basis : 111 px ; flex - shrink : 0 ; height : 66 px ; margin - left : 15 px ; opacity : . 7 ; }
. trace + . trace { margin - top : 30 px ; }
. trace - head . trace - class { color : #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; }
. trace - message { font - size : 14 px ; font - weight : normal ; margin : . 5 em 0 0 ; }
2017-08-08 14:39:42 +01:00
. trace - file - path , . trace - file - path a { color : #222; margin-top: 3px; font-size: 13px; }
2017-05-21 19:56:28 +01:00
. trace - class { color : #B0413E; }
. trace - type { padding : 0 2 px ; }
2017-08-08 14:39:42 +01:00
. trace - method { color : #B0413E; font-weight: bold; }
. trace - arguments { color : #777; font-weight: normal; padding-left: 2px; }
2017-05-21 19:56:28 +01:00
@ media ( min - width : 575 px ) {
. hidden - xs - down { display : initial ; }
2013-03-20 17:09:46 +00:00
}
EOF ;
}
private function decorate ( $content , $css )
{
return <<< EOF
<! DOCTYPE html >
< html >
< head >
2015-03-11 13:18:58 +00:00
< meta charset = " { $this -> charset } " />
2013-03-20 17:09:46 +00:00
< meta name = " robots " content = " noindex,nofollow " />
2017-05-21 19:56:28 +01:00
< style > $css </ style >
2013-03-20 17:09:46 +00:00
</ head >
2017-05-21 19:56:28 +01:00
< body >
2013-03-20 17:09:46 +00:00
$content
</ body >
</ html >
EOF ;
}
2014-05-26 11:16:49 +01:00
private function formatClass ( $class )
2013-03-20 17:09:46 +00:00
{
$parts = explode ( '\\' , $class );
2015-04-16 08:01:03 +01:00
return sprintf ( '<abbr title="%s">%s</abbr>' , $class , array_pop ( $parts ));
2013-03-20 17:09:46 +00:00
}
2014-05-26 11:16:49 +01:00
private function formatPath ( $path , $line )
{
2016-08-31 09:43:03 +01:00
$file = $this -> escapeHtml ( preg_match ( '#[^/\\\\]*+$#' , $path , $file ) ? $file [ 0 ] : $path );
2018-04-30 13:25:22 +01:00
$fmt = $this -> fileLinkFormat ? : ini_get ( 'xdebug.file_link_format' ) ? : get_cfg_var ( 'xdebug.file_link_format' );
if ( ! $fmt ) {
return sprintf ( '<span class="block trace-file-path">in <a title="%s%3$s"><strong>%s</strong>%s</a></span>' , $this -> escapeHtml ( $path ), $file , 0 < $line ? ' line ' . $line : '' );
}
if ( \is_string ( $fmt )) {
$i = strpos ( $f = $fmt , '&' , max ( strrpos ( $f , '%f' ), strrpos ( $f , '%l' ))) ? : strlen ( $f );
$fmt = array ( substr ( $f , 0 , $i )) + preg_split ( '/&([^>]++)>/' , substr ( $f , $i ), - 1 , PREG_SPLIT_DELIM_CAPTURE );
for ( $i = 1 ; isset ( $fmt [ $i ]); ++ $i ) {
if ( 0 === strpos ( $path , $k = $fmt [ $i ++ ])) {
$path = substr_replace ( $path , $fmt [ $i ], 0 , strlen ( $k ));
break ;
}
}
2014-05-26 11:16:49 +01:00
2018-04-30 13:25:22 +01:00
$link = strtr ( $fmt [ 0 ], array ( '%f' => $path , '%l' => $line ));
} else {
$link = $fmt -> format ( $path , $line );
2014-05-26 11:16:49 +01:00
}
2018-04-30 13:25:22 +01:00
return sprintf ( '<span class="block trace-file-path">in <a href="%s" title="Go to source"><strong>%s</string>%s</a></span>' , $this -> escapeHtml ( $link ), $file , 0 < $line ? ' line ' . $line : '' );
2014-05-26 11:16:49 +01:00
}
2013-03-20 17:09:46 +00:00
/**
* Formats an array as a string .
*
* @ param array $args The argument array
*
* @ return string
*/
private function formatArgs ( array $args )
{
$result = array ();
foreach ( $args as $key => $item ) {
if ( 'object' === $item [ 0 ]) {
2015-03-22 16:55:57 +00:00
$formattedValue = sprintf ( '<em>object</em>(%s)' , $this -> formatClass ( $item [ 1 ]));
2013-03-20 17:09:46 +00:00
} elseif ( 'array' === $item [ 0 ]) {
2015-03-21 10:51:07 +00:00
$formattedValue = sprintf ( '<em>array</em>(%s)' , is_array ( $item [ 1 ]) ? $this -> formatArgs ( $item [ 1 ]) : $item [ 1 ]);
2013-03-20 17:09:46 +00:00
} elseif ( 'null' === $item [ 0 ]) {
$formattedValue = '<em>null</em>' ;
} elseif ( 'boolean' === $item [ 0 ]) {
$formattedValue = '<em>' . strtolower ( var_export ( $item [ 1 ], true )) . '</em>' ;
} elseif ( 'resource' === $item [ 0 ]) {
$formattedValue = '<em>resource</em>' ;
} else {
2016-06-16 07:59:21 +01:00
$formattedValue = str_replace ( " \n " , '' , $this -> escapeHtml ( var_export ( $item [ 1 ], true )));
2013-03-20 17:09:46 +00:00
}
2017-07-26 15:58:46 +01:00
$result [] = is_int ( $key ) ? $formattedValue : sprintf ( " '%s' => %s " , $this -> escapeHtml ( $key ), $formattedValue );
2013-03-20 17:09:46 +00:00
}
return implode ( ', ' , $result );
}
2014-05-19 11:15:59 +01:00
2014-05-26 11:29:25 +01:00
/**
2015-05-20 01:38:50 +01:00
* HTML - encodes a string .
2014-05-26 11:29:25 +01:00
*/
2015-03-11 13:18:58 +00:00
private function escapeHtml ( $str )
2014-05-26 11:29:25 +01:00
{
2016-05-22 19:00:58 +01:00
return htmlspecialchars ( $str , ENT_COMPAT | ENT_SUBSTITUTE , $this -> charset );
2014-05-26 11:29:25 +01:00
}
2017-05-21 19:56:28 +01:00
private function getSymfonyGhostAsSvg ()
{
return ' < svg viewBox = " 0 0 136 81 " xmlns = " http://www.w3.org/2000/svg " fill - rule = " evenodd " clip - rule = " evenodd " stroke - linejoin = " round " stroke - miterlimit = " 1.414 " >< path d = " M92.358 20.403a23.168 23.168 0 0 1 9.003 1.881 23.67 23.67 0 0 1 5.197 3.079 24.257 24.257 0 0 1 3.457 3.296 24.771 24.771 0 0 1 5.042 9.396c.486 1.72.78 3.492.895 5.28l.008.142.028.158.015.246v13.875c.116.034.232.065.348.098.193.054.383.116.577.168.487.125.989.191 1.49.215.338.016.689.023 1.021-.059.021-.005.032-.029.048-.044l.095-.1c.243-.265.461-.552.663-.851.277-.408.523-.837.746-1.279l.042-.087c-.066-.012-.131-.026-.197-.04l-.099-.023a5.536 5.536 0 0 1-.694-.242 5.649 5.649 0 0 1-2.374-1.845 5.694 5.694 0 0 1-.824-1.594 6.514 6.514 0 0 1-.267-2.781c.045-.394.126-.779.233-1.159.079-.278.162-.562.307-.812.094-.163.129-.196.247-.341l.79-.882c.143-.143.174-.186.34-.303.249-.174.536-.289.834-.333.074-.011.15-.014.224-.02l1.188-.037c.173.004.217-.002.388.028s.211.05.375.105l.018.007c.059.026.119.05.176.079.151.076.179.104.313.2l.006-.021c.073-.187.084-.238.187-.41.077-.129.167-.249.27-.357.051-.054.108-.103.162-.154l1.124-.95c.14-.107.172-.14.327-.224.155-.085.199-.094.363-.154l.019-.006c.169-.043.211-.06.385-.077.174-.016.218-.007.392.003l1.446.158c.193.033.244.033.43.098.278.097.534.259.744.47.053.053.1.112.149.167l.923 1.158.149.213.028.054.017-.014.184-.125c.196-.104.196-.104.402-.184l1.386-.451c.064-.018.126-.038.19-.052.129-.028.259-.042.39-.043.16-.002.321.017.478.047.364.069.711.21 1.032.396.162.094.316.199.469.308.088.063.176.132.27.188l.021.011c.19.123.245.146.409.305.185.178.336.393.443.63.035.079.061.162.091.243l.439 1.428c.045.175.062.219.081.4.02.193.006.381-.015.573a7.79 7.79 0 0 1-.101.645c-.09.455-.212.901-.365 1.339-.128.366-.273.73-.445 1.077-.658 1.335-1.652 2.512-2.917 3.265a6.399 6.399 0 0 1-1.019.489 6.097 6.097 0 0 1-.631.203c-.226.058-.455.1-.686.134l-.096.012-.061.007c-.01.176-.022.352-.036.528-.034.39-.082.778-.153 1.163a14.258 14.258 0 0 1-.574 2.114c-.229.654-.484 1.306-.806 1.918a9.16 9.16 0 0 1-.386.656c-.219.348-.451.686-.697 1.013-.448.594-.946 1.148-1.521 1.614-.255.207-.52.397-.808.553-.9.489-1.919.648-2.921.735-.493.038-.986.059-1.478.099-.162.015-.324.033-.486.049-.145.011-.289.022-.434.03a15.768 15.768 0 0 1-2.778-.118c0 1.416.007 2.832-.001 4.248a9.737 9.737 0 0 1-.684 3.479 9.615 9.615 0 0 1-1.72 2.804 9.326 9.326 0 0 1-3.04 2.279 9.046 9.046 0 0 1-5.33.715 9.064 9.064 0 0 1-2.988-1.079 9.363 9.363 0 0 1-2.761-2.429 10.078 10.078 0 0 1-1.05 1.16 9.281 9.281 0 0 1-1.871 1.358 9.033 9.033 0 0 1-2.495.926 9.04 9.04 0 0 1-6.462-1.072 9.395 9.395 0 0 1-2.602-2.292l-.062-.08a10.896 10.896 0 0 1-.53.635 9.266 9.266 0 0 1-2.671 2.032 9.028 9.028 0 0 1-6.044.751 9.048 9.048 0 0 1-2.436-.934 9.343 9.343 0 0 1-2.286-1.803 9.572 9.572 0 0 1-1.783-2.757 9.705 9.705 0 0 1-.773-3.693V67.244c-.157.024-.314.047-.472.067-.487.06-.977.103-1.469.109-.313.004-.627-.009-.94-.028-.426-.025-.85-.065-1.273-.125-1.833-.264-3.65-.92-5.109-2.117a8.172 8.172 0 0 1-1.064-1.049 10.155 10.155 0 0 1-.878-1.236 15.277 15.277 0 0 1-.7-1.274 20.835 20.835 0 0 1-1.889-6.194l-.018-.142-.008-.061a6.47 6.47 0 0 1-.99-.297 6.135 6.135 0 0 1-.61-.285 6.587 6.587 0 0 1-.889-.562c-1.228-.924-2.124-2.259-2.668-3.711a9.947 9.947 0 0 1-.307-.99 10.288 10.288 0 0 1-.318-1.923c-.009-.147-.011-.293-.015-.44v-.037c.008-.175.004-.22.037-.393.033-.173.053-.213.11-.378l.561-1.417c.031-.068.06-.139.095-.206a2.028 2.028 0 0 1 .771-.803c.093-.054.194-.095.289-.145l.311-.179c.352-.194.714-.358 1.107-.44.213-.044.426-.061.643-.061l.034.001c.177.014.223.01.396.052.174.041.214.065.379.132l1.347.635c.073.04.15.076.221.121.142.091.272.2.388.325.154.166.176.222.297.414l.022.047.722-.762.168-.158c.165-.122.202-.161.385-.253.206-.102.429-.168.656-.193.076-.008.152-.008.228-.011l1.46.013c.177.011.223.007.397.046.175.038.215.061.381.126l.018.008c.154.08.196.094.338.196.142.102.169.137.294.259l.853.912.152-.067.191-.063.019-.005.196-.042c.177-.019.222-.031.401-.022.066.003.133.013.199.02l1.185.182c.073.016.147.027.219.047.288.08.558.227.784.428.151.135.177.181.303.339l.714 1.0
}
2013-03-20 17:09:46 +00:00
}