#!/usr/bin/perl use warnings; use strict; $|=1; use CGI qw/:standard *ul *table *Tr/; use Time::HiRes qw ( time ); my $begin = time; my @sp = (); my $debug = param("debug") || url_param("debug") || 0; if ($debug) { push @sp, "debug=1"; } my $submit = url({absolute=>1,}); $submit =~ s/:81//; if (@sp) { $submit .= "?".join("&",@sp); } my $title = "HISTORY"; print header,"\n", start_html($title),"\n"; print h1(a({href=>$submit,},$title)),"\n"; my @vers = @EVE::Db::versions; my %vers = (); for (@vers) { my @r = @$_; my $k = shift @r; die "dupe db $k" if exists $vers{$k}; $vers{$k} = \@r; } my $type = param("type"); $type = undef unless defined $type && $type =~ /^\d+$/; my @parm = (); my $patt = param("patt") || ""; $patt =~ s/\s+/ /g; $patt =~ s/(^ | $)//g; print hr, br, start_form({action => $submit,},),"\n", start_table,"\n"; print "Search: ", textfield(-name => 'patt', -default => $patt, -size => 20,), br, "\n"; my $lpatt; my $tcond; my @targs = (); if ($patt) { # Delete("patt"); $lpatt = $patt; $lpatt =~ s/\s+/%/g; $lpatt =~ s/(^|$)/%/g; $lpatt =~ s/%+/%/g; $tcond = "typeName like ? or description like ?"; @targs = ($lpatt, $lpatt,); } elsif ($type) { $tcond = "typeID = ?"; @targs = ($type,); } else { print submit, end_form, "\n"; goto EXITHTML; } # TODO make DBs selectable my @v = map {$_->[1]} @vers; use EVE::Db; my $dbh = EVE::Db::dbh(); die "no dbh" unless $dbh; my %types = (); for my $v (reverse @v) { die "bad version $v" unless $v =~ /^[a-z]+\d*$/; my $sth = $dbh->prepare_cached(qq{ select * from $v.invTypes where $tcond }) or die $dbh->errstr; $sth->execute(@targs) or die $sth->errstr; my $types = $sth->fetchall_hashref("typeID"); $sth->finish; for (keys %$types) { $types{$_} ||= $types->{$_}; } } $type = undef unless defined $type && exists $types{$type}; #for (sort keys %types) { # printf "%s: %s%s\n", # $_, $types{$_}->{typeName}, # br; #} if (!defined $type) { # try to auto-select type my @t = keys %types; if (scalar(@t) == 1) { # just one match? $type = $t[0]; } else { # pick shortest match my $n; for my $t (@t) { my $c = $types{$t}; my $N = $c->{typeName}; if (!defined $n || length $n > length $N) { $type = $t; $n = $N; } if (lc $N eq lc $patt) { $type = $t; last; } } } } my %types_to_name = (); for (keys %types) { $types_to_name{$_} = $types{$_}->{typeName}; } my @types_by_name = sort { lc($types_to_name{$a}) cmp lc($types_to_name{$b}) } keys %types_to_name; print "Select: ", popup_menu(-name => 'type', -values => \@types_by_name, -default => $type, -labels => \%types_to_name, ),br, "\n"; print submit, end_form, "\n"; goto EXITHTML unless $type; my %data = (); for my $v (@v) { die "bad version $v" unless $v =~ /^[a-z]+\d*$/; my $sth = $dbh->prepare_cached(qq{ select * from $v.invTypes where typeID = ? }) or die $dbh->errstr; $sth->execute($type) or die $sth->errstr; my $row = $sth->fetchrow_hashref(); $sth->finish; $data{$v} = $row; # print "mass($v): ", $row->{mass}, br, "\n"; } &print_diffs("invTypes", \@v, \%data); %data = (); for my $v (@v) { die "bad version $v" unless $v =~ /^[a-z]+\d*$/; my $sth = $dbh->prepare_cached(qq{ select ta.attributeID, at.attributeName, at.description, coalesce(ta.valueFloat, ta.valueInt) from $v.dgmTypeAttributes ta, $v.dgmAttributeTypes at where ta.typeID = ? and ta.attributeID = at.attributeID }) or die $dbh->errstr; $sth->execute($type) or die $sth->errstr; my $d = {}; my $row; while ($row = $sth->fetchrow_arrayref()) { my ($aid, $an, $ad, $av,) = @$row; my $k = span({style=>'color: green',title=>"attributeID:".$aid,}, $an); $d->{$k} = $av; } $sth->finish; $data{$v} = $d; # print "mass($v): ", $row->{mass}, br, "\n"; } &print_diffs("dgmAttributes", \@v, \%data); EXITHTML: if ($debug) { print hr,"\n"; for (sort keys %ENV) { printf "%s: %s%s\n", $_, $ENV{$_}, br; } } my $runtime = time - $begin; print hr, $runtime ? sprintf "Completed in %.3f sec.", $runtime : "", end_html,"\n"; exit 0; sub print_diffs($$) { my ($n, $h, $d,) = @_; my ($v, $k,); my %k = (); for $v (keys %$d) { for $k (keys %{$d->{$v}}) { $k{$k}++; } } print start_table({border=>1,}),"\n", Tr(th([$n,map({span({style=>'color: green',title=>$vers{$_}[1],},$_)} @$h),],),),"\n"; for $k (sort keys %k) { my $r = th($k)."\n"; my ($span,$val,$from,$to,); for $v (@$h) { my $V = exists $d->{$v}->{$k} ? &pretty($v, $k, $d->{$v}->{$k}) : "n/a"; if (defined $span) { if ((!defined $val && !defined $V) || ( defined $val && defined $V && ( ($val eq $V) || ("$val$V" =~ /^[-e\d\.]+$/ && abs($val-$V) < 0.001)))) { $span++; $to = $v; } else { $r .= td({colspan=>$span,align=>'center',}, $val." ". span({style=>'color: green',title=> sprintf "%s %s%s",$from,$vers{$from}[1], (defined $to ? sprintf(" - %s %s",$to,$vers{$to}[1]) : "",) },"dT") )."\n"; $span = undef; } } if (!defined $span) { $span = 1; $val = $V; $from = $v; $to = undef; } } if (defined $span) { $r .= td({colspan=>$span,align=>'center',}, $val." ". span({style=>'color: green',title=> sprintf "%s %s%s",$from,$vers{$from}[1], (defined $to ? sprintf(" - %s %s",$to,$vers{$to}[1]) : "",) },"dT") )."\n"; } print Tr($r,),"\n"; } print end_table,"\n"; } my %pcache; sub pretty ($$$) { my ($v, $k, $V,) = @_; return "NULL" unless defined $V; # return $pcache{$k.$V} if $pcache{$k.$V}; my $p; if ("$V" =~ /^[-\d.]+(e[-+]?\d+)?$/) { $p = "$V"; if (int($p) == $p) { $p = sprintf "%i", $p; } if ($p =~ /\.(\d*9999+)\d*(e-?\d+)?/) { my $o = "0." . ('0' x (length($1)-1)) ."1".(defined $2 ? $2 : ""); #warn "CORR: $p => $o\n"; my $k = $p+$o; $k = "$k"; if ($k =~ /(\.\d*[1-9])0000\d*(e-?\d+)?$/) { $p = $k; } } $p =~ s/(\.\d*[1-9])0000\d*(e-?\d+)?$/$1/; $p .= $2 if defined $2; # if ($id) { # $p .= " (".&pretty("$id:$v").")"; # } } unless (defined $p) { $p = escapeHTML($V); # if ($ctx) { # $p = "'$p'"; # } } $pcache{$k.$V} = $p; return $p; }