#! perl -w use strict; my $ScreenSaverTimeout = 15 * 60; my $google_reader_hwnd = -1; sub classify { my $l = shift; my @flds = split(m/,\s*/, $l); my $process = $flds[4]; my $title = $flds[5]; if ($process =~ m!outlook!i) { return "email"; } if ($process =~ m!mlpod36|pidgin!i) { return "im"; } elsif ($process =~ m!thunderbird!i) { return "personal-email"; } elsif ($process =~ m!firefox!i) { if ($title =~ m!Albion hub|SVN::Web!i) { return "web-intranet"; } elsif ($title =~ m!ONYX|QA Defect|oepprod!i) { return "web-bugs"; } elsif ($title =~ m!Google Reader!i) { $google_reader_hwnd = $flds[2]; return "personal-web"; } elsif ($flds[2] == $google_reader_hwnd) { # we assume that anything in the same FF window # as google reader is also personal browsing return "personal-web"; } elsif ($title =~ m!you are viewing:.*(application|desktop)!i) { return "webex"; } else { return "web-other"; } } elsif ($process =~ m!albion|(pre|post)gui_|ansyswbu!i) { return "testing"; } elsif ($process =~ m!wish!i and $title =~ m!ansys!i) { return "testing"; } elsif ($process =~ m!mySuiteManager!i) { return "testing"; } elsif ($process =~ m!mshta!i and $title =~ m!TestBench!i) { return "testing"; } elsif ($process =~ m!Idle!) { return "idle"; } elsif ($process =~ m!devenv!i) { return "coding"; } elsif ($process =~ m!bash|cmd|putty!i) { return "other-shell"; } elsif ($process =~ m!xemacs|notepad2?!i) { return "other-editing"; } elsif ($process =~ m!powerpnt|winword!i) { return "documents"; } elsif ($process =~ m!explorer!i) { # known other -- don't print a warning, but # there's no sensible category for it. return "other"; } else { # unknown other, maybe we need to do add # something to the table. print "other: ", $l; return "other"; } } # red => communication # blue => real work # green => personal my %colors = ( email => 'ff0000', webex => 'ff7777', im => 'ff9999', 'web-bugs' => 'ff77aa', 'web-other' => 'ff9900', 'web-intranet' => 'ff7799', 'personal-email' => '99ff00', 'personal-web' => '00ff00', coding => '0000ff', testing => '9900ff', 'other-shell' => '0099ff', 'other-editing' => '4499ff', 'other' => '9944ff', 'documents' => '000000', ); open FILE, ">chart.html" or die $!; open ACTIVITY, ">activity.xhtml" or die $!; my $GraphWidth = 800; print ACTIVITY <<"EOF"; activity chart

activity chart

EOF my $GraphRow = 0; my $GraphRowHeight = 40; my %totals; my %day_totals; my $prev_class; my $prev_time; my $today = "foobar"; while (defined (my $l = <>)) { my @flds = split(m/,\s*/, $l); (my $date = $flds[0]) =~ s! .*!!; if ($date ne $today) { # new day if (keys %day_totals) { write_graph($today, %day_totals); } %day_totals = (); $today = $date; $GraphRow += $GraphRowHeight + 5; } my @timeflds = split(":", $flds[1]); if ($timeflds[0] =~ m!\.!) { # "3.00:00:00" is three days my @dayshours = split(m/\./, $timeflds[0]); $timeflds[0] = $dayshours[0] * 24 + $dayshours[1]; } my $time = $timeflds[0] * 60 * 60 + $timeflds[1] * 60 + $timeflds[2]; my $class = classify($l); #print $class, ", ", $l; $totals{$class} += $time; $day_totals{$class} += $time; my @nowflds = split(m/[ :]/, $flds[0]); my $tod = $nowflds[1] * 60 * 60 + $nowflds[2] * 60 + $nowflds[3]; if ($class ne 'idle') { my $daylen = 24 * 60 * 60; #print "$tod +$time $class\n"; my $startx = $tod * $GraphWidth / $daylen; my $xwid = $time * $GraphWidth / $daylen; my $color = $colors{$class}; die "no colour for $class" unless defined $color; print ACTIVITY qq( \n); } # if we've just gone idle, and the previous task was active # for more than the screensaver timeout, we assume that the # screensaver enabled automatically rather than the user # locking the workstation immediately after 15 minutes doing # the same thing. It's a heuristic, but will be more often # right than wrong. if ($class eq 'idle' and $prev_time > $ScreenSaverTimeout) { print "ripping " . $ScreenSaverTimeout . " from " . $prev_class . "\n"; $totals{$prev_class} = $totals{$prev_class} - $ScreenSaverTimeout; if (not exists $day_totals{$prev_class}) { print "Screensaver started after application idle over midnight, not adjusted\n"; } else { $day_totals{$prev_class} = $day_totals{$prev_class} - $ScreenSaverTimeout; } } $prev_class = $class; $prev_time = $time; } # the last day won't have been written out write_graph($today, %day_totals); for my $class (sort { $totals{$a} <=> $totals{$b} } keys %totals) { print "$class: ", int($totals{$class} / 60), " minutes\n"; } write_graph("Overall", %totals); close FILE; print ACTIVITY <<"EOF"; EOF close ACTIVITY; sub write_graph { my $title = shift; my %totals = @_; my $total = 0; my $non_personal = 0; for my $class (keys %totals) { if ($class ne 'idle') { $total += $totals{$class}; if ($class !~ m!personal!) { $non_personal += $totals{$class}; } } } my @data; my @labels; my @colors; for my $class (sort keys %totals) { if ($class ne 'idle') { push @data, int(($totals{$class} * 100) / $total); push @labels, $class; push @colors, defined $colors{$class} ? $colors{$class} : '000000'; } } my $url = 'http://chart.apis.google.com/chart?cht=p&chd=t:' . join(',', @data) . '&chl=' . join('|', @labels) . '&chco=' . join(',', @colors) . '&chs=300x150'; $url =~ s!\&!\&!g; my $total_fmt = format_secs($total); my $nonp_fmt = format_secs($non_personal); print FILE qq(

$title

Total time $total_fmt; non-personal $nonp_fmt

); } sub format_secs { my $total = shift; my $hrs = int($total / ( 60 * 60 )); my $min = int($total / 60 - $hrs * 60); return "${hrs}h ${min}m"; }