1
0
mirror of https://gitlab.com/depesz/explain.depesz.com.git synced 2025-10-31 00:07:57 +02:00

new version of explain.depesz.com, by metys - llewandowski.pl

This commit is contained in:
depesz
2011-03-10 15:19:34 +00:00
commit 046da81e8c
20 changed files with 1886 additions and 0 deletions

23
explain.pl Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env perl
use strict;
use warnings;
use File::Basename 'dirname';
use File::Spec;
use English -no_match_vars;
use lib File::Spec->catfile( File::Spec->splitdir( dirname( __FILE__ ) ), 'lib' );
eval 'use Mojolicious::Commands';
die <<EOF if $EVAL_ERROR;
It looks like you don't have the Mojolicious Framework installed.
Please visit http://mojolicio.us for detailed installation instructions.
EOF
$ENV{ MOJO_APP } = 'Explain';
Mojolicious::Commands->start;

BIN
layout/explain.psd Executable file

Binary file not shown.

47
lib/Explain.pm Executable file
View File

@@ -0,0 +1,47 @@
package Explain;
use Mojo::Base 'Mojolicious';
sub startup {
my $self = shift;
# register Explain plugins namespace
$self->plugins->namespaces( [ "Explain::Plugin", @{ $self->plugins->namespaces } ] );
# setup charset
$self->plugin( charset => { charset => 'utf8' } );
# load configuration
my $config = $self->plugin( 'json_config' );
# setup secret passphrase
$self->secret( $config->{ secret } || 'Xwyfe-_d:yGDr+p][Vs7Kk+e3mmP=c_|s7hvExF=b|4r4^gO|' );
# startup database connection
$self->plugin( 'database', $config->{ database } || {} );
# startup mail sender
$self->plugin( 'mail_sender', $config->{ mail_sender } || {} );
# routes
my $routes = $self->routes;
# route: 'index'
$routes->route( '/' )->to( 'controller#index' )->name( 'index' );
# route: 'show'
$routes->route( '/s/:plan_id' )->to( 'controller#show' )->name( 'show' );
# route: 'history'
$routes->route( '/history/:p' )->to( 'controller#history', p => 1 )->name( 'history' );
# route: 'contact'
$routes->route( '/contact' )->to( 'controller#contact' )->name( 'contact' );
# route: 'help'
$routes->route( '/help' )->to( 'controller#help' )->name( 'help' );
return;
}
1;

135
lib/Explain/Controller.pm Executable file
View File

@@ -0,0 +1,135 @@
package Explain::Controller;
use Mojo::Base 'Mojolicious::Controller';
use English -no_match_vars;
use Pg::Explain;
use Email::Valid;
sub index {
my $self = shift;
# plan
my $plan = $self->req->param( 'plan' );
# nothing to do...
return $self->render unless $plan;
# request entity too large
return $self->render( message => 'Your plan is too long.', status => 413 )
if 10_000_000 < length $plan;
# validate plan
eval {
my $explain = Pg::Explain->new( source => $plan );
$explain->top_node;
};
# something goes wrong
return $self->render( message => q|Failed to parse your plan.| ) if $EVAL_ERROR;
# public
my $is_public = $self->req->param( 'is_public' ) ? 1 : 0;
# save to database
my $plan_id = $self->database->save_with_random_name( $plan, $is_public );
# redirect to /show/:plan_id
return $self->redirect_to( 'show', 'plan_id' => $plan_id );
}
sub show {
my $self = shift;
# value of "/:plan_id" param
my $plan_id = defined $self->stash->{ plan_id }
? $self->stash->{ plan_id } : '';
# missing or invalid
return $self->redirect_to( 'index' ) unless $plan_id =~ m{\A[a-zA-Z0-9]+\z};
# get plan source from database
my $plan = $self->database->get_plan( $plan_id );
# not found in database
return $self->redirect_to( 'index', status => 404 ) unless $plan;
# make explanation
my $explain = eval { Pg::Explain->new( source => $plan ); };
# plans are validated before save, so this should never happen
if ( $EVAL_ERROR ) {
$self->app->log->error( $EVAL_ERROR );
return $self->redirect_to( 'index' );
}
# validate explain
eval { $explain->top_node; };
# as above, should never happen
if ( $EVAL_ERROR ) {
$self->app->log->error( $EVAL_ERROR );
return $self->redirect_to( 'index' );
}
# put explain to stash
$self->stash->{ explain } = $explain;
# render will be called automatically
return;
}
sub history {
my $self = shift;
# p
my $p = $self->param( 'p' );
# get result set from database
my $rs = $self->database->get_public_list_paged( $p );
# put result set to stash
$self->stash( rs => $rs );
return;
}
sub contact {
my $self = shift;
# nothing to do...
return unless $self->req->param( 'message' );
# invalid email address
return $self->render( error => 'Invalid email address' )
unless Email::Valid->address( $self->req->param( 'email' ) || '' );
# send
$self->send_mail( {
msg => sprintf(
"\nMessage from: %s <%s>" .
"\nPosted from: %s with %s" .
"\n****************************************\n\n" .
"%s",
$self->req->param( 'name' ) || '',
$self->req->param( 'email' ),
$self->tx->remote_address,
$self->req->headers->user_agent,
$self->req->param( 'message' )
)
} );
# mail sent message
$self->flash( message => 'Mail sent' );
# get after post
$self->redirect_to( 'contact' );
}
sub help {
# direct to template
return ( shift )->render;
}
1;

174
lib/Explain/Plugin/Database.pm Executable file
View File

@@ -0,0 +1,174 @@
package Explain::Plugin::Database;
use Mojo::Base 'Mojolicious::Plugin';
use Carp;
use DBI;
__PACKAGE__->attr( dbh => undef );
has connection_args => sub { [] };
sub register {
my ( $self, $app, $config ) = @_;
# data source name
my $dsn = $config->{ dsn };
# if DSN not set directly
unless ( $dsn ) {
# driver
my $driver = $config->{ driver } || 'Pg';
# database name
my $database = $config->{ database } || lc( $ENV{ MOJO_APP } );
# assemble
my $dsn = sprintf 'dbi:%s:database=%s', $driver, $database;
$dsn .= ';host=' . $config->{ host } if $config->{ host };
$dsn .= ';port=' . $config->{ port } if $config->{ port };
}
# database (DBI) connection arguments
$self->connection_args( [
$config->{ dsn },
$config->{ username },
$config->{ password },
$config->{ options } || {}
] );
# log debug message
$app->log->debug( 'Connecting database using: ' . $app->dumper( $self->connection_args ) );
# connect
$self->dbh( DBI->connect( @{ $self->connection_args } ) );
# raise error (for case, when "RaiseError" option is not set)
confess qq|Can't connect database| unless $self->dbh;
# register helper
$app->helper(
database => sub { $self }
);
return;
}
sub save_with_random_name {
my ( $self, $content, $is_public ) = @_;
# create statement handler
my $sth = $self->dbh->prepare( 'SELECT register_plan(?, ?)' );
# execute
$sth->execute( $content, $is_public );
# register_plan returns plan id
my @row = $sth->fetchrow_array;
# finish
$sth->finish;
# return plan id
return $row[ 0 ];
}
# @depesz
# - why you don't use selectrow_array (or similar)?
sub get_plan {
my ( $self, $plan_id ) = @_;
# create statement handler
my $sth = $self->dbh->prepare( 'SELECT plan FROM plans WHERE id = ?' );
# execute
$sth->execute( $plan_id );
# fetch row
my @row = $sth->fetchrow_array;
# finish
$sth->finish;
# return plan
return $row[ 0 ];
}
sub get_public_list {
my $self = shift;
return $self->dbh->selectall_arrayref(
'SELECT id, to_char( entered_on, ? ) as date FROM plans WHERE is_public ORDER BY entered_on DESC',
{ Slice => { } },
'YYYY-MM-DD'
);
}
sub get_public_list_paged {
my $self = shift;
my $p = ( shift || '' ) =~ /\A(\d+)\z/ ? $1 : 1;
my $limit = ( shift || '' ) =~ /\A(\d+)\z/ ? $1 : 30;
# result, response...
my $rs = {
page => $p,
rows_per_page => $limit,
has_previous => ( $p > 1 ? 1 : 0 ),
has_next => 0,
rows => []
};
# OFFSET
my $offset = ( $p - 1 ) * $limit;
# LIMIT = $limit + 1, to see do we have "next"
$limit++;
# select
my $rows = $self->dbh->selectall_arrayref(
'SELECT id, to_char( entered_on, ? ) as date FROM plans WHERE is_public ORDER BY entered_on DESC LIMIT ? OFFSET ?',
{ Slice => { } },
'YYYY-MM-DD', $limit, $offset
);
# got results
if ( my $count = scalar @{ $rows || [] } ) {
# there is more (at least 1 more)
if ( $count == $limit ) {
# set "has_next"
$rs->{ has_next } = 1;
# remove "test" row
pop @{ $rows };
}
# set "rows"
$rs->{ rows } = $rows;
}
return $rs;
}
sub DESTROY {
my $self = shift;
# nothing to do...
return unless $self->dbh;
# rollback uncommited transactions
$self->dbh->rollback unless $self->connection_args->[ 3 ]->{ auto_commit };
# disconnect
$self->dbh->disconnect;
$self->dbh( undef );
return;
}
1;

View File

@@ -0,0 +1,83 @@
package Explain::Plugin::MailSender;
use Mojo::Base 'Mojolicious::Plugin';
use Mail::Sender;
__PACKAGE__->attr( config => sub { {} } );
sub register {
my ( $self, $app, $config ) = @_;
# save settings
$self->config( $config );
# register helper
$app->helper(
send_mail => sub {
my ( $controller, $mail ) = @_;
# update mail params with config values
for ( qw( smtp port subject from to cc bcc replyto confirm ) ) {
# skip if not set in config
next unless $self->config->{ $_ };
# update mail unless value not set directly
$mail->{ $_ } ||= $self->config->{ $_ };
}
# set default smtp
$mail->{ smtp } ||= '127.0.0.1';
# set mail charset and content type
$mail->{ charset } = 'utf-8';
$mail->{ ctype } = 'text/plain';
# log debug message
$controller->app->log->debug(
sprintf "Sending mail:\n%s", $controller->dumper( $mail )
);
# create Mail::Sender instance
my $sender = Mail::Sender->new( {
smtp => delete $mail->{ smtp },
from => delete $mail->{ from }
} );
# unable to create instance
unless ( ref $sender ) {
# error message
my $message = qq|Can't create Mail::Sender instance, reason: [$sender] "$Mail::Sender::Error"|;
# log error message
$controller->app->log->fatal( $message );
# die
die $message;
}
# send mail
my $result = $sender->MailMsg( $mail );
# unable to sent mail
unless ( ref $result ) {
# error message
my $message = qq|Mail send failed, reason: [$result] "$Mail::Sender::Error"|;
# log error message
$controller->app->log->fatal( $message );
# die
die $message;
}
# success
return 1;
}
);
}
1;

264
log/development.log Normal file
View File

@@ -0,0 +1,264 @@
Thu Mar 10 15:16:25 2011 debug Mojolicious::Plugin::Config:14 [9664]: Reading config file "/home/depesz/sites/new.explain.depesz.com/explain.json".
Thu Mar 10 15:16:25 2011 debug Explain::Plugin::Database:43 [9664]: Connecting database using: [
'dbi:Pg:database=depesz_explain;host=127.0.0.1;port=5900',
'depesz_explain',
undef,
{
'auto_commit' => '1',
'pg_server_prepare' => '0'
}
]
Thu Mar 10 15:16:25 2011 info Mojo::Server::Daemon:316 [9664]: Server listening (http://*:12004)
Thu Mar 10 15:16:28 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:16:28 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:16:29 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.431623s, 2.317/s).
Thu Mar 10 15:16:44 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/9oM (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:16:44 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:16:44 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.027114s, 36.881/s).
Thu Mar 10 15:20:32 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:32 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:20:32 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.013203s, 75.740/s).
Thu Mar 10 15:20:33 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:33 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:20:33 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.036023s, 27.760/s).
Thu Mar 10 15:20:35 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:35 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:20:35 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003762s, 265.816/s).
Thu Mar 10 15:20:36 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:36 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:20:36 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.021045s, 47.517/s).
Thu Mar 10 15:20:36 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:36 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:20:36 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.009784s, 102.208/s).
Thu Mar 10 15:20:37 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /contact (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:37 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->contact.
Thu Mar 10 15:20:37 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.009371s, 106.712/s).
Thu Mar 10 15:20:38 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:38 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:20:38 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003708s, 269.687/s).
Thu Mar 10 15:20:41 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:41 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:20:41 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003719s, 268.889/s).
Thu Mar 10 15:20:51 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /contact (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:51 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->contact.
Thu Mar 10 15:20:51 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.005642s, 177.242/s).
Thu Mar 10 15:20:56 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:56 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:20:56 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002477s, 403.714/s).
Thu Mar 10 15:20:57 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:20:57 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:20:57 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.035246s, 28.372/s).
Thu Mar 10 15:21:01 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history/2 (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:21:01 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:21:01 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.021629s, 46.234/s).
Thu Mar 10 15:21:04 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history/3 (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:21:04 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:21:04 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.021902s, 45.658/s).
Thu Mar 10 15:21:06 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history/2 (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:21:06 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:21:06 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.022094s, 45.261/s).
Thu Mar 10 15:21:07 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:21:07 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:21:07 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.020859s, 47.941/s).
Thu Mar 10 15:21:28 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/9oM (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:21:28 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:21:28 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.015096s, 66.243/s).
Thu Mar 10 15:21:54 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/9oM (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:21:54 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:21:54 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.013835s, 72.280/s).
Thu Mar 10 15:28:57 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /contact (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:28:57 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->contact.
Thu Mar 10 15:28:57 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002570s, 389.105/s).
Thu Mar 10 15:28:59 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:28:59 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:28:59 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003739s, 267.451/s).
Thu Mar 10 15:30:14 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:30:14 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:30:14 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.035565s, 28.118/s).
Thu Mar 10 15:30:15 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/jGO (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:30:15 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:30:15 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.006779s, 147.514/s).
Thu Mar 10 15:34:07 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:34:07 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:34:07 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.004771s, 209.600/s).
Thu Mar 10 15:34:08 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /contact (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:34:08 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->contact.
Thu Mar 10 15:34:08 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003607s, 277.239/s).
Thu Mar 10 15:34:09 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:34:09 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:34:09 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002421s, 413.052/s).
Thu Mar 10 15:34:10 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /contact (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:34:10 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->contact.
Thu Mar 10 15:34:10 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.004118s, 242.836/s).
Thu Mar 10 15:35:03 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:35:03 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:35:03 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003736s, 267.666/s).
Thu Mar 10 15:35:06 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:35:06 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:35:06 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.030598s, 32.682/s).
Thu Mar 10 15:35:07 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:35:07 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:35:07 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003948s, 253.293/s).
Thu Mar 10 15:35:08 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:35:08 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:35:08 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002309s, 433.088/s).
Thu Mar 10 15:35:20 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /contact (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:35:20 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->contact.
Thu Mar 10 15:35:20 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002565s, 389.864/s).
Thu Mar 10 15:36:48 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:36:48 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:36:48 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003919s, 255.167/s).
Thu Mar 10 15:37:07 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:07 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:37:07 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002324s, 430.293/s).
Thu Mar 10 15:37:08 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:08 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:37:08 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.025715s, 38.888/s).
Thu Mar 10 15:37:09 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:09 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:37:09 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003927s, 254.647/s).
Thu Mar 10 15:37:11 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:11 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:37:11 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.030802s, 32.465/s).
Thu Mar 10 15:37:13 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history/2 (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:13 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:37:13 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.035544s, 28.134/s).
Thu Mar 10 15:37:16 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history/3 (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:16 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:37:16 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.022099s, 45.251/s).
Thu Mar 10 15:37:18 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history/4 (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:18 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:37:18 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.031042s, 32.214/s).
Thu Mar 10 15:37:20 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history/5 (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:20 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:37:20 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.022167s, 45.112/s).
Thu Mar 10 15:37:21 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history/6 (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:21 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:37:21 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.036872s, 27.121/s).
Thu Mar 10 15:37:22 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/dDq (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:22 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:37:22 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.008671s, 115.327/s).
Thu Mar 10 15:37:28 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:37:28 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:37:28 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.004132s, 242.014/s).
Thu Mar 10 15:37:45 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:45 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:37:45 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003975s, 251.572/s).
Thu Mar 10 15:37:48 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:37:48 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:37:48 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.024544s, 40.743/s).
Thu Mar 10 15:38:28 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:38:28 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:38:28 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002357s, 424.268/s).
Thu Mar 10 15:38:36 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:38:36 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:38:36 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.023635s, 42.310/s).
Thu Mar 10 15:38:37 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:38:37 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:38:37 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002346s, 426.257/s).
Thu Mar 10 15:38:45 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:38:45 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:38:45 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.035901s, 27.854/s).
Thu Mar 10 15:38:46 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /help (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:38:46 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->help.
Thu Mar 10 15:38:46 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.004020s, 248.756/s).
Thu Mar 10 15:38:47 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:38:47 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:38:47 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002754s, 363.108/s).
Thu Mar 10 15:39:03 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:39:03 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:39:03 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003463s, 288.767/s).
Thu Mar 10 15:39:06 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.10 (maverick) Firefox/3.6.15).
Thu Mar 10 15:39:06 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:39:06 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003730s, 268.097/s).
Thu Mar 10 15:39:08 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:39:08 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:39:08 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.004498s, 222.321/s).
Thu Mar 10 15:39:29 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.10 (maverick) Firefox/3.6.15).
Thu Mar 10 15:39:29 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:39:29 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.002321s, 430.849/s).
Thu Mar 10 15:39:42 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13).
Thu Mar 10 15:39:42 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:39:42 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.021935s, 45.589/s).
Thu Mar 10 15:39:46 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: POST / (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:39:46 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:39:46 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 302 Found (0.080912s, 12.359/s).
Thu Mar 10 15:39:46 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:39:46 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:39:46 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.020144s, 49.643/s).
Thu Mar 10 15:40:02 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: POST / (Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.10 (maverick) Firefox/3.6.15).
Thu Mar 10 15:40:02 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:40:02 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 302 Found (0.234377s, 4.267/s).
Thu Mar 10 15:40:02 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/dgm (Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.10 (maverick) Firefox/3.6.15).
Thu Mar 10 15:40:02 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:40:02 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.060037s, 16.656/s).
Thu Mar 10 15:40:47 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:40:47 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:40:47 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.021085s, 47.427/s).
Thu Mar 10 15:40:50 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BUJ (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:40:50 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:40:50 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.011628s, 85.999/s).
Thu Mar 10 15:40:54 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: POST / (Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.10 (maverick) Firefox/3.6.15).
Thu Mar 10 15:40:54 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:40:55 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 302 Found (0.237831s, 4.205/s).
Thu Mar 10 15:40:55 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/hGZ (Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.10 (maverick) Firefox/3.6.15).
Thu Mar 10 15:40:55 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:40:55 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.065205s, 15.336/s).
Thu Mar 10 15:41:19 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/hGZ (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:41:19 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:41:19 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.060119s, 16.634/s).
Thu Mar 10 15:41:19 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13).
Thu Mar 10 15:41:19 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:41:19 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003791s, 263.783/s).
Thu Mar 10 15:41:21 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/hGZ (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:41:21 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:41:21 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.058923s, 16.971/s).
Thu Mar 10 15:42:19 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12).
Thu Mar 10 15:42:19 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:42:19 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.003980s, 251.256/s).
Thu Mar 10 15:43:50 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14).
Thu Mar 10 15:43:50 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:43:50 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.013713s, 72.924/s).
Thu Mar 10 15:43:58 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.8.104 Version/11.10).
Thu Mar 10 15:43:58 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:43:58 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.019401s, 51.544/s).
Thu Mar 10 15:47:01 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13).
Thu Mar 10 15:47:01 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:47:01 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.012172s, 82.156/s).
Thu Mar 10 15:47:22 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /history (Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13).
Thu Mar 10 15:47:22 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->history.
Thu Mar 10 15:47:22 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.121990s, 8.197/s).
Thu Mar 10 15:47:24 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/vZ9 (Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13).
Thu Mar 10 15:47:24 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:47:24 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.012062s, 82.905/s).
Thu Mar 10 15:47:53 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/xLR (Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13).
Thu Mar 10 15:47:53 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:47:53 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.008966s, 111.532/s).
Thu Mar 10 15:48:50 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:48:50 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:48:50 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.018939s, 52.801/s).
Thu Mar 10 15:50:02 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.10 (maverick) Firefox/3.6.15).
Thu Mar 10 15:50:02 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:50:02 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.018144s, 55.115/s).
Thu Mar 10 15:51:30 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET / (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:51:30 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->index.
Thu Mar 10 15:51:30 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.004340s, 230.415/s).
Thu Mar 10 15:52:05 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:52:05 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:52:06 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.043761s, 22.851/s).
Thu Mar 10 15:53:31 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:53:31 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:53:31 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.011976s, 83.500/s).
Thu Mar 10 15:54:42 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:54:42 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:54:42 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.012104s, 82.617/s).
Thu Mar 10 15:55:26 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:55:26 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:55:26 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.020273s, 49.327/s).
Thu Mar 10 15:55:29 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:55:29 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:55:29 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.017675s, 56.577/s).
Thu Mar 10 15:57:21 2011 debug Mojolicious::Plugin::RequestTimer:24 [9664]: GET /s/BNw (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5).
Thu Mar 10 15:57:21 2011 debug Mojolicious::Routes:458 [9664]: Dispatching Explain::Controller->show.
Thu Mar 10 15:57:21 2011 debug Mojolicious::Plugin::RequestTimer:48 [9664]: 200 OK (0.017894s, 55.885/s).

307
public/css/style.css Executable file
View File

@@ -0,0 +1,307 @@
/*
* css reset
*/
html,body,div,span,applet,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,
img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,dl,dt,dd,ol,ul,li,form,fieldset,label,legend,table,caption,tbody,
tfoot,thead,tr,th,td,object,article,aside,dialog,figure,footer,header,hgroup,nav,section
{margin:0;padding:0;border:0;outline:0;font-weight:inherit;font-style:inherit;font-family:inherit;vertical-align:baseline}
article,aside,dialog,figure,footer,header,hgroup,nav,section {display:block}
:focus {outline:0}
ol,ul {list-style:none}
table {border-collapse:separate;border-spacing:0}
caption,th,td {text-align:left;font-weight:normal}
blockquote:before, blockquote:after, q:before, q:after {content:""}
blockquote,q {quotes:"" ""}
* {margin:0;padding:0}
button::-moz-focus-inner {border:0;outline:0;padding:0}
button {-moz-box-sizing:content-box;-ms-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}
button {overflow:visible;width:0}
button[type] {width:auto}
/*
* typography
*/
body {font-family:"Helvetica Neue",Arial,Helvetica,sans-serif;font-size:87.5%}
h1,h2,h3,h4,h5,h6 {font-weight:normal}
h1 {font-size:1.6em;line-height:1;margin-bottom:0.5em}
h2 {font-size:1.6em;margin-bottom:0.75em}
h3 {font-size:1.2em;line-height:1;margin-bottom:1em}
h4 {font-size:1.1em;line-height:1.25;margin-bottom:1.25em}
h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em}
h6 {font-size:1em;font-weight:bold}
h1 img,h2 img,h3 img,h4 img,h5 img,h6 img {margin:0}
p {margin:0 0 1.5em;color:#333}
a {text-decoration:underline}
a:focus, a:hover {text-decoration:none}
blockquote {margin:1.5em;font-style:italic}
strong {font-weight:bold}
em,dfn {font-style:italic}
dfn {font-weight:bold}
sup,sub {line-height:0}
abbr,acronym {border-bottom:1px dotted #666}
address {margin:0 0 1.5em;font-style:italic}
del {color:#666}
pre {margin:1.5em 0;white-space:pre}
pre,code,tt {font:1em 'andale mono','lucida console', monospace;line-height:1.5}
li ul, li ol {margin:0 1.5em}
ul, ol {margin:0 1.5em 1.5em 1.5em}
ul {list-style-type:disc}
ol {list-style-type:decimal}
dl {margin: 0 0 1.5em 0}
dl dt {font-weight:bold}
dd {margin-left:1.5em}
/*
* misc classes
*/
.hidden {display:none}
.clearfix:after, form div.fe:after {content:".";display:block;height:0;line-height:0;clear:both;visibility:hidden}
.clearfix, form div.fe {display:inline-table}
/*\*/
* html .clearfix, * html form div.fe {height:1%}
.clearfix, form div.fe {display:block}
/**/
.clearfix, form div.fe {min-height:1px}
/*
* layout
*/
body {background:#16212c;color:#f0f0f0}
#wrapper {background:#234 url('../img/sprite.png') repeat-x 0 -300px;text-align:center}
header, nav, section {position:relative;margin:0 100px;min-width:600px;width:auto !important;width:600px;color:#16212b;text-align:left}
section {min-width:560px;width:auto !important;width:560px} /* 600 - padding */
header {height:100px}
header h1, header h2 {display:block;position:absolute}
header h1 {top:15px;left:0;font-size:3em}
header h2 {top:60px;left:70px;font-size:1.2em}
header hgroup span,
header hgroup a {display:block;text-decoration:none;color:#fff;text-shadow:#000 4px 4px 8px}
header h1 strong {font-weight:normal;color:#e80}
header h1 a:hover {text-decoration:underline}
nav {
height:35px;
margin-bottom:15px;
background:url('../img/sprite.png') repeat-x 0 -50px;
-moz-border-radius:8px/8px;
border-radius:8px/8px;
-moz-box-shadow:0px 8px 10px #16212c;
-webkit-box-shadow:0px 8px 10px #16212c;
box-shadow:0px 8px 10px #16212c
}
nav ul {position:absolute;top:0;left:20px;margin:0px;padding:0;height:35px;list-style:none;background:#123}
nav li, nav a, nav span {display:block}
nav li {float:left}
nav a, nav span {height:35px;padding:0 20px;font-size:1.35em;font-weight:bold;line-height:33px;font-size:1.35em;text-decoration:none;color:#123;background:url('../img/sprite.png') repeat-x 0 -50px;text-shadow:#666 1px 1px 4px}
nav a:hover {text-decoration:underline}
nav span {margin-left:1px;margin-right:1px;background-position:0px -120px;color:#eee}
section {
margin-bottom:20px;
padding:20px;
background:#fff;
-moz-border-radius:8px/8px;
border-radius:8px/8px;
-moz-box-shadow:0px 8px 10px #16212c;
-webkit-box-shadow:0px 8px 10px #16212c;
box-shadow:0px 8px 10px #16212c;
}
section h1 {padding-bottom:0.2em;margin-bottom:1.2em;color:#aaa;font-size:1.6em;border-bottom:1px solid #ccc}
section h2,
section h3 {color:#234}
section p a,
section p a:visited {padding:2px 4px;color:#234;border:1px dotted #e0e0e0}
section p a:hover {background:#234;color:#fff;border:1px solid #123}
.result {margin:0;padding:0}
.result-text, .result-html {margin:0;padding:0;border:1px solid #ccc;overflow:auto}
.result-text {background:#222 url('../img/code-bg.gif');color:#fff}
.result-text pre {margin:0;padding:1em}
.result .tabs ul {margin:0;padding:0;list-style:none}
.result .tabs li {display:block;float:left;margin-right:1px}
.result .tabs a {display:block;padding:4px 12px;background:#cfcfcf;color:#fff;text-decoration:none;font-weight:bold}
.result .tabs a:hover {color:#234}
.result .tabs a.current,
.result .tabs a.current:hover {background:#234;color:#fff}
.result .tabs .html a {
-moz-border-radius:4px 0px 0px 0px;
border-radius:4px 0px 0px 0px
}
.result .tabs .text a {
-moz-border-radius:0px 4px 0px 0px;
border-radius:0px 4px 0px 0px
}
.result-html table {margin:5px;border-collapse:collapse}
.result-html table th,
.result-html table td {padding:4px 8px;border:1px solid #ccc;background:#fff;text-align:left;vertical-align:top}
.result-html table th {padding:1px;background:#234}
.result-html table th a {display:block;margin:0;padding:4px 8px;font-size:1.2em;color:#fff;text-align:center;white-space:nowrap}
.result-html table th.n a {text-align:left}
.result-html table tbody tr {cursor:pointer}
.result-html table td {text-align:right}
.result-html table td.n {text-align:left}
.result-html table td.e,
.result-html table td.i,
.result-html table td.x {white-space:nowrap}
/* currently not used */
.result-html table td.c-1,
.result-html table tr.c-1 td {background:#fff}
.result-html table tr.even td {background:#e5ecf9}
/* !important overrides tr.even */
.result-html table tr.c-2 td,
.result-html table tr.c-mix td.c-2 {background:#fe8 !important}
.result-html table tr.c-3 td,
.result-html table tr.c-mix td.c-3 {background:#e80 !important;color:#fff}
.result-html table tr.c-4 td,
.result-html table tr.c-mix td.c-4 {background:#800 !important;color:#fff}
/* tr hover */
.result-html table tr.hover td,
.result-html table tr.hover.even td {background:#d0d8d8 !important}
/* !important overrides tr.c-[1..4] */
.result-html table tr.hover.c-2 td,
.result-html table tr.hover.c-mix td.c-2 {background:#ec5 !important}
.result-html table tr.hover.c-3 td,
.result-html table tr.hover.c-mix td.c-3 {background:#c60 !important}
.result-html table tr.hover.c-4 td,
.result-html table tr.hover.c-mix td.c-4 {background:#600 !important}
/* tr collapsed */
.result-html table tr.collapsed td {border-bottom:3px dashed #888}
.result-html table tr.collapsed.c-2 td,
.result-html table tr.collapsed.c-mix td.c-2 {border-bottom-color:#ec5}
.result-html table tr.collapsed.c-3 td,
.result-html table tr.collapsed.c-mix td.c-3 {border-bottom-color:#c60}
.result-html table tr.collapsed.c-4 td,
.result-html table tr.collapsed.c-mix td.c-4 {border-bottom-color:#600}
.result-html table td.n div {position:relative;min-height:22px;height:auto !important;height:22px}
.result-html table td.n p,
.result-html table td.n ul {margin:0;padding:0}
.result-html table td.n ul {list-style:none}
.result-html table td.n li {padding-top:0.5em}
/* all ico(ns) */
.result-html table td.n div.ico {position:absolute;top:-4px;left:-22px;width:22px;height:22px;background:url('../img/sprite.png') no-repeat 0px -180px;text-indent:-1000px;overflow:hidden}
/* white arrow */
.result-html table tr.c-3 td.n div.ico,
.result-html table tr.c-4 td.n div.ico {background-position:0px -224px}
/* for td.r(ows), td.l(oops) */
.result-html table .tight span {display:none}
.result-html table .tight,
.result-html table .tight a {padding-left:0 !important;padding-right:0 !important;width:10px !important;overflow:hidden;text-align:left;text-indent:-10000px}
.result-html table .tight a {margin:0 1px;background:url('../img/sprite.png') top left}
.result-html table p {color:inherit}
/* for "help" */
p.slogan {font-style:italic}
p strong {color:#234}
ul.colors {list-style:none;width:60%}
ul.colors li {padding:4px 6px;border-bottom:1px solid #fff}
ul.colors li.c-1 {background:#fff}
ul.colors li.c-2 {background:#fe8}
ul.colors li.c-3 {background:#e80;color:#fff}
ul.colors li.c-4 {background:#800;color:#fff}
/* forms */
form {display:block;margin:0 auto}
form#contact {max-width:500px}
form .fe {margin:0;padding:10px 0;background:#fff;border-bottom:1px solid #d0d8d9}
form .fe-first {padding-top:0}
form .fe-even {background:#e5ecf9}
form .fe-last {border:0;background:none}
form .fe div {margin:0 10px}
label, input, textarea {display:block;width:99%;margin:0;padding:0;font-size:1.1em;color:#123}
label {padding-bottom:0.35em}
input, textarea {padding:0.25em 0.5%;line-height:1.2em;border:1px solid #aaa}
input:hover, textarea:hover,
input:focus, textarea:focus {border-color:#666}
textarea {height:300px}
.fe_is_public div {position:relative}
.fe_is_public input {position:absolute;top:2px;left:2px;width:auto}
.fe_is_public label {width:auto;margin-left:30px}
*:first-child+html .fe_is_public input {border:0;top:0;left:0}
form .fe-buttons {padding:5px 0 0 0}
form .fe-buttons button {display:block;float:right;margin-left:5px;border:1px solid #d0d8d8;background:#e5ecf9}
form .fe-buttons button span {display:block;padding:5px 25px;color:#123}
form .fe-buttons button:hover {background:#234;border-color:123}
form .fe-buttons button:hover span {color:#fff}
form p.nfo-required {font-size:0.8em;color:#888}
form sup.fe-required {font-size:1.2em;color:#800}
/* history */
p.msg {padding:1em;border:1px dotted #e0e0e0}
p.msg-error {color:#800}
div.history {margin-bottom:20px}
div.history ul {margin:0;padding:0;list-style:none}
div.history li {display:block;float:left;margin:0 10px 10px 0}
div.history li a {display:block;width:140px;height:20px;line-height:20px;border:1px dotted #ccc;text-align:center;overflow:hidden;text-decoration:none;font-size:0.9em;font-weight:bold;color:#234}
div.history li a:hover {border:1px solid #a60;background:#e80;color:#fff}
div.paginator {position:relative;height:3em}
div.paginator a {position:absolute;top:0;font-size:1.1em;color:#234}
div.paginator a.next {right:0}
div.paginator a.prev {left:0}
footer {padding-top:15px;background:url('../img/sprite.png') repeat-x 0 -155px}
footer div {padding-top:10px;background:#16212c}
footer p {text-shadow:#101921 0px 2px 6px}
footer p,
footer a {color:#2c4054}
footer a:hover {color:#e80}

BIN
public/img/code-bg.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

BIN
public/img/sprite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

180
public/js/explain.js Normal file
View File

@@ -0,0 +1,180 @@
( function( $ ) {
var Explain = {
init : function( ) {
return this.each( function( ) {
$( this ).find( 'tbody tr' ).each( function( ) {
var row = $( this );
$.map( [ 'mouseover', 'mouseout', 'click' ], function( event, i ) {
row.bind( event, function( e ) {
Explain[ '_' + event ].apply( row, [ e ] );
} );
} );
} );
} );
},
_mouseover : function( e ) {
this.addClass( 'hover' );
var level = parseInt( this.attr( 'data-level' ) );
this.nextAll( ).each( function( i, row ) {
var r = $( row );
var l = r.attr( 'data-level' )
if ( l == level ) return false;
if ( l == level + 1 )
r.addClass( 'sub-n' );
} );
},
_mouseout : function( e ) {
this.removeClass( 'hover' );
this.parent( ).find( '.sub-n' ).removeClass( 'sub-n' );
},
_click : function( e ) {
var isCollapsed = this.hasClass( 'collapsed' ) ? true : false;
var level = parseInt( this.attr( 'data-level' ) );
var affected = 0;
this.nextAll( ).each( function( i, row ) {
var r = $( row );
var l = r.attr( 'data-level' );
if ( l <= level ) return false;
affected++;
if ( isCollapsed ) {
r.show( );
return true;
}
r.hide( );
r.removeClass( 'collapsed' );
} );
if ( ! affected ) return;
this.toggleClass( 'collapsed' );
},
toggleColumn : function( column, a ) {
var a = $( a );
var table = a.parents( 'table' ).get( 0 );
if ( !table ) return;
table = $( table );
table.find( 'td.' + column ).toggleClass( 'tight' );
table.find( 'th.' + column ).toggleClass( 'tight' );
},
colorize : function( column, a ) {
var a = $( a );
var table = $( a ).parents( 'table' ).get( 0 );
table = $( table );
table.find( 'tbody tr.n' ).map( function( i, row ) {
row = $( row );
row.removeClass( 'c-1 c-2 c-3 c-4 c-mix' );
value = 'mix';
if ( column ) value = row.attr( 'data-' + column );
row.addClass( 'c-' + value );
} );
},
toggleView : function( view ) {
var link = $( this );
if ( link.hasClass( 'current' ) ) return;
link.parents( 'ul' ).find( 'a' ).removeClass( 'current' );
link.addClass( 'current' );
var result = $( link.parents( 'div.result' ).get( 0 ) );
if ( 'text' == view.toLowerCase( ) ) {
result.find( 'div.result-html' ).hide( );
result.find( 'div.result-text' ).show( );
return;
}
result.find( 'div.result-html' ).show( );
result.find( 'div.result-text' ).hide( );
}
};
// public
$.fn.explain = function( method ) {
// what are you doing?
if ( method
&& typeof method.substr == 'function'
&& method.substr( 0, 1 ) == '_' ) {
$.error( 'Method ' + method + ' is private' );
}
// usage: $( element/selector ).explain( 'method' [, arguments ] );
if ( Explain[ method ] ) {
// "proxy" to: Explain[ 'method' ]( ... )
return Explain[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
// usage: $( 'table#id' ).explain( );
} else if ( typeof method === 'object' || ! method ) {
// "proxy" to: Explain.init( ... )
return Explain.init.apply( this, arguments );
// ...what can I do?
} else {
// exception
$.error( 'Method ' + method + ' does not exist on jQuery.explain' );
}
};
} )( jQuery );

16
public/js/jquery-1.5.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

67
sql/create.sql Executable file
View File

@@ -0,0 +1,67 @@
\connect template1 postgres
\set ON_ERROR_STOP OFF
DROP DATABASE "explain";
DROP USER "explain";
\set ON_ERROR_STOP ON
CREATE USER "explain" WITH password 'explain';
CREATE DATABASE "explain" WITH encoding 'utf8' owner "explain";
\connect "explain" postgres
CREATE procedural LANGUAGE plpgsql;
\connect "explain" "explain"
-- plan
CREATE TABLE plans (
id TEXT PRIMARY KEY,
plan TEXT NOT NULL,
entered_on timestamptz NOT NULL DEFAULT now( ),
is_public bool NOT NULL DEFAULT 'true'
);
CREATE OR REPLACE FUNCTION get_random_string( string_length INT4 ) RETURNS TEXT AS $$
DECLARE
possible_chars TEXT = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
output TEXT = '';
i INT4;
pos INT4;
BEGIN
FOR i IN 1..string_length LOOP
pos := 1 + cast( random( ) * ( length( possible_chars ) - 1 ) AS INT4 );
output := output || substr( possible_chars, pos, 1 );
END LOOP;
RETURN output;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION register_plan( in_plan TEXT, in_is_public BOOL ) RETURNS TEXT AS $$
DECLARE
use_hash_length INT4 := 2;
use_hash TEXT;
BEGIN
LOOP
use_hash := get_random_string( use_hash_length );
BEGIN
INSERT INTO plans ( id, plan, is_public, entered_on ) VALUES ( use_hash, in_plan, in_is_public, now( ) );
RETURN use_hash;
EXCEPTION when unique_violation THEN
-- do nothing
END;
use_hash_length := use_hash_length + 1;
IF use_hash_length >= 30 THEN
raise EXCEPTION 'Random string of length == 30 requested. Something is wrong.';
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;

13
t/basic.t Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More tests => 3;
use Test::Mojo;
use_ok( 'Explain' );
my $t = Test::Mojo->new( app => 'Explain' );
$t->get_ok( '/' )->status_is( 200 );

View File

@@ -0,0 +1,57 @@
% layout 'default';
% my $title = 'Contact';
% title $title;
<h1><%= $title =%></h1>
% if ( stash 'message' ) {
<div class="message">
<p><%= stash 'message' =%></p>
</div>
% }
% if ( stash 'error' ) {
<div class="message">
<p class="error"><%= stash 'error' =%></p>
</div>
% }
<form id="contact" method="post" action="<%= url_for 'contact' %>">
<div class="fe fe-first fe-odd fe_name">
<div class="fe-lbl">
<label for="name">Your name</label>
</div>
<div class="fe-el">
<input type="text" class="text" id="name" name="name" value="<%= param 'name' =%>" />
</div>
</div>
<div class="fe fe-even fe_email">
<div class="fe-lbl">
<label for="email">Your email <sup class="fe-required">*</sup></label></dt>
</div>
<div class="fe-el">
<input type="text" class="text" id="email" name="email" value="<%= param 'email' =%>" />
</div>
</div>
<div class="fe fe-odd fe_message">
<div class="fe-lbl">
<label for="message">Message <sup class="fe-required">*</sup></label>
</div>
<div class="fe-el">
<textarea id="message" name="message"><%= param 'message' =%></textarea>
</div>
</div>
<div class="fe fe-even fe-last fe-buttons">
<button type="submit" id="send_email" name="send_email"><span>Send</span></button>
</div>
<p>Or you can simply mail me at <a href="mailto:depesz@depesz.com">depesz@depesz.com</a></p>
<p class="nfo-required">All fields marked by <sup class="fe-required">*</sup> are required.</p>
</form>

View File

@@ -0,0 +1,83 @@
% layout 'default';
% my $title = 'Help';
% title $title;
<h1><%= $title =%></h1>
<p class="slogan"><strong>explain.depesz.com</strong> is tool for finding real cause for slow queries.</p>
<p>Generally, one would use <code>EXPLAIN ANALYZE</code> query; and read the output. The problem is
that not all parts of the output are easily understandable by anybody, and it's not always obvious
whether node that executes in 17.3ms is faster or slower than the one that runs in 100ms - given the
fact that the first one is executed 7 times.</p>
<p>To use the site, simply go to <a href="<%= url_for 'index' %>" title="link to: index">first page</a>
and paste there explain analyze output from your psql.</p>
<p>After uploading you will be directed to page which shows parsed, and nicely (well, at least
nice for me :) colorized to put emphasis on important parts.</p>
<p>The url for colorized output is persistent, so you can simply use it to show it to
others - for example - for those nice guys on irc channel <em>#postgresql</em> on freenode.</p>
<p>This graph uses 4 colours to mark important things:</p>
<ul class="colors">
<li class="c-1">white background - everything is fine</li>
<li class="c-2">yellow background - given node is worrying</li>
<li class="c-3">brown background - given node is more worrying</li>
<li class="c-4">red background - given node is very worrying</li>
</ul>
<p>Which color is used, is choosen based on which mode you will use: "<strong>Exclusive</strong>",
"<strong>Inclusive</strong>" or "<strong>Rows X</strong>".</p>
<h2>Exclusive</h2>
<p>This is total amount of time <a href="http://www.postgresql.org" title="link to PostgreSQL site">PostgreSQL</a> spent
evaluating this node, without time spent in its subnodes. If the node has been executed many times (for example because
of <code>Nested Loop</code> plan), this time will be correctly multiplied.</p>
<h3>Colors:</h3>
<ul class="colors">
<li class="c-1">white background - is choosen if exclusive time &lt;= 10% of total query time</li>
<li class="c-2">yellow background - is choosen if exclusive time &isin; (10%, 50%&gt; of total query time</li>
<li class="c-3">brown background - is choosen if exclusive time &isin; (50%, 90%&gt; of total query time</li>
<li class="c-4">red background - is choosen if exclusive time &gt; 90% of total query time</li>
</ul>
<h2>Inclusive</h2>
<p>This is just like <strong>Exclusive</strong>, but it doesn't exclude time of subnodes. So, by definition - top node will
have <strong>Inclusive</strong> time equal to total time of query.</p>
<h3>Colors:</h3>
<ul class="colors">
<li class="c-1">white background - is choosen if inclusive time &lt;= 10% of total query time</li>
<li class="c-2">yellow background - is choosen if inclusive time &isin; (10%, 50%&gt; of total query time</li>
<li class="c-3">brown background - is choosen if inclusive time &isin; (50%, 90%&gt; of total query time</li>
<li class="c-4">red background - is choosen if inclusive time &gt; 90% of total query time</li>
</ul>
<h2>Rows X</h2>
<p>This value stores information about how big was planner mistake when it estimated return row count.</p>
<p>For example - if planner estimated that given node will return 230 rows, but it returned 14118 rows, the
error is 14118/230 == 61.4.</p>
<p>It has to be noted that if the numbers were the other way around (estimated 14118, but really only 230), the
<strong>Rows X</strong> would be the same. To show whether planner underestimated or overestimated - there is
an arrow showing either &darr; - if planner underestimated rowcount, or &uarr; if it overestimated.</p>
<h3>Colors:</h3>
<ul class="colors">
<li class="c-1">white background - is choosen if rows-x &lt;= 10</li>
<li class="c-2">yellow background - is choosen if rows-x &isin; (10, 100&gt;</li>
<li class="c-3">brown background - is choosen if rows-x &isin; (100, 1000&gt;</li>
<li class="c-4">red background - is choosen if rows-x &gt; 1000</li>
</ul>

View File

@@ -0,0 +1,53 @@
% layout 'default';
% my $title = 'History';
% title $title;
<h1><%= $title =%><small>(page <%= $rs->{ page } =%>)</small></h1>
% my @plans = @{ $rs->{ rows } };
% if ( scalar @plans ) {
<div class="history">
% my $date = '';
% my $open = 0;
% for my $plan ( @plans ) {
% if ( $plan->{ date } ne $date ) {
% if ( $open ) {
</ul>
% $open = 0;
% }
<h3><%= $plan->{ date } =%></h3>
<ul class="clearfix date date-<%= $plan->{ date } =%>">
% $open = 1;
% }
<li><a href="<%= url_for( 'show', plan_id => $plan->{ id } ) =%>"><%= $plan->{ id } =%></a></li>
% $date = $plan->{ date };
% }
% if ( $open ) {
</ul>
% }
</div>
% if ( $rs->{ has_previous } || $rs->{ has_next } ) {
<div class="paginator">
% if ( $rs->{ has_previous } ) {
<a class="prev" href="<%= url_for 'current', p => ( $rs->{ page } - 1 ) %>" title="previous page" rel="prev">previous</a>
% }
% if ( $rs->{ has_next } ) {
<a class="next" href="<%= url_for 'current', p => ( $rs->{ page } + 1 ) %>" title="next page" rel="next">next</a>
% }
</div>
% }
% } else {
<p class="msg msg-no-results">
Sorry, but no results was found in database for this page.
</p>
% }

View File

@@ -0,0 +1,32 @@
% layout 'default';
% my $title = 'New explain';
% title $title;
<h1><%= $title =%></h1>
<form id="new-explain" method="post" action="<%= url_for( 'index' ) %>">
<div class="fe fe-odd fe-first fe_plan">
<div class="fe-lbl">
<label for="plan">Paste your explain/explain analyze here: <sup class="fe-required">*</sup></label>
</div>
<div class="fe-el">
<textarea id="plan" name="plan"></textarea>
</div>
</div>
<div class="fe fe-even fe_is_public">
<div>
<label for="is_public">Is public?</label>
<input type="checkbox" class="checkbox" id="is_public" name="is_public" value="1" checked="checked" />
</div>
</div>
<div class="fe fe-odd fe-last fe-buttons">
<button type="submit" name="submit_plan" id="submit_plan"><span>Submit</span></button>
</div>
<p class="nfo-required">All fields marked by <sup class="fe-required">*</sup> are required.</p>
</form>

274
templates/controller/show.html.ep Executable file
View File

@@ -0,0 +1,274 @@
% layout 'default';
% my $title = stash( 'plan_id' );
% title $title;
% my $row = 0;
%
% my $row_class = begin
% my $class = shift;
%
% my $next = scalar( @_ ) ? shift : 1;
%
% ++$row if $next;
%
% return sprintf '%s %s', $class, $row % 2 ? 'odd' : 'even';
% end;
% my $block = undef;
%
% $block = begin
%
% my ( $node, $level ) = @_;
%
% $level ||= 0;
%
% my $exclusive_point = 1;
% my $inclusive_point = 1;
%
% if ( $explain->top_node->total_inclusive_time && $node->total_exclusive_time ne '' && $node->total_inclusive_time ne '' ) {
%
% $exclusive_point = $node->total_exclusive_time / $explain->top_node->total_inclusive_time;
%
% if ( $exclusive_point > 0.9 ) { $exclusive_point = 4; }
% elsif ( $exclusive_point > 0.5 ) { $exclusive_point = 3; }
% elsif ( $exclusive_point > 0.1 ) { $exclusive_point = 2; }
% else { $exclusive_point = 1; }
%
% $inclusive_point = $node->total_inclusive_time / $explain->top_node->total_inclusive_time;
%
% if ( $inclusive_point > 0.9 ) { $inclusive_point = 4; }
% elsif ( $inclusive_point > 0.5 ) { $inclusive_point = 3; }
% elsif ( $inclusive_point > 0.1 ) { $inclusive_point = 2; }
% else { $inclusive_point = 1; }
% }
%
% my $rows_x = 0;
% my $rows_x_mark = '';
% my $rows_x_point = 1;
%
% if ( $node->estimated_rows && $node->actual_rows ) {
%
% if ( $node->actual_rows > $node->estimated_rows ) {
% $rows_x = $node->actual_rows / $node->estimated_rows;
% $rows_x_mark = 'down';
% } else {
% $rows_x = $node->estimated_rows / $node->actual_rows;
% $rows_x_mark = 'up';
% }
%
% if ( $rows_x > 1000 ) { $rows_x_point = 4; }
% elsif ( $rows_x > 100 ) { $rows_x_point = 3; }
% elsif ( $rows_x > 10 ) { $rows_x_point = 2; }
% else { $rows_x_point = 1; }
% }
%# tr class="(n|ip|sp) (even|odd) c-(mix|1|2|3|4)"
%# means:
%# n(ode)/i(nit)p(lan)/s(ub)p(lan)
%# c(olor)-mix(ed)|1|2|3|4
%#
%# td class="(e|i|x|r|l|n) (c-(1|2|3|4))?"
%# means:
%# e(xclusive time)/i(nclusive time)/(rows-)x/r(ows)/l(oops)/n(ode)
%# c(olor)-1|2|3|4
%#
%# important!
%# content of td.r(ows)/td.l(oops) must be wrapped in "span" element (because Opera...)
% my $margin = ( $level + 1 ) * 22;
<tr class="<%= $row_class->( 'n c-mix' ) =%>" data-level="<%= $level =%>" data-e="<%= $exclusive_point =%>" data-i="<%= $inclusive_point =%>" data-x="<%= $rows_x_point =%>">
<td class="e c-<%= $exclusive_point =%>"><%= sprintf '%.3f', $node->total_exclusive_time =%></td>
<td class="i c-<%= $inclusive_point =%>"><%= sprintf '%.3f', $node->total_inclusive_time =%></td>
<td class="x c-<%= $rows_x_point =%>">
<span class="rows-x-ico rows-x-ico-<%= $rows_x_mark %>">
<%= b( $rows_x_mark eq 'up' ? '&uarr;' : '&darr;' ) =%>
</span>
<%= sprintf '%.1f', $rows_x %>
</td>
<td class="r"><span><%= $node->actual_rows =%></span></td>
<td class="l"><span><%= $node->actual_loops =%></span></td>
<td class="n">
<div class="n" style="margin-left:<%= $margin =%>px">
<div class="ico">&rarr;</div>
<p>
<span class="node">
<%= $node->type %>
% if ( 'Bitmap Heap Scan' eq $node->type ) {
on <%= $node->scan_on->{ table_name } %> <%= $node->scan_on->{ table_alias } || '' %>
% }
% elsif ( 'Bitmap Index Scan' eq $node->type ) {
on <%= $node->scan_on->{ index_name } %>
% }
% elsif ( 'Index Scan' eq $node->type ) {
using <%= $node->scan_on->{ index_name } %> on <%= $node->scan_on->{ table_name } %> <%= $node->scan_on->{ table_alias } || '' %>
% }
% elsif ( 'Seq Scan' eq $node->type ) {
on <%= $node->scan_on->{ table_name } %> <%= $node->scan_on->{ table_alias } || '' %>
% }
</span>
<span class="est">
(cost=<%= $node->estimated_startup_cost =%>..<%= $node->estimated_total_cost %>
rows=<%= $node->estimated_rows %>
width=<%= $node->estimated_row_width =%>)
</span>
<span class="act">
(actual
time=<%= $node->actual_time_first =%>..<%= $node->actual_time_last %>
rows=<%= $node->actual_rows %>
loops=<%= $node->actual_loops =%>)
</span>
</p>
% if ( $node->extra_info ) {
<ul class="ex-nfo">
% for my $line ( @{ $node->extra_info } ) {
<li><%= $line =%></li>
% }
</ul>
% }
</div>
</td>
</tr>
% if ( $node->initplans ) {
<tr class="<%= $row_class->( 'ip' ) %>" data-level="<%= $level =%>">
<td class="e">&nbsp;</td>
<td class="i">&nbsp;</td>
<td class="x">&nbsp;</td>
<td class="r"><span>&nbsp;</span></td>
<td class="l"><span>&nbsp;</span></td>
<td class="n">
<div class="n" style="margin-left:<%= $margin =%>px">
<p><span>Initplan (for <%= $node->type =%>)</span></p>
</div>
</td>
</tr>
% for ( @{ $node->initplans } ) {
%== $block->( $_, $level + 1 );
% }
% }
% if ( $node->sub_nodes ) {
% for ( @{ $node->sub_nodes } ) {
%== $block->( $_, $level + 1 );
% }
% }
% if ( $node->subplans ) {
<tr class="<%= $row_class->( 'sp' ) %>" data-level="<%= $level =%>">
<td class="e">&nbsp;</td>
<td class="i">&nbsp;</td>
<td class="x">&nbsp;</td>
<td class="r"><span>&nbsp;</span></td>
<td class="l"><span>&nbsp;</span></td>
<td class="n">
<div class="n" style="margin-left:<%= $margin =%>px">
<p><span>SubPlan (for <%= $node->type =%>)</span></p>
</div>
</td>
</tr>
% for ( @{ $node->subplans } ) {
%== $block->( $_, $level + 1 );
% }
% }
% end;
<h1>Results</h1>
<div class="result">
<div class="tabs">
<ul class="clearfix">
<li class="html">
<a href="#html"
title="view HTML"
class="current"
onclick="$( this ).explain( 'toggleView', 'html' ); return false;"
onkeypress="return this.onclick( );">HTML</a>
</li>
<li class="text">
<a href="#text"
title="view plain text"
onclick="$( this ).explain( 'toggleView', 'text' ); return false;"
onkeypress="return this.onclick( );">TEXT</a>
</li>
</ul>
</div>
<!-- HTML view -->
<div class="result-html">
<table id="explain">
<thead>
<tr>
<th class="e">
<a href="#colorize-exclusive"
title="colorize rows based on &quot;exclusive&quot;"
onclick="$( this ).explain( 'colorize', 'e', this ); return false"
onkeypress="return this.onclick( );">exclusive</a>
</th>
<th class="i">
<a href="#colorize-inclusive"
title="colorize rows based on &quot;inclusive&quot;"
onclick="$( this ).explain( 'colorize', 'i', this ); return false"
onkeypress="return this.onclick( );">inclusive</a>
</th>
<th class="x">
<a href="#colorize-rows-x"
title="colorize rows based on &quot;rows x&quot;"
onclick="$( this ).explain( 'colorize', 'x', this ); return false"
onkeypress="return this.onclick( );">rows x</a>
</th>
<th class="r">
<a href="#toggle-rows"
title="expland/collapse &quot;rows&quot; column"
onclick="$( this ).explain( 'toggleColumn', 'r', this ); return false"
onkeypress="return this.onclick( );">rows</a>
</th>
<th class="l">
<a href="#toggle-loops"
title="expland/collapse &quot;loops&quot; column"
onclick="$( this ).explain( 'toggleColumn', 'l', this ); return false"
onkeypress="return this.onclick( );">loops</a>
</th>
<th class="n">
<a href="#column-mixed"
title="colorize rows &quot;mixed&quot; style"
onclick="$( this ).explain( 'colorize', null, this ); return false"
onkeypress="return this.onclick( );">node</a>
</th>
</tr>
</thead>
<tbody>
%== $block->( $explain->top_node );
</tbody>
</table>
<% content_for 'head' => begin %>
<script>
$( document ).ready( function( ) {
$( '#explain' ).explain( );
} );
</script>
<% end %>
</div>
<!-- TEXT view -->
<div class="result-text hidden">
<pre id="source"><%= $explain->source =%></pre>
</div>
</div>

View File

@@ -0,0 +1,78 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title><%= title %> | explain.depesz.com</title>
<link rel="stylesheet" href="<%= url_for '/' %>css/style.css" />
<!--[if lt IE 9]>
<script>
/* html5 elements */
var elements = ( "abbr,article,aside,audio,cavnas,datalist,"
+ "details,figure,footer,header,hgroup,mark,"
+ "menu,meter,output,progress,section,video,"
+ "time,nav" ).split( ',' );
for ( var i = 0 ; i < elements.length ; i++ ) {
document.createElement( elements[ i ] );
}
</script>
<![endif]-->
<script src="<%= url_for '/' %>js/jquery-1.5.1.min.js"></script>
<script src="<%= url_for '/' %>js/explain.js"></script>
<%= content_for 'head' %>
</head>
<body>
<!-- wrapper -->
<div id="wrapper">
<header>
<hgroup>
<h1>
% if ( 'index' eq stash->{ action } ) {
<span><strong>explain</strong>.depesz.com</span>
% } else {
<a href="<%= url_for 'index' %>" title="link to: index" rel="permalink"><strong>explain</strong>.depesz.com</a>
% }
</h1>
<h2><span>A tool for finding a real cause for slow queries.</span></h2>
</hgroup>
</header>
<nav>
<ul>
% for my $item ( qw( index history help contact ) ) {
<li class="item item-<%= $item %>">
% if ( stash( 'action' ) eq $item ) {
<span><%= $item =%></span>
% } else {
<a href="<%= url_for $item %>" title="link to: <%= $item %>" rel="permalink"><%= $item =%></a>
% }
</li>
% }
</ul>
</nav>
<section>
<%= content %>
</section>
<footer>
<div>
<p class="copyright">Copyright &copy; 2009 <a href="mailto:depesz@depesz.com" title="mail me">Hubert &quot;depesz&quot; Lubaczewski</a></p>
<p class="powered-by">powered by <a href="http://www.mojolicious.org" title="mojolicious web framework">mojolicious</a></p>
</div>
</footer>
</div>
<!-- /wrapper -->
</body>
</html>