--- /dev/null
+Revision history for Perl extension NetHack::NAOdash.
+
+0.001 2015-07-02T13:16+03:00
+ - Initial release
--- /dev/null
+app.psgi
+Changes
+lib/App/NAOdash.pm
+lib/App/Web/NAOdash.pm
+lib/NetHack/NAOdash.pm
+Makefile.PL
+MANIFEST
+naodash
+README
+t/NetHack-NAOdash.t
+t/perlcriticrc
+t/perlcritic.t
+t/xlogfile
+web/dash.css
+web/dash.html
--- /dev/null
+use 5.014000;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+ NAME => 'NetHack::NAOdash',
+ VERSION_FROM => 'lib/NetHack/NAOdash.pm',
+ ABSTRACT_FROM => 'lib/NetHack/NAOdash.pm',
+ AUTHOR => 'Marius Gavrilescu <marius@ieval.ro>',
+ EXE_FILES => ['naodash'],
+ MIN_PERL_VERSION => '5.14.0',
+ LICENSE => 'perl',
+ SIGN => 1,
+ PREREQ_PM => {
+ qw/File::Slurp 0
+ HTML::TreeBuilder 0
+ JSON::MaybeXS 0
+ List::MoreUtils 0
+ Plack::Component 0
+ Term::ANSIColor 0
+ Text::XLogfile 0/,
+ },
+ META_ADD => {
+ dynamic_config => 0,
+ resources => {
+ repository => 'https://git.ieval.ro/?p=nethack-naodash.git',
+ },
+ }
+);
--- /dev/null
+NetHack-NAOdash version 0.001
+=============================
+
+NetHack is a roguelike (a kind of video game) and NAO
+(http://alt.org/nethack/) is a popular NetHack public server.
+
+NetHack::NAOdash is a library that analyzes the games played by a user
+on NAO and extracts some statistics from them. One use case is
+answering the question "What should I play in NetHack now?". Besides
+NAO, it works on any NetHack installation that supports extended
+logfiles.
+
+This distribution also includes a web interface to the library
+(App::Web::NAOdash) and a command-line interface (App::NAOdash).
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+* File::Slurp
+* HTML::TreeBuilder
+* JSON::MaybeXS
+* Plack
+* Term::ANSIColor
+* Text::XLogfile
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
--- /dev/null
+#!/usr/bin/perl
+use 5.014000;
+use warnings;
+
+use App::Web::NAOdash;
+use Plack::Builder;
+
+builder {
+ mount '/dash/' => App::Web::NAOdash->new->to_app;
+ mount '/json/' => App::Web::NAOdash->new(json => 1)->to_app;
+ mount '/ok' => sub { [200, [], []] };
+ mount '/' => sub { App::Web::NAOdash::reply(404, 'Try /dash/USERNAME or /json/USERNAME')};
+}
--- /dev/null
+package App::NAOdash;
+
+use 5.014000;
+use strict;
+use warnings;
+use re '/saa';
+use utf8;
+
+our $VERSION = '0.001';
+
+use Encode qw/encode/;
+use File::Slurp;
+use NetHack::NAOdash;
+use Term::ANSIColor ':constants';
+
+my @order = qw/
+achieve_sokoban achieve_luckstone achieve_medusa achieve_bell achieve_gehennom achieve_candelabrum achieve_book achieve_invocation achieve_amulet achieve_endgame achieve_astral achieve_ascended
+
+combo_arc_hum_law combo_arc_hum_neu combo_arc_dwa_law combo_arc_gno_neu
+combo_bar_hum_neu combo_bar_hum_cha combo_bar_orc_cha
+combo_cav_hum_law combo_cav_hum_neu combo_cav_dwa_law combo_cav_gno_neu
+combo_hea_hum_neu combo_hea_gno_neu
+combo_kni_hum_law
+combo_mon_hum_law combo_mon_hum_neu combo_mon_hum_cha
+combo_pri_hum_law combo_pri_hum_neu combo_pri_hum_cha combo_pri_elf_cha
+combo_ran_hum_neu combo_ran_hum_cha combo_ran_elf_cha combo_ran_gno_neu combo_ran_orc_cha
+combo_rog_hum_cha combo_rog_orc_cha
+combo_sam_hum_law
+combo_tou_hum_neu
+combo_val_hum_law combo_val_hum_neu combo_val_dwa_law
+combo_wiz_hum_neu combo_wiz_hum_cha combo_wiz_elf_cha combo_wiz_gno_neu combo_wiz_orc_cha
+
+conduct_foodless conduct_vegan conduct_vegetarian conduct_atheist conduct_weaponless conduct_pacifist conduct_illiterate conduct_genocideless conduct_polypileless conduct_polyselfless conduct_wishless conduct_artiwishless
+
+uconduct_survivor uconduct_boneless uconduct_minscore/;
+
+sub naodash_to_ansi {
+ my ($dash) = @_;
+ my @checks = @{$dash->{checks}};
+ my %numbers = %{$dash->{numbers}};
+
+ my $base = <<"EOF";
+ACHIEVEMENTS
+============
+#Sokoban #Luckstone #Medusa #Bell #Gehennom #Candelabrum
+#Book #Invocation #Amulet #Endgame #Astral #Ascended
+
+STARTING COMBOS
+===============
+#Arc-Hum-Law #Arc-Hum-Neu #Arc-Dwa-Law #Arc-Gno-Neu
+#Bar-Hum-Neu #Bar-Hum-Cha #Bar-Orc-Cha
+#Cav-Hum-Law #Cav-Hum-Neu #Cav-Dwa-Law #Cav-Gno-Neu
+#Hea-Hum-Neu #Hea-Gno-Neu
+#Kni-Hum-Law
+#Mon-Hum-Law #Mon-Hum-Neu #Mon-Hum-Cha
+#Pri-Hum-Law #Pri-Hum-Neu #Pri-Hum-Cha #Pri-Elf-Cha
+#Ran-Hum-Neu #Ran-Hum-Cha #Ran-Elf-Cha #Ran-Gno-Neu #Ran-Orc-Cha
+#Rog-Hum-Cha #Rog-Orc-Cha
+#Sam-Hum-Law
+#Tou-Hum-Neu
+#Val-Hum-Law #Val-Hum-Neu #Val-Dwa-Law
+#Wiz-Hum-Neu #Wiz-Hum-Cha #Wiz-Elf-Cha #Wiz-Gno-Neu #Wiz-Orc-Cha
+
+CONDUCTS
+========
+#Foodless #Vegan #Vegetarian #Atheist
+#Weaponless #Pacifist #Illiterate #Genocideless
+#Polypileless #Polyselfless #Wishless #Artiwishless
+
+UNOFFICIAL CONDUCTS
+===================
+#Survivor #Boneless #Minscore
+
+NUMBERS
+=======
+Time played: $numbers{totalrealtime}
+Games: $numbers{games}
+Ascensions: $numbers{ascensions}
+Most HP: $numbers{maxhp}
+Most points: $numbers{maxpoints}
+Most conducts: $numbers{maxconducts}
+Least turns: $numbers{minturns}
+Least time: $numbers{minrealtime}
+EOF
+
+ my $rst = RESET;
+ for my $check (@order) {
+ my $color = (grep { $_ eq $check } @checks) ? GREEN '✓' : RED '✗';
+ $base =~ s/#([a-zA-Z-]+)/$color$1$rst/;
+ }
+
+ $base
+}
+
+sub run {
+ my ($user_or_path) = @_;
+ my $stats;
+ if ($user_or_path =~ /^\w+$/) { # Looks like a user
+ $stats = naodash_user $user_or_path
+ } else {
+ $stats = naodash_xlog read_file $user_or_path
+ }
+ print encode 'UTF-8', naodash_to_ansi $stats ## no critic (RequireCheckedSyscalls)
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::NAOdash - Analyze NetHack xlogfiles and extract statistics (command-line interface)
+
+=head1 SYNOPSIS
+
+ use App::NAOdash;
+ App::NAOdash::run(@ARGV);
+
+=head1 DESCRIPTION
+
+App::NAOdash is the backend of the L<naodash> script, a command-line
+interface to L<NetHack::NAOdash>.
+
+It defines two functions:
+
+=over
+
+=item B<naodash_to_ansi>(I<$stats>)
+
+Takes the result of B<naodash_user> or B<naodash_xlog> and presents it
+in a text form, using ANSI color escape sequences and unicode ticks
+(✓) and X marks (✗) to indicate the presence/absence of checks.
+
+=item B<run>(I<$user_or_path>)
+
+Analyzes the xlogfile for the given user / at the given path, passes
+the result through B<naodash_to_ansi> and prints the result.
+
+If the argument contains non-word characters, it is interpreted as a
+path. Otherwise it is interpreted as a NAO username.
+
+=back
+
+=head1 SEE ALSO
+
+L<naodash>, L<NetHack::NAOdash>, L<App::Web::NAOdash>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
--- /dev/null
+package App::Web::NAOdash;
+
+use 5.014000;
+use strict;
+use warnings;
+use re '/saa';
+use parent qw/Plack::Component/;
+
+our $VERSION = '0.001';
+
+use Digest::SHA qw/sha256_base64/;
+use File::Slurp;
+use HTML::TreeBuilder;
+use JSON::MaybeXS qw/encode_json/;
+use NetHack::NAOdash qw/naodash_user/;
+
+my ($dash, $css, $css_hash);
+
+{
+ $css = read_file 'web/dash.css';
+ $css =~ y/\n\t//d;
+ $css =~ s/([):]) /$1/g;
+ $css =~ s/ ([{(])/$1/g;
+ $css_hash = 'sha256-' . sha256_base64($css) . '=';
+ my $tb = HTML::TreeBuilder->new;
+ $tb->ignore_unknown(0);
+ $dash = $tb->parse_file('web/dash.html');
+ $dash->find('link')->postinsert([style => $css])->detach;
+}
+
+sub format_time {
+ my ($time) = @_;
+ return unless defined $time;
+ my %units = (
+ s => 60,
+ m => 60,
+ h => 24,
+ d => 7,
+ w => 1e9,
+ );
+ my @parts;
+ for (qw/s m h d w/) {
+ use integer;
+ last unless $time;
+ unshift @parts, ($time % $units{$_}) . $_;
+ $time /= $units{$_};
+ }
+ join ' ', @parts;
+}
+
+sub make_html {
+ my ($name, $result) = @_;
+ my @checks = @{$result->{checks}};
+ my %numbers = %{$result->{numbers}};
+ $numbers{totalrealtime} = format_time $numbers{totalrealtime};
+ $numbers{minrealtime} = format_time $numbers{minrealtime};
+
+ my $tree = $dash->clone;
+ $tree->find('title')->delete_content->push_content("Dashboard for $name");
+ $tree->find('a')->attr(href => $tree->find('a')->attr('href') . $name);
+ $tree->find('a')->delete_content->push_content($name);
+ for (@checks) {
+ my $el = $tree->look_down(id => $_);
+ warn "No element for check $_" unless $el; ## no critic (RequireCarping)
+ $el->attr(class => 'done') if $el;
+ }
+ while (my ($id, $num) = each %numbers) {
+ next unless defined $num;
+ my $el = $tree->look_down(id => $id);
+ warn "No element for check $id" unless $el; ## no critic (RequireCarping)
+ $el->delete_content->push_content($num);
+ }
+ $tree->as_HTML;
+}
+
+sub reply {
+ my ($code, $message, $type) = @_;
+ $type //= 'text/plain';
+ [$code, [
+ 'Cache-Control' => ($code < 500 ? 'max-age=86400' : 'no-cache'),
+ 'Content-Type' => "$type; charset=utf-8",
+ 'Content-Length' => length $message,
+# Safari implements CSP Level 1 but not CSP Level 2
+# 'Content-Security-Policy' => "default-src 'none'; style-src '$css_hash';",
+ ], [$message]]
+}
+
+sub call {
+ my ($self, $env) = @_;
+ return reply 400, 'Bad request: user contains characters outside [a-zA-Z0-9_]' unless $env->{PATH_INFO} =~ m{^/(\w+)$};
+ my $name = $1;
+ my $result = eval { naodash_user $name } or return reply 500, $@;
+
+ return reply 200, encode_json($result), 'application/json' if $self->{json};
+ return reply 200, make_html($name, $result), 'text/html';
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Web::NAOdash - Analyze NetHack xlogfiles and extract statistics (web interface)
+
+=head1 SYNOPSIS
+
+ # In app.psgi
+ use App::Web::NAOdash;
+ use Plack::Builder;
+
+ builder {
+ mount '/dash/' => App::Web::NAOdash->new->to_app;
+ mount '/json/' => App::Web::NAOdash->new(json => 1)->to_app;
+ ...
+ }
+
+=head1 DESCRIPTION
+
+App::Web::NAOdash is a web interface to L<NetHack::NAOdash>.
+
+It handles URLs of the form C</username>, where I<username> is a NAO
+username. It retrieves the xlogfile from NAO and returns the result of
+the analysis.
+
+The constructor takes a single named parameter, I<json>, that is false
+by default. The result will be returned as HTML is I<json> is false,
+as JSON if I<json> is true.
+
+=head1 SEE ALSO
+
+L<NetHack::NAOdash>, L<App::NAOdash>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
--- /dev/null
+package NetHack::NAOdash;
+
+use 5.014000;
+use strict;
+use warnings;
+use re '/saa';
+use parent qw/Exporter/;
+
+our $VERSION = '0.001';
+our @EXPORT_OK = qw/naodash_xlog naodash_user/;
+our @EXPORT = @EXPORT_OK;
+
+use HTTP::Tiny;
+use List::Util qw/max min sum/;
+use List::MoreUtils qw/uniq/;
+use Text::XLogfile qw/parse_xlogline/;
+
+sub won_game {
+ my %game = @_;
+ $game{death} eq 'ascended'
+}
+
+our @check_subs = (
+ sub { # Combos
+ my %game = @_;
+ return unless won_game %game;
+ $game{align0} //= $game{align};
+ "combo_$game{role}_$game{race}_$game{align0}"
+ },
+
+ sub { # Achievements
+ my %game = @_;
+ my @achieves = qw/bell gehennom candelabrum book invocation amulet endgame astral ascended luckstone sokoban medusa/;
+ map { $game{achieve} & (1 << $_) ? "achieve_$achieves[$_]" : () } 0 .. $#achieves
+ },
+
+ sub { # Conducts
+ my %game = @_;
+ return unless won_game %game;
+ my @conducts = qw/foodless vegan vegetarian atheist weaponless pacifist illiterate polypileless polyselfless wishless artiwishless genocideless/;
+ map { $game{conduct} & (1 << $_) ? "conduct_$conducts[$_]" : () } 0 .. $#conducts
+ },
+
+ sub { # Unofficial conducts
+ my %game = @_;
+ return unless won_game %game;
+ my @uconducts;
+ push @uconducts, 'survivor' if $game{deaths} == 0;
+ push @uconducts, 'boneless' unless $game{flags} & 32;
+ push @uconducts, 'minscore' if $game{points} - 100 * ($game{maxlvl} - 45) == 24_400;
+ map { "uconduct_$_" } @uconducts
+ },
+);
+
+our %sum_subs = (
+ games => sub { 1 },
+ ascensions => sub {
+ my %game = @_;
+ !!won_game %game
+ },
+ totalrealtime => sub {
+ my %game = @_;
+ $game{realtime} // 0
+ },
+);
+
+sub make_attr_sub ($) { ## no critic (ProhibitSubroutinePrototypes)
+ my ($attr) = @_;
+ sub {
+ my %game = @_;
+ return unless won_game %game;
+ $game{$attr} // ()
+ },
+}
+
+our %max_subs = (
+ maxhp => make_attr_sub 'maxhp',
+ maxpoints => make_attr_sub 'points',
+ maxconducts => make_attr_sub 'nconducts',
+);
+
+our %min_subs = (
+ minturns => make_attr_sub 'turns',
+ minrealtime => make_attr_sub 'realtime',
+);
+
+sub naodash_xlog { ## no critic (RequireArgUnpacking)
+ my ($xlog) = join '', @_;
+ my %number_subs = (%sum_subs, %max_subs, %min_subs);
+
+ my @checks;
+ my %numbers = map { $_ => [] } keys %number_subs;
+
+ for my $logline (split /\n/, $xlog) {
+ my %game = %{parse_xlogline $logline};
+ for (keys %game) {
+ delete $game{$_} if $game{$_} eq ''
+ }
+ next if $game{flags} & 3; # flag 0x01 is wizard mode, 0x02 is explore mode
+ push @checks, $_->(%game) for @check_subs;
+ push @{$numbers{$_}}, $number_subs{$_}->(%game) for keys %number_subs;
+ }
+
+ $numbers{$_} = sum @{$numbers{$_}} for keys %sum_subs;
+ $numbers{$_} = max @{$numbers{$_}} for keys %max_subs;
+ $numbers{$_} = min @{$numbers{$_}} for keys %min_subs;
+ @checks = uniq map { lc } @checks;
+
+ {checks => [sort @checks], numbers => \%numbers}
+}
+
+my $ht = HTTP::Tiny->new(agent => "NetHack-NAOdash/$VERSION ");
+
+sub naodash_user {
+ my ($name) = @_;
+ my $ret = $ht->get("http://alt.org/nethack/player-all-xlog.php?player=$name");
+ die 'Error while retrieving xlogfile from alt.org: ' . $ret->{status} . ' ' . $ret->{reason} . "\n" unless $ret->{success};
+ my ($xlog) = $ret->{content} =~ m{<pre>(.*)</pre>}i;
+ die "No xlogfile found for user $name\n" unless defined $xlog;
+ naodash_xlog $xlog;
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+NetHack::NAOdash - Analyze NetHack xlogfiles and extract statistics
+
+=head1 SYNOPSIS
+
+ use NetHack::NAOdash;
+ my $stats = naodash_user 'mgv'; # Retrieve and analyze mgv's xlogfile from alt.org
+ my @checks = @{$stats->{checks}}; # List of "achievements" obtained by mgv
+ my %checks = map { $_ => 1 } @checks;
+ say "mgv has ascended an orcish rogue" if $checks{combo_rog_orc_cha};
+ say "mgv has ascended an atheist character" if $checks{conduct_atheist};
+ my %numbers = %{$stats->{numbers}};
+ say "mgv has ascended $numbers{ascensions} out of $numbers{games} games";
+ say "mgv has spent $numbers{totalrealtime} seconds playing NetHack on NAO";
+
+ use File::Slurp;
+ $stats = naodash_xlog read_file 'path/to/my/xlogfile';
+ %checks = map { $_ => 1 } @{$stats->{checks}};
+ say "I have ascended a survivor" if $checks{uconduct_survivor};
+
+=head1 DESCRIPTION
+
+NetHack::NAOdash analyzes a NetHack xlogfile and reports statistics.
+There are two types of statistics: B<checks>, which are flags
+(booleans) and B<numbers> which are integers.
+
+The B<checks> are tracked across all games. That is, a B<check> will
+be true in the statistics if it is true in at least one game. Except
+for B<checks> in the I<Achievements> category, only games that end in
+an ascension are considered for awarding a B<check>.
+
+The B<checks>, sorted by category, are:
+
+=over
+
+=item B<Achievements>
+
+These start with C<achieve_> and represent significant milestones in a
+game. They are usually relevant only for users who never ascended, as
+a game that ends in an ascension generally meets all of them.
+
+ achieve_sokoban achieve_luckstone achieve_medusa achieve_bell
+ achieve_gehennom achieve_candelabrum achieve_book achieve_invocation
+ achieve_amulet achieve_endgame achieve_astral achieve_ascended
+
+=item B<Starting Combos>
+
+These look like C<combo_role_race_alignment> and represent
+role/race/alignment combinations in ascended games. The starting
+alignment, not the alignment at the end of the game is considered. For
+example, C<cav_gno_neu> is true if the user ascended at least one
+gnomish caveman.
+
+=item B<Conducts>
+
+These start with C<conduct_> and represent the 12 officially tracked
+conducts.
+
+ conduct_foodless conduct_vegan conduct_vegetarian
+ conduct_atheist conduct_weaponless conduct_pacifist
+ conduct_illiterate conduct_genocideless conduct_polypileless
+ conduct_polyselfless conduct_wishless conduct_artiwishless
+
+=item B<Unofficial Conducts>
+
+These start with C<uconduct_> and represent conducts that are not
+officially tracked by the game.
+
+ uconduct_survivor uconduct_bones uconduct_minscore
+
+=back
+
+The numbers are:
+
+=over
+
+=item B<totalrealtime>
+
+The total time spent playing NetHack on NAO, in seconds.
+
+=item B<games>
+
+The number of games played.
+
+=item B<ascensions>
+
+The number of games played that ended in an ascension.
+
+=item B<maxhp>
+
+The highest maxHP at the end of an ascension.
+
+=item B<maxpoints>
+
+The highest score obtained at the end of an ascension.
+
+=item B<maxconducts>
+
+The maximum number of conducts at the end of an ascension.
+
+=item B<minturns>
+
+The minimum turns across ascended games.
+
+=item B<minrealtime>
+
+The minimum realtime across ascended games, in seconds.
+
+=back
+
+This module exports two functions:
+
+=over
+
+=item B<naodash_xlog>(I<@lines>)
+
+=item B<naodash_xlog>(I<$xlog>)
+
+Takes the contents of an xlogfile and returns the results of the
+analysis. The arguments are joined together then split by the newline
+character, so they can be specified as a single string, as a list of
+lines, or as a combination thereof.
+
+The return value is of the following form:
+
+ { checks => ['achieve_sokoban', 'achieve_luckstone', ...],
+ numbers => {totalrealtime => 12345, games => 2, ...} }
+
+In other words, C<< @{$result->{checks}} >> is an array of B<checks>
+that are true and C<< %{$result->{numbers}} >> is a hash of
+B<numbers>.
+
+=item B<naodash_user>(I<$nao_username>)
+
+Retrieves the xlogfile of a user from NAO and gives it to
+B<naodash_xlog>. Dies if no xlogfile is found or if the server cannot
+be contacted.
+
+=back
+
+=head1 SEE ALSO
+
+L<App::NAOdash>, L<App::Web::NAOdash>, L<http://alt.org/nethack/>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
--- /dev/null
+#!/usr/bin/perl
+use 5.014000;
+use strict;
+use warnings;
+
+use App::NAOdash;
+
+App::NAOdash::run(@ARGV);
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+naodash - Analyze NetHack xlogfiles and extract statistics (command-line interface)
+
+=head1 SYNOPSIS
+
+ naodash mgv # Show statistics for the mgv user on NAO
+ naodash /path/to/xlogfile # Show statistics for a given xlogfile
+
+=head1 DESCRIPTION
+
+naodash is a command-line interface to L<NetHack::NAOdash>. It takes a
+NAO username or a path to an xlogfile, analyzes it, and prints the
+results of the analysis. A terminal with color and/or UTF-8 support is
+required. Do not parse this command's output. For computer-readable
+output, please use the L<NetHack::NAOdash> library directly.
+
+=head1 SEE ALSO
+
+L<NetHack::NAOdash>, L<http://alt.org/nethack/>, L<App::NAOdash>, L<App::Web::NAOdash>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
--- /dev/null
+#!/usr/bin/perl
+use 5.014000;
+use strict;
+use warnings;
+
+use Test::More tests => 2;
+
+BEGIN { use_ok 'NetHack::NAOdash' }
+
+open my $fh, '<', 't/xlogfile';
+my @xlog = <$fh>;
+close $fh;
+
+is_deeply naodash_xlog (@xlog), {
+ numbers => {
+ ascensions => 15,
+ games => 85,
+ maxconducts => 4,
+ maxhp => 422,
+ maxpoints => 3429164,
+ minrealtime => 43395,
+ minturns => 36028,
+ totalrealtime => 1483024,
+ },
+
+ checks => [qw/achieve_amulet achieve_ascended achieve_astral achieve_bell achieve_book achieve_candelabrum achieve_endgame achieve_gehennom achieve_invocation achieve_luckstone achieve_medusa achieve_sokoban combo_arc_dwa_law combo_bar_orc_cha combo_cav_gno_neu combo_hea_gno_neu combo_kni_hum_law combo_mon_hum_neu combo_pri_hum_law combo_pri_hum_neu combo_ran_elf_cha combo_rog_orc_cha combo_sam_hum_law combo_tou_hum_neu combo_val_dwa_law combo_wiz_elf_cha conduct_artiwishless conduct_atheist conduct_genocideless conduct_polypileless conduct_polyselfless conduct_vegetarian conduct_weaponless uconduct_boneless uconduct_survivor/]
+}, 'naodash_xlog';
--- /dev/null
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+
+use Test::More;
+
+BEGIN { plan skip_all => '$ENV{RELEASE_TESTING} is false' unless $ENV{RELEASE_TESTING} }
+use Test::Perl::Critic -profile => 't/perlcriticrc';
+
+all_critic_ok 'lib'
--- /dev/null
+severity = 1
+
+[-BuiltinFunctions::ProhibitComplexMappings]
+[-CodeLayout::RequireTidyCode]
+[-ControlStructures::ProhibitPostfixControls]
+[-ControlStructures::ProhibitUnlessBlocks]
+[-Documentation::PodSpelling]
+[-Documentation::RequirePodLinksIncludeText]
+[-InputOutput::RequireBracedFileHandleWithPrint]
+[-Modules::ProhibitAutomaticExportation]
+[-References::ProhibitDoubleSigils]
+[-RegularExpressions::ProhibitEnumeratedClasses]
+[-RegularExpressions::RequireLineBoundaryMatching]
+[-Subroutines::RequireFinalReturn]
+[-ValuesAndExpressions::ProhibitConstantPragma]
+[-ValuesAndExpressions::ProhibitEmptyQuotes]
+[-ValuesAndExpressions::ProhibitLeadingZeros]
+[-ValuesAndExpressions::ProhibitMagicNumbers]
+[-ValuesAndExpressions::ProhibitNoisyQuotes]
+[-Variables::ProhibitLocalVars]
+[-Variables::ProhibitPackageVars]
+[-Variables::ProhibitPunctuationVars]
+
+[BuiltinFunctions::ProhibitStringyEval]
+allow_includes = 1
+
+[RegularExpressions::RequireExtendedFormatting]
+minimum_regex_length_to_complain_about = 20
+
+[Documentation::RequirePodSections]
+lib_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR | COPYRIGHT AND LICENSE
+script_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR | COPYRIGHT AND LICENSE
+
+[Subroutines::RequireArgUnpacking]
+short_subroutine_statements = 5
+allow_subscripts = 1
--- /dev/null
+version=3.4.3:points=1574:deathdnum=0:deathlev=4:maxlvl=5:hp=-4:maxhp=29:deaths=1:deathdate=20140316:birthdate=20140316:uid=5:role=Wiz:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a rothe:conduct=3968:turns=2482:achieve=0:nconducts=5:nachieves=0:realtime=1078:starttime=1394973862:endtime=1395008755:gamedelta=34893:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=1691:deathdnum=0:deathlev=4:maxlvl=4:hp=-6:maxhp=28:deaths=1:deathdate=20140317:birthdate=20140317:uid=5:role=Wiz:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a rothe:conduct=4032:turns=1936:achieve=0:nconducts=6:nachieves=0:realtime=1298:starttime=1395061888:endtime=1395063195:gamedelta=1307:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=243:deathdnum=2:deathlev=3:maxlvl=3:hp=-2:maxhp=11:deaths=1:deathdate=20140317:birthdate=20140317:uid=5:role=Wiz:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a gnome:conduct=4040:turns=607:achieve=0:nconducts=7:nachieves=0:realtime=452:starttime=1395063210:endtime=1395063673:gamedelta=463:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=2559688:deathdnum=7:deathlev=-5:maxlvl=49:hp=175:maxhp=231:deaths=1:deathdate=20140428:birthdate=20140317:uid=5:role=Wiz:race=Elf:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=1024:turns=64748:achieve=4095:nconducts=1:nachieves=12:realtime=112824:starttime=1395063679:endtime=1398673207:gamedelta=3609528:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=2338:deathdnum=2:deathlev=5:maxlvl=5:hp=-5:maxhp=47:deaths=1:deathdate=20140430:birthdate=20140428:uid=5:role=Arc:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a magic missile:conduct=3968:turns=2734:achieve=0:nconducts=5:nachieves=0:realtime=4683:starttime=1398673722:endtime=1398861401:gamedelta=187679:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=64:deathdnum=0:deathlev=1:maxlvl=1:hp=-2:maxhp=12:deaths=1:deathdate=20140430:birthdate=20140430:uid=5:role=Arc:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a sewer rat:conduct=4047:turns=67:achieve=0:nconducts=10:nachieves=0:realtime=183:starttime=1398861455:endtime=1398861641:gamedelta=186:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=763:deathdnum=0:deathlev=4:maxlvl=4:hp=-2:maxhp=14:deaths=1:deathdate=20140430:birthdate=20140430:uid=5:role=Arc:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a little dog:conduct=4040:turns=920:achieve=0:nconducts=7:nachieves=0:realtime=633:starttime=1398861653:endtime=1398862299:gamedelta=646:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=138:deathdnum=0:deathlev=1:maxlvl=2:hp=0:maxhp=24:deaths=1:deathdate=20140430:birthdate=20140430:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a jackal, while reading a book:conduct=3976:turns=425:achieve=0:nconducts=6:nachieves=0:realtime=762:starttime=1398862499:endtime=1398863267:gamedelta=768:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=138584:deathdnum=0:deathlev=15:maxlvl=25:hp=-5:maxhp=101:deaths=1:deathdate=20140501:birthdate=20140430:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a mumak:conduct=3712:turns=15586:achieve=2048:nconducts=4:nachieves=1:realtime=22989:starttime=1398863275:endtime=1398970743:gamedelta=107468:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=1593:deathdnum=2:deathlev=5:maxlvl=5:hp=0:maxhp=40:deaths=1:deathdate=20140502:birthdate=20140502:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a dingo:conduct=3976:turns=2159:achieve=0:nconducts=6:nachieves=0:realtime=1705:starttime=1399046649:endtime=1399048359:gamedelta=1710:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=4:deathdnum=0:deathlev=1:maxlvl=1:hp=15:maxhp=15:deaths=0:deathdate=20140502:birthdate=20140502:uid=5:role=Bar:race=Orc:gender=Mal:align=Cha:name=mgv:death=quit:conduct=4095:turns=20:achieve=0:nconducts=12:nachieves=0:realtime=52:starttime=1399048363:endtime=1399048419:gamedelta=56:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=255:deathdnum=0:deathlev=4:maxlvl=4:hp=-2:maxhp=15:deaths=1:deathdate=20140502:birthdate=20140502:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a hobbit, while fainted from lack of food:conduct=3718:turns=1243:achieve=0:nconducts=6:nachieves=0:realtime=609:starttime=1399048429:endtime=1399049044:gamedelta=615:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=883:deathdnum=0:deathlev=4:maxlvl=4:hp=0:maxhp=36:deaths=1:deathdate=20140502:birthdate=20140502:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a rothe, while sleeping:conduct=3976:turns=1354:achieve=0:nconducts=6:nachieves=0:realtime=732:starttime=1399049051:endtime=1399049786:gamedelta=735:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=1680:deathdnum=2:deathlev=5:maxlvl=5:hp=-2:maxhp=32:deaths=1:deathdate=20140506:birthdate=20140502:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a magic missile:conduct=3968:turns=3103:achieve=0:nconducts=5:nachieves=0:realtime=2662:starttime=1399049791:endtime=1399378898:gamedelta=329107:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=2281596:deathdnum=7:deathlev=-5:maxlvl=50:hp=132:maxhp=132:deaths=0:deathdate=20140830:birthdate=20140825:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=ascended:conduct=256:turns=39454:achieve=3583:nconducts=1:nachieves=11:realtime=80436:starttime=1408969798:endtime=1409387505:gamedelta=417707:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=10568:deathdnum=2:deathlev=6:maxlvl=6:hp=0:maxhp=48:deaths=1:deathdate=20140831:birthdate=20140830:uid=5:role=Mon:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a bolt of cold:conduct=3990:turns=4933:achieve=0:nconducts=8:nachieves=0:realtime=7039:starttime=1409387614:endtime=1409472453:gamedelta=84839:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=16615:deathdnum=0:deathlev=9:maxlvl=9:hp=0:maxhp=84:deaths=1:deathdate=20140831:birthdate=20140831:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a hallucinogen-distorted soldier ant:conduct=3968:turns=7403:achieve=0:nconducts=5:nachieves=0:realtime=9151:starttime=1409474095:endtime=1409492250:gamedelta=18155:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=520:deathdnum=2:deathlev=3:maxlvl=3:hp=-5:maxhp=23:deaths=1:deathdate=20140831:birthdate=20140831:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by Yeenoghu:conduct=3976:turns=1009:achieve=0:nconducts=6:nachieves=0:realtime=997:starttime=1409492260:endtime=1409493281:gamedelta=1021:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=6057:deathdnum=0:deathlev=6:maxlvl=7:hp=0:maxhp=62:deaths=1:deathdate=20140831:birthdate=20140831:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a soldier ant:conduct=3712:turns=4652:achieve=0:nconducts=4:nachieves=0:realtime=4235:starttime=1409493340:endtime=1409509834:gamedelta=16494:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=19357:deathdnum=0:deathlev=17:maxlvl=17:hp=-1:maxhp=70:deaths=1:deathdate=20140901:birthdate=20140831:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a Woodland-elf:conduct=3968:turns=10752:achieve=0:nconducts=5:nachieves=0:realtime=11762:starttime=1409509991:endtime=1409583170:gamedelta=73179:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=2163:deathdnum=2:deathlev=7:maxlvl=7:hp=-1:maxhp=48:deaths=1:deathdate=20140901:birthdate=20140901:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a gold golem:conduct=3968:turns=2368:achieve=0:nconducts=5:nachieves=0:realtime=2080:starttime=1409583188:endtime=1409585272:gamedelta=2084:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=18132:deathdnum=0:deathlev=5:maxlvl=6:hp=-7:maxhp=61:deaths=1:deathdate=20140903:birthdate=20140901:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a wand:conduct=3968:turns=6850:achieve=0:nconducts=5:nachieves=0:realtime=11348:starttime=1409585279:endtime=1409739512:gamedelta=154233:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=46:deathdnum=0:deathlev=1:maxlvl=1:hp=-3:maxhp=16:deaths=1:deathdate=20140903:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a bolt of cold:conduct=4087:turns=211:achieve=0:nconducts=11:nachieves=0:realtime=86:starttime=1409739520:endtime=1409739611:gamedelta=91:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2546:deathdnum=2:deathlev=8:maxlvl=8:hp=-2:maxhp=48:deaths=1:deathdate=20140903:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by an ettin zombie:conduct=3968:turns=3064:achieve=0:nconducts=5:nachieves=0:realtime=2919:starttime=1409739667:endtime=1409742589:gamedelta=2922:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=6945:deathdnum=4:deathlev=5:maxlvl=7:hp=-3:maxhp=55:deaths=1:deathdate=20140903:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a soldier ant:conduct=3968:turns=4246:achieve=0:nconducts=5:nachieves=0:realtime=5091:starttime=1409742598:endtime=1409748872:gamedelta=6274:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2672:deathdnum=2:deathlev=7:maxlvl=7:hp=-1:maxhp=51:deaths=1:deathdate=20140903:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a little dog, while jumping around:conduct=3968:turns=3039:achieve=0:nconducts=5:nachieves=0:realtime=1295:starttime=1409748876:endtime=1409750175:gamedelta=1299:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=1845610:deathdnum=7:deathlev=-5:maxlvl=53:hp=113:maxhp=113:deaths=0:deathdate=20140906:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=ascended:conduct=1024:turns=37986:achieve=4095:nconducts=1:nachieves=12:realtime=74502:starttime=1409750185:endtime=1410000662:gamedelta=250477:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=5852:deathdnum=0:deathlev=7:maxlvl=7:hp=-1:maxhp=67:deaths=1:deathdate=20140906:birthdate=20140906:uid=5:role=Tou:race=Hum:gender=Mal:align=Neu:name=mgv:death=poisoned by a killer bee:conduct=3968:turns=3667:achieve=0:nconducts=5:nachieves=0:realtime=2293:starttime=1410012348:endtime=1410014648:gamedelta=2300:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=3775:deathdnum=0:deathlev=8:maxlvl=9:hp=-3:maxhp=48:deaths=1:deathdate=20140906:birthdate=20140906:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a panther:conduct=3976:turns=2917:achieve=0:nconducts=6:nachieves=0:realtime=1636:starttime=1410014800:endtime=1410016443:gamedelta=1643:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=5595:deathdnum=0:deathlev=5:maxlvl=5:hp=-8:maxhp=62:deaths=1:deathdate=20140906:birthdate=20140906:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a bolt of cold:conduct=3976:turns=2990:achieve=0:nconducts=6:nachieves=0:realtime=1590:starttime=1410016463:endtime=1410018058:gamedelta=1595:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=4853:deathdnum=2:deathlev=6:maxlvl=6:hp=-2:maxhp=54:deaths=1:deathdate=20140906:birthdate=20140906:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a soldier ant:conduct=3976:turns=2328:achieve=0:nconducts=6:nachieves=0:realtime=1517:starttime=1410018068:endtime=1410024764:gamedelta=6696:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=287599:deathdnum=1:deathlev=30:maxlvl=30:hp=-2:maxhp=100:deaths=1:deathdate=20140908:birthdate=20140906:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a stone golem:conduct=2304:turns=23103:achieve=3074:nconducts=2:nachieves=3:realtime=31860:starttime=1410024774:endtime=1410168612:gamedelta=143838:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=2524230:deathdnum=7:deathlev=-5:maxlvl=51:hp=167:maxhp=204:deaths=0:deathdate=20140910:birthdate=20140908:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=ascended:conduct=0:turns=44351:achieve=4095:nconducts=0:nachieves=12:realtime=52600:starttime=1410168699:endtime=1410385768:gamedelta=217069:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=1801:deathdnum=0:deathlev=5:maxlvl=5:hp=0:maxhp=39:deaths=1:deathdate=20140911:birthdate=20140911:uid=5:role=Rog:race=Orc:gender=Mal:align=Cha:name=mgv:death=killed by a housecat:conduct=3968:turns=2341:achieve=0:nconducts=5:nachieves=0:realtime=1717:starttime=1410455388:endtime=1410457112:gamedelta=1724:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=6436:deathdnum=0:deathlev=6:maxlvl=6:hp=0:maxhp=51:deaths=1:deathdate=20140912:birthdate=20140911:uid=5:role=Rog:race=Orc:gender=Mal:align=Cha:name=mgv:death=killed by a giant ant:conduct=3968:turns=3487:achieve=0:nconducts=5:nachieves=0:realtime=2001:starttime=1410457121:endtime=1410502968:gamedelta=45847:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=2828716:deathdnum=7:deathlev=-5:maxlvl=45:hp=95:maxhp=138:deaths=2:deathdate=20140925:birthdate=20140912:uid=5:role=Rog:race=Orc:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=256:turns=44079:achieve=4095:nconducts=1:nachieves=12:realtime=63926:starttime=1410502985:endtime=1411665285:gamedelta=1162300:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=1818:deathdnum=2:deathlev=6:maxlvl=6:hp=-1:maxhp=41:deaths=1:deathdate=20140926:birthdate=20140926:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=poisoned by a little dart:conduct=3976:turns=1681:achieve=0:nconducts=6:nachieves=0:realtime=1064:starttime=1411746730:endtime=1411747812:gamedelta=1082:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=20623:deathdnum=0:deathlev=10:maxlvl=10:hp=0:maxhp=57:deaths=1:deathdate=20140926:birthdate=20140926:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a wand:conduct=2432:turns=7562:achieve=0:nconducts=3:nachieves=0:realtime=6040:starttime=1411747821:endtime=1411759627:gamedelta=11806:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=1860:deathdnum=2:deathlev=6:maxlvl=6:hp=-5:maxhp=43:deaths=1:deathdate=20140926:birthdate=20140926:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a wolf, while praying:conduct=3968:turns=1686:achieve=0:nconducts=5:nachieves=0:realtime=1010:starttime=1411760269:endtime=1411761350:gamedelta=1081:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=33002:deathdnum=4:deathlev=3:maxlvl=8:hp=0:maxhp=82:deaths=1:deathdate=20140928:birthdate=20140926:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a manes, while praying:conduct=3968:turns=9933:achieve=0:nconducts=5:nachieves=0:realtime=6683:starttime=1411761382:endtime=1411892399:gamedelta=131017:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=20253:deathdnum=0:deathlev=9:maxlvl=9:hp=-3:maxhp=59:deaths=1:deathdate=20140928:birthdate=20140928:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a crocodile:conduct=3968:turns=6982:achieve=0:nconducts=5:nachieves=0:realtime=4587:starttime=1411892564:endtime=1411897302:gamedelta=4738:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=670:deathdnum=2:deathlev=4:maxlvl=4:hp=-3:maxhp=31:deaths=1:deathdate=20141002:birthdate=20140928:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a hill orc:conduct=3968:turns=1026:achieve=0:nconducts=5:nachieves=0:realtime=389:starttime=1411897345:endtime=1412255074:gamedelta=357729:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=7612:deathdnum=2:deathlev=11:maxlvl=11:hp=-3:maxhp=55:deaths=1:deathdate=20141002:birthdate=20141002:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by an ettin zombie:conduct=3968:turns=4768:achieve=0:nconducts=5:nachieves=0:realtime=4228:starttime=1412255090:endtime=1412259385:gamedelta=4295:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=7127:deathdnum=2:deathlev=7:maxlvl=7:hp=0:maxhp=68:deaths=1:deathdate=20141120:birthdate=20141120:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a hallucinogen-distorted soldier ant:conduct=3968:turns=2576:achieve=0:nconducts=5:nachieves=0:realtime=2289:starttime=1416501954:endtime=1416504250:gamedelta=2296:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=85271:deathdnum=0:deathlev=12:maxlvl=13:hp=-3:maxhp=110:deaths=1:deathdate=20141125:birthdate=20141120:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by an invisible sergeant:conduct=3200:turns=19073:achieve=0:nconducts=3:nachieves=0:realtime=22508:starttime=1416504271:endtime=1416905326:gamedelta=401055:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2614:deathdnum=2:deathlev=7:maxlvl=7:hp=0:maxhp=35:deaths=1:deathdate=20141125:birthdate=20141125:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a raven:conduct=3972:turns=3107:achieve=0:nconducts=6:nachieves=0:realtime=2949:starttime=1416905500:endtime=1416908452:gamedelta=2952:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=124804:deathdnum=0:deathlev=23:maxlvl=23:hp=-3:maxhp=112:deaths=1:deathdate=20141126:birthdate=20141125:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by an invisible stalker:conduct=3712:turns=24828:achieve=1024:nconducts=4:nachieves=1:realtime=26890:starttime=1416908461:endtime=1417017705:gamedelta=109244:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2682952:deathdnum=7:deathlev=-5:maxlvl=49:hp=384:maxhp=384:deaths=1:deathdate=20141130:birthdate=20141126:uid=5:role=Tou:race=Hum:gender=Mal:align=Neu:name=mgv:death=ascended:conduct=0:turns=47585:achieve=4095:nconducts=0:nachieves=12:realtime=55676:starttime=1417017822:endtime=1417387940:gamedelta=370118:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=4172:deathdnum=2:deathlev=5:maxlvl=8:hp=0:maxhp=48:deaths=1:deathdate=20141201:birthdate=20141201:uid=5:role=Ran:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a dwarf zombie, while frozen by a monster's gaze:conduct=3968:turns=2846:achieve=0:nconducts=5:nachieves=0:realtime=2263:starttime=1417417112:endtime=1417424607:gamedelta=7495:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=418339:deathdnum=0:deathlev=20:maxlvl=26:hp=-3:maxhp=93:deaths=1:deathdate=20141204:birthdate=20141201:uid=5:role=Ran:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a troll, while unconscious from rotten food:conduct=1664:turns=30737:achieve=3584:nconducts=3:nachieves=3:realtime=44405:starttime=1417424641:endtime=1417711176:gamedelta=286535:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=64547:deathdnum=2:deathlev=12:maxlvl=12:hp=-3:maxhp=80:deaths=1:deathdate=20141206:birthdate=20141204:uid=5:role=Ran:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a lynx, while reading a book:conduct=2432:turns=17778:achieve=1536:nconducts=3:nachieves=2:realtime=23032:starttime=1417711383:endtime=1417853691:gamedelta=142308:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=140:deathdnum=0:deathlev=3:maxlvl=3:hp=-2:maxhp=10:deaths=1:deathdate=20141206:birthdate=20141206:uid=5:role=Hea:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a boiling potion:conduct=3983:turns=447:achieve=0:nconducts=9:nachieves=0:realtime=355:starttime=1417853810:endtime=1417854174:gamedelta=364:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=2930688:deathdnum=7:deathlev=-5:maxlvl=51:hp=326:maxhp=334:deaths=0:deathdate=20141220:birthdate=20141206:uid=5:role=Hea:race=Gno:gender=Mal:align=Neu:name=mgv:death=ascended:conduct=256:turns=54221:achieve=4095:nconducts=1:nachieves=12:realtime=56624:starttime=1417854183:endtime=1419061983:gamedelta=1207800:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=1090:deathdnum=2:deathlev=8:maxlvl=8:hp=-2:maxhp=20:deaths=1:deathdate=20141220:birthdate=20141220:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a giant spider:conduct=3968:turns=5272:achieve=0:nconducts=5:nachieves=0:realtime=6237:starttime=1419062033:endtime=1419070797:gamedelta=8764:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2683318:deathdnum=7:deathlev=-5:maxlvl=50:hp=407:maxhp=422:deaths=0:deathdate=20141222:birthdate=20141220:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=ascended:conduct=1280:turns=49351:achieve=3071:nconducts=2:nachieves=11:realtime=64246:starttime=1419070817:endtime=1419254211:gamedelta=183394:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=33334:deathdnum=0:deathlev=8:maxlvl=8:hp=-2:maxhp=60:deaths=1:deathdate=20141223:birthdate=20141222:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by an ettin mummy:conduct=3968:turns=12157:achieve=1024:nconducts=5:nachieves=1:realtime=16233:starttime=1419262619:endtime=1419325395:gamedelta=62776:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=1124:deathdnum=2:deathlev=4:maxlvl=5:hp=-1:maxhp=39:deaths=1:deathdate=20141223:birthdate=20141223:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a fire ant:conduct=3968:turns=2261:achieve=0:nconducts=5:nachieves=0:realtime=3269:starttime=1419325436:endtime=1419328708:gamedelta=3272:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=28262:deathdnum=0:deathlev=6:maxlvl=8:hp=-3:maxhp=66:deaths=1:deathdate=20141224:birthdate=20141223:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a winter wolf, while frozen by a potion:conduct=3968:turns=11253:achieve=1024:nconducts=5:nachieves=1:realtime=15181:starttime=1419328718:endtime=1419406538:gamedelta=77820:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=506:deathdnum=2:deathlev=3:maxlvl=3:hp=-1:maxhp=21:deaths=1:deathdate=20141224:birthdate=20141224:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a gnome lord:conduct=4040:turns=903:achieve=0:nconducts=7:nachieves=0:realtime=343:starttime=1419406548:endtime=1419406911:gamedelta=363:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=89736:deathdnum=0:deathlev=14:maxlvl=14:hp=82:maxhp=83:deaths=1:deathdate=20141224:birthdate=20141224:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=petrified by a chickatrice corpse:conduct=1792:turns=19468:achieve=1024:nconducts=3:nachieves=1:realtime=14484:starttime=1419406918:endtime=1419448155:gamedelta=41237:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=1495:deathdnum=2:deathlev=5:maxlvl=5:hp=-10:maxhp=37:deaths=1:deathdate=20141225:birthdate=20141225:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a bolt of cold:conduct=3968:turns=1818:achieve=0:nconducts=5:nachieves=0:realtime=947:starttime=1419494273:endtime=1419495223:gamedelta=950:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=39140:deathdnum=0:deathlev=10:maxlvl=10:hp=0:maxhp=95:deaths=1:deathdate=20141225:birthdate=20141225:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a gargoyle:conduct=3968:turns=14552:achieve=1024:nconducts=5:nachieves=1:realtime=10904:starttime=1419495231:endtime=1419513464:gamedelta=18233:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=20944:deathdnum=4:deathlev=5:maxlvl=10:hp=0:maxhp=56:deaths=1:deathdate=20141227:birthdate=20141227:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a hell hound:conduct=3712:turns=7314:achieve=0:nconducts=4:nachieves=0:realtime=4502:starttime=1419678536:endtime=1419716191:gamedelta=37655:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=57399:deathdnum=2:deathlev=7:maxlvl=10:hp=-2:maxhp=66:deaths=1:deathdate=20141228:birthdate=20141227:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a gelatinous cube:conduct=3840:turns=18163:achieve=1024:nconducts=4:nachieves=1:realtime=13206:starttime=1419716255:endtime=1419787047:gamedelta=70792:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=2270808:deathdnum=7:deathlev=-5:maxlvl=50:hp=346:maxhp=347:deaths=0:deathdate=20141231:birthdate=20141229:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=1024:turns=43334:achieve=2047:nconducts=1:nachieves=11:realtime=67591:starttime=1419838527:endtime=1420045200:gamedelta=206673:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=2515342:deathdnum=7:deathlev=-5:maxlvl=50:hp=136:maxhp=300:deaths=0:deathdate=20150103:birthdate=20141231:uid=5:role=Mon:race=Hum:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=2448:turns=36028:achieve=3583:nconducts=4:nachieves=11:realtime=43868:starttime=1420045271:endtime=1420274165:gamedelta=228894:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=2276534:deathdnum=7:deathlev=-5:maxlvl=49:hp=210:maxhp=279:deaths=0:deathdate=20150104:birthdate=20150103:uid=5:role=Sam:race=Hum:gender=Mal:align=Law:name=mgv:death=ascended:conduct=1280:turns=38395:achieve=3583:nconducts=2:nachieves=11:realtime=43395:starttime=1420274625:endtime=1420407069:gamedelta=132444:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=1199780:deathdnum=1:deathlev=27:maxlvl=27:hp=258:maxhp=258:deaths=1:deathdate=20150111:birthdate=20150105:uid=5:role=Bar:race=Orc:gender=Mal:align=Cha:name=mgv:death=petrified by a cockatrice:conduct=1536:turns=46138:achieve=2050:nconducts=2:nachieves=2:realtime=53085:starttime=1420466437:endtime=1420971804:gamedelta=505367:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=3429164:deathdnum=7:deathlev=-5:maxlvl=50:hp=218:maxhp=267:deaths=0:deathdate=20150116:birthdate=20150111:uid=5:role=Bar:race=Orc:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=3456:turns=54089:achieve=3583:nconducts=4:nachieves=11:realtime=68260:starttime=1420977142:endtime=1421444562:gamedelta=467420:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=2865500:deathdnum=7:deathlev=-5:maxlvl=47:hp=400:maxhp=400:deaths=0:deathdate=20150119:birthdate=20150117:uid=5:role=Val:race=Dwa:gender=Mal:align=Law:name=mgv:death=ascended:conduct=2048:turns=38549:achieve=3583:nconducts=1:nachieves=11:realtime=53826:starttime=1421480609:endtime=1421681276:gamedelta=200667:gender0=Fem:align0=Law:flags=32
+version=3.4.3:points=11731:deathdnum=2:deathlev=5:maxlvl=8:hp=0:maxhp=53:deaths=1:deathdate=20150119:birthdate=20150119:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a gray unicorn:conduct=3976:turns=6641:achieve=0:nconducts=6:nachieves=0:realtime=2828:starttime=1421701566:endtime=1421704416:gamedelta=2850:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=2877:deathdnum=2:deathlev=5:maxlvl=5:hp=-2:maxhp=41:deaths=1:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a rothe:conduct=3976:turns=2041:achieve=0:nconducts=6:nachieves=0:realtime=3094:starttime=1421738623:endtime=1421741735:gamedelta=3112:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=9558:deathdnum=0:deathlev=4:maxlvl=6:hp=0:maxhp=56:deaths=1:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a Woodland-elf:conduct=3976:turns=5389:achieve=0:nconducts=6:nachieves=0:realtime=2765:starttime=1421741744:endtime=1421745095:gamedelta=3351:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=6280:deathdnum=2:deathlev=5:maxlvl=5:hp=28:maxhp=70:deaths=0:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=quit:conduct=3968:turns=4366:achieve=0:nconducts=5:nachieves=0:realtime=3049:starttime=1421745102:endtime=1421748153:gamedelta=3051:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=893:deathdnum=0:deathlev=3:maxlvl=4:hp=0:maxhp=36:deaths=1:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a brown mold:conduct=3976:turns=2039:achieve=0:nconducts=6:nachieves=0:realtime=762:starttime=1421748176:endtime=1421748941:gamedelta=765:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2282:deathdnum=2:deathlev=5:maxlvl=5:hp=-2:maxhp=59:deaths=1:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a soldier ant:conduct=3976:turns=1835:achieve=0:nconducts=6:nachieves=0:realtime=893:starttime=1421748958:endtime=1421749853:gamedelta=895:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=11176:deathdnum=0:deathlev=13:maxlvl=13:hp=-10:maxhp=41:deaths=1:deathdate=20150121:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a wand:conduct=3976:turns=7112:achieve=0:nconducts=6:nachieves=0:realtime=4630:starttime=1421749861:endtime=1421846411:gamedelta=96550:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=159:deathdnum=0:deathlev=1:maxlvl=1:hp=14:maxhp=14:deaths=0:deathdate=20150121:birthdate=20150121:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=quit:conduct=4032:turns=166:achieve=0:nconducts=6:nachieves=0:realtime=199:starttime=1421846431:endtime=1421846632:gamedelta=201:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=6804:deathdnum=2:deathlev=5:maxlvl=6:hp=-1:maxhp=68:deaths=1:deathdate=20150124:birthdate=20150121:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a jaguar:conduct=3976:turns=3752:achieve=0:nconducts=6:nachieves=0:realtime=3581:starttime=1421846639:endtime=1422090230:gamedelta=243591:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=113905:deathdnum=0:deathlev=26:maxlvl=26:hp=84:maxhp=84:deaths=1:deathdate=20150127:birthdate=20150124:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=drowned in a pool of water by an electric eel:conduct=3720:turns=18464:achieve=1024:nconducts=5:nachieves=1:realtime=23801:starttime=1422090240:endtime=1422395519:gamedelta=305279:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=80743:deathdnum=0:deathlev=15:maxlvl=18:hp=-5:maxhp=84:deaths=1:deathdate=20150204:birthdate=20150130:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a giant mummy:conduct=3720:turns=17783:achieve=0:nconducts=5:nachieves=0:realtime=25745:starttime=1422624841:endtime=1423076735:gamedelta=451894:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=3591:deathdnum=2:deathlev=5:maxlvl=5:hp=-4:maxhp=61:deaths=1:deathdate=20150208:birthdate=20150204:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a soldier ant:conduct=3976:turns=3172:achieve=0:nconducts=6:nachieves=0:realtime=2767:starttime=1423076771:endtime=1423382793:gamedelta=306022:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2903014:deathdnum=7:deathlev=-5:maxlvl=52:hp=311:maxhp=397:deaths=0:deathdate=20150627:birthdate=20150208:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=ascended:conduct=2440:turns=37729:achieve=4095:nconducts=4:nachieves=12:realtime=86482:starttime=1423382814:endtime=1435429536:gamedelta=12046722:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=17192:deathdnum=0:deathlev=6:maxlvl=6:hp=0:maxhp=64:deaths=1:deathdate=20150627:birthdate=20150627:uid=5:role=Mon:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a rabid rat, while frozen by a monster's gaze:conduct=3988:turns=7550:achieve=1024:nconducts=7:nachieves=1:realtime=7266:starttime=1435431361:endtime=1435438629:gamedelta=7268:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=2765250:deathdnum=7:deathlev=-5:maxlvl=47:hp=264:maxhp=295:deaths=0:deathdate=20150701:birthdate=20150627:uid=5:role=Mon:race=Hum:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=2436:turns=40262:achieve=4095:nconducts=4:nachieves=12:realtime=53850:starttime=1435438727:endtime=1435752162:gamedelta=313435:gender0=Mal:align0=Neu:flags=32
--- /dev/null
+html {
+ color: #DDD;
+ background-color: #000;
+ margin: 0;
+ padding: 0 2% 1%;
+ line-height: 1.5;
+}
+
+h2 {
+ text-align: center;
+ display: table;
+ white-space: nowrap;
+ margin: 0.5em;
+ text-transform: uppercase;
+ font-family: monospace;
+ font-size: 1.5em;
+ font-weight: 100;
+}
+
+h2:before,
+h2:after {
+ content: ' ';
+ display: table-cell;
+ position: relative;
+ top: 0.55em;
+ width: 48%;
+ border-top: 1px dashed #BBB;
+}
+
+h2:before {
+ right: 1.5%;
+}
+
+h2:after {
+ left: 1.5%;
+}
+
+#title {
+ text-align: center;
+}
+
+span[title] {
+ color: #F66;
+ font-family: monospace;
+ font-size: 1.25em;
+ margin-right: 1.5em;
+}
+
+
+span[title].done {
+ color: #7E7;
+}
+
+dl {
+ font-family: monospace;
+ font-size: 1.25em;
+ margin-top: 0;
+}
+
+dt {
+ font-weight: bold;
+ float: left;
+ clear: left;
+}
+
+dt:after {
+ content: ":";
+}
+
+dd {
+ float: left;
+ margin-left: 1em;
+}
+
+footer {
+ margin-top: 1em;
+ text-align: center;
+ clear: both;
+}
+
+a:link {
+ color: #66F;
+ text-decoration: none;
+}
+
+a:visited {
+ color: #84B;
+}
+
+@media (min-width: 500px) {
+ .cols {
+ -moz-columns: 2;
+ -webkit-columns: 2;
+ }
+}
--- /dev/null
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>NAO dashboard for NAME</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="stylesheet" href="dash.css">
+
+<h1 id="title">NAO dashboard for <a href="http://alt.org/nethack/plr.php?player=">NAME</a></h1>
+
+<div id="achievements">
+<h2>Achievements</h2>
+<span id="achieve_sokoban" title="Finished Sokoban">Sokoban</span>
+<span id="achieve_luckstone" title="Got the luckstone at the Mine's End">Luckstone</span>
+<span id="achieve_medusa" title="Killed Medusa">Medusa</span>
+<span id="achieve_bell" title="Got the Bell of Opening">Bell</span>
+<span id="achieve_gehennom" title="Reached Gehennom">Gehennom</span>
+<span id="achieve_candelabrum" title="Got the Candelabrum of Invocation">Candelabrum</span>
+<span id="achieve_book" title="Got the Book of the Dead">Book</span>
+<span id="achieve_invocation" title="Performed the Invocation">Invocation</span>
+<span id="achieve_amulet" title="Got the Amulet of Yendor">Amulet</span>
+<span id="achieve_endgame" title="Reached the Endgame">Endgame</span>
+<span id="achieve_astral" title="Reached the Astral Plane">Astral</span>
+<span id="achieve_ascended" title="Ascended">Ascended</span>
+</div>
+
+<div id="combos">
+<h2>Starting Combos</h2>
+<div class="cols">
+<span id="combo_arc_hum_law" title="">Arc-Hum-Law</span>
+<span id="combo_arc_hum_neu" title="">Arc-Hum-Neu</span>
+<span id="combo_arc_dwa_law" title="">Arc-Dwa-Law</span>
+<span id="combo_arc_gno_neu" title="">Arc-Gno-Neu</span>
+<br>
+
+<span id="combo_bar_hum_neu" title="">Bar-Hum-Neu</span>
+<span id="combo_bar_hum_cha" title="">Bar-Hum-Cha</span>
+<span id="combo_bar_orc_cha" title="">Bar-Orc-Cha</span>
+<br>
+
+<span id="combo_cav_hum_law" title="">Cav-Hum-Law</span>
+<span id="combo_cav_hum_neu" title="">Cav-Hum-Neu</span>
+<span id="combo_cav_dwa_law" title="">Cav-Dwa-Law</span>
+<span id="combo_cav_gno_neu" title="">Cav-Gno-Neu</span>
+<br>
+
+<span id="combo_hea_hum_neu" title="">Hea-Hum-Neu</span>
+<span id="combo_hea_gno_neu" title="">Hea-Gno-Neu</span>
+<br>
+
+<span id="combo_kni_hum_law" title="">Kni-Hum-Law</span>
+<br>
+
+<span id="combo_mon_hum_law" title="">Mon-Hum-Law</span>
+<span id="combo_mon_hum_neu" title="">Mon-Hum-Neu</span>
+<span id="combo_mon_hum_cha" title="">Mon-Hum-Cha</span>
+<br>
+
+<span id="combo_pri_hum_law" title="">Pri-Hum-Law</span>
+<span id="combo_pri_hum_neu" title="">Pri-Hum-Neu</span>
+<span id="combo_pri_hum_cha" title="">Pri-Hum-Cha</span>
+<span id="combo_pri_elf_cha" title="">Pri-Elf-Cha</span>
+<br>
+
+<span id="combo_ran_hum_neu" title="">Ran-Hum-Neu</span>
+<span id="combo_ran_hum_cha" title="">Ran-Hum-Cha</span>
+<span id="combo_ran_elf_cha" title="">Ran-Elf-Cha</span>
+<span id="combo_ran_gno_neu" title="">Ran-Gno-Neu</span>
+<span id="combo_ran_orc_cha" title="">Ran-Orc-Cha</span>
+<br>
+
+<span id="combo_rog_hum_cha" title="">Rog-Hum-Cha</span>
+<span id="combo_rog_orc_cha" title="">Rog-Orc-Cha</span>
+<br>
+
+<span id="combo_sam_hum_law" title="">Sam-Hum-Law</span>
+<br>
+
+<span id="combo_tou_hum_neu" title="">Tou-Hum-Neu</span>
+<br>
+
+<span id="combo_val_hum_law" title="">Val-Hum-Law</span>
+<span id="combo_val_hum_neu" title="">Val-Hum-Neu</span>
+<span id="combo_val_dwa_law" title="">Val-Dwa-Law</span>
+<br>
+
+<span id="combo_wiz_hum_neu" title="">Wiz-Hum-Neu</span>
+<span id="combo_wiz_hum_cha" title="">Wiz-Hum-Cha</span>
+<span id="combo_wiz_elf_cha" title="">Wiz-Elf-Cha</span>
+<span id="combo_wiz_gno_neu" title="">Wiz-Gno-Neu</span>
+<span id="combo_wiz_orc_cha" title="">Wiz-Orc-Cha</span>
+</div>
+</div>
+
+<div id="conducts">
+<h2>Conducts</h2>
+<span id="conduct_foodless" title="You have gone without food">Foodless</span>
+<span id="conduct_vegan" title="You have followed a strict vegan diet">Vegan</span>
+<span id="conduct_vegetarian" title="You have been vegetarian">Vegetarian</span>
+<span id="conduct_atheist" title="You have been an atheist">Atheist</span>
+<span id="conduct_weaponless" title="You have never hit with a wielded weapon">Weaponless</span>
+<span id="conduct_pacifist" title="You have been a pacifist">Pacifist</span>
+<span id="conduct_illiterate" title="You have been illiterate">Illiterate</span>
+<span id="conduct_genocideless" title="You have never genocided any monsters">Genocideless</span>
+<span id="conduct_polypileless" title="You have never polymorphed an object">Polypileless</span>
+<span id="conduct_polyselfless" title="You have never changed form">Polyselfless</span>
+<span id="conduct_wishless" title="You used no wishes">Wishless</span>
+<span id="conduct_artiwishless" title="You have not wished for any artifacts">Artiwishless</span>
+</div>
+
+<div id="unofficial_conducts">
+<h2>Unofficial conducts</h2>
+<span id="uconduct_survivor" title="You survived">Survivor</span>
+<span id="uconduct_boneless" title="You never used bones">Boneless</span>
+<span id="uconduct_minscore" title="You got the minimum possible score for your dungeon">Minscore</span>
+</div>
+
+<div id="numbers">
+<h2>Numbers</h2>
+<div class="cols">
+<dl>
+<dt>Time played<dd id="totalrealtime">
+<dt>Games<dd id="games">
+<dt>Ascensions<dd id="ascensions">
+<dt>Most HP<dd id="maxhp">
+<dt>Most points<dd id="maxpoints">
+<dt>Most conducts<dd id="maxconducts">
+<dt>Least turns<dd id="minturns">
+<dt>Least time<dd id="minrealtime">
+</dl>
+</div>
+</div>
+
+<footer><small><a href="https://git.ieval.ro/?p=nethack-naodash.git">Code repository</a> • <a href="https://metacpan.org/release/NetHack-NAOdash">MetaCPAN release page</a> • Send feedback and patches to <a href="mailto:marius@ieval.ro">marius@ieval.ro</a> or mgv @ <a href="https://freenode.net/">Freenode</a></small></footer>